Files
fastapi-best-architecture/backend/app/admin/service/user_service.py
T

236 lines
11 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import random
from fastapi import Request
from sqlalchemy import Select
from backend.app.admin.crud.crud_dept import dept_dao
from backend.app.admin.crud.crud_role import role_dao
from backend.app.admin.crud.crud_user import user_dao
from backend.app.admin.model import User
from backend.app.admin.schema.user import (
AddUserParam,
AvatarParam,
RegisterUserParam,
ResetPasswordParam,
UpdateUserParam,
UpdateUserRoleParam,
)
from backend.common.exception import errors
from backend.common.security.jwt import get_hash_password, get_token, password_verify, superuser_verify
from backend.core.conf import settings
from backend.database.db_mysql import async_db_session
from backend.database.db_redis import redis_client
class UserService:
@staticmethod
async def register(*, obj: RegisterUserParam) -> None:
async with async_db_session.begin() as db:
if not obj.password:
raise errors.ForbiddenError(msg='密码为空')
username = await user_dao.get_by_username(db, obj.username)
if username:
raise errors.ForbiddenError(msg='用户已注册')
obj.nickname = obj.nickname if obj.nickname else f'#{random.randrange(10000, 88888)}'
nickname = await user_dao.get_by_nickname(db, obj.nickname)
if nickname:
raise errors.ForbiddenError(msg='昵称已注册')
email = await user_dao.check_email(db, obj.email)
if email:
raise errors.ForbiddenError(msg='邮箱已注册')
await user_dao.create(db, obj)
@staticmethod
async def add(*, request: Request, obj: AddUserParam) -> None:
async with async_db_session.begin() as db:
await superuser_verify(request)
username = await user_dao.get_by_username(db, obj.username)
if username:
raise errors.ForbiddenError(msg='用户已注册')
obj.nickname = obj.nickname if obj.nickname else f'#{random.randrange(88888, 99999)}'
nickname = await user_dao.get_by_nickname(db, obj.nickname)
if nickname:
raise errors.ForbiddenError(msg='昵称已注册')
if not obj.password:
raise errors.ForbiddenError(msg='密码为空')
email = await user_dao.check_email(db, obj.email)
if email:
raise errors.ForbiddenError(msg='邮箱已注册')
dept = await dept_dao.get(db, obj.dept_id)
if not dept:
raise errors.NotFoundError(msg='部门不存在')
for role_id in obj.roles:
role = await role_dao.get(db, role_id)
if not role:
raise errors.NotFoundError(msg='角色不存在')
await user_dao.add(db, obj)
@staticmethod
async def pwd_reset(*, request: Request, obj: ResetPasswordParam) -> int:
async with async_db_session.begin() as db:
if not await password_verify(f'{obj.old_password}{request.user.salt}', request.user.password):
raise errors.ForbiddenError(msg='原密码错误')
np1 = obj.new_password
np2 = obj.confirm_password
if np1 != np2:
raise errors.ForbiddenError(msg='密码输入不一致')
new_pwd = await get_hash_password(f'{obj.new_password}{request.user.salt}')
count = await user_dao.reset_password(db, request.user.id, new_pwd)
prefix = [
f'{settings.TOKEN_REDIS_PREFIX}:{request.user.id}:',
f'{settings.TOKEN_REFRESH_REDIS_PREFIX}:{request.user.id}:',
]
for i in prefix:
await redis_client.delete_prefix(i)
return count
@staticmethod
async def get_userinfo(*, username: str) -> User:
async with async_db_session() as db:
user = await user_dao.get_with_relation(db, username=username)
if not user:
raise errors.NotFoundError(msg='用户不存在')
return user
@staticmethod
async def update(*, request: Request, username: str, obj: UpdateUserParam) -> int:
async with async_db_session.begin() as db:
if not request.user.is_superuser:
if request.user.username != username:
raise errors.ForbiddenError(msg='你只能修改自己的信息')
input_user = await user_dao.get_with_relation(db, username=username)
if not input_user:
raise errors.NotFoundError(msg='用户不存在')
if input_user.username != obj.username:
_username = await user_dao.get_by_username(db, obj.username)
if _username:
raise errors.ForbiddenError(msg='用户名已注册')
if input_user.nickname != obj.nickname:
nickname = await user_dao.get_by_nickname(db, obj.nickname)
if nickname:
raise errors.ForbiddenError(msg='昵称已注册')
if input_user.email != obj.email:
email = await user_dao.check_email(db, obj.email)
if email:
raise errors.ForbiddenError(msg='邮箱已注册')
count = await user_dao.update_userinfo(db, input_user, obj)
return count
@staticmethod
async def update_roles(*, request: Request, username: str, obj: UpdateUserRoleParam) -> None:
async with async_db_session.begin() as db:
if not request.user.is_superuser:
if request.user.username != username:
raise errors.AuthorizationError
input_user = await user_dao.get_with_relation(db, username=username)
if not input_user:
raise errors.NotFoundError(msg='用户不存在')
for role_id in obj.roles:
role = await role_dao.get(db, role_id)
if not role:
raise errors.NotFoundError(msg='角色不存在')
await user_dao.update_role(db, input_user, obj)
await redis_client.delete_prefix(f'{settings.PERMISSION_REDIS_PREFIX}:{request.user.uuid}')
@staticmethod
async def update_avatar(*, request: Request, username: str, avatar: AvatarParam) -> int:
async with async_db_session.begin() as db:
if not request.user.is_superuser:
if request.user.username != username:
raise errors.AuthorizationError
input_user = await user_dao.get_by_username(db, username)
if not input_user:
raise errors.NotFoundError(msg='用户不存在')
count = await user_dao.update_avatar(db, input_user, avatar)
return count
@staticmethod
async def get_select(*, dept: int, username: str = None, phone: str = None, status: int = None) -> Select:
return await user_dao.get_list(dept=dept, 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 superuser_verify(request)
if not await user_dao.get(db, pk):
raise errors.NotFoundError(msg='用户不存在')
else:
user_id = request.user.id
if pk == user_id:
raise errors.ForbiddenError(msg='非法操作')
super_status = await user_dao.get_super(db, user_id)
count = await user_dao.set_super(db, pk, False if super_status else True)
return count
@staticmethod
async def update_staff(*, request: Request, pk: int) -> int:
async with async_db_session.begin() as db:
await superuser_verify(request)
if not await user_dao.get(db, pk):
raise errors.NotFoundError(msg='用户不存在')
else:
user_id = request.user.id
if pk == user_id:
raise errors.ForbiddenError(msg='非法操作')
staff_status = await user_dao.get_staff(db, user_id)
count = await user_dao.set_staff(db, pk, False if staff_status else True)
return count
@staticmethod
async def update_status(*, request: Request, pk: int) -> int:
async with async_db_session.begin() as db:
await superuser_verify(request)
if not await user_dao.get(db, pk):
raise errors.NotFoundError(msg='用户不存在')
else:
user_id = request.user.id
if pk == user_id:
raise errors.ForbiddenError(msg='非法操作')
status = await user_dao.get_status(db, user_id)
count = await user_dao.set_status(db, pk, False if status else True)
return count
@staticmethod
async def update_multi_login(*, request: Request, pk: int) -> int:
async with async_db_session.begin() as db:
await superuser_verify(request)
if not await user_dao.get(db, pk):
raise errors.NotFoundError(msg='用户不存在')
else:
count = await user_dao.set_multi_login(db, pk)
token = await get_token(request)
user_id = request.user.id
latest_multi_login = await user_dao.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(*, username: str) -> int:
async with async_db_session.begin() as db:
input_user = await user_dao.get_by_username(db, username)
if not input_user:
raise errors.NotFoundError(msg='用户不存在')
count = await user_dao.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
user_service = UserService()