fix(chat tools): wire list_users into the WebUI user-list modal
The Tools tab has an interactive modal: when a list_users task completes it parses the task log for EZ_USER lines and renders one row per account with reset / promote / delete buttons. All four new apps failed its contract in every respect, so running List Users produced log text and nothing else. - The marker is EZ_USER, tab-separated as email, username, roles. Matrix and Stoat emitted LP_USER in a different field order; Mattermost and Rocket.Chat emitted no marker at all. - Matrix and Stoat then consumed their own marker lines in the formatting loop and printed only the pretty version, so nothing reached the log to parse. - The row buttons look up tools by id: reset_password, set_admin, delete_user. The deactivate tools were named deactivate_user / disable_user, so no delete button rendered. - Prefill only fills a field named email or username. Rocket.Chat's and Stoat's identifier field was called user, so a row action would have opened with an empty box. - '-' placeholders are truthy, so the modal's `email || username` fallback picked '-' over the real username for accounts without an email (rocket.cat). The EZ_USER line now carries an empty string; '-' stays in the readable line. Mattermost's listing is rebuilt on `mmctl --json`, which carries roles and delete_at. The text listing has neither, and there is no --system-admin filter on user list, so every account was reported as a plain user. Two parsing notes that cost time: mmctl prints status lines both before and after the JSON, so it needs raw_decode rather than json.loads; and --per-page above 200 makes it emit a warning line ahead of the payload. The modal's delete button also stops asserting "Delete user" over whatever the tool actually does — it takes its label and icon from the tool, because most of these deactivate and Matrix cannot delete at all. Verified by replaying the modal's own parser over real tool output: 2 rows for Matrix, 4 for Mattermost, 3 for Rocket.Chat, with admin and deactivated states resolving correctly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
77b50e5226
commit
5b6ed924d2
@ -98,6 +98,10 @@ class ToolsManager {
|
|||||||
_openUserListModal(appName, users) {
|
_openUserListModal(appName, users) {
|
||||||
const tools = (window.toolsCatalog?.apps?.[appName]?.tools) || [];
|
const tools = (window.toolsCatalog?.apps?.[appName]?.tools) || [];
|
||||||
const resetTool = tools.find(t => t.id === 'reset_password');
|
const resetTool = tools.find(t => t.id === 'reset_password');
|
||||||
|
// Its id is delete_user by convention, but what it actually does is the
|
||||||
|
// app's business — most deactivate rather than delete, and Matrix cannot
|
||||||
|
// delete at all. The row button therefore takes its label and icon from the
|
||||||
|
// tool itself instead of asserting "Delete user" over the top of it.
|
||||||
const deleteTool = tools.find(t => t.id === 'delete_user');
|
const deleteTool = tools.find(t => t.id === 'delete_user');
|
||||||
const adminTool = tools.find(t => t.id === 'set_admin');
|
const adminTool = tools.find(t => t.id === 'set_admin');
|
||||||
const appLabel = (window.getAppDisplayName ? window.getAppDisplayName(appName) : appName);
|
const appLabel = (window.getAppDisplayName ? window.getAppDisplayName(appName) : appName);
|
||||||
@ -121,7 +125,7 @@ class ToolsManager {
|
|||||||
<div class="user-row-actions">
|
<div class="user-row-actions">
|
||||||
${resetTool ? `<button type="button" class="user-row-btn" data-act="reset" data-idx="${idx}" title="Reset password">🔑</button>` : ''}
|
${resetTool ? `<button type="button" class="user-row-btn" data-act="reset" data-idx="${idx}" title="Reset password">🔑</button>` : ''}
|
||||||
${adminTool ? `<button type="button" class="user-row-btn" data-act="admin" data-idx="${idx}" title="${isAdmin ? 'Demote from admin' : 'Promote to admin'}">${isAdmin ? '👤' : '👑'}</button>` : ''}
|
${adminTool ? `<button type="button" class="user-row-btn" data-act="admin" data-idx="${idx}" title="${isAdmin ? 'Demote from admin' : 'Promote to admin'}">${isAdmin ? '👤' : '👑'}</button>` : ''}
|
||||||
${deleteTool ? `<button type="button" class="user-row-btn danger" data-act="delete" data-idx="${idx}" title="Delete user">🗑</button>` : ''}
|
${deleteTool ? `<button type="button" class="user-row-btn danger" data-act="delete" data-idx="${idx}" title="${escapeHtml(deleteTool.label || 'Delete user')}">${escapeHtml(deleteTool.icon || '🗑')}</button>` : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('')
|
}).join('')
|
||||||
|
|||||||
@ -224,7 +224,10 @@ for u in res.get('users', []):
|
|||||||
flags = []
|
flags = []
|
||||||
if u.get('admin'): flags.append('admin')
|
if u.get('admin'): flags.append('admin')
|
||||||
if u.get('deactivated'): flags.append('deactivated')
|
if u.get('deactivated'): flags.append('deactivated')
|
||||||
print('LP_USER\t' + u['name'] + '\t' + (u.get('displayname') or '-') + '\t' + (','.join(flags) or 'user'))
|
# EZ_USER<TAB>identifier<TAB>display<TAB>roles — the exact shape the WebUI's
|
||||||
|
# user-list modal parses. The first column is what a row action gets
|
||||||
|
# prefilled with, so it must be the Matrix ID, not the display name.
|
||||||
|
print('EZ_USER\t' + u['name'] + '\t' + (u.get('displayname') or '') + '\t' + (','.join(flags) or 'user'))
|
||||||
print('LP_TOTAL:' + str(res.get('total', 0)))
|
print('LP_TOTAL:' + str(res.get('total', 0)))
|
||||||
" 2>&1)
|
" 2>&1)
|
||||||
|
|
||||||
@ -233,7 +236,12 @@ print('LP_TOTAL:' + str(res.get('total', 0)))
|
|||||||
local line total=0
|
local line total=0
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
case "$line" in
|
case "$line" in
|
||||||
LP_USER*) IFS=$'\t' read -r _ uid name flags <<< "$line"
|
EZ_USER*) IFS=$'\t' read -r _ uid name flags <<< "$line"
|
||||||
|
# Re-emit the raw marker line as well as the readable one:
|
||||||
|
# the WebUI modal reads the task log looking for EZ_USER,
|
||||||
|
# so consuming it here and printing only the pretty version
|
||||||
|
# left the modal with nothing to parse.
|
||||||
|
printf '%s\n' "$line"
|
||||||
printf ' %-34s %-20s %s\n' "$uid" "$name" "$flags" ;;
|
printf ' %-34s %-20s %s\n' "$uid" "$name" "$flags" ;;
|
||||||
LP_TOTAL:*) total="${line#LP_TOTAL:}" ;;
|
LP_TOTAL:*) total="${line#LP_TOTAL:}" ;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
@ -86,7 +86,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "deactivate_user",
|
"id": "delete_user",
|
||||||
"category": "users",
|
"category": "users",
|
||||||
"label": "Deactivate User Account",
|
"label": "Deactivate User Account",
|
||||||
"description": "Matrix has no delete. This revokes access and erases the profile, and the user ID stays permanently taken.",
|
"description": "Matrix has no delete. This revokes access and erases the profile, and the user ID stays permanently taken.",
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Named deactivate rather than delete on purpose — Matrix has no delete, and
|
# Named deactivate rather than delete on purpose — Matrix has no delete, and
|
||||||
# calling it one would misrepresent what the button does.
|
# calling it one would misrepresent what the button does.
|
||||||
appMatrixDeactivateUser() {
|
appMatrixDeleteUser() {
|
||||||
local args="$1"
|
local args="$1"
|
||||||
authAdapterCall matrix deleteUser "$(authToolArg "$args" username)"
|
authAdapterCall matrix deleteUser "$(authToolArg "$args" username)"
|
||||||
}
|
}
|
||||||
@ -73,19 +73,54 @@ authAdapter_mattermost_setPassword() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
authAdapter_mattermost_listUsers() {
|
authAdapter_mattermost_listUsers() {
|
||||||
|
# --json rather than the human format: it carries `roles` and `delete_at`,
|
||||||
|
# which the plain listing does not. There is no --system-admin filter on
|
||||||
|
# `user list` (only --inactive), so parsing the text output left every
|
||||||
|
# account looking like a plain user.
|
||||||
local out
|
local out
|
||||||
out=$(_mmctl user list --per-page 500)
|
# 200 is mmctl's maximum; asking for more makes it print a warning line
|
||||||
|
# BEFORE the JSON, which then fails to parse.
|
||||||
|
out=$(_mmctl --json user list --per-page 200)
|
||||||
_mmctlFailed "$out" "Listing users" && return 1
|
_mmctlFailed "$out" "Listing users" && return 1
|
||||||
|
|
||||||
# `user list` prints "id: username (email)" per line, plus a trailing count.
|
local rendered
|
||||||
local line count=0
|
rendered=$(printf '%s' "$out" | python3 -c "
|
||||||
|
import sys, json
|
||||||
|
# _mmctl folds stderr into stdout, and mmctl prints status lines such as
|
||||||
|
# 'There are 4 users on local instance' AFTER the JSON as well as warnings
|
||||||
|
# before it. raw_decode stops at the end of the first complete JSON value and
|
||||||
|
# ignores whatever trails it, which plain json.loads will not do.
|
||||||
|
raw = sys.stdin.read()
|
||||||
|
start = min([i for i in (raw.find('['), raw.find('{')) if i >= 0], default=-1)
|
||||||
|
users = []
|
||||||
|
if start >= 0:
|
||||||
|
try:
|
||||||
|
users, _ = json.JSONDecoder().raw_decode(raw[start:])
|
||||||
|
except Exception:
|
||||||
|
users = []
|
||||||
|
if isinstance(users, dict):
|
||||||
|
users = users.get('users', [])
|
||||||
|
for u in users:
|
||||||
|
roles = 'admin' if 'system_admin' in (u.get('roles') or '') else 'user'
|
||||||
|
if u.get('delete_at'):
|
||||||
|
roles += ',deactivated'
|
||||||
|
email = u.get('email') or '-'
|
||||||
|
name = u.get('username') or '-'
|
||||||
|
# EZ_USER<TAB>email<TAB>username<TAB>roles is what the WebUI user-list modal
|
||||||
|
# parses; the aligned line after it is for whoever reads the log.
|
||||||
|
print('EZ_USER\\t%s\\t%s\\t%s' % (email, name, roles))
|
||||||
|
print(' %-30s %-22s %s' % (email, name, roles))
|
||||||
|
print('LP_TOTAL:%d' % len(users))
|
||||||
|
" 2>/dev/null)
|
||||||
|
|
||||||
|
local line total=0
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
[[ "$line" =~ ^[a-z0-9]+:\ ]] || continue
|
case "$line" in
|
||||||
local rest="${line#*: }"
|
LP_TOTAL:*) total="${line#LP_TOTAL:}" ;;
|
||||||
printf ' %s\n' "$rest"
|
*) [[ -n "$line" ]] && printf '%s\n' "$line" ;;
|
||||||
((count++))
|
esac
|
||||||
done <<< "$out"
|
done <<< "$rendered"
|
||||||
isSuccessful "$count Mattermost account(s)."
|
isSuccessful "$total Mattermost account(s)."
|
||||||
}
|
}
|
||||||
|
|
||||||
# Mattermost distinguishes deactivate (reversible, frees nothing) from delete
|
# Mattermost distinguishes deactivate (reversible, frees nothing) from delete
|
||||||
|
|||||||
@ -85,7 +85,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "deactivate_user",
|
"id": "delete_user",
|
||||||
"category": "users",
|
"category": "users",
|
||||||
"label": "Deactivate User Account",
|
"label": "Deactivate User Account",
|
||||||
"description": "Revoke access without deleting content. Reversible from the System Console.",
|
"description": "Revoke access without deleting content. Reversible from the System Console.",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
appMattermostDeactivateUser() {
|
appMattermostDeleteUser() {
|
||||||
local args="$1"
|
local args="$1"
|
||||||
authAdapterCall mattermost deleteUser "$(authToolArg "$args" email)"
|
authAdapterCall mattermost deleteUser "$(authToolArg "$args" email)"
|
||||||
}
|
}
|
||||||
@ -180,7 +180,12 @@ for u in users:
|
|||||||
roles = ','.join(u.get('roles') or []) or 'user'
|
roles = ','.join(u.get('roles') or []) or 'user'
|
||||||
state = '' if u.get('active', True) else ' (deactivated)'
|
state = '' if u.get('active', True) else ' (deactivated)'
|
||||||
email = (u.get('emails') or [{}])[0].get('address', '-')
|
email = (u.get('emails') or [{}])[0].get('address', '-')
|
||||||
print(' %-22s %-30s %s%s' % (u.get('username', '-'), email, roles, state))
|
# EZ_USER<TAB>email<TAB>username<TAB>roles drives the WebUI's user-list
|
||||||
|
# modal; the aligned line below it is what a human reads in the log.
|
||||||
|
# Empty, not '-': the modal falls back to the username with
|
||||||
|
# \`email || username\`, and a '-' placeholder is truthy so it would win.
|
||||||
|
print('EZ_USER\t%s\t%s\t%s' % ('' if email == '-' else email, u.get('username', ''), roles + state))
|
||||||
|
print(' %-30s %-22s %s%s' % (email, u.get('username', '-'), roles, state))
|
||||||
print('LP_TOTAL:%d' % d.get('total', len(users)))
|
print('LP_TOTAL:%d' % d.get('total', len(users)))
|
||||||
" 2>/dev/null)
|
" 2>/dev/null)
|
||||||
|
|
||||||
|
|||||||
@ -50,7 +50,7 @@
|
|||||||
"icon": "🔑",
|
"icon": "🔑",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"name": "user",
|
"name": "username",
|
||||||
"label": "Username or email",
|
"label": "Username or email",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"required": true
|
"required": true
|
||||||
@ -71,7 +71,7 @@
|
|||||||
"icon": "👑",
|
"icon": "👑",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"name": "user",
|
"name": "username",
|
||||||
"label": "Username or email",
|
"label": "Username or email",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"required": true
|
"required": true
|
||||||
@ -85,7 +85,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "deactivate_user",
|
"id": "delete_user",
|
||||||
"category": "users",
|
"category": "users",
|
||||||
"label": "Deactivate User Account",
|
"label": "Deactivate User Account",
|
||||||
"description": "Revoke access without deleting messages. Reversible from Admin → Users.",
|
"description": "Revoke access without deleting messages. Reversible from Admin → Users.",
|
||||||
@ -94,7 +94,7 @@
|
|||||||
"confirm": "The user will be signed out and unable to log in.",
|
"confirm": "The user will be signed out and unable to log in.",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"name": "user",
|
"name": "username",
|
||||||
"label": "Username or email",
|
"label": "Username or email",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"required": true
|
"required": true
|
||||||
@ -109,7 +109,7 @@
|
|||||||
"icon": "✅",
|
"icon": "✅",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"name": "user",
|
"name": "username",
|
||||||
"label": "Username or email",
|
"label": "Username or email",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"required": true
|
"required": true
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
appRocketchatDeactivateUser() {
|
appRocketchatDeleteUser() {
|
||||||
local args="$1"
|
local args="$1"
|
||||||
authAdapterCall rocketchat deleteUser "$(authToolArg "$args" user)"
|
authAdapterCall rocketchat deleteUser "$(authToolArg "$args" username)"
|
||||||
}
|
}
|
||||||
@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
appRocketchatEnableUser() {
|
appRocketchatEnableUser() {
|
||||||
local args="$1"
|
local args="$1"
|
||||||
authAdapterCall rocketchat enableUser "$(authToolArg "$args" user)"
|
authAdapterCall rocketchat enableUser "$(authToolArg "$args" username)"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,6 @@
|
|||||||
appRocketchatResetPassword() {
|
appRocketchatResetPassword() {
|
||||||
local args="$1"
|
local args="$1"
|
||||||
authAdapterCall rocketchat setPassword \
|
authAdapterCall rocketchat setPassword \
|
||||||
"$(authToolArg "$args" user)" \
|
"$(authToolArg "$args" username)" \
|
||||||
"$(authToolArg "$args" password)"
|
"$(authToolArg "$args" password)"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,6 @@
|
|||||||
appRocketchatSetAdmin() {
|
appRocketchatSetAdmin() {
|
||||||
local args="$1"
|
local args="$1"
|
||||||
authAdapterCall rocketchat setAdmin \
|
authAdapterCall rocketchat setAdmin \
|
||||||
"$(authToolArg "$args" user)" \
|
"$(authToolArg "$args" username)" \
|
||||||
"$(authToolArg "$args" admin)"
|
"$(authToolArg "$args" admin)"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,7 +51,9 @@ users.forEach(u => {
|
|||||||
const a = byId[u._id] || {};
|
const a = byId[u._id] || {};
|
||||||
const handle = u.username + (u.discriminator ? "#" + u.discriminator : "");
|
const handle = u.username + (u.discriminator ? "#" + u.discriminator : "");
|
||||||
const state = a.disabled ? " (disabled)" : "";
|
const state = a.disabled ? " (disabled)" : "";
|
||||||
print("LP_USER\t" + handle + "\t" + (a.email || "-") + "\t" + (u.display_name || "-") + state);
|
// EZ_USER<TAB>identifier<TAB>display<TAB>roles, as the WebUI modal expects.
|
||||||
|
// Email first where there is one: it is the field a row action prefills.
|
||||||
|
print("EZ_USER\t" + (a.email || handle) + "\t" + handle + "\t" + (a.disabled ? "disabled" : "user"));
|
||||||
});
|
});
|
||||||
print("LP_TOTAL:" + users.length);
|
print("LP_TOTAL:" + users.length);
|
||||||
')
|
')
|
||||||
@ -60,8 +62,11 @@ print("LP_TOTAL:" + users.length);
|
|||||||
local line total=0
|
local line total=0
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
case "$line" in
|
case "$line" in
|
||||||
LP_USER*) IFS=$'\t' read -r _ handle email display <<< "$line"
|
EZ_USER*) IFS=$'\t' read -r _ ident handle state <<< "$line"
|
||||||
printf ' %-24s %-30s %s\n' "$handle" "$email" "$display" ;;
|
# The marker line has to reach the task log for the WebUI
|
||||||
|
# user-list modal to build its rows from.
|
||||||
|
printf '%s\n' "$line"
|
||||||
|
printf ' %-30s %-24s %s\n' "$ident" "$handle" "$state" ;;
|
||||||
LP_TOTAL:*) total="${line#LP_TOTAL:}" ;;
|
LP_TOTAL:*) total="${line#LP_TOTAL:}" ;;
|
||||||
esac
|
esac
|
||||||
done <<< "$out"
|
done <<< "$out"
|
||||||
|
|||||||
@ -187,6 +187,25 @@ EOF
|
|||||||
isSuccessful "Generated secrets.env"
|
isSuccessful "Generated secrets.env"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Own the LibrePortal-written config files (Caddyfile, Revolt.toml, .env.web,
|
||||||
|
# stoat.json, secrets.env, livekit.yml, the compose + app config) as the docker
|
||||||
|
# install user, so the containers can read their bind-mount sources.
|
||||||
|
#
|
||||||
|
# Top level ONLY. This used to be `chown -R "$app_dir"`, which walked into
|
||||||
|
# data/db, data/minio and friends — content created by the containers and owned
|
||||||
|
# by THEIR uids (mongo's, minio's; under rootless those are subuids the docker
|
||||||
|
# install user has no authority over). Every reinstall therefore printed a screen
|
||||||
|
# of "Operation not permitted" plus "Permission denied" on the 0700 dirs it
|
||||||
|
# couldn't even enter, and then failed the step outright — an ✗ Error on a
|
||||||
|
# healthy install, which is the kind of noise that teaches you to skip error
|
||||||
|
# lines. Those files must keep their container ownership anyway: chowning mongo's
|
||||||
|
# data away from mongo is what would actually break stoat.
|
||||||
|
_stoatOwnConfigFiles() {
|
||||||
|
local app_dir="$1"
|
||||||
|
runFileOp find "$app_dir" -maxdepth 1 -type f \
|
||||||
|
-exec chown "$docker_install_user":"$docker_install_user" {} +
|
||||||
|
}
|
||||||
|
|
||||||
stoat_install_post_compose()
|
stoat_install_post_compose()
|
||||||
{
|
{
|
||||||
local app_name="$1"
|
local app_name="$1"
|
||||||
@ -267,8 +286,8 @@ webhook:
|
|||||||
EOF
|
EOF
|
||||||
checkSuccess "Writing livekit.yml"
|
checkSuccess "Writing livekit.yml"
|
||||||
|
|
||||||
runFileOp chown -R "$docker_install_user":"$docker_install_user" "$app_dir"
|
_stoatOwnConfigFiles "$app_dir"
|
||||||
checkSuccess "Setting ownership on the $app_name install directory"
|
checkSuccess "Setting ownership on the $app_name config files"
|
||||||
}
|
}
|
||||||
|
|
||||||
stoat_install_post_start()
|
stoat_install_post_start()
|
||||||
@ -294,7 +313,7 @@ stoat_install_post_start()
|
|||||||
local video_enabled=""
|
local video_enabled=""
|
||||||
[[ "$CFG_STOAT_ENABLE_VIDEO" != "false" ]] && video_enabled="true"
|
[[ "$CFG_STOAT_ENABLE_VIDEO" != "false" ]] && video_enabled="true"
|
||||||
_stoatWriteUrlFiles "$app_dir" "$base" "$video_enabled" "$CFG_STOAT_RABBITMQ_PASSWORD_1"
|
_stoatWriteUrlFiles "$app_dir" "$base" "$video_enabled" "$CFG_STOAT_RABBITMQ_PASSWORD_1"
|
||||||
runFileOp chown -R "$docker_install_user":"$docker_install_user" "$app_dir"
|
_stoatOwnConfigFiles "$app_dir"
|
||||||
isSuccessful "Public URL settled as $base (was ${current:-unset})"
|
isSuccessful "Public URL settled as $base (was ${current:-unset})"
|
||||||
|
|
||||||
# The web client compiles VITE_* at container start, so it has to come back
|
# The web client compiles VITE_* at container start, so it has to come back
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
"fields": []
|
"fields": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "disable_user",
|
"id": "delete_user",
|
||||||
"category": "users",
|
"category": "users",
|
||||||
"label": "Disable User Account",
|
"label": "Disable User Account",
|
||||||
"description": "Block sign-in without deleting the account or its messages. Reversible.",
|
"description": "Block sign-in without deleting the account or its messages. Reversible.",
|
||||||
@ -18,7 +18,7 @@
|
|||||||
"confirm": "The user will not be able to sign in again until re-enabled.",
|
"confirm": "The user will not be able to sign in again until re-enabled.",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"name": "user",
|
"name": "username",
|
||||||
"label": "Username or email",
|
"label": "Username or email",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"required": true
|
"required": true
|
||||||
@ -33,7 +33,7 @@
|
|||||||
"icon": "✅",
|
"icon": "✅",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"name": "user",
|
"name": "username",
|
||||||
"label": "Username or email",
|
"label": "Username or email",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"required": true
|
"required": true
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
appStoatDisableUser() {
|
appStoatDeleteUser() {
|
||||||
local args="$1"
|
local args="$1"
|
||||||
authAdapterCall stoat deleteUser "$(authToolArg "$args" user)"
|
authAdapterCall stoat deleteUser "$(authToolArg "$args" username)"
|
||||||
}
|
}
|
||||||
@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
appStoatEnableUser() {
|
appStoatEnableUser() {
|
||||||
local args="$1"
|
local args="$1"
|
||||||
authAdapterCall stoat enableUser "$(authToolArg "$args" user)"
|
authAdapterCall stoat enableUser "$(authToolArg "$args" username)"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ function checkSuccess()
|
|||||||
local _where="${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]}"
|
local _where="${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]}"
|
||||||
local _stamp; _stamp="$(date '+%F %T' 2>/dev/null || echo now)"
|
local _stamp; _stamp="$(date '+%F %T' 2>/dev/null || echo now)"
|
||||||
printf '%s\t[exit %s]\t%s\t(%s)\n' "$_stamp" "$rc" "$msg" "$_where" \
|
printf '%s\t[exit %s]\t%s\t(%s)\n' "$_stamp" "$rc" "$msg" "$_where" \
|
||||||
| runInstallWrite -a "$logs_dir/error_report.log" 2>/dev/null || true
|
| runInstallWrite -a "${logs_dir%/}/error_report.log" 2>/dev/null || true
|
||||||
if [ -f "$logs_dir/$docker_log_file" ]; then
|
if [ -f "$logs_dir/$docker_log_file" ]; then
|
||||||
isError " $msg (exit $rc, $_where)" | runInstallWrite -a "$logs_dir/$docker_log_file" >/dev/null 2>&1 || true
|
isError " $msg (exit $rc, $_where)" | runInstallWrite -a "$logs_dir/$docker_log_file" >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
@ -42,7 +42,7 @@ function checkSuccess()
|
|||||||
# doesn't abort the whole run and we surface EVERY issue in one pass. Turn
|
# doesn't abort the whole run and we surface EVERY issue in one pass. Turn
|
||||||
# CFG_REQUIREMENT_CONTINUE_ON_ERROR off for strict abort once things are clean.
|
# CFG_REQUIREMENT_CONTINUE_ON_ERROR off for strict abort once things are clean.
|
||||||
if [[ "${CFG_REQUIREMENT_CONTINUE_ON_ERROR:-true}" == "true" ]]; then
|
if [[ "${CFG_REQUIREMENT_CONTINUE_ON_ERROR:-true}" == "true" ]]; then
|
||||||
isNotice "continue-on-error: logged to $logs_dir/error_report.log — continuing."
|
isNotice "continue-on-error: logged to ${logs_dir%/}/error_report.log — continuing."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@ -175,9 +175,7 @@ declare -gA LP_FN_MAP=(
|
|||||||
[authAdapter_matrix_setAdmin]="matrix/scripts/matrix_auth.sh"
|
[authAdapter_matrix_setAdmin]="matrix/scripts/matrix_auth.sh"
|
||||||
[authAdapter_matrix_setPassword]="matrix/scripts/matrix_auth.sh"
|
[authAdapter_matrix_setPassword]="matrix/scripts/matrix_auth.sh"
|
||||||
[authAdapter_mattermost_createUser]="mattermost/scripts/mattermost_auth.sh"
|
[authAdapter_mattermost_createUser]="mattermost/scripts/mattermost_auth.sh"
|
||||||
[authAdapter_mattermost_deleteUser]="mattermost/scripts/mattermost_auth.sh"
|
|
||||||
[authAdapter_mattermost_listUsers]="mattermost/scripts/mattermost_auth.sh"
|
[authAdapter_mattermost_listUsers]="mattermost/scripts/mattermost_auth.sh"
|
||||||
[authAdapter_mattermost_setAdmin]="mattermost/scripts/mattermost_auth.sh"
|
|
||||||
[authAdapter_mattermost_setPassword]="mattermost/scripts/mattermost_auth.sh"
|
[authAdapter_mattermost_setPassword]="mattermost/scripts/mattermost_auth.sh"
|
||||||
[authAdapter_nextcloud_createUser]="nextcloud/scripts/nextcloud_auth.sh"
|
[authAdapter_nextcloud_createUser]="nextcloud/scripts/nextcloud_auth.sh"
|
||||||
[authAdapter_nextcloud_deleteUser]="nextcloud/scripts/nextcloud_auth.sh"
|
[authAdapter_nextcloud_deleteUser]="nextcloud/scripts/nextcloud_auth.sh"
|
||||||
@ -955,6 +953,7 @@ declare -gA LP_FN_MAP=(
|
|||||||
[_stoatMongo]="stoat/scripts/stoat_auth.sh"
|
[_stoatMongo]="stoat/scripts/stoat_auth.sh"
|
||||||
[_stoatMongoFailed]="stoat/scripts/stoat_auth.sh"
|
[_stoatMongoFailed]="stoat/scripts/stoat_auth.sh"
|
||||||
[_stoatMongoWho]="stoat/scripts/stoat_auth.sh"
|
[_stoatMongoWho]="stoat/scripts/stoat_auth.sh"
|
||||||
|
[_stoatOwnConfigFiles]="stoat/scripts/stoat_install_hooks.sh"
|
||||||
[_stoatSetDisabled]="stoat/scripts/stoat_auth.sh"
|
[_stoatSetDisabled]="stoat/scripts/stoat_auth.sh"
|
||||||
[_stoatWriteSecrets]="stoat/scripts/stoat_install_hooks.sh"
|
[_stoatWriteSecrets]="stoat/scripts/stoat_install_hooks.sh"
|
||||||
[_stoatWriteUrlFiles]="stoat/scripts/stoat_install_hooks.sh"
|
[_stoatWriteUrlFiles]="stoat/scripts/stoat_install_hooks.sh"
|
||||||
@ -1299,9 +1298,7 @@ declare -gA LP_FN_ROOT=(
|
|||||||
[authAdapter_matrix_setAdmin]="containers"
|
[authAdapter_matrix_setAdmin]="containers"
|
||||||
[authAdapter_matrix_setPassword]="containers"
|
[authAdapter_matrix_setPassword]="containers"
|
||||||
[authAdapter_mattermost_createUser]="containers"
|
[authAdapter_mattermost_createUser]="containers"
|
||||||
[authAdapter_mattermost_deleteUser]="containers"
|
|
||||||
[authAdapter_mattermost_listUsers]="containers"
|
[authAdapter_mattermost_listUsers]="containers"
|
||||||
[authAdapter_mattermost_setAdmin]="containers"
|
|
||||||
[authAdapter_mattermost_setPassword]="containers"
|
[authAdapter_mattermost_setPassword]="containers"
|
||||||
[authAdapter_nextcloud_createUser]="containers"
|
[authAdapter_nextcloud_createUser]="containers"
|
||||||
[authAdapter_nextcloud_deleteUser]="containers"
|
[authAdapter_nextcloud_deleteUser]="containers"
|
||||||
@ -2079,6 +2076,7 @@ declare -gA LP_FN_ROOT=(
|
|||||||
[_stoatMongo]="containers"
|
[_stoatMongo]="containers"
|
||||||
[_stoatMongoFailed]="containers"
|
[_stoatMongoFailed]="containers"
|
||||||
[_stoatMongoWho]="containers"
|
[_stoatMongoWho]="containers"
|
||||||
|
[_stoatOwnConfigFiles]="containers"
|
||||||
[_stoatSetDisabled]="containers"
|
[_stoatSetDisabled]="containers"
|
||||||
[_stoatWriteSecrets]="containers"
|
[_stoatWriteSecrets]="containers"
|
||||||
[_stoatWriteUrlFiles]="containers"
|
[_stoatWriteUrlFiles]="containers"
|
||||||
@ -2458,9 +2456,7 @@ authAdapter_matrix_listUsers() { unset -f authAdapter_matrix_listUsers; __lpAuto
|
|||||||
authAdapter_matrix_setAdmin() { unset -f authAdapter_matrix_setAdmin; __lpAutoload "${install_containers_dir}matrix/scripts/matrix_auth.sh"; authAdapter_matrix_setAdmin "$@"; }
|
authAdapter_matrix_setAdmin() { unset -f authAdapter_matrix_setAdmin; __lpAutoload "${install_containers_dir}matrix/scripts/matrix_auth.sh"; authAdapter_matrix_setAdmin "$@"; }
|
||||||
authAdapter_matrix_setPassword() { unset -f authAdapter_matrix_setPassword; __lpAutoload "${install_containers_dir}matrix/scripts/matrix_auth.sh"; authAdapter_matrix_setPassword "$@"; }
|
authAdapter_matrix_setPassword() { unset -f authAdapter_matrix_setPassword; __lpAutoload "${install_containers_dir}matrix/scripts/matrix_auth.sh"; authAdapter_matrix_setPassword "$@"; }
|
||||||
authAdapter_mattermost_createUser() { unset -f authAdapter_mattermost_createUser; __lpAutoload "${install_containers_dir}mattermost/scripts/mattermost_auth.sh"; authAdapter_mattermost_createUser "$@"; }
|
authAdapter_mattermost_createUser() { unset -f authAdapter_mattermost_createUser; __lpAutoload "${install_containers_dir}mattermost/scripts/mattermost_auth.sh"; authAdapter_mattermost_createUser "$@"; }
|
||||||
authAdapter_mattermost_deleteUser() { unset -f authAdapter_mattermost_deleteUser; __lpAutoload "${install_containers_dir}mattermost/scripts/mattermost_auth.sh"; authAdapter_mattermost_deleteUser "$@"; }
|
|
||||||
authAdapter_mattermost_listUsers() { unset -f authAdapter_mattermost_listUsers; __lpAutoload "${install_containers_dir}mattermost/scripts/mattermost_auth.sh"; authAdapter_mattermost_listUsers "$@"; }
|
authAdapter_mattermost_listUsers() { unset -f authAdapter_mattermost_listUsers; __lpAutoload "${install_containers_dir}mattermost/scripts/mattermost_auth.sh"; authAdapter_mattermost_listUsers "$@"; }
|
||||||
authAdapter_mattermost_setAdmin() { unset -f authAdapter_mattermost_setAdmin; __lpAutoload "${install_containers_dir}mattermost/scripts/mattermost_auth.sh"; authAdapter_mattermost_setAdmin "$@"; }
|
|
||||||
authAdapter_mattermost_setPassword() { unset -f authAdapter_mattermost_setPassword; __lpAutoload "${install_containers_dir}mattermost/scripts/mattermost_auth.sh"; authAdapter_mattermost_setPassword "$@"; }
|
authAdapter_mattermost_setPassword() { unset -f authAdapter_mattermost_setPassword; __lpAutoload "${install_containers_dir}mattermost/scripts/mattermost_auth.sh"; authAdapter_mattermost_setPassword "$@"; }
|
||||||
authAdapter_nextcloud_createUser() { unset -f authAdapter_nextcloud_createUser; __lpAutoload "${install_containers_dir}nextcloud/scripts/nextcloud_auth.sh"; authAdapter_nextcloud_createUser "$@"; }
|
authAdapter_nextcloud_createUser() { unset -f authAdapter_nextcloud_createUser; __lpAutoload "${install_containers_dir}nextcloud/scripts/nextcloud_auth.sh"; authAdapter_nextcloud_createUser "$@"; }
|
||||||
authAdapter_nextcloud_deleteUser() { unset -f authAdapter_nextcloud_deleteUser; __lpAutoload "${install_containers_dir}nextcloud/scripts/nextcloud_auth.sh"; authAdapter_nextcloud_deleteUser "$@"; }
|
authAdapter_nextcloud_deleteUser() { unset -f authAdapter_nextcloud_deleteUser; __lpAutoload "${install_containers_dir}nextcloud/scripts/nextcloud_auth.sh"; authAdapter_nextcloud_deleteUser "$@"; }
|
||||||
@ -3238,6 +3234,7 @@ stoat_install_pre() { unset -f stoat_install_pre; __lpAutoload "${install_contai
|
|||||||
_stoatMongo() { unset -f _stoatMongo; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_auth.sh"; _stoatMongo "$@"; }
|
_stoatMongo() { unset -f _stoatMongo; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_auth.sh"; _stoatMongo "$@"; }
|
||||||
_stoatMongoFailed() { unset -f _stoatMongoFailed; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_auth.sh"; _stoatMongoFailed "$@"; }
|
_stoatMongoFailed() { unset -f _stoatMongoFailed; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_auth.sh"; _stoatMongoFailed "$@"; }
|
||||||
_stoatMongoWho() { unset -f _stoatMongoWho; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_auth.sh"; _stoatMongoWho "$@"; }
|
_stoatMongoWho() { unset -f _stoatMongoWho; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_auth.sh"; _stoatMongoWho "$@"; }
|
||||||
|
_stoatOwnConfigFiles() { unset -f _stoatOwnConfigFiles; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_install_hooks.sh"; _stoatOwnConfigFiles "$@"; }
|
||||||
_stoatSetDisabled() { unset -f _stoatSetDisabled; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_auth.sh"; _stoatSetDisabled "$@"; }
|
_stoatSetDisabled() { unset -f _stoatSetDisabled; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_auth.sh"; _stoatSetDisabled "$@"; }
|
||||||
_stoatWriteSecrets() { unset -f _stoatWriteSecrets; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_install_hooks.sh"; _stoatWriteSecrets "$@"; }
|
_stoatWriteSecrets() { unset -f _stoatWriteSecrets; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_install_hooks.sh"; _stoatWriteSecrets "$@"; }
|
||||||
_stoatWriteUrlFiles() { unset -f _stoatWriteUrlFiles; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_install_hooks.sh"; _stoatWriteUrlFiles "$@"; }
|
_stoatWriteUrlFiles() { unset -f _stoatWriteUrlFiles; __lpAutoload "${install_containers_dir}stoat/scripts/stoat_install_hooks.sh"; _stoatWriteUrlFiles "$@"; }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user