Each app now carries everything under containers/<app>/: Tools-tab actions in tools/ (declaration <app>.tools.json + function <app>_<tool_id>.sh) and logic helpers in scripts/ (e.g. <app>_auth.sh). The container scan live-sources every .sh under the app (maxdepth 3, prunes only resources/) and webui_tools.sh auto-merges the .tools.json, so an app is a true drop-in — no central edit, no array regen. - Empty the central webui_tools.sh heredoc; all 34 tools across 11 apps now come from per-app declarations (verified byte-identical to the old output). - Retire the orphaned mattermost tool scripts to scripts/unused (there is no containers/mattermost; its install fn already lived in unused). - Update the dispatch comment/error path, the auth-adapter doc, and DEVELOPMENT.md to the new convention. - Regenerate static arrays (files_app.sh no longer lists app/containers/*). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
114 lines
4.3 KiB
Bash
114 lines
4.3 KiB
Bash
#!/bin/bash
|
|
|
|
# Nextcloud exposes all admin operations through its `occ` CLI inside the
|
|
# container. We `docker exec` as www-data so file permissions stay sane, and
|
|
# pipe passwords via the OC_PASS env var (occ supports --password-from-env).
|
|
|
|
_nextcloudOcc() {
|
|
runFileOp docker exec -u www-data nextcloud-service php occ "$@" 2>&1
|
|
}
|
|
|
|
_nextcloudOccWithPass() {
|
|
local pass="$1"; shift
|
|
runFileOp docker exec -e OC_PASS="$pass" -u www-data nextcloud-service php occ "$@" 2>&1
|
|
}
|
|
|
|
authAdapter_nextcloud_setPassword() {
|
|
local username="$1" password="$2"
|
|
[[ -z "$username" ]] && { isError "Username is required."; return 1; }
|
|
[[ -z "$password" ]] && password=$(generateRandomPassword)
|
|
|
|
local out
|
|
out=$(_nextcloudOccWithPass "$password" user:resetpassword --password-from-env "$username")
|
|
if echo "$out" | grep -qi "user.* does not exist\|user not found"; then
|
|
isError "No Nextcloud user '$username'."; return 1
|
|
fi
|
|
if ! echo "$out" | grep -qi "successfully"; then
|
|
isError "Nextcloud reset failed: $out"; return 1
|
|
fi
|
|
|
|
if [[ "$username" == "${CFG_NEXTCLOUD_ADMIN_USER:-}" ]]; then
|
|
authPersistCfg nextcloud ADMIN_PASSWORD "$password"
|
|
fi
|
|
isSuccessful "Nextcloud password set for $username — New password: $password"
|
|
}
|
|
|
|
authAdapter_nextcloud_createUser() {
|
|
local username="$1" password="$2" displayName="$3" isAdmin="$4"
|
|
[[ -z "$username" ]] && { isError "Username is required."; return 1; }
|
|
[[ -z "$displayName" ]] && displayName="$username"
|
|
[[ -z "$password" ]] && password=$(generateRandomPassword)
|
|
|
|
local out args=(--password-from-env --display-name="$displayName")
|
|
[[ "$isAdmin" == "true" ]] && args+=(--group=admin)
|
|
|
|
out=$(_nextcloudOccWithPass "$password" user:add "${args[@]}" "$username")
|
|
if echo "$out" | grep -qi "user.* already exists\|user already exists"; then
|
|
isError "User '$username' already exists."; return 1
|
|
fi
|
|
if ! echo "$out" | grep -qi "user .* was created\|user.* added"; then
|
|
isError "Nextcloud create failed: $out"; return 1
|
|
fi
|
|
|
|
if [[ "$isAdmin" == "true" && -z "${CFG_NEXTCLOUD_ADMIN_USER:-}" ]]; then
|
|
authPersistCfg nextcloud ADMIN_USER "$username"
|
|
authPersistCfg nextcloud ADMIN_PASSWORD "$password"
|
|
fi
|
|
isSuccessful "Nextcloud user created — Username: $username — Password: $password"
|
|
}
|
|
|
|
authAdapter_nextcloud_listUsers() {
|
|
local users_json admin_json
|
|
users_json=$(_nextcloudOcc user:list --output=json)
|
|
admin_json=$(_nextcloudOcc group:list --output=json)
|
|
# users_json: {"alice":"Alice","bob":"Bob"} ; admin members come from group:list.
|
|
# Format each line as EZ_USER<tab>username<tab>display<tab>roles to match the
|
|
# tab-separated shape the dispatcher prints back to the UI.
|
|
python3 - "$users_json" "$admin_json" <<'PY'
|
|
import json, sys
|
|
try:
|
|
users = json.loads(sys.argv[1] or "{}")
|
|
except Exception:
|
|
users = {}
|
|
try:
|
|
groups = json.loads(sys.argv[2] or "{}")
|
|
except Exception:
|
|
groups = {}
|
|
admins = set(groups.get("admin", []))
|
|
for username, display in users.items():
|
|
role = "admin" if username in admins else "user"
|
|
print(f"EZ_USER\t{username}\t{display or username}\t{role}")
|
|
PY
|
|
}
|
|
|
|
authAdapter_nextcloud_deleteUser() {
|
|
local username="$1"
|
|
[[ -z "$username" ]] && { isError "Username is required."; return 1; }
|
|
local out
|
|
out=$(_nextcloudOcc user:delete "$username")
|
|
if echo "$out" | grep -qi "user.* does not exist\|user not found"; then
|
|
isError "No Nextcloud user '$username'."; return 1
|
|
fi
|
|
if ! echo "$out" | grep -qi "the specified user was deleted\|user .* deleted"; then
|
|
isError "Nextcloud delete failed: $out"; return 1
|
|
fi
|
|
isSuccessful "Nextcloud user '$username' deleted."
|
|
}
|
|
|
|
authAdapter_nextcloud_setAdmin() {
|
|
local username="$1" isAdmin="$2"
|
|
[[ -z "$username" ]] && { isError "Username is required."; return 1; }
|
|
local target="${isAdmin}"; [[ "$target" != "true" ]] && target="false"
|
|
|
|
local out
|
|
if [[ "$target" == "true" ]]; then
|
|
out=$(_nextcloudOcc group:adduser admin "$username")
|
|
else
|
|
out=$(_nextcloudOcc group:removeuser admin "$username")
|
|
fi
|
|
if echo "$out" | grep -qi "user.* does not exist\|user not found"; then
|
|
isError "No Nextcloud user '$username'."; return 1
|
|
fi
|
|
isSuccessful "Nextcloud user '$username' admin → $target."
|
|
}
|