Skip to content

Commit 75fd5af

Browse files
committed
[feat]: 组织管理基本功能
1 parent 5ce6150 commit 75fd5af

File tree

2 files changed

+65
-67
lines changed

2 files changed

+65
-67
lines changed

app/api/v1/endpoints/group.py

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
from fastapi import APIRouter, Query, Body, UploadFile, File, Depends, HTTPException
22
from sqlalchemy.ext.asyncio import AsyncSession
3+
from cryptography.fernet import Fernet
34
import os
45
import glob
6+
from datetime import date, datetime
7+
import json
58

69
from app.utils.get_db import get_db
710
from app.utils.auth import get_current_user
8-
from app.curd.group import crud_create, crud_apply_to_enter, crud_get_applications, crud_reply_to_enter, crud_modify_basic_info, crud_modify_admin_list, crud_remove_member, crud_leave_group, crud_get_basic_info, crud_get_people_info, crud_get_my_level
9-
from app.schemas.group import ApplyToEnter, LeaveGroup, GetBasicInfo
11+
from app.curd.group import crud_create, crud_gen_invite_code, crud_enter_group, crud_modify_basic_info, crud_modify_admin_list, crud_remove_member, crud_leave_group, crud_get_basic_info, crud_get_people_info, crud_get_my_level
12+
from app.schemas.group import EnterGroup, LeaveGroup
1013

1114
router = APIRouter()
1215

@@ -28,22 +31,40 @@ async def create(group_name: str = Query(...), group_desc: str = Query(...), gro
2831
f.write(content)
2932
return {"msg": "Group created successfully"}
3033

31-
@router.post("/applyToEnter", response_model=dict)
32-
async def apply_to_enter(model: ApplyToEnter, db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
33-
group_id = model.group_id
34-
user_id = user.get("id")
35-
await crud_apply_to_enter(user_id, group_id, db)
36-
return {"msg": "Application sent successfully"}
34+
@router.get("/genInviteCode", response_model=dict)
35+
async def gen_invite_code(user_email: str = Query(...), group_id: int = Query(...), db: AsyncSession = Depends(get_db)):
36+
await crud_gen_invite_code(user_email, db)
37+
today = date.today()
38+
data = {
39+
"email": user_email,
40+
"group_id": group_id,
41+
"date": today.isoformat()
42+
}
43+
json_data = json.dumps(data).encode()
44+
fernet = Fernet(os.getenv("FERNET_SECRET_KEY"))
45+
encrypted = fernet.encrypt(json_data)
46+
return {"inviteCode": encrypted}
3747

38-
@router.get("/getApplications", response_model=dict)
39-
async def get_applications(group_id: int = Query(...), db: AsyncSession = Depends(get_db)):
40-
users = await crud_get_applications(group_id, db)
41-
return {"users": users}
48+
@router.post("/enterGroup", response_model=dict)
49+
async def enter_group(inviteCode: EnterGroup, db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
50+
code = inviteCode.inviteCode
51+
fernet = Fernet(os.getenv("FERNET_SECRET_KEY"))
4252

43-
@router.post("/replyToEnter", response_model=dict)
44-
async def reply_to_enter(user_id: int = Body(...), group_id: int = Body(...), reply: bool = Body(...), db: AsyncSession = Depends(get_db)):
45-
msg = await crud_reply_to_enter(user_id, group_id, reply, db)
46-
return {"msg": msg}
53+
decrypted = fernet.decrypt(code.encode())
54+
data = json.loads(decrypted)
55+
56+
user_email = user.get("email")
57+
invite_email = data["email"]
58+
if user_email != invite_email:
59+
raise HTTPException(status_code=405, detail="Not your invite code")
60+
61+
invite_date = datetime.strptime(data["date"], "%Y-%m-%d").date()
62+
today = date.today()
63+
if today > invite_date:
64+
raise HTTPException(status_code=406, detail="Invite Code already expired")
65+
66+
await crud_enter_group(user.get("id"), data["group_id"], db)
67+
return {"msg": "Enter thr group successfully"}
4768

4869
@router.post("/modifyBasicInfo", response_model=dict)
4970
async def modify_basic_info(group_id: int = Query(...), group_name: str | None = Query(None), group_desc: str | None = Query(None), group_avatar: UploadFile | None = File(None), db: AsyncSession = Depends(get_db)):
@@ -84,9 +105,8 @@ async def leave_group(model: LeaveGroup, db: AsyncSession = Depends(get_db), use
84105
return {"msg": "You successfully left the group"}
85106

86107
@router.get("/getBasicInfo", response_model=dict)
87-
async def get_basic_info(model: GetBasicInfo, db: AsyncSession = Depends(get_db)):
88-
group_id = model.group_id
89-
name, desc = crud_get_basic_info(group_id, db)
108+
async def get_basic_info(group_id: int = Query(...), db: AsyncSession = Depends(get_db)):
109+
name, desc = await crud_get_basic_info(group_id, db)
90110
find = glob.glob(os.path.join("/lhcos-data/group-avatar", f"{group_id}.*"))
91111
avatar = 'default.png' if not find else find[0].removeprefix("/lhcos-data/group-avatar\\\\")
92112
avatar = '/lhcos-data/group-avatar/' + avatar

app/curd/group.py

Lines changed: 26 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
from fastapi import HTTPException
22
from sqlalchemy.ext.asyncio import AsyncSession
3-
from sqlalchemy.exc import IntegrityError
43
from sqlalchemy import select, insert, delete, update
5-
from app.models.model import User, Group, Folder, Article, Note, Tag, user_group, enter_application
4+
from app.models.model import User, Group, Folder, Article, Note, Tag, user_group
65

76
async def crud_create(leader: int, name: str, description: str, db: AsyncSession):
87
new_group = Group(leader=leader, name=name, description=description)
@@ -11,51 +10,30 @@ async def crud_create(leader: int, name: str, description: str, db: AsyncSession
1110
await db.refresh(new_group)
1211
return new_group.id
1312

14-
async def crud_apply_to_enter(user_id: int, group_id: int, db: AsyncSession):
15-
# 是否已经在组织中
16-
query = select(user_group).where(user_group.c.user_id == user_id, user_group.c.group_id == group_id)
13+
async def crud_gen_invite_code(user_email: str, db: AsyncSession):
14+
# 检查邮箱存在性
15+
query = select(User.id).where(User.email == user_email)
1716
result = await db.execute(query)
18-
existing = result.first()
19-
if existing:
20-
raise HTTPException(status_code=405, detail="Already in the group")
21-
query = select(Group).where(Group.id == group_id)
17+
user_id = result.scalar_one_or_none()
18+
if not user_id:
19+
raise HTTPException(status_code=405, detail="User not existed")
20+
21+
async def crud_enter_group(user_id: int, group_id: int, db: AsyncSession):
22+
# 检查是否已经在组织内
23+
# 已经是组织leader
24+
query = select(Group).where(Group.id == group_id, Group.leader == user_id)
2225
result = await db.execute(query)
2326
group = result.scalar_one_or_none()
24-
if group.leader == user_id:
25-
raise HTTPException(status_code=405, detail="Already in the group")
26-
27-
# 插入申请表,若已存在申请则抛出异常
28-
query = insert(enter_application).values(user_id=user_id, group_id=group_id)
29-
try:
30-
await db.execute(query)
31-
await db.commit()
32-
except IntegrityError:
33-
await db.rollback()
34-
raise HTTPException(status_code=405, detail="Don't apply repeatedly")
35-
36-
async def crud_get_applications(group_id: int, db: AsyncSession):
37-
query = select(User.id, User.username).where(User.id.in_(
38-
select(enter_application.c.user_id).where(enter_application.c.group_id == group_id)
39-
))
40-
result = await db.execute(query)
41-
users = result.all()
42-
return [{"user_id": user.id, "user_name": user.username} for user in users]
43-
44-
async def crud_reply_to_enter(user_id: int, group_id: int, reply: bool, db: AsyncSession):
45-
# 答复后,需要从待处理申请的表中删除表项
46-
query = delete(enter_application).where(enter_application.c.user_id == user_id, enter_application.c.group_id == group_id)
27+
# 已经是组织admin或member
28+
query = select(user_group).where(user_group.c.user_id == user_id, user_group.c.group_id == group_id)
4729
result = await db.execute(query)
48-
if result.rowcount == 0: # 如果没有删除任何行,说明不存在该项
49-
raise HTTPException(status_code=405, detail="Application is not existed or already handled")
50-
await db.commit()
51-
52-
if reply:
53-
new_relation = insert(user_group).values(user_id=user_id, group_id=group_id)
54-
await db.execute(new_relation)
55-
await db.commit()
56-
return "Add new member successfully"
30+
row = result.first()
31+
if group or row:
32+
raise HTTPException(status_code=408, detail="You are already in the group")
5733

58-
return "Refuse the application successfully"
34+
new_relation = insert(user_group).values(user_id=user_id, group_id=group_id)
35+
await db.execute(new_relation)
36+
await db.commit()
5937

6038
async def crud_modify_basic_info(db: AsyncSession, id: int, name: str | None = None, desc: str | None = None):
6139
update_data = {}
@@ -116,16 +94,16 @@ async def crud_get_people_info(group_id: int, db: AsyncSession):
11694
admin_ids = result.scalars().all()
11795
query = select(User).where(User.id.in_(admin_ids))
11896
result = await db.execute(query)
119-
users = result.all()
97+
users = result.scalars().all()
12098
admins = [{"id": user.id, "name": user.username, "avatar": user.avatar} for user in users]
12199

122100
# 普通成员信息
123101
query = select(user_group.c.user_id).where(user_group.c.group_id == group_id, user_group.c.is_admin == False)
124102
result = await db.execute(query)
125-
member_ids = result.scalars.all()
103+
member_ids = result.scalars().all()
126104
query = select(User).where(User.id.in_(member_ids))
127105
result = await db.execute(query)
128-
users = result.all()
106+
users = result.scalars().all()
129107
members = [{"id": user.id, "name": user.username, "avatar": user.avatar} for user in users]
130108

131109
return leader, admins, members
@@ -139,12 +117,12 @@ async def crud_get_my_level(user_id: int, group_id: int, db: AsyncSession):
139117
return 1
140118
query = select(user_group).where(user_group.c.user_id == user_id, user_group.c.group_id == group_id)
141119
result = await db.execute(query)
142-
relation = result.first()
120+
relation = result.first() # relation[0] relation[1] relation[2] 分别为表的第1、2、3列
143121
# 是否是管理员
144-
if relation and relation["is_admin"]:
122+
if relation and relation[2]:
145123
return 2
146124
# 是否是普通成员
147-
if relation: # and not relation["is_admin"]:
125+
if relation:
148126
return 3
149127
# 未加入组织
150128
return 4

0 commit comments

Comments
 (0)