From 6721ae550db9afc60a2f2addf2aa63f6ed657604 Mon Sep 17 00:00:00 2001 From: htylight Date: Sun, 10 Sep 2023 20:21:19 +0800 Subject: [PATCH] restructure static file directory --- src/crud/group_chat_crud.py | 25 ++++++++++++++++ src/routers/group_chat.py | 13 ++++++++- src/routers/user_account.py | 57 +++++++++++++++++++++++-------------- src/routers/user_profile.py | 6 ++-- src/utils/email_code.py | 2 +- src/utils/static_file.py | 16 +++++++---- src/utils/token_handler.py | 35 ++++++++++++----------- 7 files changed, 105 insertions(+), 49 deletions(-) diff --git a/src/crud/group_chat_crud.py b/src/crud/group_chat_crud.py index a924ce1..d3676e5 100644 --- a/src/crud/group_chat_crud.py +++ b/src/crud/group_chat_crud.py @@ -192,3 +192,28 @@ async def delete_group_chat(group_chat_id: str, members: list[str]): raise Exception finally: await session.close() + + +async def delete_group_chat_member(group_chat_id: str, member_id: str): + session = async_session() + try: + group_chat: GroupChat = ( + await session.scalars( + select(GroupChat).where(GroupChat.id == group_chat_id) + ) + ).one() + group_chat.members.remove(member_id) + flag_modified(group_chat, "members") + + contact: Contact = ( + await session.scalars(select(Contact).where(Contact.user_id == member_id)) + ).one() + del contact.group_chats[group_chat_id] + flag_modified(contact, "group_chats") + + session.add_all([group_chat, contact]) + await session.commit() + except Exception: + raise Exception + finally: + session.close() diff --git a/src/routers/group_chat.py b/src/routers/group_chat.py index f0117a8..5b6eb3a 100644 --- a/src/routers/group_chat.py +++ b/src/routers/group_chat.py @@ -54,6 +54,7 @@ async def invite_members(member_invitation: GroupChatMembers): @router.get("/member_name_avatar", response_model=MemberNameAvatarResponse) async def get_member_name_avatar(group_chat_id: str, member_id: str, is_friend: bool): res = await group_chat_crud.select_member_name_avatar(member_id, is_friend) + print(res) data = {} if is_friend: if res.get(group_chat_id): @@ -66,7 +67,7 @@ async def get_member_name_avatar(group_chat_id: str, member_id: str, is_friend: # make sure this user is still in this group chat data["remark"] = res[2][group_chat_id]["myRemark"] data["nickname"] = res[0] - data["avatar"] = res[1] + data["avatar"] = res[1] or "" return { "code": 10800, @@ -149,3 +150,13 @@ async def delete_group_chat(deletion: GroupChatMembers): except Exception as e: print(f"Delete Group Chat Fail With Error: {e}") return {"code": 9999, "msg": "Server Error"} + + +@router.post("/quit", response_model=BaseResponseModel) +async def quit_group_chat(group_chat_id: str, member_id: str): + try: + await group_chat_crud.delete_group_chat_member(group_chat_id, member_id) + return {"code": 10800, "msg": "Quit Group Chat Successfully"} + except Exception as e: + print(f"Quit Group Chat Fail With Error: {e}") + return {"code": 9999, "msg": "Server Error"} diff --git a/src/routers/user_account.py b/src/routers/user_account.py index fe92d3d..8c64e58 100644 --- a/src/routers/user_account.py +++ b/src/routers/user_account.py @@ -6,7 +6,7 @@ from ..utils import password from ..utils.email_code import send_email, has_code, verify_code from ..response_models.base import BaseResponseModel -router = APIRouter(prefix='/user_account', tags=['user_account']) +router = APIRouter(prefix="/user_account", tags=["user_account"]) class ChangedAccount(BaseModel): @@ -17,58 +17,71 @@ class ChangedAccount(BaseModel): code: str | None = None -@router.post('/change/username', response_model=BaseResponseModel) +@router.post("/change/username", response_model=BaseResponseModel) async def change_username(changed_account: ChangedAccount): - is_existed, user = await user_crud.select_account_by('username', changed_account.username) + is_existed, user = await user_crud.select_account_by( + "username", changed_account.username + ) if is_existed: - return {'code': 10401, 'msg': f'This Username ({changed_account.username}) Has Been Used'} + return { + "code": 10401, + "msg": f"This Username ({changed_account.username}) Has Been Used", + } - await user_crud.update_account('username', changed_account.id, changed_account.username) + await user_crud.update_account( + "username", changed_account.id, changed_account.username + ) - return {'code': 10400, 'msg': 'Update Username Successfully'} + return {"code": 10400, "msg": "Update Username Successfully"} -@router.get('/get/email_code', response_model=BaseResponseModel) +@router.get("/get/email_code", response_model=BaseResponseModel) async def get_change_email_code(email: str, background_tasks: BackgroundTasks): - is_existed, _ = await user_crud.select_account_by('email', email) + is_existed, _ = await user_crud.select_account_by("email", email) if is_existed: - return {'code': 10401, 'msg': f'This Email ({email}) Has Been Used'} + return {"code": 10401, "msg": f"This Email ({email}) Has Been Used"} if has_code(email): - return {'code': 10402, 'msg': f'Code of Email ({email}) Is Still Available'} + return {"code": 10402, "msg": f"Code of Email ({email}) Is Still Available"} background_tasks.add_task(send_email, email) - return {'code': 10400, 'msg': 'Send Verification Code Successfully'} + return {"code": 10400, "msg": "Send Verification Code Successfully"} -@router.post('/change/email', response_model=BaseResponseModel) +@router.post("/change/email", response_model=BaseResponseModel) async def change_email(changed_account: ChangedAccount): is_correct = verify_code(changed_account.email, changed_account.code) if not is_correct: - return {'code': 10403, 'msg': f'Email Code ({changed_account.code}) Is Not Correct'} + return { + "code": 10403, + "msg": f"Email Code ({changed_account.code}) Is Not Correct", + } - await user_crud.update_account('email', changed_account.id, changed_account.email) + await user_crud.update_account("email", changed_account.id, changed_account.email) - return {'code': 10400, 'msg': 'Update Email Successfully'} + return {"code": 10400, "msg": "Update Email Successfully"} -@router.get('/get/password_code', response_model=BaseResponseModel) +@router.get("/get/password_code", response_model=BaseResponseModel) async def get_change_password_code(email: str, background_tasks: BackgroundTasks): if has_code(email): - return {'code': 10402, 'msg': f'Code of Email ({email}) Is Still Available'} + return {"code": 10402, "msg": f"Code of Email ({email}) Is Still Available"} background_tasks.add_task(send_email, email) - return {'code': 10400, 'msg': 'Send Verification Code Successfully'} + return {"code": 10400, "msg": "Send Verification Code Successfully"} -@router.post('/change/password', response_model=BaseResponseModel) +@router.post("/change/password", response_model=BaseResponseModel) async def change_password(changed_account: ChangedAccount): is_correct = verify_code(changed_account.email, changed_account.code) if not is_correct: - return {'code': 10403, 'msg': f'Email Code ({changed_account.code}) Is Not Correct'} + return { + "code": 10403, + "msg": f"Email Code ({changed_account.code}) Is Not Correct", + } hashed_password = password.get_hashed_password(changed_account.password) - await user_crud.update_account('password', changed_account.id, hashed_password) + await user_crud.update_account("password", changed_account.id, hashed_password) - return {'code': 10400, 'msg': 'Update Email Successfully'} \ No newline at end of file + return {"code": 10400, "msg": "Update Email Successfully"} diff --git a/src/routers/user_profile.py b/src/routers/user_profile.py index 4f508ec..0a2836f 100755 --- a/src/routers/user_profile.py +++ b/src/routers/user_profile.py @@ -48,13 +48,13 @@ async def get_profile(id: str): @router.get("/avatar") async def download_avatar(avatar_filename: str): - avatar_dir_path = static_file.create_dir("avatars") - return FileResponse(avatar_dir_path / avatar_filename) + user_avatar_dir_path = static_file.create_avatar_dir("user", "avatars") + return FileResponse(user_avatar_dir_path / avatar_filename) @router.post("/change/avatar", response_model=UserAvatarResponse) async def change_avatar(id: str, file: Uint8List): - avatar_dir_path = static_file.create_dir("avatars") + avatar_dir_path = static_file.create_avatar_dir("user", "avatars") avatar_filename = static_file.create_avatar_filename() async with await open_file(avatar_dir_path / avatar_filename, "wb") as f: diff --git a/src/utils/email_code.py b/src/utils/email_code.py index 5fba145..c07f410 100755 --- a/src/utils/email_code.py +++ b/src/utils/email_code.py @@ -29,7 +29,7 @@ def send_email(to: str): msg = EmailMessage() connect_email_server() msg["Subject"] = "Together app signup verification code" - msg["From"] = "TogetherApp " + msg["From"] = f"TogetherApp <{username}>" msg["To"] = f"<{to}>" email_content = f"""\ diff --git a/src/utils/static_file.py b/src/utils/static_file.py index 1a4f68e..dee84e0 100755 --- a/src/utils/static_file.py +++ b/src/utils/static_file.py @@ -35,11 +35,17 @@ alphabet = [ ] -def create_dir(dir_name: str) -> Path: - avatar_dir_path = Path(os.getcwd()) / "static" / dir_name - if not avatar_dir_path.exists(): - avatar_dir_path.mkdir() - return avatar_dir_path +def create_avatar_dir(type: Literal["user", "group_chat"], dir_name: str) -> Path: + if type == "user": + avatar_dir_path = Path(os.getcwd()) / "static" / dir_name / "user" + if not avatar_dir_path.exists(): + avatar_dir_path.mkdir() + return avatar_dir_path + else: + avatar_dir_path = Path(os.getcwd()) / "static" / dir_name / "group_chat" + if not avatar_dir_path.exists(): + avatar_dir_path.mkdir() + return avatar_dir_path def create_avatar_filename() -> str: diff --git a/src/utils/token_handler.py b/src/utils/token_handler.py index 690581a..668faba 100644 --- a/src/utils/token_handler.py +++ b/src/utils/token_handler.py @@ -6,10 +6,10 @@ from fastapi.security import OAuth2PasswordBearer from jose import jwt, ExpiredSignatureError, JWTError # openssl rand -hex 32 -SECRET_KEY = '1c3c03b79d084f0c7b41ba11d1d9a4979f72d9fc6eaaaa0a855065e8a5be0468' -ALGORITHM = 'HS256' +SECRET_KEY = "1c3c03b79d084f0c7b41ba11d1d9a4979f72d9fc6eaaaa0a855065e8a5be0468" +ALGORITHM = "HS256" -oauth2_scheme = OAuth2PasswordBearer(tokenUrl='token') +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") class SigninClaim(TypedDict): @@ -22,33 +22,34 @@ class SigninClaim(TypedDict): def create_signin_token(id: str, device_id: str) -> str: claim: SigninClaim = { - 'sub': id, - 'iss': 'together', - 'iat': datetime.now().timestamp(), - 'exp': (datetime.now() + timedelta(days=23)).timestamp(), - 'device_id': device_id, + "sub": id, + "iss": "together", + "iat": datetime.now().timestamp(), + "exp": (datetime.now() + timedelta(days=23)).timestamp(), + "device_id": device_id, } return jwt.encode(claim, SECRET_KEY, algorithm=ALGORITHM) -def verify_signin_token(token) -> Tuple[str | None, str]: +def verify_signin_token(token: str) -> Tuple[str | None, str]: try: claim: SigninClaim = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - if claim['exp'] - datetime.now().timestamp() <= 10*24*60*60: - new_token = _prolong_token(token) - return new_token, claim['sub'] + print(claim["sub"]) + if claim["exp"] - datetime.now().timestamp() <= 10 * 24 * 60 * 60: + new_token = _prolong_token(claim) + return new_token, claim["sub"] else: - return None, claim['sub'] + return None, claim["sub"] except ExpiredSignatureError: - print(f'{token} expire ========================') + print(f"{token} expire ========================") raise ExpiredSignatureError except JWTError: - print(f'This token {token} is not sign by me ==========================') + print(f"This token {token} is not sign by me ==========================") raise JWTError def _prolong_token(claim: SigninClaim) -> str: - claim['iat'] = datetime.now().timestamp() - claim['exp'] = (datetime.now() + timedelta(days=30)).timestamp() + claim["iat"] = datetime.now().timestamp() + claim["exp"] = (datetime.now() + timedelta(days=30)).timestamp() token = jwt.encode(claim, SECRET_KEY, algorithm=ALGORITHM) return token