portal: improve jellyfin/mailu status

This commit is contained in:
Brad Stein 2026-01-02 12:11:40 -03:00
parent d986cbd922
commit 90f0937f73
3 changed files with 26 additions and 16 deletions

View File

@ -37,6 +37,7 @@ def register(app) -> None:
jellyfin_status = "ready" jellyfin_status = "ready"
jellyfin_sync_status = "unknown" jellyfin_sync_status = "unknown"
jellyfin_sync_detail = "" jellyfin_sync_detail = ""
jellyfin_user_is_ldap = False
if not admin_client().ready(): if not admin_client().ready():
mailu_status = "server not configured" mailu_status = "server not configured"
@ -46,6 +47,8 @@ def register(app) -> None:
elif username: elif username:
try: try:
user = admin_client().find_user(username) or {} user = admin_client().find_user(username) or {}
if isinstance(user, dict):
jellyfin_user_is_ldap = bool(user.get("federationLink"))
if not keycloak_email: if not keycloak_email:
keycloak_email = str(user.get("email") or "") keycloak_email = str(user.get("email") or "")
@ -82,17 +85,24 @@ def register(app) -> None:
elif username: elif username:
mailu_username = f"{username}@{settings.MAILU_DOMAIN}" mailu_username = f"{username}@{settings.MAILU_DOMAIN}"
if not mailu_app_password and mailu_status == "ready":
mailu_status = "needs app password"
if jellyfin_status == "ready": if jellyfin_status == "ready":
if _tcp_check( ldap_reachable = _tcp_check(
settings.JELLYFIN_LDAP_HOST, settings.JELLYFIN_LDAP_HOST,
settings.JELLYFIN_LDAP_PORT, settings.JELLYFIN_LDAP_PORT,
settings.JELLYFIN_LDAP_CHECK_TIMEOUT_SEC, settings.JELLYFIN_LDAP_CHECK_TIMEOUT_SEC,
): )
jellyfin_sync_status = "ok" if not ldap_reachable:
jellyfin_sync_detail = "LDAP reachable"
else:
jellyfin_sync_status = "degraded" jellyfin_sync_status = "degraded"
jellyfin_sync_detail = "LDAP unreachable" jellyfin_sync_detail = "LDAP unreachable"
elif not jellyfin_user_is_ldap:
jellyfin_sync_status = "degraded"
jellyfin_sync_detail = "Keycloak user is not LDAP-backed"
else:
jellyfin_sync_status = "ok"
jellyfin_sync_detail = "LDAP-backed (Keycloak is source of truth)"
return jsonify( return jsonify(
{ {

View File

@ -35,7 +35,7 @@
<span class="v mono">{{ mailu.smtp }}</span> <span class="v mono">{{ mailu.smtp }}</span>
</div> </div>
<div class="row"> <div class="row">
<span class="k mono">Username</span> <span class="k mono">Email</span>
<span class="v mono">{{ mailu.username }}</span> <span class="v mono">{{ mailu.username }}</span>
</div> </div>
</div> </div>
@ -87,13 +87,13 @@
<h2>Jellyfin</h2> <h2>Jellyfin</h2>
<span <span
class="pill mono" class="pill mono"
:class="jellyfin.syncStatus === 'ok' ? 'pill-ok' : jellyfin.syncStatus === 'degraded' ? 'pill-warn' : ''" :class="jellyfin.syncStatus === 'ok' ? 'pill-ok' : jellyfin.syncStatus === 'degraded' ? 'pill-bad' : ''"
> >
{{ {{
jellyfin.syncStatus === "ok" jellyfin.syncStatus === "ok"
? "in sync" ? "in sync"
: jellyfin.syncStatus === "degraded" : jellyfin.syncStatus === "degraded"
? "check sync" ? "out of sync"
: jellyfin.status : jellyfin.status
}} }}
</span> </span>

View File

@ -44,7 +44,7 @@
const sections = [ const sections = [
{ {
title: "Cloud", title: "Cloud",
description: "Files, photos, mail, calendars, and documents — the primary hub for Atlas users.", description: "Your personal cloud hub: files, photos, mail, calendars, and collaborative documents.",
groups: [ groups: [
{ {
title: "Nextcloud", title: "Nextcloud",
@ -53,7 +53,7 @@ const sections = [
name: "Cloud", name: "Cloud",
url: "https://cloud.bstein.dev", url: "https://cloud.bstein.dev",
target: "_blank", target: "_blank",
description: "Your personal cloud storage and productivity suite.", description: "Storage, mail, photos, and office docs — the main Atlas hub.",
}, },
], ],
}, },
@ -61,7 +61,7 @@ const sections = [
}, },
{ {
title: "Security", title: "Security",
description: "Password security, secrets, and account hygiene.", description: "Passwords for humans, secrets for infrastructure.",
groups: [ groups: [
{ {
title: "Personal", title: "Personal",
@ -89,16 +89,16 @@ const sections = [
}, },
{ {
title: "Communications", title: "Communications",
description: "Discord-like chat, calls, and rooms — plus Atlas AI chat bots.", description: "Chat rooms, calls, and bots. Element X (mobile) is the recommended client.",
groups: [ groups: [
{ {
title: "Chat", title: "Chat",
apps: [ apps: [
{ {
name: "Element", name: "Element X",
url: "https://live.bstein.dev", url: "https://live.bstein.dev",
target: "_blank", target: "_blank",
description: "Matrix chat rooms with voice/video powered by local infra.", description: "Matrix rooms with calls powered by Atlas infra.",
}, },
{ {
name: "AI Chat", name: "AI Chat",
@ -112,7 +112,7 @@ const sections = [
}, },
{ {
title: "Streaming", title: "Streaming",
description: "Family media streaming and upload workflows.", description: "Stream media and publish uploads into your library.",
groups: [ groups: [
{ {
title: "Media", title: "Media",
@ -135,7 +135,7 @@ const sections = [
}, },
{ {
title: "Dev", title: "Dev",
description: "Source control, CI, registry, GitOps, and observability.", description: "Build and ship: source control, CI, registry, and GitOps.",
groups: [ groups: [
{ {
title: "Source & CI", title: "Source & CI",