Skip to content

Commit 82d1f3d

Browse files
authored
Информация о пользователе для админки тех. поддержки (#52)
* Информация о пользователе от лк мгу * small changes * small fix * Создание админки * добавил получение информации о пользователе для админки * small fix * изменил get_user_info * black isort * small changes and fixes * linting fixed * добавил проверку на существование пользователя
1 parent 25b0ed8 commit 82d1f3d

File tree

8 files changed

+147
-6
lines changed

8 files changed

+147
-6
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ db:
2222
docker run -d -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust --name db-userdata_api postgres:15
2323

2424
migrate:
25-
alembic upgrade head
25+
source ./venv/bin/activate && alembic upgrade head

tests/test_routes/test_users_get.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from time import sleep
2-
31
import pytest
42

53
from userdata_api.models.db import Info, Param

userdata_api/routes/admin.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from typing import Any
2+
3+
from auth_lib.fastapi import UnionAuth
4+
from fastapi import APIRouter, Depends
5+
6+
from userdata_api.schemas.admin import UserCardGet, UserCardUpdate
7+
from userdata_api.schemas.response_model import StatusResponseModel
8+
from userdata_api.utils.admin import get_user_info, patch_user_info
9+
10+
11+
admin = APIRouter(prefix="/admin", tags=["Admin"])
12+
13+
14+
@admin.get("/user/{user_id}", response_model=UserCardGet)
15+
async def get_user_card(
16+
user_id: int,
17+
user: dict[str, Any] = Depends(UnionAuth(scopes=["userdata.info.admin"], allow_none=False, auto_error=True)),
18+
):
19+
"""
20+
Получает профсоюзную информацию пользователя.
21+
22+
Скоупы: `["userdata.info.admin"]`
23+
"""
24+
25+
return await get_user_info(user_id, user)
26+
27+
28+
@admin.patch("/user/{user_id}", response_model=StatusResponseModel)
29+
async def update_user_card(
30+
new_info: UserCardUpdate,
31+
user_id: int,
32+
user: dict[str, Any] = Depends(UnionAuth(scopes=["userdata.info.admin"], allow_none=False, auto_error=True)),
33+
) -> StatusResponseModel:
34+
"""
35+
Обновить данные в профсоюзной информации пользователя.
36+
37+
Скоупы: `["userdata.info.admin"]`
38+
39+
- **user_id**: id пользователя.
40+
"""
41+
42+
await patch_user_info(new_info, user_id, user)
43+
return StatusResponseModel(status="Success", message="User patch succeeded", ru="Изменение успешно")

userdata_api/routes/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from settings import get_settings
66
from userdata_api import __version__
77

8+
from .admin import admin
89
from .category import category
910
from .param import param
1011
from .source import source
@@ -41,3 +42,4 @@
4142
app.include_router(category)
4243
app.include_router(param)
4344
app.include_router(user)
45+
app.include_router(admin)

userdata_api/routes/user.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
from auth_lib.fastapi import UnionAuth
44
from fastapi import APIRouter, Depends, Query
5-
from fastapi_sqlalchemy import db
65

7-
from userdata_api.models.db import Category, Info
86
from userdata_api.schemas.response_model import StatusResponseModel
97
from userdata_api.schemas.user import UserInfoGet, UserInfoUpdate, UsersInfoGet
108
from userdata_api.utils.user import get_user_info as get

userdata_api/schemas/admin.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from .base import Base
2+
3+
4+
class UserCardGet(Base):
5+
user_id: int
6+
full_name: str | None = None
7+
student_card_number: str | None = None
8+
union_card_number: str | None = None
9+
is_union_member: str
10+
11+
12+
class UserCardUpdate(Base):
13+
full_name: str | None = None
14+
student_card_number: str | None = None

userdata_api/utils/admin.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
from __future__ import annotations
2+
3+
from fastapi_sqlalchemy import db
4+
5+
from userdata_api.exceptions import ObjectNotFound
6+
from userdata_api.models.db import Info, Param
7+
from userdata_api.schemas.admin import UserCardGet, UserCardUpdate
8+
from userdata_api.schemas.user import UserInfo, UserInfoUpdate
9+
10+
from .user import patch_user_info as user_patch
11+
12+
13+
async def patch_user_info(new: UserCardUpdate, user_id: int, user: dict[str, int | list[dict[str, str | int]]]) -> None:
14+
"""
15+
Обновить информацию о пользователе в соотетствии с переданным токеном.
16+
17+
Метод обновляет только информацию из источников `admin`.
18+
19+
Для обновления от имени админа нужен скоуп `userdata.info.admin`
20+
21+
:param new: модель запроса, в ней то, на что будет изменена информация о пользователе
22+
:param user_id: Айди пользователя
23+
:param user: Сессия пользователя выполняющего запрос
24+
:return: get_user_info для текущего пользователя с переданными правами
25+
"""
26+
update_info = []
27+
if new.full_name is not None:
28+
update_info.append(UserInfo(category="Личная информация", param="Полное имя", value=new.full_name))
29+
if new.student_card_number is not None:
30+
update_info.append(
31+
UserInfo(category="Учёба", param="Номер студенческого билета", value=new.student_card_number)
32+
)
33+
if update_info:
34+
update_request = UserInfoUpdate(items=update_info, source="admin")
35+
await user_patch(update_request, user_id, user)
36+
37+
38+
async def get_user_info(user_id: int, user: dict[str, int | list[dict[str, str | int]]]) -> UserCardGet:
39+
"""
40+
Получить профсоюзную информацию пользователя для админки.
41+
42+
:param user_id: Айди пользователя, информацию о котором запрашиваем
43+
:param user: Сессия пользователя, выполняющего запрос (должен иметь права администратора)
44+
:return: Словарь с данными пользователя:
45+
- user_id: ID пользователя
46+
- full_name: Полное имя (из параметра "Полное имя")
47+
- student_card_number: Номер студенческого билета (из параметра "Номер студенческого билета")
48+
- union_card_number: Номер профсоюзного билета (из параметра "Номер профсоюзного билета")
49+
- is_union_member: Статус мэтчинга (из параметра "Членство в профсоюзе")
50+
- last_check_timestamp: Дата последней проверки
51+
"""
52+
users = db.session.query(Info).filter(Info.owner_id == user_id).first()
53+
if not users:
54+
raise ObjectNotFound(Info, user_id)
55+
full_name = (
56+
db.session.query(Info)
57+
.join(Info.param)
58+
.filter(Info.owner_id == user_id, Param.name == "Полное имя")
59+
.one_or_none()
60+
)
61+
is_union_member = (
62+
db.session.query(Info)
63+
.join(Info.param)
64+
.filter(Info.owner_id == user_id, Param.name == "Членство в профсоюзе")
65+
.one_or_none()
66+
)
67+
student_card_number = (
68+
db.session.query(Info)
69+
.join(Info.param)
70+
.filter(Info.owner_id == user_id, Param.name == "Номер студенческого билета")
71+
.one_or_none()
72+
)
73+
union_card_number = (
74+
db.session.query(Info)
75+
.join(Info.param)
76+
.filter(Info.owner_id == user_id, Param.name == "Номер профсоюзного билета")
77+
.one_or_none()
78+
)
79+
result = {
80+
"user_id": user_id,
81+
"full_name": full_name.value if full_name else None,
82+
"student_card_number": student_card_number.value if student_card_number else None,
83+
"union_card_number": union_card_number.value if union_card_number else None,
84+
"is_union_member": is_union_member.value if is_union_member else "false",
85+
}
86+
return result

userdata_api/utils/user.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from re import search
44

55
from fastapi_sqlalchemy import db
6-
from sqlalchemy import String, cast, func, not_, or_
6+
from sqlalchemy import not_, or_
77

88
from userdata_api.exceptions import Forbidden, InvalidValidation, ObjectNotFound
99
from userdata_api.models.db import Category, Info, Param, Source, ViewType

0 commit comments

Comments
 (0)