#!/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_USERusernamedisplayroles 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." }