feat!: remove the shared demo account
The demo account — one shared user that whitelisted emails entered from the login page, reset on a schedule — goes end to end (owner decision, E34): demo.py and the reset job, users.is_demo and demo_whitelist (migration 0098 deletes the demo user, its audit rows, the reset job's override and notices, then drops the column and table; the downgrade restores the empty schema), the /auth/demo entry, the admin whitelist and reset, the Demo tab, the banner, the login page's "Try the demo", and every is_demo branch in routes, userscope, scheduler and the UI. require_human only ever refused the demo account, so its 87 uses become current_user (owner-approved); require_write_scope keeps its own check. The login page's "or" divider now shows only beside the Google button: without the demo entry under it, an instance without Google would have said "or" to nothing. A contract test (removedFeatures) fails on the word anywhere in the backend, frontend, e2e or scripts — seen red on a planted hit. Size ceilings tightened for the modules that shrank; admin.py is back under the limit.
This commit is contained in:
@@ -342,7 +342,7 @@ function AccessRow({
|
||||
// Sign-in methods: link a Google account to a password account (or vice-versa set a password),
|
||||
// so either method can reach the same account. Google connect is a full-page OAuth round-trip
|
||||
// (auth.py attaches the identity to the current session via /auth/link); the password form posts
|
||||
// directly with inline errors. Demo accounts never see this (handled by the caller).
|
||||
// directly with inline errors.
|
||||
function SignInMethods({ me }: { me: Me }) {
|
||||
const { t } = useTranslation();
|
||||
const qc = useQueryClient();
|
||||
@@ -785,13 +785,11 @@ export function AccountHeader({ me }: { me: Me }) {
|
||||
<div className="text-xs text-muted truncate">{me.email}</div>
|
||||
{/* Translated, like the sidebar's tooltip: the raw `user` read in English under HU. */}
|
||||
<div className="text-xs text-muted">{t(`nav.role.${roleKey(me)}`)}</div>
|
||||
{!me.is_demo && (
|
||||
<div className="text-xs text-muted" data-testid="account-last-login">
|
||||
{me.last_login_at
|
||||
? t("settings.account.lastLogin", { time: formatDateTime(me.last_login_at, lang) })
|
||||
: t("settings.account.lastLoginNone")}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-xs text-muted" data-testid="account-last-login">
|
||||
{me.last_login_at
|
||||
? t("settings.account.lastLogin", { time: formatDateTime(me.last_login_at, lang) })
|
||||
: t("settings.account.lastLoginNone")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
@@ -823,17 +821,13 @@ function Account({ me, onOpenWizard }: { me: Me; onOpenWizard: () => void }) {
|
||||
<>
|
||||
<AccountHeader me={me} />
|
||||
|
||||
{!me.is_demo && <SignInMethods me={me} />}
|
||||
<SignInMethods me={me} />
|
||||
|
||||
{me.role === "admin" && me.plex_enabled && <PlexWatchSync />}
|
||||
|
||||
{!me.is_demo && <DownloadAuth />}
|
||||
<DownloadAuth />
|
||||
|
||||
{me.is_demo ? (
|
||||
<Section title={t("settings.account.youtubeAccess")}>
|
||||
<p className="text-xs text-muted leading-relaxed">{t("settings.account.demoNotice")}</p>
|
||||
</Section>
|
||||
) : me.google_enabled ? (
|
||||
{me.google_enabled ? (
|
||||
// YouTube access requires Google OAuth; hidden when this instance has no Google configured.
|
||||
<Section title={t("settings.account.youtubeAccess")}>
|
||||
<p className="text-xs text-muted leading-relaxed mb-1">
|
||||
@@ -865,17 +859,15 @@ function Account({ me, onOpenWizard }: { me: Me; onOpenWizard: () => void }) {
|
||||
</Section>
|
||||
) : null}
|
||||
|
||||
{!me.is_demo && (
|
||||
<Section title={t("settings.account.dangerZone")}>
|
||||
<p className="text-xs text-muted leading-relaxed mb-2">
|
||||
{t("settings.account.deleteHint")}
|
||||
</p>
|
||||
<Button variant="danger-soft" size="md" onClick={onDeleteAccount}>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
{t("settings.account.deleteAccount")}
|
||||
</Button>
|
||||
</Section>
|
||||
)}
|
||||
<Section title={t("settings.account.dangerZone")}>
|
||||
<p className="text-xs text-muted leading-relaxed mb-2">
|
||||
{t("settings.account.deleteHint")}
|
||||
</p>
|
||||
<Button variant="danger-soft" size="md" onClick={onDeleteAccount}>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
{t("settings.account.deleteAccount")}
|
||||
</Button>
|
||||
</Section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user