modularize service layer, add mobile nav drawer, and sync docs
This commit is contained in:
parent
7f7a8ce2b0
commit
6b6ed91b92
72 changed files with 8122 additions and 7501 deletions
107
app/services/domains/portability/scholar_import.py
Normal file
107
app/services/domains/portability/scholar_import.py
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.db.models import ScholarProfile
|
||||
from app.services.domains.portability.normalize import _normalize_optional_text
|
||||
from app.services.domains.scholars import application as scholar_service
|
||||
|
||||
|
||||
async def _load_user_scholar_map(
|
||||
db_session: AsyncSession,
|
||||
*,
|
||||
user_id: int,
|
||||
) -> dict[str, ScholarProfile]:
|
||||
result = await db_session.execute(
|
||||
select(ScholarProfile).where(ScholarProfile.user_id == user_id)
|
||||
)
|
||||
profiles = list(result.scalars().all())
|
||||
return {profile.scholar_id: profile for profile in profiles}
|
||||
|
||||
|
||||
def _apply_imported_scholar_values(
|
||||
*,
|
||||
profile: ScholarProfile,
|
||||
display_name: str | None,
|
||||
profile_image_override_url: str | None,
|
||||
is_enabled: bool,
|
||||
) -> bool:
|
||||
updated = False
|
||||
if display_name and profile.display_name != display_name:
|
||||
profile.display_name = display_name
|
||||
updated = True
|
||||
if profile.profile_image_override_url != profile_image_override_url:
|
||||
profile.profile_image_override_url = profile_image_override_url
|
||||
updated = True
|
||||
if bool(profile.is_enabled) != bool(is_enabled):
|
||||
profile.is_enabled = bool(is_enabled)
|
||||
updated = True
|
||||
return updated
|
||||
|
||||
|
||||
def _new_scholar_profile(
|
||||
*,
|
||||
user_id: int,
|
||||
scholar_id: str,
|
||||
display_name: str | None,
|
||||
profile_image_override_url: str | None,
|
||||
is_enabled: bool,
|
||||
) -> ScholarProfile:
|
||||
return ScholarProfile(
|
||||
user_id=user_id,
|
||||
scholar_id=scholar_id,
|
||||
display_name=display_name,
|
||||
profile_image_override_url=profile_image_override_url,
|
||||
is_enabled=bool(is_enabled),
|
||||
)
|
||||
|
||||
|
||||
async def _upsert_imported_scholars(
|
||||
db_session: AsyncSession,
|
||||
*,
|
||||
user_id: int,
|
||||
scholars: list[dict[str, Any]],
|
||||
) -> tuple[dict[str, ScholarProfile], dict[str, int]]:
|
||||
scholar_map = await _load_user_scholar_map(db_session, user_id=user_id)
|
||||
counters = {"scholars_created": 0, "scholars_updated": 0, "skipped_records": 0}
|
||||
for item in scholars:
|
||||
try:
|
||||
scholar_id = scholar_service.validate_scholar_id(str(item["scholar_id"]))
|
||||
display_name = scholar_service.normalize_display_name(
|
||||
str(item.get("display_name") or "")
|
||||
)
|
||||
override_url = scholar_service.normalize_profile_image_url(
|
||||
_normalize_optional_text(item.get("profile_image_override_url"))
|
||||
)
|
||||
except (KeyError, scholar_service.ScholarServiceError):
|
||||
counters["skipped_records"] += 1
|
||||
continue
|
||||
|
||||
is_enabled = bool(item.get("is_enabled", True))
|
||||
existing = scholar_map.get(scholar_id)
|
||||
if existing is None:
|
||||
profile = _new_scholar_profile(
|
||||
user_id=user_id,
|
||||
scholar_id=scholar_id,
|
||||
display_name=display_name,
|
||||
profile_image_override_url=override_url,
|
||||
is_enabled=is_enabled,
|
||||
)
|
||||
db_session.add(profile)
|
||||
scholar_map[scholar_id] = profile
|
||||
counters["scholars_created"] += 1
|
||||
continue
|
||||
|
||||
if _apply_imported_scholar_values(
|
||||
profile=existing,
|
||||
display_name=display_name,
|
||||
profile_image_override_url=override_url,
|
||||
is_enabled=is_enabled,
|
||||
):
|
||||
counters["scholars_updated"] += 1
|
||||
|
||||
await db_session.flush()
|
||||
return scholar_map, counters
|
||||
Loading…
Add table
Add a link
Reference in a new issue