Files
Wu Clan abcc9d2308 Add sync to async decorator support (#96)
* Add sync to async decorator support

* Update ASyncTranslator to asgiref
2023-06-06 20:13:33 +08:00

169 lines
7.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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