feat(sharing): user picker in share dialog

Replace the free-text username input with a Select populated from a new
/sharing/users endpoint. Users already on the target's share list are
filtered out, and the trigger surfaces loading / empty states. Matches
the existing permission model since sharing only ever required knowing
a username.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-15 10:34:09 +02:00
parent a073ee7fb9
commit 967cf23b82
3 changed files with 90 additions and 13 deletions

View File

@@ -59,6 +59,34 @@ class SharedFolderResponse(BaseModel):
photo_count: int
class ShareableUser(BaseModel):
id: str
username: str
# ── Shareable users ──────────────────────────────────────────────────────
@router.get("/users", response_model=list[ShareableUser])
async def list_shareable_users(
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""List every active user other than the caller, for the share-picker
dropdown. Sharing only requires knowing a username today, so surfacing
the list is no wider an attack surface than the free-text input it
replaces. Inactive accounts are filtered out."""
result = await db.execute(
select(User)
.where(User.id != current_user.id)
.where(User.is_active.is_(True))
.order_by(User.username)
)
return [
ShareableUser(id=str(u.id), username=u.username)
for u in result.scalars().all()
]
# ── Heap sharing ─────────────────────────────────────────────────────────
@router.get("/heaps/shared-with-me")