Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions backend/app/api/v1/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
from backend.app.common.response.response_schema import response_base
from backend.app.database.db_mysql import CurrentSession
from backend.app.schemas.user import (
CreateUser,
RegisterUser,
GetAllUserInfo,
ResetPassword,
UpdateUser,
Avatar,
GetCurrentUserInfo,
UpdateUserRole,
AddUser,
)
from backend.app.services.user_service import UserService
from backend.app.utils.serializers import select_to_json
Expand All @@ -25,11 +26,17 @@


@router.post('/register', summary='用户注册')
async def user_register(obj: CreateUser):
async def user_register(obj: RegisterUser):
await UserService.register(obj=obj)
return await response_base.success()


@router.post('/add', summary='添加用户', dependencies=[DependsRBAC])
async def add_user(obj: AddUser):
await UserService.add(obj=obj)
return await response_base.success()


@router.post('/password/reset', summary='密码重置', dependencies=[DependsJwtAuth])
async def password_reset(request: Request, obj: ResetPassword):
count = await UserService.pwd_reset(request=request, obj=obj)
Expand Down
18 changes: 15 additions & 3 deletions backend/app/crud/crud_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,37 @@
from backend.app.common import jwt
from backend.app.crud.base import CRUDBase
from backend.app.models import User, Role
from backend.app.schemas.user import CreateUser, UpdateUser, Avatar, UpdateUserRole
from backend.app.schemas.user import RegisterUser, UpdateUser, Avatar, UpdateUserRole, AddUser


class CRUDUser(CRUDBase[User, CreateUser, UpdateUser]):
class CRUDUser(CRUDBase[User, RegisterUser, UpdateUser]):
async def get(self, db: AsyncSession, user_id: int) -> User | None:
return await self.get_(db, pk=user_id)

async def get_by_username(self, db: AsyncSession, username: str) -> User | None:
user = await db.execute(select(self.model).where(self.model.username == username))
return user.scalars().first()

async def get_by_nickname(self, db: AsyncSession, nickname: str) -> User | None:
user = await db.execute(select(self.model).where(self.model.nickname == nickname))
return user.scalars().first()

async def update_login_time(self, db: AsyncSession, username: str, login_time: datetime) -> int:
user = await db.execute(
update(self.model).where(self.model.username == username).values(last_login_time=login_time)
)
await db.commit()
return user.rowcount

async def create(self, db: AsyncSession, obj: CreateUser) -> NoReturn:
async def create(self, db: AsyncSession, obj: RegisterUser) -> NoReturn:
salt = text_captcha(5)
obj.password = await jwt.get_hash_password(obj.password + salt)
dict_obj = obj.dict()
dict_obj.update({'salt': salt})
new_user = self.model(**dict_obj)
db.add(new_user)

async def add(self, db: AsyncSession, obj: AddUser) -> NoReturn:
salt = text_captcha(5)
obj.password = await jwt.get_hash_password(obj.password + salt)
dict_obj = obj.dict(exclude={'roles'})
Expand Down
20 changes: 17 additions & 3 deletions backend/app/schemas/user.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import random
from datetime import datetime

from email_validator import validate_email, EmailNotValidError
Expand All @@ -20,10 +21,23 @@ class AuthLogin(Auth):
captcha: str


class CreateUser(Auth):
dept_id: int | None = None
class RegisterUser(Auth):
nickname: str = Field(f'用户{random.randrange(10000, 99999)}')
email: str = Field(..., example='user@example.com')

@validator('email')
def email_validate(cls, v):
try:
validate_email(v, check_deliverability=False).email
except EmailNotValidError:
raise ValueError('邮箱格式错误')
return v


class AddUser(Auth):
dept_id: int
roles: list[int]
nickname: str
nickname: str = Field(f'用户{random.randrange(10000, 99999)}')
email: str = Field(..., example='user@example.com')

@validator('email')
Expand Down
5 changes: 3 additions & 2 deletions backend/app/services/menu_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ async def get_user_menu_tree(*, request: Request):
async with async_db_session() as db:
roles = request.user.roles
menu_ids = []
for role in roles:
menu_ids.extend([menu.id for menu in role.menus])
if roles:
for role in roles:
menu_ids.extend([menu.id for menu in role.menus])
menu_select = await MenuDao.get_role_menus(db, request.user.is_superuser, menu_ids)
menu_tree = await get_tree_data(menu_select)
return menu_tree
Expand Down
36 changes: 26 additions & 10 deletions backend/app/services/user_service.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import NoReturn

from fastapi import Request
from sqlalchemy import Select

Expand All @@ -15,27 +13,44 @@
from backend.app.crud.crud_user import UserDao
from backend.app.database.db_mysql import async_db_session
from backend.app.models import User
from backend.app.schemas.user import CreateUser, ResetPassword, UpdateUser, Avatar, UpdateUserRole
from backend.app.schemas.user import RegisterUser, ResetPassword, UpdateUser, Avatar, UpdateUserRole, AddUser


class UserService:
@staticmethod
async def register(*, obj: CreateUser) -> NoReturn:
async def register(*, obj: RegisterUser) -> None:
async with async_db_session.begin() as db:
username = await UserDao.get_by_username(db, obj.username)
if username:
raise errors.ForbiddenError(msg='该用户名已注册')
nickname = await UserDao.get_by_nickname(db, obj.nickname)
if nickname:
raise errors.ForbiddenError(msg='该昵称已注册')
email = await UserDao.check_email(db, obj.email)
if email:
raise errors.ForbiddenError(msg='该邮箱已注册')
await UserDao.create(db, obj)

@staticmethod
async def add(*, obj: AddUser) -> None:
async with async_db_session.begin() as db:
username = await UserDao.get_by_username(db, obj.username)
if username:
raise errors.ForbiddenError(msg='该用户名已注册')
nickname = await UserDao.get_by_nickname(db, obj.nickname)
if nickname:
raise errors.ForbiddenError(msg='该昵称已注册')
dept = await DeptDao.get(db, obj.dept_id)
if not dept:
raise errors.NotFoundError(msg='部门不存在')
for role_id in obj.roles:
role = await RoleDao.get(db, role_id)
if not role:
raise errors.NotFoundError(msg='角色不存在')
await UserDao.create(db, obj)
email = await UserDao.check_email(db, obj.email)
if email:
raise errors.ForbiddenError(msg='该邮箱已注册')
await UserDao.add(db, obj)

@staticmethod
async def pwd_reset(*, request: Request, obj: ResetPassword) -> int:
Expand Down Expand Up @@ -72,16 +87,17 @@ async def update(*, request: Request, username: str, obj: UpdateUser) -> int:
if not input_user:
raise errors.NotFoundError(msg='用户不存在')
if input_user.username != obj.username:
username = await UserDao.get_by_username(db, obj.username)
if username:
_username = await UserDao.get_by_username(db, obj.username)
if _username:
raise errors.ForbiddenError(msg='该用户名已存在')
if input_user.nickname != obj.nickname:
nickname = await UserDao.get_by_nickname(db, obj.nickname)
if nickname:
raise errors.ForbiddenError(msg='改昵称已存在')
if input_user.email != obj.email:
email = await UserDao.check_email(db, obj.email)
if email:
raise errors.ForbiddenError(msg='该邮箱已注册')
dept = await DeptDao.get(db, obj.dept_id)
if not dept:
raise errors.NotFoundError(msg='部门不存在')
count = await UserDao.update_userinfo(db, input_user, obj)
return count

Expand Down