Merge feature/birthday-sync: sync DOB to umbral contacts on profile/settings change

This commit is contained in:
Kyle 2026-03-07 06:19:16 +08:00
commit 36309c2460
3 changed files with 38 additions and 0 deletions

View File

@ -25,6 +25,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func from sqlalchemy import select, func
from app.database import get_db from app.database import get_db
from app.services.connection import sync_birthday_to_contacts
from app.models.user import User from app.models.user import User
from app.models.session import UserSession from app.models.session import UserSession
from app.models.settings import Settings from app.models.settings import Settings
@ -686,6 +687,12 @@ async def update_profile(
current_user.email = update_data["email"] current_user.email = update_data["email"]
if "date_of_birth" in update_data: if "date_of_birth" in update_data:
current_user.date_of_birth = update_data["date_of_birth"] current_user.date_of_birth = update_data["date_of_birth"]
settings_result = await db.execute(
select(Settings).where(Settings.user_id == current_user.id)
)
user_settings = settings_result.scalar_one_or_none()
share = user_settings.share_birthday if user_settings else False
await sync_birthday_to_contacts(db, current_user.id, share_birthday=share, date_of_birth=update_data["date_of_birth"])
if "umbral_name" in update_data: if "umbral_name" in update_data:
current_user.umbral_name = update_data["umbral_name"] current_user.umbral_name = update_data["umbral_name"]

View File

@ -7,6 +7,7 @@ from app.models.settings import Settings
from app.models.user import User from app.models.user import User
from app.schemas.settings import SettingsUpdate, SettingsResponse from app.schemas.settings import SettingsUpdate, SettingsResponse
from app.routers.auth import get_current_user, get_current_settings from app.routers.auth import get_current_user, get_current_settings
from app.services.connection import sync_birthday_to_contacts
router = APIRouter() router = APIRouter()
@ -78,6 +79,7 @@ async def get_settings(
async def update_settings( async def update_settings(
settings_update: SettingsUpdate, settings_update: SettingsUpdate,
db: AsyncSession = Depends(get_db), db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
current_settings: Settings = Depends(get_current_settings) current_settings: Settings = Depends(get_current_settings)
): ):
"""Update settings.""" """Update settings."""
@ -91,9 +93,18 @@ async def update_settings(
except ValueError as e: except ValueError as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
old_share_birthday = current_settings.share_birthday
for key, value in update_data.items(): for key, value in update_data.items():
setattr(current_settings, key, value) setattr(current_settings, key, value)
if "share_birthday" in update_data and update_data["share_birthday"] != old_share_birthday:
await sync_birthday_to_contacts(
db, current_user.id,
share_birthday=update_data["share_birthday"],
date_of_birth=current_user.date_of_birth,
)
await db.commit() await db.commit()
await db.refresh(current_settings) await db.refresh(current_settings)

View File

@ -9,6 +9,7 @@ from datetime import date as date_type
from types import SimpleNamespace from types import SimpleNamespace
from typing import Optional from typing import Optional
from sqlalchemy import update
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from app.models.person import Person from app.models.person import Person
@ -134,6 +135,25 @@ def create_person_from_connection(
) )
async def sync_birthday_to_contacts(
db: AsyncSession,
user_id: int,
share_birthday: bool,
date_of_birth: Optional[date_type],
) -> None:
"""Sync user's DOB to all Person records where linked_user_id == user_id.
Caller passes resolved values no internal re-query."""
new_birthday = date_of_birth if share_birthday else None
result = await db.execute(
update(Person)
.where(Person.linked_user_id == user_id)
.values(birthday=new_birthday)
)
logger.info("sync_birthday_to_contacts user_id=%s updated %s person(s)", user_id, result.rowcount)
async def detach_umbral_contact(person: Person) -> None: async def detach_umbral_contact(person: Person) -> None:
"""Convert an umbral contact back to a standard contact. Does NOT commit. """Convert an umbral contact back to a standard contact. Does NOT commit.