mirror of
https://github.com/fastapi-practices/fastapi_best_architecture.git
synced 2025-08-18 23:11:48 +08:00
169 lines
7.5 KiB
Python
169 lines
7.5 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
from typing import NoReturn
|
||
|
||
from email_validator import validate_email, EmailNotValidError
|
||
from fastapi import Request
|
||
from sqlalchemy import Select
|
||
|
||
from backend.app.common import jwt
|
||
from backend.app.common.exception import errors
|
||
from backend.app.common.jwt import get_token, jwt_decode
|
||
from backend.app.common.redis import redis_client
|
||
from backend.app.core.conf import settings
|
||
from backend.app.crud.crud_dept import DeptDao
|
||
from backend.app.crud.crud_role import RoleDao
|
||
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
|
||
from backend.app.utils import re_verify
|
||
|
||
|
||
class UserService:
|
||
@staticmethod
|
||
async def register(obj: CreateUser) -> NoReturn:
|
||
async with async_db_session.begin() as db:
|
||
username = await UserDao.get_by_username(db, obj.username)
|
||
if username:
|
||
raise errors.ForbiddenError(msg='该用户名已注册')
|
||
email = await UserDao.check_email(db, obj.email)
|
||
if email:
|
||
raise errors.ForbiddenError(msg='该邮箱已注册')
|
||
try:
|
||
validate_email(obj.email, check_deliverability=False).email
|
||
except EmailNotValidError:
|
||
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)
|
||
|
||
@staticmethod
|
||
async def pwd_reset(obj: ResetPassword) -> int:
|
||
async with async_db_session.begin() as db:
|
||
pwd1 = obj.password1
|
||
pwd2 = obj.password2
|
||
if pwd1 != pwd2:
|
||
raise errors.ForbiddenError(msg='两次密码输入不一致')
|
||
count = await UserDao.reset_password(db, obj.id, obj.password2)
|
||
return count
|
||
|
||
@staticmethod
|
||
async def get_userinfo(username: str) -> User:
|
||
async with async_db_session() as db:
|
||
user = await UserDao.get_with_relation(db, username=username)
|
||
if not user:
|
||
raise errors.NotFoundError(msg='用户不存在')
|
||
return user
|
||
|
||
@staticmethod
|
||
async def update(*, request: Request, username: str, obj: UpdateUser) -> int:
|
||
async with async_db_session.begin() as db:
|
||
await jwt.superuser_verify(request)
|
||
input_user = await UserDao.get_with_relation(db, username=username)
|
||
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:
|
||
raise errors.ForbiddenError(msg='该用户名已存在')
|
||
if input_user.email != obj.email:
|
||
_email = await UserDao.check_email(db, obj.email)
|
||
if _email:
|
||
raise errors.ForbiddenError(msg='该邮箱已注册')
|
||
try:
|
||
validate_email(obj.email, check_deliverability=False).email
|
||
except EmailNotValidError:
|
||
raise errors.ForbiddenError(msg='邮箱格式错误')
|
||
if obj.phone is not None:
|
||
if not re_verify.is_phone(obj.phone):
|
||
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='角色不存在')
|
||
count = await UserDao.update_userinfo(db, input_user, obj)
|
||
return count
|
||
|
||
@staticmethod
|
||
async def update_avatar(*, request: Request, username: str, avatar: Avatar) -> int:
|
||
async with async_db_session.begin() as db:
|
||
await jwt.superuser_verify(request)
|
||
input_user = await UserDao.get_by_username(db, username)
|
||
if not input_user:
|
||
raise errors.NotFoundError(msg='用户不存在')
|
||
count = await UserDao.update_avatar(db, input_user, avatar)
|
||
return count
|
||
|
||
@staticmethod
|
||
async def get_select(*, username: str = None, phone: str = None, status: bool = None) -> Select:
|
||
return await UserDao.get_all(username=username, phone=phone, status=status)
|
||
|
||
@staticmethod
|
||
async def update_permission(*, request: Request, pk: int) -> int:
|
||
async with async_db_session.begin() as db:
|
||
await jwt.superuser_verify(request)
|
||
if not await UserDao.get(db, pk):
|
||
raise errors.NotFoundError(msg='用户不存在')
|
||
else:
|
||
count = await UserDao.set_super(db, pk)
|
||
return count
|
||
|
||
@staticmethod
|
||
async def update_active(*, request: Request, pk: int) -> int:
|
||
async with async_db_session.begin() as db:
|
||
await jwt.superuser_verify(request)
|
||
if not await UserDao.get(db, pk):
|
||
raise errors.NotFoundError(msg='用户不存在')
|
||
else:
|
||
count = await UserDao.set_active(db, pk)
|
||
return count
|
||
|
||
@staticmethod
|
||
async def update_multi_login(*, request: Request, pk: int) -> int:
|
||
async with async_db_session.begin() as db:
|
||
await jwt.superuser_verify(request)
|
||
if not await UserDao.get(db, pk):
|
||
raise errors.NotFoundError(msg='用户不存在')
|
||
else:
|
||
count = await UserDao.set_multi_login(db, pk)
|
||
token = await get_token(request)
|
||
user_id, role_ids = await jwt_decode(token)
|
||
latest_multi_login = await UserDao.get_multi_login(db, pk)
|
||
# TODO: 删除用户 refresh token, 此操作需要传参,暂时不考虑实现
|
||
# 当前用户修改自身时(普通/超级),除当前token外,其他token失效
|
||
if pk == user_id:
|
||
if not latest_multi_login:
|
||
prefix = f'{settings.TOKEN_REDIS_PREFIX}:{pk}:'
|
||
await redis_client.delete_prefix(prefix, exclude=prefix + token)
|
||
# 超级用户修改他人时,他人token将全部失效
|
||
else:
|
||
if not latest_multi_login:
|
||
prefix = f'{settings.TOKEN_REDIS_PREFIX}:{pk}:'
|
||
await redis_client.delete_prefix(prefix)
|
||
return count
|
||
|
||
@staticmethod
|
||
async def delete(*, request: Request, username: str) -> int:
|
||
async with async_db_session.begin() as db:
|
||
await jwt.superuser_verify(request)
|
||
input_user = await UserDao.get_by_username(db, username)
|
||
if not input_user:
|
||
raise errors.NotFoundError(msg='用户不存在')
|
||
count = await UserDao.delete(db, input_user.id)
|
||
prefix = [
|
||
f'{settings.TOKEN_REDIS_PREFIX}:{input_user.id}:',
|
||
f'{settings.TOKEN_REFRESH_REDIS_PREFIX}:{input_user.id}:',
|
||
]
|
||
for i in prefix:
|
||
await redis_client.delete_prefix(i)
|
||
return count
|