portal: surface Vaultwarden status
This commit is contained in:
parent
7902d7658f
commit
a6db3762a3
@ -326,11 +326,39 @@ def provision_access_request(request_code: str) -> ProvisionResult:
|
||||
try:
|
||||
if not user_id:
|
||||
raise RuntimeError("missing user id")
|
||||
result = invite_user(mailu_email or f"{username}@{settings.MAILU_DOMAIN}")
|
||||
vaultwarden_email = mailu_email or f"{username}@{settings.MAILU_DOMAIN}"
|
||||
try:
|
||||
full = admin_client().get_user(user_id)
|
||||
attrs = full.get("attributes") or {}
|
||||
override = None
|
||||
if isinstance(attrs, dict):
|
||||
raw = attrs.get("vaultwarden_email")
|
||||
if isinstance(raw, list):
|
||||
for item in raw:
|
||||
if isinstance(item, str) and item.strip():
|
||||
override = item.strip()
|
||||
break
|
||||
elif isinstance(raw, str) and raw.strip():
|
||||
override = raw.strip()
|
||||
if override:
|
||||
vaultwarden_email = override
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
result = invite_user(vaultwarden_email)
|
||||
if result.ok:
|
||||
_upsert_task(conn, request_code, "vaultwarden_invite", "ok", result.status)
|
||||
else:
|
||||
_upsert_task(conn, request_code, "vaultwarden_invite", "error", result.detail or result.status)
|
||||
|
||||
# Persist Vaultwarden association/status on the Keycloak user so the portal can display it quickly.
|
||||
try:
|
||||
now_iso = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
admin_client().set_user_attribute(username, "vaultwarden_email", vaultwarden_email)
|
||||
admin_client().set_user_attribute(username, "vaultwarden_status", result.status)
|
||||
admin_client().set_user_attribute(username, "vaultwarden_synced_at", now_iso)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc:
|
||||
_upsert_task(
|
||||
conn,
|
||||
|
||||
@ -40,6 +40,9 @@ def register(app) -> None:
|
||||
nextcloud_mail_primary_email = ""
|
||||
nextcloud_mail_account_count = ""
|
||||
nextcloud_mail_synced_at = ""
|
||||
vaultwarden_email = ""
|
||||
vaultwarden_status = ""
|
||||
vaultwarden_synced_at = ""
|
||||
jellyfin_status = "ready"
|
||||
jellyfin_sync_status = "unknown"
|
||||
jellyfin_sync_detail = ""
|
||||
@ -85,9 +88,31 @@ def register(app) -> None:
|
||||
nextcloud_mail_synced_at = str(raw_synced[0])
|
||||
elif isinstance(raw_synced, str) and raw_synced:
|
||||
nextcloud_mail_synced_at = raw_synced
|
||||
raw_vw_email = attrs.get("vaultwarden_email")
|
||||
if isinstance(raw_vw_email, list) and raw_vw_email:
|
||||
vaultwarden_email = str(raw_vw_email[0])
|
||||
elif isinstance(raw_vw_email, str) and raw_vw_email:
|
||||
vaultwarden_email = raw_vw_email
|
||||
raw_vw_status = attrs.get("vaultwarden_status")
|
||||
if isinstance(raw_vw_status, list) and raw_vw_status:
|
||||
vaultwarden_status = str(raw_vw_status[0])
|
||||
elif isinstance(raw_vw_status, str) and raw_vw_status:
|
||||
vaultwarden_status = raw_vw_status
|
||||
raw_vw_synced = attrs.get("vaultwarden_synced_at")
|
||||
if isinstance(raw_vw_synced, list) and raw_vw_synced:
|
||||
vaultwarden_synced_at = str(raw_vw_synced[0])
|
||||
elif isinstance(raw_vw_synced, str) and raw_vw_synced:
|
||||
vaultwarden_synced_at = raw_vw_synced
|
||||
|
||||
user_id = user.get("id") if isinstance(user, dict) else None
|
||||
if user_id and (not keycloak_email or not mailu_email or not mailu_app_password):
|
||||
if user_id and (
|
||||
not keycloak_email
|
||||
or not mailu_email
|
||||
or not mailu_app_password
|
||||
or not vaultwarden_email
|
||||
or not vaultwarden_status
|
||||
or not vaultwarden_synced_at
|
||||
):
|
||||
full = admin_client().get_user(str(user_id))
|
||||
if not keycloak_email:
|
||||
keycloak_email = str(full.get("email") or "")
|
||||
@ -124,14 +149,34 @@ def register(app) -> None:
|
||||
nextcloud_mail_synced_at = str(raw_synced[0])
|
||||
elif isinstance(raw_synced, str) and raw_synced:
|
||||
nextcloud_mail_synced_at = raw_synced
|
||||
if not vaultwarden_email:
|
||||
raw_vw_email = attrs.get("vaultwarden_email")
|
||||
if isinstance(raw_vw_email, list) and raw_vw_email:
|
||||
vaultwarden_email = str(raw_vw_email[0])
|
||||
elif isinstance(raw_vw_email, str) and raw_vw_email:
|
||||
vaultwarden_email = raw_vw_email
|
||||
if not vaultwarden_status:
|
||||
raw_vw_status = attrs.get("vaultwarden_status")
|
||||
if isinstance(raw_vw_status, list) and raw_vw_status:
|
||||
vaultwarden_status = str(raw_vw_status[0])
|
||||
elif isinstance(raw_vw_status, str) and raw_vw_status:
|
||||
vaultwarden_status = raw_vw_status
|
||||
if not vaultwarden_synced_at:
|
||||
raw_vw_synced = attrs.get("vaultwarden_synced_at")
|
||||
if isinstance(raw_vw_synced, list) and raw_vw_synced:
|
||||
vaultwarden_synced_at = str(raw_vw_synced[0])
|
||||
elif isinstance(raw_vw_synced, str) and raw_vw_synced:
|
||||
vaultwarden_synced_at = raw_vw_synced
|
||||
except Exception:
|
||||
mailu_status = "unavailable"
|
||||
nextcloud_mail_status = "unavailable"
|
||||
vaultwarden_status = "unavailable"
|
||||
jellyfin_status = "unavailable"
|
||||
jellyfin_sync_status = "unknown"
|
||||
jellyfin_sync_detail = "unavailable"
|
||||
|
||||
mailu_username = mailu_email or (f"{username}@{settings.MAILU_DOMAIN}" if username else "")
|
||||
vaultwarden_username = vaultwarden_email or mailu_username
|
||||
|
||||
if not mailu_app_password and mailu_status == "ready":
|
||||
mailu_status = "needs app password"
|
||||
@ -162,6 +207,9 @@ def register(app) -> None:
|
||||
jellyfin_sync_status = "ok"
|
||||
jellyfin_sync_detail = "LDAP-backed (Keycloak is source of truth)"
|
||||
|
||||
if not vaultwarden_status:
|
||||
vaultwarden_status = "needs provisioning"
|
||||
|
||||
return jsonify(
|
||||
{
|
||||
"user": {"username": username, "email": keycloak_email, "groups": g.keycloak_groups},
|
||||
@ -172,6 +220,11 @@ def register(app) -> None:
|
||||
"account_count": nextcloud_mail_account_count,
|
||||
"synced_at": nextcloud_mail_synced_at,
|
||||
},
|
||||
"vaultwarden": {
|
||||
"status": vaultwarden_status,
|
||||
"username": vaultwarden_username,
|
||||
"synced_at": vaultwarden_synced_at,
|
||||
},
|
||||
"jellyfin": {
|
||||
"status": jellyfin_status,
|
||||
"username": username,
|
||||
|
||||
@ -123,6 +123,47 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card module">
|
||||
<div class="module-head">
|
||||
<h2>Vaultwarden</h2>
|
||||
<span
|
||||
class="pill mono"
|
||||
:class="
|
||||
vaultwarden.status === 'ready' || vaultwarden.status === 'already_present'
|
||||
? 'pill-ok'
|
||||
: vaultwarden.status === 'unavailable' || vaultwarden.status === 'error'
|
||||
? 'pill-bad'
|
||||
: ''
|
||||
"
|
||||
>
|
||||
{{ vaultwarden.status }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="muted">
|
||||
Password manager for Atlas accounts. Store your Element recovery key here. Signups are admin-provisioned.
|
||||
</p>
|
||||
<div class="kv">
|
||||
<div class="row">
|
||||
<span class="k mono">URL</span>
|
||||
<a class="v mono link" href="https://vault.bstein.dev" target="_blank" rel="noreferrer">vault.bstein.dev</a>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="k mono">Username</span>
|
||||
<span class="v mono">{{ vaultwarden.username }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="k mono">Synced</span>
|
||||
<span class="v mono">{{ vaultwarden.syncedAt || "never" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="vaultwarden.status === 'invited'" class="hint mono">
|
||||
Invitation created. Open Vaultwarden and complete setup by choosing a master password.
|
||||
</div>
|
||||
<div v-if="vaultwarden.error" class="error-box">
|
||||
<div class="mono">{{ vaultwarden.error }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card module">
|
||||
<div class="module-head">
|
||||
<h2>Jellyfin</h2>
|
||||
@ -231,6 +272,13 @@ const jellyfin = reactive({
|
||||
error: "",
|
||||
});
|
||||
|
||||
const vaultwarden = reactive({
|
||||
status: "loading",
|
||||
username: "",
|
||||
syncedAt: "",
|
||||
error: "",
|
||||
});
|
||||
|
||||
const nextcloudMail = reactive({
|
||||
status: "loading",
|
||||
primaryEmail: "",
|
||||
@ -260,6 +308,7 @@ onMounted(() => {
|
||||
mailu.status = "login required";
|
||||
nextcloudMail.status = "login required";
|
||||
jellyfin.status = "login required";
|
||||
vaultwarden.status = "login required";
|
||||
}
|
||||
});
|
||||
|
||||
@ -271,6 +320,7 @@ watch(
|
||||
mailu.status = "login required";
|
||||
nextcloudMail.status = "login required";
|
||||
jellyfin.status = "login required";
|
||||
vaultwarden.status = "login required";
|
||||
admin.enabled = false;
|
||||
admin.requests = [];
|
||||
return;
|
||||
@ -284,6 +334,7 @@ watch(
|
||||
async function refreshOverview() {
|
||||
mailu.error = "";
|
||||
jellyfin.error = "";
|
||||
vaultwarden.error = "";
|
||||
nextcloudMail.error = "";
|
||||
try {
|
||||
const resp = await authFetch("/api/account/overview", {
|
||||
@ -302,6 +353,9 @@ async function refreshOverview() {
|
||||
nextcloudMail.primaryEmail = data.nextcloud_mail?.primary_email || "";
|
||||
nextcloudMail.accountCount = data.nextcloud_mail?.account_count || "";
|
||||
nextcloudMail.syncedAt = data.nextcloud_mail?.synced_at || "";
|
||||
vaultwarden.status = data.vaultwarden?.status || "unknown";
|
||||
vaultwarden.username = data.vaultwarden?.username || auth.email || auth.username;
|
||||
vaultwarden.syncedAt = data.vaultwarden?.synced_at || "";
|
||||
jellyfin.status = data.jellyfin?.status || "ready";
|
||||
jellyfin.username = data.jellyfin?.username || auth.username;
|
||||
jellyfin.syncStatus = data.jellyfin?.sync_status || "";
|
||||
@ -309,12 +363,14 @@ async function refreshOverview() {
|
||||
} catch (err) {
|
||||
mailu.status = "unavailable";
|
||||
nextcloudMail.status = "unavailable";
|
||||
vaultwarden.status = "unavailable";
|
||||
jellyfin.status = "unavailable";
|
||||
jellyfin.syncStatus = "";
|
||||
jellyfin.syncDetail = "";
|
||||
const message = err?.message ? `Failed to load account status (${err.message})` : "Failed to load account status.";
|
||||
mailu.error = message;
|
||||
nextcloudMail.error = message;
|
||||
vaultwarden.error = message;
|
||||
jellyfin.error = message;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user