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

@@ -9,9 +9,12 @@ from duty_teller.db.repository import (
delete_duties_in_range,
get_duties,
get_duties_for_user,
get_duty_by_id,
get_or_create_user,
get_or_create_user_by_full_name,
get_users_for_admin,
insert_duty,
update_duty_user,
update_user_display_name,
)
@@ -217,6 +220,52 @@ def test_get_or_create_user_keeps_name_when_flag_true_updates_username(session):
assert u2.username == "new_username"
def test_get_duty_by_id_returns_duty(session, user_a):
"""get_duty_by_id returns the duty when it exists."""
duty = insert_duty(
session, user_a.id, "2026-02-01T09:00:00Z", "2026-02-01T18:00:00Z"
)
found = get_duty_by_id(session, duty.id)
assert found is not None
assert found.id == duty.id
assert found.user_id == user_a.id
assert found.start_at == "2026-02-01T09:00:00Z"
def test_get_duty_by_id_returns_none_when_missing(session):
"""get_duty_by_id returns None for non-existent id."""
assert get_duty_by_id(session, 99999) is None
def test_update_duty_user_changes_user(session, user_a):
"""update_duty_user updates user_id and returns the duty."""
user_b = get_or_create_user_by_full_name(session, "User B")
duty = insert_duty(
session, user_a.id, "2026-02-01T09:00:00Z", "2026-02-01T18:00:00Z"
)
updated = update_duty_user(session, duty.id, user_b.id, commit=True)
assert updated is not None
assert updated.id == duty.id
assert updated.user_id == user_b.id
session.refresh(duty)
assert duty.user_id == user_b.id
def test_update_duty_user_returns_none_when_duty_missing(session, user_a):
"""update_duty_user returns None when duty does not exist."""
assert update_duty_user(session, 99999, user_a.id, commit=True) is None
def test_get_users_for_admin_returns_all_ordered_by_full_name(session, user_a):
"""get_users_for_admin returns all users ordered by full_name."""
get_or_create_user_by_full_name(session, "Alice")
get_or_create_user_by_full_name(session, "Борис")
users = get_users_for_admin(session)
assert len(users) >= 3
full_names = [u.full_name for u in users]
assert full_names == sorted(full_names)
def test_update_user_display_name_sets_flag_then_get_or_create_user_keeps_name(session):
"""update_user_display_name sets name and flag; get_or_create_user then does not overwrite name."""
get_or_create_user(