mirror of
https://github.com/velocitatem/cvfs.git
synced 2026-05-31 08:43:37 +00:00
feat(dashboard): complete CV branching dashboard with auth and full editing workflow
- Visual branch heritage tree with colored dots and connecting lines, depth-aware expand/collapse - Dashboard 3-tab layout: Content (inline block editing + patch staging), Patches (diff view), Submissions (AI suggestions) - Inline block editing: click to edit any CV block, stage edits, save as named branch with pre-filled patches - Submissions tab: create applications, request AI tailoring suggestions, accept/reject per suggestion - Simple hardcoded login (username/password via env vars LOGIN_USER/LOGIN_PASS, defaults admin/admin) - Authentik OIDC integration: authorize redirect + callback exchange, configurable via NEXT_PUBLIC_AUTHENTIK_* - Middleware protecting /dashboard with session cookie verification (HMAC-SHA256) - Auth API routes: /api/auth/login, /api/auth/logout, /api/auth/callback, /api/auth/token - Backend: GET/PATCH submission routes for listing submissions and accepting/rejecting AI suggestions - API client: OIDC bearer token forwarding from client-readable cookie https://claude.ai/code/session_01CdisLhbC2kVt2hxfJ7TNPf
This commit is contained in:
@@ -84,6 +84,55 @@ async def request_ai_suggestions(
|
||||
return created
|
||||
|
||||
|
||||
async def list_submissions(
|
||||
session: AsyncSession,
|
||||
*,
|
||||
owner_id: str,
|
||||
version_id: str | None = None,
|
||||
) -> list[Submission]:
|
||||
stmt = (
|
||||
select(Submission)
|
||||
.join(Submission.version)
|
||||
.join(CvVersion.document)
|
||||
.where(CvDocument.owner_id == owner_id)
|
||||
.options(selectinload(Submission.suggestions))
|
||||
)
|
||||
if version_id:
|
||||
stmt = stmt.where(Submission.version_id == version_id)
|
||||
result = await session.execute(stmt)
|
||||
return list(result.scalars().all())
|
||||
|
||||
|
||||
async def get_submission(
|
||||
session: AsyncSession, *, owner_id: str, submission_id: str
|
||||
) -> Submission | None:
|
||||
return await _get_submission_for_owner(session, owner_id, submission_id)
|
||||
|
||||
|
||||
async def update_suggestion(
|
||||
session: AsyncSession,
|
||||
*,
|
||||
owner_id: str,
|
||||
submission_id: str,
|
||||
suggestion_id: str,
|
||||
accepted: bool,
|
||||
) -> AiSuggestion | None:
|
||||
submission = await _get_submission_for_owner(session, owner_id, submission_id)
|
||||
if not submission:
|
||||
return None
|
||||
stmt = select(AiSuggestion).where(
|
||||
AiSuggestion.id == suggestion_id, AiSuggestion.submission_id == submission_id
|
||||
)
|
||||
result = await session.execute(stmt)
|
||||
suggestion = result.scalars().one_or_none()
|
||||
if not suggestion:
|
||||
return None
|
||||
suggestion.accepted = accepted
|
||||
await session.commit()
|
||||
await session.refresh(suggestion)
|
||||
return suggestion
|
||||
|
||||
|
||||
async def _get_version_for_owner(
|
||||
session: AsyncSession, owner_id: str, version_id: str
|
||||
) -> CvVersion | None:
|
||||
|
||||
Reference in New Issue
Block a user