{% extends "base.html" %}
{% from "components/ui.html" import action, ago, anywhere_tag, breadcrumb, card, csrf_field, danger_card, empty, fact, facts, icon, related, rights_tags, row_form, secret_card, tabs, tick, tick_all with context %}
{% from "components/audit.html" import activity_rows %}
{% from "components/grants.html" import grant_editor, grants_of, role_checks, role_tags, sending_of, service_editor, service_of %}
{% block title %}{{ user.name }} · {{ APP_NAME }}{% endblock %}
{% block heading %}{{ user.name }}{% endblock %}
{% block subheading %}{{ breadcrumb([("Users", "/ui/users"), (user.name, None)]) }}{% endblock %}
{% block content %}
{% if new_token %}
{% call secret_card("New token", new_token) %}Copy it now. Only its hash is kept. It cannot be shown again.{% endcall %}
{% endif %}
{% if new_password %}
{% call secret_card("One-time password", new_password) %}Pass it to {{ user.name }} over a safe channel. It must be changed at the first sign-in.{% endcall %}
{% endif %}
{% set state %}{% if is_me %}you {% endif %}{% if not user.ui_sign_in %}API only {% endif %}{% if user.disabled %}disabled{% else %}active{% endif %}{% endset %}
{{ tabs(tabs_shown, tab, "/ui/users/" ~ user.id) }}
{% if tab == "rights" %}
{% call facts("User", tags=state) %}
{% call fact("Roles") %}{{ role_tags(user.roles) }}{% endcall %}
{% call fact("Service rights") %}{{ service_of(user.service) }}{% endcall %}
{% call fact("Grants") %}{{ grants_of(user.grants, names) }}{% endcall %}
{{ fact("Id", user.id, cls="mono") }}
{% endcall %}
{% call card("Effective rights", meta="The rights of the user and of its roles together" ~ (". They apply once the user is enabled again" if user.disabled else "") ~ ".", tight=True) %}
{% if effective.accounts %}
{% else %}
No rights on any account you can see.
{% endif %}
{% if effective.groups or effective.operations %}
- Of the service
- {{ rights_tags(effective.groups, effective.operations) }}
{% endif %}
{% endcall %}
{% if can_update %}
{% endif %}
{% elif tab == "access" %}
{% call facts("Sign-in", tags=state) %}
{% call fact("To the UI") %}{% if not user.ui_sign_in %}off: an API user, tokens only{% elif sign_in.must_change %}with a password set for it, to change at the next sign-in{% elif sign_in.has_password %}with a password{% else %}not possible: no password yet{% endif %}{% if is_me and user.ui_sign_in %} · Change your password{% endif %}{% endcall %}
{% if user.ui_sign_in %}{% call fact("Second factor") %}{% if sign_in.second_factor %}on a code of an authenticator app after the password{% else %}off{% endif %}{% if is_me %} · {% if sign_in.second_factor %}Your devices{% else %}Set up a second factor{% endif %}{% endif %}{% endcall %}{% endif %}
{{ fact("Last sign-in", sign_in.last_sign_in_at | when) }}
{% endcall %}
{% if not is_me and can_set_password and user.ui_sign_in %}
{% call card("Password", meta="Whoever sets a password can sign in as that user.") %}
{% endcall %}
{% endif %}
{% if not is_me and factor and factor.totp %}
{% call related("Second factor", count=factor.totp | length, meta="authenticator apps (TOTP), " ~ factor.recovery_codes_left ~ " recovery codes left. Only " ~ user.name ~ " adds one.") %}
{% if can_remove_factor %}
Removing every device lets {{ user.name }} sign in with the password alone, e.g. after every device is lost. Its sessions end.
{{ action("/ui/users/" ~ user.id ~ "/second-factor/remove", "Remove every device", confirm="Remove every device of the second factor of " ~ user.name ~ "? It signs in with the password alone then.", cls="danger", icon="trash") }}
{% endif %}
{% endcall %}
{% endif %}
{% if can_list_tokens %}
{% set active = tokens | selectattr(1, "equalto", "active") | list %}
{% set batch = can_revoke and active | length > 1 %}
{% call related("Tokens", count=tokens | length, meta="for the API and the MCP server", add=("New token" if can_create_token else None), add_form="new-token", add_open=not tokens or typed_token) %}
{% if batch %}
{% endif %}
{% if not tokens %}{{ empty("No token yet.") }}{% endif %}
{% endcall %}
{% endif %}
{% elif tab == "activity" %}
{% if activity is not none %}
{% call related("Recent activity", meta="what this user did, newest first") %}
{% if activity %}{{ activity_rows(activity, outcomes, False, who=False) }}{% else %}{{ empty("Nothing in the audit.") }}{% endif %}
{% endcall %}
{% endif %}
{% endif %}
{% if can_delete %}
{{ danger_card("Delete", "Deletes the user and all its tokens. What it sent stays in the send audit.", "/ui/users/" ~ user.id ~ "/delete", "Delete user", "Delete " ~ user.name ~ " and its tokens?") }}
{% endif %}
{% endblock %}