feat: Implement user profile preferences for start page, Git identity, and task drawer auto-open, alongside Git server default branch configuration.

This commit is contained in:
2026-03-08 10:19:38 +03:00
parent 12d17ec35e
commit e864a9e08b
30 changed files with 2041 additions and 211 deletions

View File

@@ -8,6 +8,7 @@
from fastapi import HTTPException
import pytest
import asyncio
from unittest.mock import MagicMock
from src.api.routes import git as git_routes
@@ -195,4 +196,121 @@ def test_get_repository_status_batch_deduplicates_and_truncates_ids(monkeypatch)
assert "1" in response.statuses
# [/DEF:test_get_repository_status_batch_deduplicates_and_truncates_ids:Function]
# [DEF:test_commit_changes_applies_profile_identity_before_commit:Function]
# @PURPOSE: Ensure commit route configures repository identity from profile preferences before commit call.
# @PRE: Profile preference contains git_username/git_email for current user.
# @POST: git_service.configure_identity receives resolved identity and commit proceeds.
def test_commit_changes_applies_profile_identity_before_commit(monkeypatch):
class IdentityGitService:
def __init__(self):
self.configured_identity = None
self.commit_payload = None
def configure_identity(self, dashboard_id: int, git_username: str, git_email: str):
self.configured_identity = (dashboard_id, git_username, git_email)
def commit_changes(self, dashboard_id: int, message: str, files):
self.commit_payload = (dashboard_id, message, files)
class PreferenceRow:
git_username = "user_1"
git_email = "user1@mail.ru"
class PreferenceQuery:
def filter(self, *_args, **_kwargs):
return self
def first(self):
return PreferenceRow()
class DbStub:
def query(self, _model):
return PreferenceQuery()
class UserStub:
id = "u-1"
class CommitPayload:
message = "test"
files = ["dashboards/a.yaml"]
identity_service = IdentityGitService()
monkeypatch.setattr(git_routes, "git_service", identity_service)
monkeypatch.setattr(
git_routes,
"_resolve_dashboard_id_from_ref",
lambda *_args, **_kwargs: 12,
)
asyncio.run(
git_routes.commit_changes(
"dashboard-12",
CommitPayload(),
config_manager=MagicMock(),
db=DbStub(),
current_user=UserStub(),
)
)
assert identity_service.configured_identity == (12, "user_1", "user1@mail.ru")
assert identity_service.commit_payload == (12, "test", ["dashboards/a.yaml"])
# [/DEF:test_commit_changes_applies_profile_identity_before_commit:Function]
# [DEF:test_pull_changes_applies_profile_identity_before_pull:Function]
# @PURPOSE: Ensure pull route configures repository identity from profile preferences before pull call.
# @PRE: Profile preference contains git_username/git_email for current user.
# @POST: git_service.configure_identity receives resolved identity and pull proceeds.
def test_pull_changes_applies_profile_identity_before_pull(monkeypatch):
class IdentityGitService:
def __init__(self):
self.configured_identity = None
self.pulled_dashboard_id = None
def configure_identity(self, dashboard_id: int, git_username: str, git_email: str):
self.configured_identity = (dashboard_id, git_username, git_email)
def pull_changes(self, dashboard_id: int):
self.pulled_dashboard_id = dashboard_id
class PreferenceRow:
git_username = "user_1"
git_email = "user1@mail.ru"
class PreferenceQuery:
def filter(self, *_args, **_kwargs):
return self
def first(self):
return PreferenceRow()
class DbStub:
def query(self, _model):
return PreferenceQuery()
class UserStub:
id = "u-1"
identity_service = IdentityGitService()
monkeypatch.setattr(git_routes, "git_service", identity_service)
monkeypatch.setattr(
git_routes,
"_resolve_dashboard_id_from_ref",
lambda *_args, **_kwargs: 12,
)
asyncio.run(
git_routes.pull_changes(
"dashboard-12",
config_manager=MagicMock(),
db=DbStub(),
current_user=UserStub(),
)
)
assert identity_service.configured_identity == (12, "user_1", "user1@mail.ru")
assert identity_service.pulled_dashboard_id == 12
# [/DEF:test_pull_changes_applies_profile_identity_before_pull:Function]
# [/DEF:backend.src.api.routes.__tests__.test_git_status_route:Module]

View File

@@ -15,8 +15,10 @@ from src.app import app
from src.core.database import get_db
from src.dependencies import get_config_manager, get_current_user
from src.schemas.profile import (
ProfilePermissionState,
ProfilePreference,
ProfilePreferenceResponse,
ProfileSecuritySummary,
SupersetAccountCandidate,
SupersetAccountLookupResponse,
)
@@ -80,9 +82,27 @@ def _build_preference_response(user_id: str = "u-1") -> ProfilePreferenceRespons
superset_username="John_Doe",
superset_username_normalized="john_doe",
show_only_my_dashboards=True,
git_username="ivan.ivanov",
git_email="ivan@company.local",
has_git_personal_access_token=True,
git_personal_access_token_masked="iv***al",
start_page="reports",
auto_open_task_drawer=False,
dashboards_table_density="compact",
created_at=now,
updated_at=now,
),
security=ProfileSecuritySummary(
read_only=True,
auth_source="adfs",
current_role="Data Engineer",
role_source="adfs",
roles=["Data Engineer"],
permissions=[
ProfilePermissionState(key="migration:run", allowed=True),
ProfilePermissionState(key="admin:users", allowed=False),
],
),
)
# [/DEF:_build_preference_response:Function]
@@ -104,6 +124,16 @@ def test_get_profile_preferences_returns_self_payload(profile_route_deps_fixture
assert payload["status"] == "success"
assert payload["preference"]["user_id"] == mock_user.id
assert payload["preference"]["superset_username_normalized"] == "john_doe"
assert payload["preference"]["git_username"] == "ivan.ivanov"
assert payload["preference"]["git_email"] == "ivan@company.local"
assert payload["preference"]["has_git_personal_access_token"] is True
assert payload["preference"]["git_personal_access_token_masked"] == "iv***al"
assert payload["preference"]["start_page"] == "reports"
assert payload["preference"]["auto_open_task_drawer"] is False
assert payload["preference"]["dashboards_table_density"] == "compact"
assert payload["security"]["read_only"] is True
assert payload["security"]["current_role"] == "Data Engineer"
assert payload["security"]["permissions"][0]["key"] == "migration:run"
service.get_my_preference.assert_called_once_with(mock_user)
# [/DEF:test_get_profile_preferences_returns_self_payload:Function]
@@ -123,6 +153,12 @@ def test_patch_profile_preferences_success(profile_route_deps_fixture):
json={
"superset_username": "John_Doe",
"show_only_my_dashboards": True,
"git_username": "ivan.ivanov",
"git_email": "ivan@company.local",
"git_personal_access_token": "ghp_1234567890",
"start_page": "reports-logs",
"auto_open_task_drawer": False,
"dashboards_table_density": "free",
},
)
@@ -131,7 +167,21 @@ def test_patch_profile_preferences_success(profile_route_deps_fixture):
assert payload["status"] == "success"
assert payload["preference"]["superset_username"] == "John_Doe"
assert payload["preference"]["show_only_my_dashboards"] is True
assert payload["preference"]["git_username"] == "ivan.ivanov"
assert payload["preference"]["git_email"] == "ivan@company.local"
assert payload["preference"]["start_page"] == "reports"
assert payload["preference"]["auto_open_task_drawer"] is False
assert payload["preference"]["dashboards_table_density"] == "compact"
service.update_my_preference.assert_called_once()
called_kwargs = service.update_my_preference.call_args.kwargs
assert called_kwargs["current_user"] == mock_user
assert called_kwargs["payload"].git_username == "ivan.ivanov"
assert called_kwargs["payload"].git_email == "ivan@company.local"
assert called_kwargs["payload"].git_personal_access_token == "ghp_1234567890"
assert called_kwargs["payload"].start_page == "reports-logs"
assert called_kwargs["payload"].auto_open_task_drawer is False
assert called_kwargs["payload"].dashboards_table_density == "free"
# [/DEF:test_patch_profile_preferences_success:Function]