From dee6b40277c457f63628ae174d7b6cb51d9e9b1d Mon Sep 17 00:00:00 2001 From: wu hao <15392746632@qq.com> Date: Sat, 1 May 2021 12:57:46 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/api_v1/api.py | 11 ++- api/api_v1/endpoints/dashboard.py | 126 ------------------------------ api/api_v1/endpoints/login.py | 93 ---------------------- api/api_v1/endpoints/project.py | 46 ----------- api/api_v1/endpoints/user.py | 64 +++++++++++++++ api/deps.py | 80 +------------------ core/config.py | 14 ++-- core/security.py | 1 - crud/__init__.py | 5 -- crud/base.py | 78 ++---------------- crud/crud_item.py | 34 -------- crud/crud_user.py | 58 +++++--------- crud/curd_authority.py | 85 -------------------- crud/curd_dashboard.py | 28 ------- crud/curd_folder.py | 27 ------- crud/curd_project.py | 35 --------- crud/curd_space.py | 23 ------ db/__init__.py | 2 + db/base.py | 1 - db/base_class.py | 14 ---- db/init_db.py | 24 ++++-- db/mongodb.py | 14 ++++ db/mongodb_utils.py | 12 +++ db/session.py | 7 -- initial_data.py | 2 +- main.py | 21 +++-- models/__init__.py | 1 - models/authority.py | 21 ----- models/dashboard.py | 19 ----- models/folders.py | 15 ---- models/project.py | 18 ----- models/space.py | 22 ------ models/user.py | 13 --- schemas/__init__.py | 11 +-- schemas/authority.py | 38 --------- schemas/base.py | 22 ++++++ schemas/dashboard.py | 42 ---------- schemas/folders.py | 35 --------- schemas/msg.py | 5 -- schemas/project.py | 27 ------- schemas/space.py | 35 --------- schemas/token.py | 3 +- schemas/tree.py | 9 --- schemas/user.py | 36 ++++----- 44 files changed, 203 insertions(+), 1074 deletions(-) delete mode 100644 api/api_v1/endpoints/dashboard.py delete mode 100644 api/api_v1/endpoints/login.py create mode 100644 api/api_v1/endpoints/user.py delete mode 100644 crud/crud_item.py delete mode 100644 crud/curd_authority.py delete mode 100644 crud/curd_dashboard.py delete mode 100644 crud/curd_folder.py delete mode 100644 crud/curd_project.py delete mode 100644 crud/curd_space.py delete mode 100644 db/base.py delete mode 100644 db/base_class.py create mode 100644 db/mongodb.py create mode 100644 db/mongodb_utils.py delete mode 100644 db/session.py delete mode 100644 models/__init__.py delete mode 100644 models/authority.py delete mode 100644 models/dashboard.py delete mode 100644 models/folders.py delete mode 100644 models/project.py delete mode 100644 models/space.py delete mode 100644 models/user.py delete mode 100644 schemas/authority.py create mode 100644 schemas/base.py delete mode 100644 schemas/dashboard.py delete mode 100644 schemas/folders.py delete mode 100644 schemas/msg.py delete mode 100644 schemas/project.py delete mode 100644 schemas/space.py delete mode 100644 schemas/tree.py diff --git a/api/api_v1/api.py b/api/api_v1/api.py index 904778d..f626bb5 100644 --- a/api/api_v1/api.py +++ b/api/api_v1/api.py @@ -1,10 +1,9 @@ from fastapi import APIRouter -from api.api_v1.endpoints import login -from api.api_v1.endpoints import project -from api.api_v1.endpoints import dashboard +from api.api_v1.endpoints import user + + api_router = APIRouter() -api_router.include_router(login.router, tags=["登录接口"], prefix='/user') -api_router.include_router(project.router, tags=["项目管理"], prefix='/project') -api_router.include_router(dashboard.router, tags=["看板管理"], prefix='/dashboard') +api_router.include_router(user.router, tags=["登录接口"], prefix='/user') + diff --git a/api/api_v1/endpoints/dashboard.py b/api/api_v1/endpoints/dashboard.py deleted file mode 100644 index 7c2d5aa..0000000 --- a/api/api_v1/endpoints/dashboard.py +++ /dev/null @@ -1,126 +0,0 @@ -from typing import Any, List - -from fastapi import APIRouter, Body, Depends, HTTPException, Request -from sqlalchemy.orm import Session - -import crud, models, schemas -from api import deps - -router = APIRouter() - - -@router.get('/') -def read_dashboard(project_id: int = Depends(deps.check_project), - db: Session = Depends(deps.get_db), - current_user: models.User = Depends(deps.get_current_active_user) - ): - dashboard = crud.authority.get_my_dashboard(db=db, project_id=project_id, user_id=current_user.id) - return dashboard - - -# 新建看板 -@router.post("/create-dashboard") -def create_dashboard(dashboard_in: schemas.DashboardIn, - db: Session = Depends(deps.get_db), - current_user: models.User = Depends(deps.get_current_active_user)) -> Any: - user_id = current_user.id - tree = deps.check_tree(db=db, **dashboard_in.dict(), user_id=user_id) - dashboard = crud.dashboard.create_with_dashboard(db=db, obj_in=schemas.DashboardCreate(**dashboard_in.dict()), - user_id=current_user.id, - ) - - # 自己创建的拥有权限 - crud.authority.create_with_authority(db=db, obj_in=schemas.AuthorityCreate( - dashboard_id=dashboard.id, - project_id=tree.project_id, - authority='rw', - space_id=tree.space_id, - folder_id=tree.folder_id - ), user_id=user_id) - - return {"msg": "新建成功", 'code': 0} - - -# 删除看板 -@router.post("/delete-dashboard") -def create_dashboard(dashboard_del: schemas.DashboardDelete, - db: Session = Depends(deps.get_db), - current_user: models.User = Depends(deps.get_current_active_user)) -> Any: - """ - 只能删除自己创建的 会级联删除权限表 - :param dashboard_del: - :param db: - :param current_user: - :return: - """ - user_id = current_user.id - dashboard = crud.dashboard.delete_my(db, id=dashboard_del.id, user_id=user_id) - - - return {"msg": "删除成功", 'code': 0, 'data': dashboard} - - -@router.post("/create-folder") -def create_folder(folder_in: schemas.FolderIn, - db: Session = Depends(deps.get_db), - current_user: models.User = Depends(deps.get_current_active_user)) -> Any: - user_id = current_user.id - tree = deps.check_tree(db, **folder_in.dict(), user_id=user_id) - folder = crud.folder.create_with_folder(db=db, obj_in=schemas.FolderCreate(**folder_in.dict()), - user_id=current_user.id) - # 自己创建的拥有权限 - crud.authority.create_with_authority(db=db, obj_in=schemas.AuthorityCreate( - project_id=tree.project_id, - authority='rw', - space_id=tree.space_id, - folder_id=folder.id - ), user_id=user_id) - return {"msg": "新建成功", 'code': 0} - - -# 删除文件夹 -@router.post("/delete-folder") -def delete_folder(folder_del: schemas.FolderDelete, - db: Session = Depends(deps.get_db), - current_user: models.User = Depends(deps.get_current_active_user)) -> Any: - """ - 只能删除自己创建的 会级联删除权限表 - :param dashboard_del: - :param db: - :param current_user: - :return: - """ - user_id = current_user.id - folder = crud.folder.delete_my(db, id=folder_del.id, user_id=user_id) - - return {"msg": "删除成功", 'code': 0, 'data': folder} - - -@router.post("/create-space") -def create_space(space_in: schemas.SpaceIn, - db: Session = Depends(deps.get_db), - current_user: models.User = Depends(deps.get_current_active_user)) -> Any: - user_id = current_user.id - tree = deps.check_tree(db, **space_in.dict(), user_id=user_id) - space = crud.space.create_with_space(db=db, obj_in=schemas.SpaceCreate(**space_in.dict()), user_id=user_id) - # 自己创建的拥有权限 - crud.authority.create_with_authority(db=db, obj_in=schemas.AuthorityCreate( - project_id=tree.project_id, - authority='rw', - space_id=space.id, - ), user_id=current_user.id) - return {"msg": "新建成功", 'code': 0} - - -# 删除文件夹 -@router.post("/delete-space") -def delete_space(space_del: schemas.SpaceDelete, - db: Session = Depends(deps.get_db), - current_user: models.User = Depends(deps.get_current_active_user)) -> Any: - """ - 只能删除自己创建的 会级联删除权限表 - """ - user_id = current_user.id - space = crud.space.delete_my(db, id=space_del.id, user_id=user_id) - - return {"msg": "删除成功", 'code': 0, 'data': space} diff --git a/api/api_v1/endpoints/login.py b/api/api_v1/endpoints/login.py deleted file mode 100644 index 0b98030..0000000 --- a/api/api_v1/endpoints/login.py +++ /dev/null @@ -1,93 +0,0 @@ -import json -from datetime import timedelta -from typing import Any - -from fastapi import APIRouter, Body, Depends, HTTPException, Request -from fastapi.security import OAuth2PasswordRequestForm -from sqlalchemy.orm import Session - -import crud, models, schemas -from api import deps -from core import security -from core.config import settings -from core.security import get_password_hash -from utils import ( - verify_password_reset_token, -) - -router = APIRouter() - - -@router.post("/login") -def login( - # data: schemas.UserLogin, - data: OAuth2PasswordRequestForm = Depends(), - db: Session = Depends(deps.get_db), -) -> Any: - """ - OAuth2兼容令牌登录,获取将来令牌的访问令牌 - """ - user = crud.user.authenticate( - db, name=data.username, password=data.password - ) - if not user: - raise HTTPException(status_code=400, detail="Incorrect name or password") - elif not crud.user.is_active(user): - raise HTTPException(status_code=400, detail="Inactive user") - access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) - - return { - 'data': { - 'name': user.name, - 'email': user.email, - 'access_token': security.create_access_token( - expires_delta=access_token_expires, id=user.id, email=user.email, is_active=user.is_active, - is_superuser=user.is_superuser, name=user.name - ), - "token_type": "bearer", - - }, - 'access_token': security.create_access_token( - expires_delta=access_token_expires, id=user.id, email=user.email, is_active=user.is_active, - is_superuser=user.is_superuser, name=user.name - ), - "token_type": "bearer", - - 'code': 0, - 'msg': 'success', - } - - -@router.get("/me", response_model=schemas.UserDBBase) -def me(current_user: models.User = Depends(deps.get_current_active_user)) -> Any: - """ - Test access token - """ - return current_user - - -@router.post("/reset-password", response_model=schemas.Msg) -def reset_password( - token: str = Body(...), - new_password: str = Body(...), - db: Session = Depends(deps.get_db), -) -> Any: - """ - 重设密码 - """ - user_id = verify_password_reset_token(token) - if not user_id: - raise HTTPException(status_code=400, detail="Invalid token") - user = crud.user.get(db, user_id) - if not user: - raise HTTPException( - status_code=404, - detail="The user with this username does not exist in the system.", - ) - elif not crud.user.is_active(user): - raise HTTPException(status_code=400, detail="Inactive user") - hashed_password = get_password_hash(new_password) - user.hashed_password = hashed_password - db.add(user) - db.commit() - return {"msg": "Password updated successfully"} diff --git a/api/api_v1/endpoints/project.py b/api/api_v1/endpoints/project.py index 74de0fc..e69de29 100644 --- a/api/api_v1/endpoints/project.py +++ b/api/api_v1/endpoints/project.py @@ -1,46 +0,0 @@ -from datetime import timedelta -from typing import Any, List - -from fastapi import APIRouter, Body, Depends, HTTPException, Request -from sqlalchemy.orm import Session - -import crud, models, schemas -from api import deps - -router = APIRouter() - - -@router.get("/", response_model=List[schemas.Project]) -def read_project(db: Session = Depends(deps.get_db), - current_user: models.User = Depends(deps.get_current_active_user) - ) -> Any: - my_project = crud.project.get_my_project(db=db, user_id=current_user.id) - - return my_project - - -@router.post("/create-project", response_model=schemas.Project) -def create_project(project_in: schemas.ProjectCreate, db: Session = Depends(deps.get_db), - current_user: models.User = Depends(deps.get_current_active_superuser) - ) -> Any: - project = crud.project.create_with_project(db=db, obj_in=project_in, user_id=current_user.id) - # 我的看板 新建 未分组 和 共享给我的 文件夹 - unknown_folder = schemas.FolderCreate( - user_id=current_user.id, - name='未分组的' - ) - share_folder = schemas.FolderCreate( - user_id=current_user.id, - name='共享给我的' - ) - folder1 = crud.folder.create_with_folder(db=db, obj_in=unknown_folder, user_id=current_user.id, ) - folder2 = crud.folder.create_with_folder(db=db, obj_in=share_folder, user_id=current_user.id) - - # 拥有这俩个文件夹权限 - authority1 = schemas.AuthorityCreate(project_id=project.id, authority='rw', folder_id=folder1.id) - authority2 = schemas.AuthorityCreate(project_id=project.id, authority='rw', folder_id=folder2.id) - - crud.authority.create_with_authority(db=db, obj_in=authority1, user_id=current_user.id) - crud.authority.create_with_authority(db=db, obj_in=authority2, user_id=current_user.id) - - return project diff --git a/api/api_v1/endpoints/user.py b/api/api_v1/endpoints/user.py new file mode 100644 index 0000000..26951db --- /dev/null +++ b/api/api_v1/endpoints/user.py @@ -0,0 +1,64 @@ +from datetime import timedelta +from typing import Any + +from fastapi import APIRouter, Body, Depends, HTTPException, Request +from fastapi.security import OAuth2PasswordRequestForm +from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase + +import crud, schemas +from api import deps +from core import security +from core.config import settings +from core.security import get_password_hash +from db import get_database +from utils import ( + verify_password_reset_token, +) + +router = APIRouter() + + +@router.post("/login") +async def login( + # data: schemas.UserLogin, + data: OAuth2PasswordRequestForm = Depends(), + db: AsyncIOMotorDatabase = Depends(get_database) +) -> dict: + """ + OAuth2兼容令牌登录,获取将来令牌的访问令牌 + """ + user = await crud.user.authenticate(db, + name=data.username, password=data.password + ) + if not user: + raise HTTPException(status_code=400, detail="Incorrect name or password") + access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) + + return { + 'data': { + 'name': user.name, + 'email': user.email, + # 'access_token': security.create_access_token( + # expires_delta=access_token_expires, id=user.id, email=user.email, is_active=user.is_active, + # is_superuser=user.is_superuser, name=user.name + # ), + # "token_type": "bearer", + + }, + 'access_token': security.create_access_token( + expires_delta=access_token_expires, _id=str(user.id), email=user.email, + is_superuser=user.is_superuser, name=user.name + ), + "token_type": "bearer", + + 'code': 0, + 'msg': 'success', + } + + +@router.get("/me", response_model=schemas.User) +def me(current_user: schemas.User = Depends(deps.get_current_user)) -> Any: + """ + Test access token + """ + return current_user diff --git a/api/deps.py b/api/deps.py index a75a379..168b3dc 100644 --- a/api/deps.py +++ b/api/deps.py @@ -1,40 +1,26 @@ -import json -from typing import Generator - from fastapi import Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer from jose import jwt from pydantic import ValidationError -from sqlalchemy.orm import Session -import crud, models, schemas +import schemas from core import security from core.config import settings -from db.session import SessionLocal -from models.authority import Authority reusable_oauth2 = OAuth2PasswordBearer( - tokenUrl=f"{settings.API_V1_STR}/user/login/" + tokenUrl=f"{settings.API_V1_STR}/user/login" ) -def get_db() -> Generator: - try: - db = SessionLocal() - yield db - finally: - db.close() - - def get_current_user(token: str = Depends(reusable_oauth2) - ) -> schemas.UserDBBase: + ) -> schemas.UserDB: # def get_current_user(token: str # ) -> schemas.UserDBBase: try: payload = jwt.decode( token, settings.SECRET_KEY, algorithms=[security.ALGORITHM] ) - user = schemas.UserDBBase(**payload) + user = schemas.UserDB(**payload) except (jwt.JWTError, ValidationError): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, @@ -43,61 +29,3 @@ def get_current_user(token: str = Depends(reusable_oauth2) if not user: raise HTTPException(status_code=404, detail="User not found") return user - - -def get_current_active_user( - current_user: models.User = Depends(get_current_user), -) -> models.User: - if not crud.user.is_active(current_user): - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -def get_current_active_superuser( - current_user: models.User = Depends(get_current_user), -) -> models.User: - if not crud.user.is_superuser(current_user): - raise HTTPException( - status_code=400, detail="The user doesn't have enough privileges" - ) - return current_user - - -def check_project(project_id: int, db: Session = Depends(get_db)): - if not crud.project.get(db, id=project_id): - raise HTTPException(status_code=404, detail="没有这个项目") - return project_id - - -def check_tree(db, *, project_id: int, - user_id: int, - space_id: int = None, - folder_id: int = None, - dashboard_id: int = None, - **kwargs - ) -> schemas.Tree: - - - - where = [ - Authority.project_id == project_id, - Authority.user_id == user_id - ] - - if space_id is not None: - where.append(Authority.space_id == space_id) - - if folder_id is not None: - where.append(Authority.folder_id == folder_id) - - if dashboard_id is not None: - where.append(Authority.dashboard_id == dashboard_id) - - if not db.query(Authority).filter(*where).first(): - raise HTTPException(status_code=406, detail='请检查参数') - - return schemas.Tree(project_id=project_id, - space_id=space_id, - folder_id=folder_id, - dashboard_id=dashboard_id - ) diff --git a/core/config.py b/core/config.py index 26627b3..3c64c34 100644 --- a/core/config.py +++ b/core/config.py @@ -7,17 +7,15 @@ class Settings(BaseSettings): PROJECT_NAME: str = 'X数据分析后台' API_V1_STR: str = '/api/v1' - ALLOW_ANONYMOUS: tuple = ('login','openapi.json') - BACKEND_CORS_ORIGINS: List[str] = ['*'] - MYSQL_HOST: str = '127.0.0.1' - MYSQL_PORT: int = 3306 - MYSQL_USER: str = 'root' - MYSQL_PASSWORD: str = 'root' - MYSQL_DB: str = 'xdata' + MDB_HOST: str = '10.0.0.7' + MDB_PORT: int = 27017 + MDB_USER: str = 'root' + MDB_PASSWORD: str = 'iamciniao' + MDB_DB: str = 'xdata' - SQLALCHEMY_DATABASE_URI = f'mysql+pymysql://{MYSQL_USER}:{MYSQL_PASSWORD}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DB}' + DATABASE_URI = f'mongodb://{MDB_USER}:{MDB_PASSWORD}@{MDB_HOST}:{MDB_PORT}/admin' FIRST_EMAIL: str = '15392746632@qq.com' FIRST_SUPERUSER_PASSWORD: str = '123456' diff --git a/core/security.py b/core/security.py index de9d365..bd16324 100644 --- a/core/security.py +++ b/core/security.py @@ -1,5 +1,4 @@ from datetime import datetime, timedelta -from typing import Any, Union from jose import jwt from passlib.context import CryptContext diff --git a/crud/__init__.py b/crud/__init__.py index b49ff09..64aec81 100644 --- a/crud/__init__.py +++ b/crud/__init__.py @@ -1,6 +1 @@ from .crud_user import user -from .curd_project import project -from .curd_folder import folder -from .curd_dashboard import dashboard -from .curd_space import space -from .curd_authority import authority diff --git a/crud/base.py b/crud/base.py index 763c2da..21a917c 100644 --- a/crud/base.py +++ b/crud/base.py @@ -1,75 +1,9 @@ -from typing import Any, Dict, Generic, List, Optional, Type, TypeVar, Union - -from fastapi import HTTPException -from fastapi.encoders import jsonable_encoder -from pydantic import BaseModel -from sqlalchemy.orm import Session - -from db.base_class import Base - -ModelType = TypeVar("ModelType", bound=Base) -CreateSchemaType = TypeVar("CreateSchemaType", bound=BaseModel) -UpdateSchemaType = TypeVar("UpdateSchemaType", bound=BaseModel) +from bson import ObjectId -class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]): - def __init__(self, model: Type[ModelType]): - """ - CRUD object with default methods to Create, Read, Update, Delete (CRUD). +class CRUDBase: + def __init__(self, coll_name): + self.coll_name = coll_name - **Parameters** - - * `model`: A SQLAlchemy model class - * `schema`: A Pydantic model (schema) class - """ - self.model = model - - def get(self, db: Session, id: Any) -> Optional[ModelType]: - return db.query(self.model).filter(self.model.id == id).first() - - def get_multi( - self, db: Session, *, skip: int = 0, limit: int = 100 - ) -> List[ModelType]: - return db.query(self.model).offset(skip).limit(limit).all() - - def create(self, db: Session, *, obj_in: CreateSchemaType) -> ModelType: - obj_in_data = jsonable_encoder(obj_in) - db_obj = self.model(**obj_in_data) # type: ignore - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj - - def update( - self, - db: Session, - *, - db_obj: ModelType, - obj_in: Union[UpdateSchemaType, Dict[str, Any]] - ) -> ModelType: - obj_data = jsonable_encoder(db_obj) - if isinstance(obj_in, dict): - update_data = obj_in - else: - update_data = obj_in.dict(exclude_unset=True) - for field in obj_data: - if field in update_data: - setattr(db_obj, field, update_data[field]) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj - - def remove(self, db: Session, *, id: int) -> ModelType: - obj = db.query(self.model).get(id) - db.delete(obj) - db.commit() - return obj - - def delete_my(self, db: Session, *, id: int, user_id: int) -> ModelType: - obj = db.query(self.model).filter(self.model.id == id, self.model.user_id == user_id).first() - if not obj: - raise HTTPException(status_code=406, detail='找不到你要删除的') - db.delete(obj) - db.commit() - return obj + async def get(self, coll, id: ObjectId): + return await coll.find_one({'_id': id}) diff --git a/crud/crud_item.py b/crud/crud_item.py deleted file mode 100644 index dcb87cd..0000000 --- a/crud/crud_item.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import List - -from fastapi.encoders import jsonable_encoder -from sqlalchemy.orm import Session - -from app.crud.base import CRUDBase -from app.models.item import Item -from app.schemas.item import ItemCreate, ItemUpdate - - -class CRUDItem(CRUDBase[Item, ItemCreate, ItemUpdate]): - def create_with_owner( - self, db: Session, *, obj_in: ItemCreate, owner_id: int - ) -> Item: - obj_in_data = jsonable_encoder(obj_in) - db_obj = self.model(**obj_in_data, owner_id=owner_id) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj - - def get_multi_by_owner( - self, db: Session, *, owner_id: int, skip: int = 0, limit: int = 100 - ) -> List[Item]: - return ( - db.query(self.model) - .filter(Item.owner_id == owner_id) - .offset(skip) - .limit(limit) - .all() - ) - - -item = CRUDItem(Item) diff --git a/crud/crud_user.py b/crud/crud_user.py index 90a9b46..3c0a5e0 100644 --- a/crud/crud_user.py +++ b/crud/crud_user.py @@ -1,55 +1,37 @@ -from typing import Any, Dict, Optional, Union - -from sqlalchemy.orm import Session +from motor.motor_asyncio import AsyncIOMotorDatabase from core.security import get_password_hash, verify_password from crud.base import CRUDBase -from models.user import User -from schemas.user import UserCreate, UserUpdate +from schemas import UserCreate, UserDBRW + +__all__ = 'user', -class CRUDUser(CRUDBase[User, UserCreate, UserUpdate]): - def get_by_user(self, db: Session, *, name: str) -> Optional[User]: - return db.query(User).filter(User.name == name).first() +class CRUDUser(CRUDBase): - def create(self, db: Session, *, obj_in: UserCreate) -> User: - db_obj = User( + async def get_by_user(self, db: AsyncIOMotorDatabase, name: str): + res = await db[self.coll_name].find_one({'name': name}) + return res + + async def create(self, db: AsyncIOMotorDatabase, obj_in: UserCreate): + db_obj = UserDBRW( email=obj_in.email, hashed_password=get_password_hash(obj_in.password), name=obj_in.name, is_superuser=obj_in.is_superuser, ) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj + return await db[self.coll_name].insert_one(db_obj.dict(skip_defaults=True)) - def update( - self, db: Session, *, db_obj: User, obj_in: Union[UserUpdate, Dict[str, Any]] - ) -> User: - if isinstance(obj_in, dict): - update_data = obj_in - else: - update_data = obj_in.dict(exclude_unset=True) - if update_data["password"]: - hashed_password = get_password_hash(update_data["password"]) - del update_data["password"] - update_data["hashed_password"] = hashed_password - return super().update(db, db_obj=db_obj, obj_in=update_data) - - def authenticate(self, db: Session, *, name: str, password: str) -> Optional[User]: - user = self.get_by_user(db, name=name) - if not user: + async def authenticate(self, db: AsyncIOMotorDatabase, name: str, password: str): + user_obj = UserDBRW(**await self.get_by_user(db, name=name)) + if not user_obj: return None - if not verify_password(password, user.hashed_password): + if not verify_password(password, user_obj.hashed_password): return None - return user + return user_obj - def is_active(self, user: User) -> bool: - return user.is_active - - def is_superuser(self, user: User) -> bool: - return user.is_superuser + async def create_index(self, db: AsyncIOMotorDatabase): + await db[self.coll_name].create_index('username', unique=True) -user = CRUDUser(User) +user = CRUDUser('user') diff --git a/crud/curd_authority.py b/crud/curd_authority.py deleted file mode 100644 index 0b28c60..0000000 --- a/crud/curd_authority.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, Dict, Optional, Union - -from fastapi.encoders import jsonable_encoder -from sqlalchemy.orm import Session - -from crud.base import CRUDBase -from models.authority import Authority -from schemas import AuthorityCreate, AuthorityUpdate - - -class CRUDAuthority(CRUDBase[Authority, AuthorityCreate, AuthorityUpdate]): - def create_with_authority( - self, db: Session, *, obj_in: AuthorityCreate, user_id: int - ) -> Authority: - obj_in_data = jsonable_encoder(obj_in) - - db_obj = self.model(**obj_in_data, user_id=user_id) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj - - def get_my_dashboard(self, db: Session, project_id: int, user_id: int): - dashboards = db.query(Authority).filter(Authority.project_id == project_id, Authority.user_id == user_id).all() - res = {'kanban': dict(), 'space': dict()} - for item in dashboards: - # 是空间的 - dashboard = item.dashboard - folder = item.folder - space = item.space - if space: - s = res['space'].setdefault(space.id, {'dashboard': [], 'folder': {}}) - s['name'] = space.name - s['id'] = space.id - if folder: - f = s['folder'].setdefault(folder.id, {'dashboard': []}) - f['name'] = folder.name - f['id'] = folder.id - if dashboard: - f['dashboard'].append({ - 'name': dashboard.name, - 'id': dashboard.id - }) - elif dashboard: - d = s['dashboard'] - d.append({ - 'name': dashboard.name, - 'id': dashboard.id - }) - - else: - # 是看板的文件夹 - folder = item.folder - f = res['kanban'].setdefault(folder.id, {'dashboard': []}) - f['name'] = folder.name - f['id'] = folder.id - if dashboard: - f['dashboard'].append({ - 'name': dashboard.name, - 'id': dashboard.id - }) - return res - - def delete(self, db: Session, user_id: int, project_id: int = None, folder_id: int = None, space_id: int = None, - dashboard_id: int = None): - where = [ - Authority.user_id == user_id - ] - if project_id is not None: - where.append(Authority.project_id == project_id) - - if space_id is not None: - where.append(Authority.space_id == space_id) - - if folder_id is not None: - where.append(Authority.folder_id == folder_id) - - if dashboard_id is not None: - where.append(Authority.dashboard_id == dashboard_id) - - if not db.query(Authority).filter(*where).delete(): - return - - -authority = CRUDAuthority(Authority) diff --git a/crud/curd_dashboard.py b/crud/curd_dashboard.py deleted file mode 100644 index 16a46d2..0000000 --- a/crud/curd_dashboard.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Any, Dict, Optional, Union - -from fastapi import HTTPException -from fastapi.encoders import jsonable_encoder -from sqlalchemy.orm import Session - -from crud.base import CRUDBase -from models.authority import Authority -from models.dashboard import Dashboard -from models.folders import Folder -from models.space import Space -from schemas import DashboardCreate, DashboardUpdate - - -class CRUDDashboard(CRUDBase[Dashboard, DashboardCreate, DashboardUpdate]): - def create_with_dashboard( - self, db: Session, *, obj_in: DashboardCreate, user_id: int - ) -> Dashboard: - obj_in_data = jsonable_encoder(obj_in) - db_obj = self.model(**obj_in_data, user_id=user_id) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj - - - -dashboard = CRUDDashboard(Dashboard) diff --git a/crud/curd_folder.py b/crud/curd_folder.py deleted file mode 100644 index 04c1336..0000000 --- a/crud/curd_folder.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Any, Dict, Optional, Union - -from fastapi import HTTPException -from fastapi.encoders import jsonable_encoder -from sqlalchemy.orm import Session - -from crud.base import CRUDBase -from models.folders import Folder -from schemas import FolderUpdate, FolderCreate - - -class CRUDFolder(CRUDBase[Folder, FolderCreate, FolderUpdate]): - def create_with_folder( - self, db: Session, *, obj_in: FolderCreate, user_id: int - ) -> Folder: - obj_in_data = jsonable_encoder(obj_in) - db_obj = self.model(**obj_in_data, user_id=user_id) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj - - - - - -folder = CRUDFolder(Folder) diff --git a/crud/curd_project.py b/crud/curd_project.py deleted file mode 100644 index 5acd838..0000000 --- a/crud/curd_project.py +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Any, Dict, Optional, Union - -from fastapi import HTTPException -from fastapi.encoders import jsonable_encoder -from sqlalchemy.orm import Session - -from crud.base import CRUDBase -from models.authority import Authority - -from models.project import Project - -from schemas.project import ProjectCreate, ProjectUpdate - - -class CRUDProject(CRUDBase[Project, ProjectCreate, ProjectUpdate]): - def create_with_project( - self, db: Session, *, obj_in: ProjectCreate, user_id: int - ) -> Project: - if db.query(self.model).filter(self.model.name == obj_in.name).first(): - raise HTTPException(status_code=406, detail="项目名已存在") - - obj_in_data = jsonable_encoder(obj_in) - db_obj = Project(**obj_in_data, user_id=user_id) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj - - def get_my_project( - self, db: Session, *, user_id: int - ) -> Project: - return db.query(self.model).join(Authority).filter(Authority.user_id == user_id).all() - - -project = CRUDProject(Project) diff --git a/crud/curd_space.py b/crud/curd_space.py deleted file mode 100644 index 91e95d2..0000000 --- a/crud/curd_space.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Any, Dict, Optional, Union - -from fastapi.encoders import jsonable_encoder -from sqlalchemy.orm import Session - -from crud.base import CRUDBase -from models.space import Space -from schemas import SpaceCreate, SpaceUpdate - - -class CRUDSpace(CRUDBase[Space, SpaceCreate, SpaceUpdate]): - def create_with_space( - self, db: Session, *, obj_in: SpaceCreate, user_id: int - ) -> Space: - obj_in_data = jsonable_encoder(obj_in) - db_obj = self.model(**obj_in_data, user_id=user_id) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj - - -space = CRUDSpace(Space) diff --git a/db/__init__.py b/db/__init__.py index e69de29..e300192 100644 --- a/db/__init__.py +++ b/db/__init__.py @@ -0,0 +1,2 @@ +from .mongodb_utils import * +from .mongodb import get_database diff --git a/db/base.py b/db/base.py deleted file mode 100644 index e8857cd..0000000 --- a/db/base.py +++ /dev/null @@ -1 +0,0 @@ -from .base_class import Base # noqa \ No newline at end of file diff --git a/db/base_class.py b/db/base_class.py deleted file mode 100644 index 0b94d5c..0000000 --- a/db/base_class.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Any - -from sqlalchemy.ext.declarative import as_declarative, declared_attr - - -@as_declarative() -class Base: - id: Any - __name__: str - - # 自动生成表名 - @declared_attr - def __tablename__(cls) -> str: - return cls.__name__.lower() diff --git a/db/init_db.py b/db/init_db.py index 5097a85..de8b2dd 100644 --- a/db/init_db.py +++ b/db/init_db.py @@ -1,11 +1,16 @@ -from sqlalchemy.orm import Session -import crud, schemas +import crud +import schemas from core.config import settings -from db import base # noqa: F401 + +# 创建一个超级用户、、 +from db import connect_to_mongo, get_database + +connect_to_mongo() +db = get_database() -def init_db(db: Session) -> None: - user = crud.user.get_by_user(db, name=settings.FIRST_NAME) +async def create_superuser(): + user = await crud.user.get_by_user(db=db, name=settings.FIRST_NAME) if not user: user_in = schemas.UserCreate( name=settings.FIRST_NAME, @@ -13,4 +18,11 @@ def init_db(db: Session) -> None: password=settings.FIRST_SUPERUSER_PASSWORD, is_superuser=True, ) - user = crud.user.create(db, obj_in=user_in) # noqa: F841 + await crud.user.create(db, user_in) + await crud.user.create_index(db) + + +import asyncio + +loop = asyncio.get_event_loop() +loop.run_until_complete(create_superuser()) diff --git a/db/mongodb.py b/db/mongodb.py new file mode 100644 index 0000000..af9eace --- /dev/null +++ b/db/mongodb.py @@ -0,0 +1,14 @@ +from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase + +from core.config import settings + + +class DataBase: + client: AsyncIOMotorClient = None + + +db = DataBase() + + +def get_database() -> AsyncIOMotorDatabase: + return db.client[settings.MDB_DB] diff --git a/db/mongodb_utils.py b/db/mongodb_utils.py new file mode 100644 index 0000000..ce8c970 --- /dev/null +++ b/db/mongodb_utils.py @@ -0,0 +1,12 @@ +from motor.motor_asyncio import AsyncIOMotorClient + +from core.config import settings +from .mongodb import db + + +def connect_to_mongo(): + db.client = AsyncIOMotorClient(settings.DATABASE_URI) + + +def close_mongo_connection(): + db.client.close() diff --git a/db/session.py b/db/session.py deleted file mode 100644 index 4e2ceb6..0000000 --- a/db/session.py +++ /dev/null @@ -1,7 +0,0 @@ -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker - -from core.config import settings - -engine = create_engine(settings.SQLALCHEMY_DATABASE_URI, pool_pre_ping=True) -SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) diff --git a/initial_data.py b/initial_data.py index 7a02390..996f856 100644 --- a/initial_data.py +++ b/initial_data.py @@ -1,7 +1,7 @@ import logging from db.init_db import init_db -from db.session import SessionLocal +from db.mongodb_utils import SessionLocal logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) diff --git a/main.py b/main.py index ea45f4b..b5f50dd 100644 --- a/main.py +++ b/main.py @@ -1,17 +1,12 @@ -import time - import uvicorn -from fastapi import FastAPI, Request, Depends -from starlette.middleware.cors import CORSMiddleware -from fastapi.responses import JSONResponse -from api.api_v1.api import api_router -from api.deps import get_current_user +from fastapi import FastAPI + from core.config import settings +from starlette.middleware.cors import CORSMiddleware -app = FastAPI(title=settings.PROJECT_NAME, openapi_url=f"{settings.API_V1_STR}/openapi.json") +from db import connect_to_mongo, close_mongo_connection -allow_anonymous = [f'{settings.API_V1_STR}/{page}' for page in settings.ALLOW_ANONYMOUS] -allow_anonymous.extend(['/docs']) +app = FastAPI(title=settings.PROJECT_NAME) if settings.BACKEND_CORS_ORIGINS: app.add_middleware( @@ -21,8 +16,12 @@ if settings.BACKEND_CORS_ORIGINS: allow_methods=["*"], allow_headers=["*"], ) +app.add_event_handler("startup", connect_to_mongo) +app.add_event_handler("shutdown", close_mongo_connection) + +from api.api_v1.api import api_router app.include_router(api_router, prefix=settings.API_V1_STR) if __name__ == '__main__': - uvicorn.run(app='main:app', host="0.0.0.0", port=8888, reload=True, debug=True) + uvicorn.run(app='main:app', host="127.0.0.1", port=8889, reload=True, debug=True) diff --git a/models/__init__.py b/models/__init__.py deleted file mode 100644 index b7bb9be..0000000 --- a/models/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .user import User \ No newline at end of file diff --git a/models/authority.py b/models/authority.py deleted file mode 100644 index ea630d9..0000000 --- a/models/authority.py +++ /dev/null @@ -1,21 +0,0 @@ -import datetime - -from sqlalchemy import Boolean, Column, Integer, String, ForeignKey, DateTime, Enum -from sqlalchemy.orm import relationship, backref - -from db.base_class import Base - - -class Authority(Base): - id = Column(Integer, primary_key=True, index=True) - user_id = Column(Integer, ForeignKey('user.id')) - project_id = Column(Integer, ForeignKey('project.id')) - dashboard_id = Column(Integer, ForeignKey('dashboard.id')) - folder_id = Column(Integer, ForeignKey('folder.id')) - space_id = Column(Integer, ForeignKey('space.id')) - authority = Column(Enum('rw', 'r')) - create_date = Column(DateTime, default=datetime.datetime.now()) - - dashboard = relationship('Dashboard', backref="authority") - folder = relationship('Folder', backref="authority") - space = relationship('Space', backref="authority") diff --git a/models/dashboard.py b/models/dashboard.py deleted file mode 100644 index 36c126f..0000000 --- a/models/dashboard.py +++ /dev/null @@ -1,19 +0,0 @@ -import datetime - -from sqlalchemy import Boolean, Column, Integer, String, ForeignKey, DateTime -from sqlalchemy.orm import relationship, backref - -from db.base_class import Base -from models.authority import Authority - - -class Dashboard(Base): - id = Column(Integer, primary_key=True, index=True) - name = Column(String) - user_id = Column(Integer, ForeignKey('user.id')) - create_date = Column(DateTime, default=datetime.datetime.now()) - - - # authority = relationship('Authority', backref="dashboard",cascade="all,delete-orphan") - - # authority = relationship('Authority', backref=backref("dashboard", lazy="joined")) diff --git a/models/folders.py b/models/folders.py deleted file mode 100644 index dc2b5b5..0000000 --- a/models/folders.py +++ /dev/null @@ -1,15 +0,0 @@ -import datetime - -from sqlalchemy import Boolean, Column, Integer, String, ForeignKey, DateTime -from sqlalchemy.orm import relationship, backref - -from db.base_class import Base - - -class Folder(Base): - id = Column(Integer, primary_key=True, index=True) - name = Column(String) - user_id = Column(Integer, ForeignKey('user.id')) - create_date = Column(DateTime, default=datetime.datetime.now()) - - # authority = relationship('Authority', backref="folder", cascade="all, delete") diff --git a/models/project.py b/models/project.py deleted file mode 100644 index ccc4eee..0000000 --- a/models/project.py +++ /dev/null @@ -1,18 +0,0 @@ -import datetime -import uuid - -from sqlalchemy import Boolean, Column, Integer, String, ForeignKey, DateTime -from sqlalchemy.orm import relationship - -from db.base_class import Base - - -class Project(Base): - id = Column(Integer, primary_key=True, index=True) - app_id = Column(String, unique=True, default=uuid.uuid1().hex) - name = Column(String) - user_id = Column(Integer, ForeignKey('user.id')) - create_date = Column(DateTime, default=datetime.datetime.now()) - - # authority = relationship('Authority', backref="project", cascade="all, delete") - diff --git a/models/space.py b/models/space.py deleted file mode 100644 index 31b21a2..0000000 --- a/models/space.py +++ /dev/null @@ -1,22 +0,0 @@ -import datetime - -from sqlalchemy import Boolean, Column, Integer, String, ForeignKey, DateTime -from sqlalchemy.orm import relationship, backref - -from db.base_class import Base - - -class Space(Base): - id = Column(Integer, primary_key=True, index=True) - name = Column(String) - user_id = Column(Integer, ForeignKey('user.id')) - create_date = Column(DateTime, default=datetime.datetime.now()) - - # authority = relationship('Authority', backref="space", cascade="all, delete") - - - - # dashboard = relationship('Dashboard', backref=backref("space", lazy="joined")) - # folder = relationship('Folder', backref=backref("space", lazy="joined")) - - diff --git a/models/user.py b/models/user.py deleted file mode 100644 index 6ac184b..0000000 --- a/models/user.py +++ /dev/null @@ -1,13 +0,0 @@ -from sqlalchemy import Boolean, Column, Integer, String -from sqlalchemy.orm import relationship -from db.base_class import Base - - -class User(Base): - id = Column(Integer, primary_key=True, index=True) - name = Column(String, index=True) - email = Column(String, unique=True, index=True, nullable=False) - hashed_password = Column(String, nullable=False) - is_active = Column(Boolean(), default=True) - is_superuser = Column(Boolean(), default=False) - # dashboard = relationship('Dashboard', back_populates='user') diff --git a/schemas/__init__.py b/schemas/__init__.py index bb0340e..f4a2da0 100644 --- a/schemas/__init__.py +++ b/schemas/__init__.py @@ -1,10 +1 @@ -from .user import User, UserCreate, UserInDB, UserUpdate, UserLogin, UserBase, UserDBBase -from .token import Token, TokenPayload -from .msg import Msg - -from .project import ProjectCreate, Project -from .folders import FolderCreate, FolderUpdate, FolderIn, FolderDelete -from .dashboard import Dashboard, DashboardCreate, DashboardUpdate, DashboardIn, DashboardDelete -from .space import SpaceCreate, SpaceUpdate, SpaceIn, SpaceDelete -from .authority import AuthorityCreate, AuthorityUpdate -from .tree import Tree +from .user import * diff --git a/schemas/authority.py b/schemas/authority.py deleted file mode 100644 index ee96ad9..0000000 --- a/schemas/authority.py +++ /dev/null @@ -1,38 +0,0 @@ -from datetime import datetime -from enum import Enum -from pydantic import BaseModel - - -class AuthorityBase(BaseModel): - project_id: int = None - dashboard_id: int = None - authority: str = None - space_id: int = None - folder_id: int = None - - -class AuthorityCreate(AuthorityBase): - project_id: int - authority: str - - - -class AuthorityUpdate(AuthorityBase): - pass - - -class AuthorityEnum(str, Enum): - write = 'rw' - read = 'r' - - -class Authority(AuthorityBase): - id = int - user_id = int - project_id = int - dashboard_id = int - authority = AuthorityEnum - create_date = datetime - - class Config: - orm_mode = True diff --git a/schemas/base.py b/schemas/base.py new file mode 100644 index 0000000..340473f --- /dev/null +++ b/schemas/base.py @@ -0,0 +1,22 @@ +from typing import Optional, Union + +from bson import ObjectId +from pydantic import BaseModel, Field + + +# mongodb _id 类型 +class OId(ObjectId): + @classmethod + def __get_validators__(cls): + yield cls.validate + + @classmethod + def validate(cls, v): + try: + return ObjectId(v) + except: + raise ValueError('无效的格式') + + +class DBBase(BaseModel): + id: Union[OId, str] = Field(None, alias='_id') diff --git a/schemas/dashboard.py b/schemas/dashboard.py deleted file mode 100644 index 9636e2d..0000000 --- a/schemas/dashboard.py +++ /dev/null @@ -1,42 +0,0 @@ -from datetime import datetime -from typing import Optional - -from pydantic import BaseModel, root_validator, Field - - -class DashboardBase(BaseModel): - name: str = None - - -class DashboardIn(DashboardBase): - project_id: int - space_id: int = None - folder_id: int = None - - # @root_validator(pre=True) - # def check_parent(cls, values): - # if (values.get('folder_id') is None) ^ (values.get('space_id') is None): - # return values - # else: - # raise ValueError('必须属于文件夹或者空间') - - -class DashboardDelete(BaseModel): - id: int - - -class DashboardCreate(DashboardBase): - name: str - - -class DashboardUpdate(DashboardBase): - pass - - -class Dashboard(DashboardBase): - name: str - user_id: int - create_date: datetime - - class Config: - orm_mode = True diff --git a/schemas/folders.py b/schemas/folders.py deleted file mode 100644 index 138dac1..0000000 --- a/schemas/folders.py +++ /dev/null @@ -1,35 +0,0 @@ -from datetime import datetime - -from pydantic import BaseModel, root_validator - - -class FolderBase(BaseModel): - name: str = None - - -class FolderIn(FolderBase): - project_id: int - space_id: int = None - name: str - - -class FolderDelete(BaseModel): - id: int - - -class FolderCreate(FolderBase): - name: str - - -class FolderUpdate(FolderBase): - pass - - -class Folder(FolderBase): - id: int - name: str - user_id: int - create_date: datetime - - class Config: - orm_mode = True diff --git a/schemas/msg.py b/schemas/msg.py deleted file mode 100644 index 945e0c6..0000000 --- a/schemas/msg.py +++ /dev/null @@ -1,5 +0,0 @@ -from pydantic import BaseModel - - -class Msg(BaseModel): - msg: str diff --git a/schemas/project.py b/schemas/project.py deleted file mode 100644 index 1a065a9..0000000 --- a/schemas/project.py +++ /dev/null @@ -1,27 +0,0 @@ -from datetime import datetime - -from pydantic import BaseModel - - -# 创建项目请求 -class ProjectBase(BaseModel): - name: str = None - - -class ProjectCreate(ProjectBase): - name: str - - -class ProjectUpdate(ProjectBase): - pass - - -class Project(ProjectBase): - id: int - app_id: str - name: str - user_id: int - create_date: datetime - - class Config: - orm_mode = True diff --git a/schemas/space.py b/schemas/space.py deleted file mode 100644 index 13b5219..0000000 --- a/schemas/space.py +++ /dev/null @@ -1,35 +0,0 @@ -from datetime import datetime - -from pydantic import BaseModel - - -class SpaceBase(BaseModel): - name: str = None - - -class SpaceIn(SpaceBase): - project_id: int - name: str - - -class SpaceDelete(BaseModel): - id: int - - -class SpaceCreate(SpaceBase): - name: str - - -class SpaceUpdate(SpaceBase): - pass - - -class Space(SpaceBase): - id: int - name: str - user_id: int - project_id: int - create_date: datetime - - class Config: - orm_mode = True diff --git a/schemas/token.py b/schemas/token.py index 03a65de..49c3e66 100644 --- a/schemas/token.py +++ b/schemas/token.py @@ -11,5 +11,4 @@ class Token(BaseModel): msg: str -class TokenPayload(BaseModel): - user_id: int = None + diff --git a/schemas/tree.py b/schemas/tree.py deleted file mode 100644 index 6dcac49..0000000 --- a/schemas/tree.py +++ /dev/null @@ -1,9 +0,0 @@ -from pydantic import BaseModel - - -class Tree(BaseModel): - project_id: int - space_id: int = None - folder_id: int = None - dashboard_id: int = None - diff --git a/schemas/user.py b/schemas/user.py index d65988e..d910822 100644 --- a/schemas/user.py +++ b/schemas/user.py @@ -1,44 +1,42 @@ from typing import Optional -from pydantic import BaseModel, EmailStr +from schemas.base import DBBase + +from pydantic import BaseModel, EmailStr, Field -# Shared properties class UserBase(BaseModel): email: Optional[EmailStr] = None - is_active: Optional[bool] = True is_superuser: bool = False name: Optional[str] = None +class User(UserBase): + name: str + + class UserLogin(BaseModel): username: str = ... password: str = ... -# Properties to receive via API on creation class UserCreate(UserBase): email: EmailStr password: str -# Properties to receive via API on update -class UserUpdate(UserBase): - password: Optional[str] = None +# **************************************************************************** +# mongodb 模型 -class UserDBBase(UserBase): - id: Optional[int] = None - - class Config: - orm_mode = True +class UserDB(DBBase): + email: EmailStr + is_superuser: bool + name: str -# Additional properties to return via API -class User(UserDBBase): - pass - - -# Additional properties stored in DB -class UserInDB(UserDBBase): +class UserDBRW(UserDB): hashed_password: str + + +