restructure static file directory
parent
9eed55164a
commit
6721ae550d
|
@ -192,3 +192,28 @@ async def delete_group_chat(group_chat_id: str, members: list[str]):
|
||||||
raise Exception
|
raise Exception
|
||||||
finally:
|
finally:
|
||||||
await session.close()
|
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()
|
||||||
|
|
|
@ -54,6 +54,7 @@ async def invite_members(member_invitation: GroupChatMembers):
|
||||||
@router.get("/member_name_avatar", response_model=MemberNameAvatarResponse)
|
@router.get("/member_name_avatar", response_model=MemberNameAvatarResponse)
|
||||||
async def get_member_name_avatar(group_chat_id: str, member_id: str, is_friend: bool):
|
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)
|
res = await group_chat_crud.select_member_name_avatar(member_id, is_friend)
|
||||||
|
print(res)
|
||||||
data = {}
|
data = {}
|
||||||
if is_friend:
|
if is_friend:
|
||||||
if res.get(group_chat_id):
|
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
|
# make sure this user is still in this group chat
|
||||||
data["remark"] = res[2][group_chat_id]["myRemark"]
|
data["remark"] = res[2][group_chat_id]["myRemark"]
|
||||||
data["nickname"] = res[0]
|
data["nickname"] = res[0]
|
||||||
data["avatar"] = res[1]
|
data["avatar"] = res[1] or ""
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"code": 10800,
|
"code": 10800,
|
||||||
|
@ -149,3 +150,13 @@ async def delete_group_chat(deletion: GroupChatMembers):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Delete Group Chat Fail With Error: {e}")
|
print(f"Delete Group Chat Fail With Error: {e}")
|
||||||
return {"code": 9999, "msg": "Server Error"}
|
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"}
|
||||||
|
|
|
@ -6,7 +6,7 @@ from ..utils import password
|
||||||
from ..utils.email_code import send_email, has_code, verify_code
|
from ..utils.email_code import send_email, has_code, verify_code
|
||||||
from ..response_models.base import BaseResponseModel
|
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):
|
class ChangedAccount(BaseModel):
|
||||||
|
@ -17,58 +17,71 @@ class ChangedAccount(BaseModel):
|
||||||
code: str | None = None
|
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):
|
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:
|
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):
|
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:
|
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):
|
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)
|
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):
|
async def change_email(changed_account: ChangedAccount):
|
||||||
is_correct = verify_code(changed_account.email, changed_account.code)
|
is_correct = verify_code(changed_account.email, changed_account.code)
|
||||||
if not is_correct:
|
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):
|
async def get_change_password_code(email: str, background_tasks: BackgroundTasks):
|
||||||
if has_code(email):
|
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)
|
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):
|
async def change_password(changed_account: ChangedAccount):
|
||||||
is_correct = verify_code(changed_account.email, changed_account.code)
|
is_correct = verify_code(changed_account.email, changed_account.code)
|
||||||
if not is_correct:
|
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)
|
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'}
|
return {"code": 10400, "msg": "Update Email Successfully"}
|
||||||
|
|
|
@ -48,13 +48,13 @@ async def get_profile(id: str):
|
||||||
|
|
||||||
@router.get("/avatar")
|
@router.get("/avatar")
|
||||||
async def download_avatar(avatar_filename: str):
|
async def download_avatar(avatar_filename: str):
|
||||||
avatar_dir_path = static_file.create_dir("avatars")
|
user_avatar_dir_path = static_file.create_avatar_dir("user", "avatars")
|
||||||
return FileResponse(avatar_dir_path / avatar_filename)
|
return FileResponse(user_avatar_dir_path / avatar_filename)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/change/avatar", response_model=UserAvatarResponse)
|
@router.post("/change/avatar", response_model=UserAvatarResponse)
|
||||||
async def change_avatar(id: str, file: Uint8List):
|
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()
|
avatar_filename = static_file.create_avatar_filename()
|
||||||
|
|
||||||
async with await open_file(avatar_dir_path / avatar_filename, "wb") as f:
|
async with await open_file(avatar_dir_path / avatar_filename, "wb") as f:
|
||||||
|
|
|
@ -29,7 +29,7 @@ def send_email(to: str):
|
||||||
msg = EmailMessage()
|
msg = EmailMessage()
|
||||||
connect_email_server()
|
connect_email_server()
|
||||||
msg["Subject"] = "Together app signup verification code"
|
msg["Subject"] = "Together app signup verification code"
|
||||||
msg["From"] = "TogetherApp <together_app@outlook.com>"
|
msg["From"] = f"TogetherApp <{username}>"
|
||||||
msg["To"] = f"<{to}>"
|
msg["To"] = f"<{to}>"
|
||||||
|
|
||||||
email_content = f"""\
|
email_content = f"""\
|
||||||
|
|
|
@ -35,8 +35,14 @@ alphabet = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def create_dir(dir_name: str) -> Path:
|
def create_avatar_dir(type: Literal["user", "group_chat"], dir_name: str) -> Path:
|
||||||
avatar_dir_path = Path(os.getcwd()) / "static" / dir_name
|
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():
|
if not avatar_dir_path.exists():
|
||||||
avatar_dir_path.mkdir()
|
avatar_dir_path.mkdir()
|
||||||
return avatar_dir_path
|
return avatar_dir_path
|
||||||
|
|
|
@ -6,10 +6,10 @@ from fastapi.security import OAuth2PasswordBearer
|
||||||
from jose import jwt, ExpiredSignatureError, JWTError
|
from jose import jwt, ExpiredSignatureError, JWTError
|
||||||
|
|
||||||
# openssl rand -hex 32
|
# openssl rand -hex 32
|
||||||
SECRET_KEY = '1c3c03b79d084f0c7b41ba11d1d9a4979f72d9fc6eaaaa0a855065e8a5be0468'
|
SECRET_KEY = "1c3c03b79d084f0c7b41ba11d1d9a4979f72d9fc6eaaaa0a855065e8a5be0468"
|
||||||
ALGORITHM = 'HS256'
|
ALGORITHM = "HS256"
|
||||||
|
|
||||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl='token')
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||||
|
|
||||||
|
|
||||||
class SigninClaim(TypedDict):
|
class SigninClaim(TypedDict):
|
||||||
|
@ -22,33 +22,34 @@ class SigninClaim(TypedDict):
|
||||||
|
|
||||||
def create_signin_token(id: str, device_id: str) -> str:
|
def create_signin_token(id: str, device_id: str) -> str:
|
||||||
claim: SigninClaim = {
|
claim: SigninClaim = {
|
||||||
'sub': id,
|
"sub": id,
|
||||||
'iss': 'together',
|
"iss": "together",
|
||||||
'iat': datetime.now().timestamp(),
|
"iat": datetime.now().timestamp(),
|
||||||
'exp': (datetime.now() + timedelta(days=23)).timestamp(),
|
"exp": (datetime.now() + timedelta(days=23)).timestamp(),
|
||||||
'device_id': device_id,
|
"device_id": device_id,
|
||||||
}
|
}
|
||||||
return jwt.encode(claim, SECRET_KEY, algorithm=ALGORITHM)
|
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:
|
try:
|
||||||
claim: SigninClaim = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
claim: SigninClaim = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
||||||
if claim['exp'] - datetime.now().timestamp() <= 10*24*60*60:
|
print(claim["sub"])
|
||||||
new_token = _prolong_token(token)
|
if claim["exp"] - datetime.now().timestamp() <= 10 * 24 * 60 * 60:
|
||||||
return new_token, claim['sub']
|
new_token = _prolong_token(claim)
|
||||||
|
return new_token, claim["sub"]
|
||||||
else:
|
else:
|
||||||
return None, claim['sub']
|
return None, claim["sub"]
|
||||||
except ExpiredSignatureError:
|
except ExpiredSignatureError:
|
||||||
print(f'{token} expire ========================')
|
print(f"{token} expire ========================")
|
||||||
raise ExpiredSignatureError
|
raise ExpiredSignatureError
|
||||||
except JWTError:
|
except JWTError:
|
||||||
print(f'This token {token} is not sign by me ==========================')
|
print(f"This token {token} is not sign by me ==========================")
|
||||||
raise JWTError
|
raise JWTError
|
||||||
|
|
||||||
|
|
||||||
def _prolong_token(claim: SigninClaim) -> str:
|
def _prolong_token(claim: SigninClaim) -> str:
|
||||||
claim['iat'] = datetime.now().timestamp()
|
claim["iat"] = datetime.now().timestamp()
|
||||||
claim['exp'] = (datetime.now() + timedelta(days=30)).timestamp()
|
claim["exp"] = (datetime.now() + timedelta(days=30)).timestamp()
|
||||||
token = jwt.encode(claim, SECRET_KEY, algorithm=ALGORITHM)
|
token = jwt.encode(claim, SECRET_KEY, algorithm=ALGORITHM)
|
||||||
return token
|
return token
|
||||||
|
|
Loading…
Reference in New Issue