feat: implement admin panel functionality in Mini App

- Added new API endpoints for admin features: `GET /api/admin/me`, `GET /api/admin/users`, and `PATCH /api/admin/duties/:id` to manage user duties.
- Introduced `UserForAdmin` and `AdminDutyReassignBody` schemas for handling admin-related data.
- Updated documentation to include Mini App design guidelines and admin panel functionalities.
- Enhanced tests for admin API to ensure proper access control and functionality.
- Improved error handling and localization for admin actions.
This commit is contained in:
2026-03-06 09:57:26 +03:00
parent 68b1884b73
commit c390a4dd6e
28 changed files with 2045 additions and 15 deletions

View File

@@ -4,6 +4,7 @@ from duty_teller.db.models import Base, User, Duty, Role
from duty_teller.db.schemas import (
UserCreate,
UserInDb,
UserForAdmin,
DutyCreate,
DutyInDb,
DutyWithUser,
@@ -16,11 +17,14 @@ from duty_teller.db.session import (
)
from duty_teller.db.repository import (
delete_duties_in_range,
get_duties,
get_duty_by_id,
get_or_create_user,
get_or_create_user_by_full_name,
get_duties,
get_users_for_admin,
insert_duty,
set_user_phone,
update_duty_user,
update_user_display_name,
)
@@ -31,6 +35,7 @@ __all__ = [
"Role",
"UserCreate",
"UserInDb",
"UserForAdmin",
"DutyCreate",
"DutyInDb",
"DutyWithUser",
@@ -39,11 +44,14 @@ __all__ = [
"get_session",
"session_scope",
"delete_duties_in_range",
"get_duties",
"get_duty_by_id",
"get_or_create_user",
"get_or_create_user_by_full_name",
"get_duties",
"get_users_for_admin",
"insert_duty",
"set_user_phone",
"update_duty_user",
"update_user_display_name",
"init_db",
]

View File

@@ -322,6 +322,61 @@ def delete_duties_in_range(
return count
def get_duty_by_id(session: Session, duty_id: int) -> Duty | None:
"""Return duty by primary key.
Args:
session: DB session.
duty_id: Duty id (duties.id).
Returns:
Duty or None if not found.
"""
return session.get(Duty, duty_id)
def update_duty_user(
session: Session,
duty_id: int,
new_user_id: int,
*,
commit: bool = True,
) -> Duty | None:
"""Update the assigned user of a duty.
Args:
session: DB session.
duty_id: Duty id (duties.id).
new_user_id: New user id (users.id).
commit: If True, commit immediately. If False, caller commits.
Returns:
Updated Duty or None if duty not found.
"""
duty = session.get(Duty, duty_id)
if duty is None:
return None
duty.user_id = new_user_id
if commit:
session.commit()
session.refresh(duty)
else:
session.flush()
return duty
def get_users_for_admin(session: Session) -> list[User]:
"""Return all users ordered by full_name for admin dropdown (id, full_name, username).
Args:
session: DB session.
Returns:
List of User instances ordered by full_name.
"""
return session.query(User).order_by(User.full_name).all()
def get_duties(
session: Session,
from_date: str,

View File

@@ -69,6 +69,21 @@ class DutyWithUser(DutyInDb):
model_config = ConfigDict(from_attributes=True)
class UserForAdmin(BaseModel):
"""User summary for admin dropdown: id, full_name, username, role_id."""
id: int
full_name: str
username: str | None = None
role_id: int | None = None
class AdminDutyReassignBody(BaseModel):
"""Request body for PATCH /api/admin/duties/:id — reassign duty to another user."""
user_id: int
class CalendarEvent(BaseModel):
"""External calendar event (e.g. holiday) for a single day."""