onboarding: mark vaultwarden status and adjust guides

This commit is contained in:
Brad Stein 2026-01-23 16:51:10 -03:00
parent e339e17bd4
commit 070729f66c
2 changed files with 32 additions and 8 deletions

View File

@ -955,18 +955,35 @@ def register(app) -> None:
if isinstance(completed, bool): if isinstance(completed, bool):
mark_done = completed mark_done = completed
request_username = row.get("username") or ""
if mark_done: if mark_done:
prerequisites = ONBOARDING_STEP_PREREQUISITES.get(step, set()) prerequisites = ONBOARDING_STEP_PREREQUISITES.get(step, set())
if prerequisites: if prerequisites:
current_completed = _completed_onboarding_steps(conn, code, row.get("username") or "") current_completed = _completed_onboarding_steps(conn, code, request_username)
missing = sorted(prerequisites - current_completed) missing = sorted(prerequisites - current_completed)
if missing: if missing:
return jsonify({"error": "step is blocked", "blocked_by": missing}), 409 return jsonify({"error": "step is blocked", "blocked_by": missing}), 409
if step == "vaultwarden_master_password": if step == "vaultwarden_master_password":
try: try:
_request_keycloak_password_rotation(conn, code, row.get("username") or "") _request_keycloak_password_rotation(conn, code, request_username)
except Exception: except Exception:
return jsonify({"error": "failed to request keycloak password rotation"}), 502 return jsonify({"error": "failed to request keycloak password rotation"}), 502
if request_username and admin_client().ready():
try:
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
admin_client().set_user_attribute(
request_username,
"vaultwarden_master_password_set_at",
now,
)
admin_client().set_user_attribute(
request_username,
"vaultwarden_status",
"already_present",
)
except Exception:
return jsonify({"error": "failed to update vaultwarden status"}), 502
conn.execute( conn.execute(
""" """
@ -983,7 +1000,6 @@ def register(app) -> None:
) )
# Re-evaluate completion to update request status to ready if applicable. # Re-evaluate completion to update request status to ready if applicable.
request_username = row.get("username") or ""
status = _advance_status(conn, code, request_username, status) status = _advance_status(conn, code, request_username, status)
onboarding_payload = _onboarding_payload(conn, code, request_username) onboarding_payload = _onboarding_payload(conn, code, request_username)
except Exception: except Exception:

View File

@ -917,7 +917,7 @@ async function setStepCompletion(stepId, completed) {
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ request_code: requestCode.value.trim(), step: stepId, completed }), body: JSON.stringify({ request_code: requestCode.value.trim(), step: stepId, completed }),
}); });
if (resp.status === 401 && requester === authFetch) { if ([401, 403].includes(resp.status) && requester === authFetch) {
resp = await fetch("/api/access/request/onboarding/attest", { resp = await fetch("/api/access/request/onboarding/attest", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
@ -981,7 +981,7 @@ async function requestKeycloakPasswordRotation() {
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ request_code: requestCode.value.trim() }), body: JSON.stringify({ request_code: requestCode.value.trim() }),
}); });
if (resp.status === 401 && requester === authFetch) { if ([401, 403].includes(resp.status) && requester === authFetch) {
resp = await fetch("/api/access/request/onboarding/keycloak-password-rotate", { resp = await fetch("/api/access/request/onboarding/keycloak-password-rotate", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
@ -1246,9 +1246,10 @@ button.copy:disabled {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 8px; gap: 10px;
flex-wrap: nowrap; flex-wrap: nowrap;
color: var(--text-muted); color: var(--text-muted);
width: 100%;
} }
.stepper-meta .pill { .stepper-meta .pill {
@ -1487,20 +1488,27 @@ button.copy:disabled {
background: rgba(0, 0, 0, 0.2); background: rgba(0, 0, 0, 0.2);
padding: 0; padding: 0;
cursor: zoom-in; cursor: zoom-in;
display: flex;
flex-direction: column;
gap: 6px;
} }
.guide-shot figcaption { .guide-shot figcaption {
margin: 0; margin: 0;
padding: 10px 12px 6px; padding: 10px 12px 6px;
font-size: 15px; font-size: 17px;
font-weight: 600; font-weight: 600;
color: var(--text-strong); color: var(--text-strong);
} }
.guide-shot img { .guide-shot img {
width: 100%;
display: block; display: block;
border-radius: 10px; border-radius: 10px;
max-width: 100%;
width: auto;
height: auto;
max-height: min(60vh, 520px);
margin: 0 auto 10px;
} }
.guide-pagination { .guide-pagination {