From 7881a437b6b548bbafb5d3fcb5deb83d34e7c2a7 Mon Sep 17 00:00:00 2001 From: petrCher <88943157+petrCher@users.noreply.github.com> Date: Sun, 7 Dec 2025 19:00:51 +0300 Subject: [PATCH 01/11] =?UTF-8?q?=D0=98=D0=BD=D1=84=D0=BE=D1=80=D0=BC?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BE=20=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D0=B5=20=D0=BE=D1=82?= =?UTF-8?q?=20=D0=BB=D0=BA=20=D0=BC=D0=B3=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- tests/test_routes/test_users_get.py | 2 -- userdata_api/routes/admin.py | 42 +++++++++++++++++++++++++++++ userdata_api/routes/base.py | 2 ++ userdata_api/routes/user.py | 2 -- userdata_api/schemas/admin.py | 17 ++++++++++++ userdata_api/schemas/user.py | 8 ++++++ userdata_api/utils/admin.py | 38 ++++++++++++++++++++++++++ userdata_api/utils/user.py | 2 +- 9 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 userdata_api/routes/admin.py create mode 100644 userdata_api/schemas/admin.py create mode 100644 userdata_api/utils/admin.py diff --git a/Makefile b/Makefile index 16652ca..4a75ed1 100644 --- a/Makefile +++ b/Makefile @@ -22,4 +22,4 @@ db: docker run -d -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust --name db-userdata_api postgres:15 migrate: - alembic upgrade head + source ./venv/bin/activate && alembic upgrade head diff --git a/tests/test_routes/test_users_get.py b/tests/test_routes/test_users_get.py index 65d1753..3e779f9 100644 --- a/tests/test_routes/test_users_get.py +++ b/tests/test_routes/test_users_get.py @@ -1,5 +1,3 @@ -from time import sleep - import pytest from userdata_api.models.db import Info, Param diff --git a/userdata_api/routes/admin.py b/userdata_api/routes/admin.py new file mode 100644 index 0000000..aa2d5f6 --- /dev/null +++ b/userdata_api/routes/admin.py @@ -0,0 +1,42 @@ +from typing import Any + +from auth_lib.fastapi import UnionAuth +from fastapi import APIRouter, Depends + +from userdata_api.schemas.admin import UserDebugCardGet, UserDebugCardUpdate +from userdata_api.schemas.response_model import StatusResponseModel +from userdata_api.utils.admin import get_user_info as get +from userdata_api.utils.admin import patch_user_info as patch + + +admin = APIRouter(prefix="/admin", tags=["Admin"]) + + +@admin.get("/user/{user_id}", response_model=UserDebugCardGet) +async def get_user_debug_card( + user_id: int, ##or full_name + user: dict[str, Any] = Depends(UnionAuth(scopes=[], allow_none=False, auto_error=True)), ##scopes +) -> UserDebugCardGet: + """ + Получает профсоюзную информацию пользователя. + """ + + return UserDebugCardGet.model_validate(await get(user_id, user)) + + +@admin.patch("/user/{user_id}", response_model=StatusResponseModel) +async def update_user_debug_card( + new_info: UserDebugCardUpdate, + user_id: int, + user: dict[str, Any] = Depends(UnionAuth(scopes=[], allow_none=False, auto_error=True)), ##scopes +) -> StatusResponseModel: + """ + Обновить данные в профсоюзной информации пользователя. + + - **user_id**: id пользователя. + + Возвращает **ObjectNotFound** пользователь с указанным user_id не найден. + """ + + await patch(new_info, user_id, user) + return StatusResponseModel(status="Success", message="User patch succeeded", ru="Изменение успешно") diff --git a/userdata_api/routes/base.py b/userdata_api/routes/base.py index 35b8667..84b566b 100644 --- a/userdata_api/routes/base.py +++ b/userdata_api/routes/base.py @@ -5,6 +5,7 @@ from settings import get_settings from userdata_api import __version__ +from .admin import admin from .category import category from .param import param from .source import source @@ -41,3 +42,4 @@ app.include_router(category) app.include_router(param) app.include_router(user) +app.include_router(admin) diff --git a/userdata_api/routes/user.py b/userdata_api/routes/user.py index 3b64f0a..7ff8fe5 100644 --- a/userdata_api/routes/user.py +++ b/userdata_api/routes/user.py @@ -2,9 +2,7 @@ from auth_lib.fastapi import UnionAuth from fastapi import APIRouter, Depends, Query -from fastapi_sqlalchemy import db -from userdata_api.models.db import Category, Info from userdata_api.schemas.response_model import StatusResponseModel from userdata_api.schemas.user import UserInfoGet, UserInfoUpdate, UsersInfoGet from userdata_api.utils.user import get_user_info as get diff --git a/userdata_api/schemas/admin.py b/userdata_api/schemas/admin.py new file mode 100644 index 0000000..6f5ea7d --- /dev/null +++ b/userdata_api/schemas/admin.py @@ -0,0 +1,17 @@ +from datetime import datetime + +from .base import Base + + +class UserDebugCardGet(Base): + user_id: int + full_name: str | None = None + student_card_number: str | None = None + union_card_number: str | None = None + is_union_member: str + last_check_timestamp: datetime | None = None + + +class UserDebugCardUpdate(Base): + full_name: str | None = None + student_card_number: str | None = None diff --git a/userdata_api/schemas/user.py b/userdata_api/schemas/user.py index b48d27f..3bb3366 100644 --- a/userdata_api/schemas/user.py +++ b/userdata_api/schemas/user.py @@ -34,3 +34,11 @@ class UsersInfoGet(Base): class UserInfoUpdate(UserInfoGet): source: constr(min_length=1) + + +class UserDebugCard(Base): + user_id: int + full_name: str | None = None + student_card_number: str | None = None + union_card_number: str | None = None + is_union_member: str diff --git a/userdata_api/utils/admin.py b/userdata_api/utils/admin.py new file mode 100644 index 0000000..903a6c5 --- /dev/null +++ b/userdata_api/utils/admin.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +from userdata_api.schemas.admin import UserDebugCardGet, UserDebugCardUpdate + + +async def patch_user_info( + new: UserDebugCardUpdate, user_id: int, user: dict[str, int | list[dict[str, str | int]]] +) -> None: + """ + Обновить информацию о пользователе в соотетствии с переданным токеном. + + Метод обновляет только информацию из источников `admin`, `user` или `dwh`. + + Для обновления от имени админа нужен скоуп `userdata.info.admin` + + Для обновления информации из dwh нужен скоуп `userdata.info.dwh` + + :param new: модель запроса, в ней то, на что будет изменена информация о пользователе + :param user_id: Айди пользователя + :param user: Сессия пользователя выполняющего запрос + :return: get_user_info для текущего пользователя с переданными правами + """ + + +async def get_user_info(user_id: int, user: dict[str, int | list[dict[str, str | int]]]) -> UserDebugCardGet: + """ + Получить профсоюзную информацию пользователя для админки. + + :param user_id: Айди пользователя, информацию о котором запрашиваем + :param user: Сессия пользователя, выполняющего запрос (должен иметь права администратора) + :return: Словарь с данными пользователя: + - user_id: ID пользователя + - full_name: Полное имя (из параметра "Полное имя") + - student_card_number: Номер студенческого билета (из параметра "Номер студенческого билета") + - union_card_number: Номер профсоюзного билета (из параметра "Номер профсоюзного билета") + - is_union_member: Статус мэтчинга (из параметра "Членство в профсоюзе") + - last_check_timestamp: Дата последней проверки + """ diff --git a/userdata_api/utils/user.py b/userdata_api/utils/user.py index 9a32865..a854e00 100644 --- a/userdata_api/utils/user.py +++ b/userdata_api/utils/user.py @@ -3,7 +3,7 @@ from re import search from fastapi_sqlalchemy import db -from sqlalchemy import String, cast, func, not_, or_ +from sqlalchemy import not_, or_ from userdata_api.exceptions import Forbidden, InvalidValidation, ObjectNotFound from userdata_api.models.db import Category, Info, Param, Source, ViewType From adb809f1085f71a4681f58db0a49f19db9d9693f Mon Sep 17 00:00:00 2001 From: petrCher <88943157+petrCher@users.noreply.github.com> Date: Sun, 7 Dec 2025 19:07:15 +0300 Subject: [PATCH 02/11] small changes --- tests/test_routes/test_users_get.py | 2 ++ userdata_api/routes/user.py | 2 ++ userdata_api/schemas/user.py | 10 +--------- userdata_api/utils/user.py | 2 +- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tests/test_routes/test_users_get.py b/tests/test_routes/test_users_get.py index 3e779f9..65d1753 100644 --- a/tests/test_routes/test_users_get.py +++ b/tests/test_routes/test_users_get.py @@ -1,3 +1,5 @@ +from time import sleep + import pytest from userdata_api.models.db import Info, Param diff --git a/userdata_api/routes/user.py b/userdata_api/routes/user.py index 7ff8fe5..3b64f0a 100644 --- a/userdata_api/routes/user.py +++ b/userdata_api/routes/user.py @@ -2,7 +2,9 @@ from auth_lib.fastapi import UnionAuth from fastapi import APIRouter, Depends, Query +from fastapi_sqlalchemy import db +from userdata_api.models.db import Category, Info from userdata_api.schemas.response_model import StatusResponseModel from userdata_api.schemas.user import UserInfoGet, UserInfoUpdate, UsersInfoGet from userdata_api.utils.user import get_user_info as get diff --git a/userdata_api/schemas/user.py b/userdata_api/schemas/user.py index 3bb3366..402f213 100644 --- a/userdata_api/schemas/user.py +++ b/userdata_api/schemas/user.py @@ -33,12 +33,4 @@ class UsersInfoGet(Base): class UserInfoUpdate(UserInfoGet): - source: constr(min_length=1) - - -class UserDebugCard(Base): - user_id: int - full_name: str | None = None - student_card_number: str | None = None - union_card_number: str | None = None - is_union_member: str + source: constr(min_length=1) \ No newline at end of file diff --git a/userdata_api/utils/user.py b/userdata_api/utils/user.py index a854e00..9a32865 100644 --- a/userdata_api/utils/user.py +++ b/userdata_api/utils/user.py @@ -3,7 +3,7 @@ from re import search from fastapi_sqlalchemy import db -from sqlalchemy import not_, or_ +from sqlalchemy import String, cast, func, not_, or_ from userdata_api.exceptions import Forbidden, InvalidValidation, ObjectNotFound from userdata_api.models.db import Category, Info, Param, Source, ViewType From 9085119d730804e673a6f9553b339eb7fdd8b6c7 Mon Sep 17 00:00:00 2001 From: petrCher <88943157+petrCher@users.noreply.github.com> Date: Sun, 7 Dec 2025 19:09:00 +0300 Subject: [PATCH 03/11] small fix --- userdata_api/schemas/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/userdata_api/schemas/user.py b/userdata_api/schemas/user.py index 402f213..b48d27f 100644 --- a/userdata_api/schemas/user.py +++ b/userdata_api/schemas/user.py @@ -33,4 +33,4 @@ class UsersInfoGet(Base): class UserInfoUpdate(UserInfoGet): - source: constr(min_length=1) \ No newline at end of file + source: constr(min_length=1) From ab0aeb6bd9fce5c580a2251908fc322de59d0742 Mon Sep 17 00:00:00 2001 From: petrCher <88943157+petrCher@users.noreply.github.com> Date: Sun, 7 Dec 2025 20:31:56 +0300 Subject: [PATCH 04/11] =?UTF-8?q?=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- userdata_api/routes/admin.py | 8 ++++++-- userdata_api/schemas/admin.py | 3 --- userdata_api/utils/admin.py | 33 +++++++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/userdata_api/routes/admin.py b/userdata_api/routes/admin.py index aa2d5f6..fb8c208 100644 --- a/userdata_api/routes/admin.py +++ b/userdata_api/routes/admin.py @@ -15,10 +15,12 @@ @admin.get("/user/{user_id}", response_model=UserDebugCardGet) async def get_user_debug_card( user_id: int, ##or full_name - user: dict[str, Any] = Depends(UnionAuth(scopes=[], allow_none=False, auto_error=True)), ##scopes + user: dict[str, Any] = Depends(UnionAuth(scopes=["userdata.info.admin"], allow_none=False, auto_error=True)), ) -> UserDebugCardGet: """ Получает профсоюзную информацию пользователя. + + Скоупы: `["userdata.info.admin"]` """ return UserDebugCardGet.model_validate(await get(user_id, user)) @@ -28,11 +30,13 @@ async def get_user_debug_card( async def update_user_debug_card( new_info: UserDebugCardUpdate, user_id: int, - user: dict[str, Any] = Depends(UnionAuth(scopes=[], allow_none=False, auto_error=True)), ##scopes + user: dict[str, Any] = Depends(UnionAuth(scopes=["userdata.info.admin"], allow_none=False, auto_error=True)), ) -> StatusResponseModel: """ Обновить данные в профсоюзной информации пользователя. + Скоупы: `["userdata.info.admin"]` + - **user_id**: id пользователя. Возвращает **ObjectNotFound** пользователь с указанным user_id не найден. diff --git a/userdata_api/schemas/admin.py b/userdata_api/schemas/admin.py index 6f5ea7d..ce6ca5e 100644 --- a/userdata_api/schemas/admin.py +++ b/userdata_api/schemas/admin.py @@ -1,5 +1,3 @@ -from datetime import datetime - from .base import Base @@ -9,7 +7,6 @@ class UserDebugCardGet(Base): student_card_number: str | None = None union_card_number: str | None = None is_union_member: str - last_check_timestamp: datetime | None = None class UserDebugCardUpdate(Base): diff --git a/userdata_api/utils/admin.py b/userdata_api/utils/admin.py index 903a6c5..3fe889a 100644 --- a/userdata_api/utils/admin.py +++ b/userdata_api/utils/admin.py @@ -1,6 +1,15 @@ from __future__ import annotations +from re import search + +from fastapi_sqlalchemy import db +from sqlalchemy import String, cast, func, not_, or_ + +from userdata_api.exceptions import Forbidden, InvalidValidation, ObjectNotFound +from userdata_api.models.db import Category, Info, Param, Source, ViewType from userdata_api.schemas.admin import UserDebugCardGet, UserDebugCardUpdate +from .user import patch_user_info as user_patch +from userdata_api.schemas.user import UserInfoUpdate, UserInfo async def patch_user_info( @@ -9,18 +18,34 @@ async def patch_user_info( """ Обновить информацию о пользователе в соотетствии с переданным токеном. - Метод обновляет только информацию из источников `admin`, `user` или `dwh`. + Метод обновляет только информацию из источников `admin`. Для обновления от имени админа нужен скоуп `userdata.info.admin` - Для обновления информации из dwh нужен скоуп `userdata.info.dwh` - :param new: модель запроса, в ней то, на что будет изменена информация о пользователе :param user_id: Айди пользователя :param user: Сессия пользователя выполняющего запрос :return: get_user_info для текущего пользователя с переданными правами """ - + update_info = [] + if new.full_name is not None: + update_info.append(UserInfo( + category="Личная информация", + param="Полное имя", + value=new.full_name + )) + if new.student_card_number is not None: + update_info.append(UserInfo( + category="Учёба", + param="Номер студенческого билета", + value=new.student_card_number + )) + if update_info: + update_request = UserInfoUpdate( + items=update_info, + source="admin" + ) + await user_patch(update_request, user_id, user) async def get_user_info(user_id: int, user: dict[str, int | list[dict[str, str | int]]]) -> UserDebugCardGet: """ From a05192d6d5ace37bb4ea9bf02d82993d068bd48a Mon Sep 17 00:00:00 2001 From: petrCher <88943157+petrCher@users.noreply.github.com> Date: Sun, 7 Dec 2025 20:47:52 +0300 Subject: [PATCH 05/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20=D0=BE=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=20=D0=B4=D0=BB=D1=8F=20=D0=B0=D0=B4?= =?UTF-8?q?=D0=BC=D0=B8=D0=BD=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- userdata_api/utils/admin.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/userdata_api/utils/admin.py b/userdata_api/utils/admin.py index 3fe889a..5ba300a 100644 --- a/userdata_api/utils/admin.py +++ b/userdata_api/utils/admin.py @@ -9,6 +9,7 @@ from userdata_api.models.db import Category, Info, Param, Source, ViewType from userdata_api.schemas.admin import UserDebugCardGet, UserDebugCardUpdate from .user import patch_user_info as user_patch +from .user import get_user_info as user_get from userdata_api.schemas.user import UserInfoUpdate, UserInfo @@ -61,3 +62,21 @@ async def get_user_info(user_id: int, user: dict[str, int | list[dict[str, str | - is_union_member: Статус мэтчинга (из параметра "Членство в профсоюзе") - last_check_timestamp: Дата последней проверки """ + user_info_response = await user_get(user_id, user) + result = { + "user_id": user_id, + "full_name": None, + "student_card_number": None, + "union_card_number": None, + "is_union_member": "false", + } + for item in user_info_response.items: + if item.param == "Полное имя": + result["full_name"] = item.value + elif item.param == "Номер студенческого билета": + result["student_card_number"] = item.value + elif item.param == "Номер профсоюзного билета": + result["union_card_number"] = item.value + elif item.param == "Членство в профсоюзе": + result["is_union_member"] = item.value + return result From 32ba77445e73f4b26ac4e8fe9b4e7027506542a3 Mon Sep 17 00:00:00 2001 From: petrCher <88943157+petrCher@users.noreply.github.com> Date: Sun, 7 Dec 2025 21:31:04 +0300 Subject: [PATCH 06/11] small fix --- userdata_api/routes/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/userdata_api/routes/admin.py b/userdata_api/routes/admin.py index fb8c208..e38b4b2 100644 --- a/userdata_api/routes/admin.py +++ b/userdata_api/routes/admin.py @@ -14,7 +14,7 @@ @admin.get("/user/{user_id}", response_model=UserDebugCardGet) async def get_user_debug_card( - user_id: int, ##or full_name + user_id: int, user: dict[str, Any] = Depends(UnionAuth(scopes=["userdata.info.admin"], allow_none=False, auto_error=True)), ) -> UserDebugCardGet: """ From 9bed589bfcf7b8385fb1d2319df644ca3a17a3e8 Mon Sep 17 00:00:00 2001 From: petrCher <88943157+petrCher@users.noreply.github.com> Date: Sun, 7 Dec 2025 21:54:07 +0300 Subject: [PATCH 07/11] =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20get=5Fuser=5Finfo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- userdata_api/utils/admin.py | 42 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/userdata_api/utils/admin.py b/userdata_api/utils/admin.py index 5ba300a..669f47b 100644 --- a/userdata_api/utils/admin.py +++ b/userdata_api/utils/admin.py @@ -1,15 +1,9 @@ from __future__ import annotations -from re import search - from fastapi_sqlalchemy import db -from sqlalchemy import String, cast, func, not_, or_ - -from userdata_api.exceptions import Forbidden, InvalidValidation, ObjectNotFound -from userdata_api.models.db import Category, Info, Param, Source, ViewType +from userdata_api.models.db import Info, Param from userdata_api.schemas.admin import UserDebugCardGet, UserDebugCardUpdate from .user import patch_user_info as user_patch -from .user import get_user_info as user_get from userdata_api.schemas.user import UserInfoUpdate, UserInfo @@ -62,21 +56,27 @@ async def get_user_info(user_id: int, user: dict[str, int | list[dict[str, str | - is_union_member: Статус мэтчинга (из параметра "Членство в профсоюзе") - last_check_timestamp: Дата последней проверки """ - user_info_response = await user_get(user_id, user) + full_name = db.session.query(Info).join(Info.param).filter( + Info.owner_id == user_id, + Param.name == "Полное имя" + ).one_or_none() + is_union_member = db.session.query(Info).join(Info.param).filter( + Info.owner_id == user_id, + Param.name == "Членство в профсоюзе" + ).one_or_none() + student_card_number = db.session.query(Info).join(Info.param).filter( + Info.owner_id == user_id, + Param.name == "Номер студенческого билета" + ).one_or_none() + union_card_number = db.session.query(Info).join(Info.param).filter( + Info.owner_id == user_id, + Param.name == "Номер профсоюзного билета" + ).one_or_none() result = { "user_id": user_id, - "full_name": None, - "student_card_number": None, - "union_card_number": None, - "is_union_member": "false", + "full_name": full_name.value if full_name else None, + "student_card_number": student_card_number.value if student_card_number else None, + "union_card_number": union_card_number.value if union_card_number else None, + "is_union_member": is_union_member.value if is_union_member else "false", } - for item in user_info_response.items: - if item.param == "Полное имя": - result["full_name"] = item.value - elif item.param == "Номер студенческого билета": - result["student_card_number"] = item.value - elif item.param == "Номер профсоюзного билета": - result["union_card_number"] = item.value - elif item.param == "Членство в профсоюзе": - result["is_union_member"] = item.value return result From 7dc3d735137fb4287e771f7e2d4ab4b13656f6df Mon Sep 17 00:00:00 2001 From: petrCher <88943157+petrCher@users.noreply.github.com> Date: Sun, 7 Dec 2025 22:22:59 +0300 Subject: [PATCH 08/11] black isort --- tests/test_routes/test_users_get.py | 2 - userdata_api/routes/user.py | 2 - userdata_api/utils/admin.py | 64 +++++++++++++++-------------- userdata_api/utils/user.py | 2 +- 4 files changed, 34 insertions(+), 36 deletions(-) diff --git a/tests/test_routes/test_users_get.py b/tests/test_routes/test_users_get.py index 65d1753..3e779f9 100644 --- a/tests/test_routes/test_users_get.py +++ b/tests/test_routes/test_users_get.py @@ -1,5 +1,3 @@ -from time import sleep - import pytest from userdata_api.models.db import Info, Param diff --git a/userdata_api/routes/user.py b/userdata_api/routes/user.py index 3b64f0a..7ff8fe5 100644 --- a/userdata_api/routes/user.py +++ b/userdata_api/routes/user.py @@ -2,9 +2,7 @@ from auth_lib.fastapi import UnionAuth from fastapi import APIRouter, Depends, Query -from fastapi_sqlalchemy import db -from userdata_api.models.db import Category, Info from userdata_api.schemas.response_model import StatusResponseModel from userdata_api.schemas.user import UserInfoGet, UserInfoUpdate, UsersInfoGet from userdata_api.utils.user import get_user_info as get diff --git a/userdata_api/utils/admin.py b/userdata_api/utils/admin.py index 669f47b..5733bab 100644 --- a/userdata_api/utils/admin.py +++ b/userdata_api/utils/admin.py @@ -1,10 +1,12 @@ from __future__ import annotations from fastapi_sqlalchemy import db + from userdata_api.models.db import Info, Param from userdata_api.schemas.admin import UserDebugCardGet, UserDebugCardUpdate +from userdata_api.schemas.user import UserInfo, UserInfoUpdate + from .user import patch_user_info as user_patch -from userdata_api.schemas.user import UserInfoUpdate, UserInfo async def patch_user_info( @@ -24,24 +26,16 @@ async def patch_user_info( """ update_info = [] if new.full_name is not None: - update_info.append(UserInfo( - category="Личная информация", - param="Полное имя", - value=new.full_name - )) + update_info.append(UserInfo(category="Личная информация", param="Полное имя", value=new.full_name)) if new.student_card_number is not None: - update_info.append(UserInfo( - category="Учёба", - param="Номер студенческого билета", - value=new.student_card_number - )) - if update_info: - update_request = UserInfoUpdate( - items=update_info, - source="admin" + update_info.append( + UserInfo(category="Учёба", param="Номер студенческого билета", value=new.student_card_number) ) + if update_info: + update_request = UserInfoUpdate(items=update_info, source="admin") await user_patch(update_request, user_id, user) + async def get_user_info(user_id: int, user: dict[str, int | list[dict[str, str | int]]]) -> UserDebugCardGet: """ Получить профсоюзную информацию пользователя для админки. @@ -56,22 +50,30 @@ async def get_user_info(user_id: int, user: dict[str, int | list[dict[str, str | - is_union_member: Статус мэтчинга (из параметра "Членство в профсоюзе") - last_check_timestamp: Дата последней проверки """ - full_name = db.session.query(Info).join(Info.param).filter( - Info.owner_id == user_id, - Param.name == "Полное имя" - ).one_or_none() - is_union_member = db.session.query(Info).join(Info.param).filter( - Info.owner_id == user_id, - Param.name == "Членство в профсоюзе" - ).one_or_none() - student_card_number = db.session.query(Info).join(Info.param).filter( - Info.owner_id == user_id, - Param.name == "Номер студенческого билета" - ).one_or_none() - union_card_number = db.session.query(Info).join(Info.param).filter( - Info.owner_id == user_id, - Param.name == "Номер профсоюзного билета" - ).one_or_none() + full_name = ( + db.session.query(Info) + .join(Info.param) + .filter(Info.owner_id == user_id, Param.name == "Полное имя") + .one_or_none() + ) + is_union_member = ( + db.session.query(Info) + .join(Info.param) + .filter(Info.owner_id == user_id, Param.name == "Членство в профсоюзе") + .one_or_none() + ) + student_card_number = ( + db.session.query(Info) + .join(Info.param) + .filter(Info.owner_id == user_id, Param.name == "Номер студенческого билета") + .one_or_none() + ) + union_card_number = ( + db.session.query(Info) + .join(Info.param) + .filter(Info.owner_id == user_id, Param.name == "Номер профсоюзного билета") + .one_or_none() + ) result = { "user_id": user_id, "full_name": full_name.value if full_name else None, diff --git a/userdata_api/utils/user.py b/userdata_api/utils/user.py index 9a32865..a854e00 100644 --- a/userdata_api/utils/user.py +++ b/userdata_api/utils/user.py @@ -3,7 +3,7 @@ from re import search from fastapi_sqlalchemy import db -from sqlalchemy import String, cast, func, not_, or_ +from sqlalchemy import not_, or_ from userdata_api.exceptions import Forbidden, InvalidValidation, ObjectNotFound from userdata_api.models.db import Category, Info, Param, Source, ViewType From 7a2191fa72c0ed0efbb2151a2637926510e42304 Mon Sep 17 00:00:00 2001 From: petrCher <88943157+petrCher@users.noreply.github.com> Date: Fri, 12 Dec 2025 22:40:50 +0300 Subject: [PATCH 09/11] small changes and fixes --- userdata_api/routes/admin.py | 22 ++++++++++------------ userdata_api/schemas/admin.py | 6 +++--- userdata_api/utils/admin.py | 8 ++++---- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/userdata_api/routes/admin.py b/userdata_api/routes/admin.py index e38b4b2..282fe08 100644 --- a/userdata_api/routes/admin.py +++ b/userdata_api/routes/admin.py @@ -3,32 +3,32 @@ from auth_lib.fastapi import UnionAuth from fastapi import APIRouter, Depends -from userdata_api.schemas.admin import UserDebugCardGet, UserDebugCardUpdate +from userdata_api.schemas.admin import UserCardGet, UserCardUpdate from userdata_api.schemas.response_model import StatusResponseModel -from userdata_api.utils.admin import get_user_info as get -from userdata_api.utils.admin import patch_user_info as patch +from userdata_api.utils.admin import get_user_info +from userdata_api.utils.admin import patch_user_info admin = APIRouter(prefix="/admin", tags=["Admin"]) -@admin.get("/user/{user_id}", response_model=UserDebugCardGet) -async def get_user_debug_card( +@admin.get("/user/{user_id}", response_model=UserCardGet) +async def get_user_card( user_id: int, user: dict[str, Any] = Depends(UnionAuth(scopes=["userdata.info.admin"], allow_none=False, auto_error=True)), -) -> UserDebugCardGet: +) -> UserCardGet: """ Получает профсоюзную информацию пользователя. Скоупы: `["userdata.info.admin"]` """ - return UserDebugCardGet.model_validate(await get(user_id, user)) + return UserCardGet.model_validate(await get_user_info(user_id, user)) @admin.patch("/user/{user_id}", response_model=StatusResponseModel) -async def update_user_debug_card( - new_info: UserDebugCardUpdate, +async def update_user_card( + new_info: UserCardUpdate, user_id: int, user: dict[str, Any] = Depends(UnionAuth(scopes=["userdata.info.admin"], allow_none=False, auto_error=True)), ) -> StatusResponseModel: @@ -38,9 +38,7 @@ async def update_user_debug_card( Скоупы: `["userdata.info.admin"]` - **user_id**: id пользователя. - - Возвращает **ObjectNotFound** пользователь с указанным user_id не найден. """ - await patch(new_info, user_id, user) + await patch_user_info(new_info, user_id, user) return StatusResponseModel(status="Success", message="User patch succeeded", ru="Изменение успешно") diff --git a/userdata_api/schemas/admin.py b/userdata_api/schemas/admin.py index ce6ca5e..09facc6 100644 --- a/userdata_api/schemas/admin.py +++ b/userdata_api/schemas/admin.py @@ -1,14 +1,14 @@ from .base import Base -class UserDebugCardGet(Base): +class UserCardGet(Base): user_id: int full_name: str | None = None student_card_number: str | None = None union_card_number: str | None = None - is_union_member: str + is_union_member: bool -class UserDebugCardUpdate(Base): +class UserCardUpdate(Base): full_name: str | None = None student_card_number: str | None = None diff --git a/userdata_api/utils/admin.py b/userdata_api/utils/admin.py index 5733bab..1c7a44c 100644 --- a/userdata_api/utils/admin.py +++ b/userdata_api/utils/admin.py @@ -3,14 +3,14 @@ from fastapi_sqlalchemy import db from userdata_api.models.db import Info, Param -from userdata_api.schemas.admin import UserDebugCardGet, UserDebugCardUpdate +from userdata_api.schemas.admin import UserCardGet, UserCardUpdate from userdata_api.schemas.user import UserInfo, UserInfoUpdate from .user import patch_user_info as user_patch async def patch_user_info( - new: UserDebugCardUpdate, user_id: int, user: dict[str, int | list[dict[str, str | int]]] + new: UserCardUpdate, user_id: int, user: dict[str, int | list[dict[str, str | int]]] ) -> None: """ Обновить информацию о пользователе в соотетствии с переданным токеном. @@ -36,7 +36,7 @@ async def patch_user_info( await user_patch(update_request, user_id, user) -async def get_user_info(user_id: int, user: dict[str, int | list[dict[str, str | int]]]) -> UserDebugCardGet: +async def get_user_info(user_id: int, user: dict[str, int | list[dict[str, str | int]]]) -> UserCardGet: """ Получить профсоюзную информацию пользователя для админки. @@ -79,6 +79,6 @@ async def get_user_info(user_id: int, user: dict[str, int | list[dict[str, str | "full_name": full_name.value if full_name else None, "student_card_number": student_card_number.value if student_card_number else None, "union_card_number": union_card_number.value if union_card_number else None, - "is_union_member": is_union_member.value if is_union_member else "false", + "is_union_member": is_union_member.value if is_union_member else False, } return result From bf9e1968aa44c0006c38925f4a55c805e9febb1c Mon Sep 17 00:00:00 2001 From: petrCher <88943157+petrCher@users.noreply.github.com> Date: Fri, 12 Dec 2025 23:12:52 +0300 Subject: [PATCH 10/11] linting fixed --- userdata_api/routes/admin.py | 7 +++---- userdata_api/schemas/admin.py | 2 +- userdata_api/utils/admin.py | 6 ++---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/userdata_api/routes/admin.py b/userdata_api/routes/admin.py index 282fe08..36e6597 100644 --- a/userdata_api/routes/admin.py +++ b/userdata_api/routes/admin.py @@ -5,8 +5,7 @@ from userdata_api.schemas.admin import UserCardGet, UserCardUpdate from userdata_api.schemas.response_model import StatusResponseModel -from userdata_api.utils.admin import get_user_info -from userdata_api.utils.admin import patch_user_info +from userdata_api.utils.admin import get_user_info, patch_user_info admin = APIRouter(prefix="/admin", tags=["Admin"]) @@ -16,14 +15,14 @@ async def get_user_card( user_id: int, user: dict[str, Any] = Depends(UnionAuth(scopes=["userdata.info.admin"], allow_none=False, auto_error=True)), -) -> UserCardGet: +): """ Получает профсоюзную информацию пользователя. Скоупы: `["userdata.info.admin"]` """ - return UserCardGet.model_validate(await get_user_info(user_id, user)) + return await get_user_info(user_id, user) @admin.patch("/user/{user_id}", response_model=StatusResponseModel) diff --git a/userdata_api/schemas/admin.py b/userdata_api/schemas/admin.py index 09facc6..d819749 100644 --- a/userdata_api/schemas/admin.py +++ b/userdata_api/schemas/admin.py @@ -6,7 +6,7 @@ class UserCardGet(Base): full_name: str | None = None student_card_number: str | None = None union_card_number: str | None = None - is_union_member: bool + is_union_member: str class UserCardUpdate(Base): diff --git a/userdata_api/utils/admin.py b/userdata_api/utils/admin.py index 1c7a44c..166c8ac 100644 --- a/userdata_api/utils/admin.py +++ b/userdata_api/utils/admin.py @@ -9,9 +9,7 @@ from .user import patch_user_info as user_patch -async def patch_user_info( - new: UserCardUpdate, user_id: int, user: dict[str, int | list[dict[str, str | int]]] -) -> None: +async def patch_user_info(new: UserCardUpdate, user_id: int, user: dict[str, int | list[dict[str, str | int]]]) -> None: """ Обновить информацию о пользователе в соотетствии с переданным токеном. @@ -79,6 +77,6 @@ async def get_user_info(user_id: int, user: dict[str, int | list[dict[str, str | "full_name": full_name.value if full_name else None, "student_card_number": student_card_number.value if student_card_number else None, "union_card_number": union_card_number.value if union_card_number else None, - "is_union_member": is_union_member.value if is_union_member else False, + "is_union_member": is_union_member.value if is_union_member else "false", } return result From 4a030626cb0057aa5203df68b657bed1738602cb Mon Sep 17 00:00:00 2001 From: petrCher <88943157+petrCher@users.noreply.github.com> Date: Fri, 12 Dec 2025 23:26:16 +0300 Subject: [PATCH 11/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D1=83=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D1=81=D1=83=D1=89=D0=B5=D1=81=D1=82=D0=B2=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- userdata_api/utils/admin.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/userdata_api/utils/admin.py b/userdata_api/utils/admin.py index 166c8ac..9f08971 100644 --- a/userdata_api/utils/admin.py +++ b/userdata_api/utils/admin.py @@ -2,6 +2,7 @@ from fastapi_sqlalchemy import db +from userdata_api.exceptions import ObjectNotFound from userdata_api.models.db import Info, Param from userdata_api.schemas.admin import UserCardGet, UserCardUpdate from userdata_api.schemas.user import UserInfo, UserInfoUpdate @@ -48,6 +49,9 @@ async def get_user_info(user_id: int, user: dict[str, int | list[dict[str, str | - is_union_member: Статус мэтчинга (из параметра "Членство в профсоюзе") - last_check_timestamp: Дата последней проверки """ + users = db.session.query(Info).filter(Info.owner_id == user_id).first() + if not users: + raise ObjectNotFound(Info, user_id) full_name = ( db.session.query(Info) .join(Info.param)