Files
Qortal-Nextcloud-Integration/scripts/ensure-nextcloud-default-app-bundle.sh

405 lines
11 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_root="$(cd "${script_dir}/.." && pwd)"
source "${script_dir}/lib-compose-project.sh"
compose_file="${repo_root}/docker-compose.devprod.yml"
env_file="${repo_root}/.env.devprod"
skip_indices="0"
skip_bundle="0"
usage() {
cat <<USAGE
Usage: ./scripts/ensure-nextcloud-default-app-bundle.sh [options]
Ensures optional Nextcloud default apps are installed/enabled and applies the
configured default dashboard/apps order. Also runs db:add-missing-indices unless
explicitly skipped.
Options:
--compose-file <path> Compose file to use (default: docker-compose.devprod.yml)
--env-file <path> Env file to use (default: .env.devprod)
--skip-indices Do not run occ db:add-missing-indices
--skip-bundle Do not install/enable the default app bundle
-h, --help Show this help
USAGE
}
read_env_value() {
local key="$1"
local default_value="${2:-}"
local value=""
if command -v rg >/dev/null 2>&1; then
value="$(rg -m1 "^${key}=" "${env_file}" | cut -d= -f2- || true)"
else
value="$(grep -m1 -E "^${key}=" "${env_file}" | cut -d= -f2- || true)"
fi
if [[ -z "${value}" ]]; then
echo "${default_value}"
return 0
fi
if [[ "${value}" =~ ^\".*\"$ ]]; then
value="${value:1:${#value}-2}"
elif [[ "${value}" =~ ^\'.*\'$ ]]; then
value="${value:1:${#value}-2}"
fi
echo "${value}"
}
normalize_bool_01() {
local raw="${1:-}"
case "$(echo "${raw}" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')" in
1|true|yes|y|on)
echo "1"
;;
0|false|no|n|off)
echo "0"
;;
*)
echo ""
;;
esac
}
trim_csv() {
local raw="${1:-}"
echo "${raw}" \
| tr '\n' ',' \
| sed -E 's/[[:space:]]*,[[:space:]]*/,/g; s/^,+//; s/,+$//; s/,+/,/g'
}
ensure_docker_access() {
local docker_path=""
docker_path="$(type -P docker || true)"
if [[ -z "${docker_path}" ]]; then
echo "docker is required"
exit 1
fi
if "${docker_path}" info >/dev/null 2>&1; then
DOCKER_CMD=("${docker_path}")
return 0
fi
if ! command -v sudo >/dev/null 2>&1; then
echo "docker is installed but this user cannot access it, and sudo is unavailable."
exit 1
fi
if sudo -n "${docker_path}" info >/dev/null 2>&1; then
DOCKER_CMD=(sudo "${docker_path}")
echo "Using sudo for docker commands."
return 0
fi
echo "docker requires elevated privileges on this machine."
echo "You may be prompted for your sudo password."
if sudo "${docker_path}" info >/dev/null 2>&1; then
DOCKER_CMD=(sudo "${docker_path}")
echo "Using sudo for docker commands."
return 0
fi
echo "Unable to access docker, even with sudo."
exit 1
}
docker() {
"${DOCKER_CMD[@]}" "$@"
}
compose_cmd() {
docker compose -f "${compose_file}" --env-file "${env_file}" "$@"
}
ensure_app_enabled() {
local app_id="${1:-}"
if [[ -z "${app_id}" ]]; then
return 1
fi
compose_cmd exec -T --user www-data app php occ app:enable --force "${app_id}" >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
return 0
fi
compose_cmd exec -T --user www-data app php occ app:install "${app_id}" >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
return 1
fi
compose_cmd exec -T --user www-data app php occ app:enable --force "${app_id}" >/dev/null 2>&1
}
occ_app_get() {
local app_id="${1:-}"
local key="${2:-}"
local value=""
if [[ -z "${app_id}" || -z "${key}" ]]; then
return 1
fi
value="$(compose_cmd exec -T --user www-data app php occ config:app:get "${app_id}" "${key}" 2>/dev/null | tr -d '\r' || true)"
if [[ "${value}" == "false" ]]; then
value=""
fi
echo "${value}"
}
is_app_enabled() {
local app_id="${1:-}"
local app_list_file=""
if [[ -z "${app_id}" ]]; then
return 1
fi
app_list_file="$(mktemp)"
if ! compose_cmd exec -T --user www-data app php occ app:list >"${app_list_file}" 2>/dev/null; then
rm -f "${app_list_file}" >/dev/null 2>&1 || true
return 1
fi
if grep -qE "^[[:space:]]+- ${app_id}([[:space:]:]|$)" "${app_list_file}"; then
rm -f "${app_list_file}" >/dev/null 2>&1 || true
return 0
fi
rm -f "${app_list_file}" >/dev/null 2>&1 || true
return 1
}
libresign_default_cn() {
local cn=""
local domain=""
cn="$(read_env_value "LIBRESIGN_CERT_CN" "")"
if [[ -n "${cn}" ]]; then
echo "${cn}"
return 0
fi
domain="$(read_env_value "NEXTCLOUD_DOMAIN" "")"
if [[ -z "${domain}" ]]; then
domain="$(read_env_value "NEXTCLOUD_TRUSTED_DOMAINS" "")"
domain="${domain%%,*}"
domain="${domain%% *}"
fi
if [[ -n "${domain}" ]]; then
echo "NuQloud ${domain} Root CA"
return 0
fi
echo "NuQloud Root CA"
}
ensure_libresign_setup() {
local auto_setup_raw=""
local auto_setup="1"
local auto_install_raw=""
local auto_install="1"
local java_path=""
local jsignpdf_path=""
local pdftk_path=""
local root_cert=""
local engine=""
local cn=""
local org=""
local country=""
local state=""
local locality=""
local ou_raw=""
local status_local=0
local occ_args=()
local ou_value=""
if ! is_app_enabled "libresign"; then
return 0
fi
auto_setup_raw="$(read_env_value "LIBRESIGN_AUTO_SETUP" "1")"
auto_setup="$(normalize_bool_01 "${auto_setup_raw}")"
if [[ -z "${auto_setup}" ]]; then
auto_setup="1"
fi
auto_install_raw="$(read_env_value "LIBRESIGN_AUTO_INSTALL_BINARIES" "1")"
auto_install="$(normalize_bool_01 "${auto_install_raw}")"
if [[ -z "${auto_install}" ]]; then
auto_install="1"
fi
java_path="$(occ_app_get "libresign" "java_path")"
jsignpdf_path="$(occ_app_get "libresign" "jsignpdf_jar_path")"
pdftk_path="$(occ_app_get "libresign" "pdftk_path")"
root_cert="$(occ_app_get "libresign" "rootCert")"
if [[ "${auto_install}" == "1" && -z "${java_path}" ]]; then
if ! compose_cmd exec -T --user www-data app php occ libresign:install --java >/dev/null 2>&1; then
echo "Warning: could not install LibreSign Java runtime."
status_local=1
fi
java_path="$(occ_app_get "libresign" "java_path")"
fi
if [[ "${auto_install}" == "1" && -z "${jsignpdf_path}" ]]; then
if ! compose_cmd exec -T --user www-data app php occ libresign:install --jsignpdf >/dev/null 2>&1; then
echo "Warning: could not install LibreSign JSignPdf runtime."
status_local=1
fi
jsignpdf_path="$(occ_app_get "libresign" "jsignpdf_jar_path")"
fi
if [[ "${auto_install}" == "1" && -z "${pdftk_path}" ]]; then
if ! compose_cmd exec -T --user www-data app php occ libresign:install --pdftk >/dev/null 2>&1; then
echo "Warning: could not install LibreSign PDFtk runtime."
status_local=1
fi
pdftk_path="$(occ_app_get "libresign" "pdftk_path")"
fi
if [[ "${auto_setup}" == "1" && -z "${root_cert}" ]]; then
engine="$(echo "$(read_env_value "LIBRESIGN_CERT_ENGINE" "openssl")" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')"
if [[ "${engine}" != "cfssl" ]]; then
engine="openssl"
fi
cn="$(libresign_default_cn)"
org="$(read_env_value "LIBRESIGN_CERT_O" "$(read_env_value "NUQLOUD_BILLING_COMPANY_NAME" "NuQloud")")"
country="$(read_env_value "LIBRESIGN_CERT_C" "")"
state="$(read_env_value "LIBRESIGN_CERT_ST" "")"
locality="$(read_env_value "LIBRESIGN_CERT_L" "")"
ou_raw="$(read_env_value "LIBRESIGN_CERT_OU" "Document Signing")"
occ_args=("libresign:configure:${engine}" "--cn=${cn}")
if [[ -n "${org}" ]]; then
occ_args+=("--o=${org}")
fi
if [[ -n "${country}" ]]; then
occ_args+=("--c=${country}")
fi
if [[ -n "${state}" ]]; then
occ_args+=("--st=${state}")
fi
if [[ -n "${locality}" ]]; then
occ_args+=("--l=${locality}")
fi
IFS=',;' read -r -a ou_values <<< "${ou_raw}"
for ou_value in "${ou_values[@]}"; do
ou_value="$(echo "${ou_value}" | xargs)"
if [[ -n "${ou_value}" ]]; then
occ_args+=("--ou=${ou_value}")
fi
done
if ! compose_cmd exec -T --user www-data app php occ "${occ_args[@]}" >/dev/null 2>&1; then
echo "Warning: could not configure LibreSign root certificate."
status_local=1
fi
root_cert="$(occ_app_get "libresign" "rootCert")"
fi
if [[ "${auto_install}" == "1" ]]; then
if [[ -z "${java_path}" || -z "${jsignpdf_path}" || -z "${pdftk_path}" ]]; then
status_local=1
fi
fi
if [[ "${auto_setup}" == "1" && -z "${root_cert}" ]]; then
status_local=1
fi
return "${status_local}"
}
while [[ $# -gt 0 ]]; do
case "$1" in
--compose-file)
compose_file="${2:-}"
shift 2
;;
--compose-file=*)
compose_file="${1#*=}"
shift
;;
--env-file)
env_file="${2:-}"
shift 2
;;
--env-file=*)
env_file="${1#*=}"
shift
;;
--skip-indices)
skip_indices="1"
shift
;;
--skip-bundle)
skip_bundle="1"
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1"
usage
exit 1
;;
esac
done
if [[ "${compose_file}" != /* ]]; then
compose_file="${repo_root}/${compose_file}"
fi
if [[ "${env_file}" != /* ]]; then
env_file="${repo_root}/${env_file}"
fi
if [[ ! -f "${compose_file}" ]]; then
echo "Missing compose file: ${compose_file}"
exit 1
fi
if [[ ! -f "${env_file}" ]]; then
echo "Missing env file: ${env_file}"
exit 1
fi
export_compose_project_name_from_env "${env_file}" || true
ensure_docker_access
bundle_enabled_raw="$(read_env_value "INSTALL_DEFAULT_APP_BUNDLE" "$(read_env_value "INSTALL_DEFAULT_NEXTCLOUD_APP_BUNDLE" "0")")"
bundle_enabled="$(normalize_bool_01 "${bundle_enabled_raw}")"
if [[ -z "${bundle_enabled}" ]]; then
bundle_enabled="0"
fi
default_app_bundle="$(trim_csv "$(read_env_value "NEXTCLOUD_DEFAULT_APP_BUNDLE" "notify_push,user_oidc,activity,announcementcenter,calendar,collectives,systemtags,comments,contacts,deck,external,files_accesscontrol,libresign,mail,notes,passwords,circles,groupfolders")")"
default_app_order="$(trim_csv "$(read_env_value "NEXTCLOUD_DEFAULT_APP_ORDER" "dashboard,files,calendar,mail,deck,contacts,notes,collectives")")"
status=0
if [[ "${skip_bundle}" != "1" && "${bundle_enabled}" == "1" && -n "${default_app_bundle}" ]]; then
IFS=',' read -r -a app_ids <<< "${default_app_bundle}"
for raw_app_id in "${app_ids[@]}"; do
app_id="$(echo "${raw_app_id}" | xargs)"
if [[ -z "${app_id}" ]]; then
continue
fi
if ensure_app_enabled "${app_id}"; then
continue
fi
echo "Warning: could not install/enable Nextcloud app bundle item '${app_id}'."
status=1
done
if [[ -n "${default_app_order}" ]]; then
if ! compose_cmd exec -T --user www-data app php occ config:system:set defaultapp --value="${default_app_order}" >/dev/null 2>&1; then
echo "Warning: could not set Nextcloud defaultapp order to '${default_app_order}'."
status=1
fi
fi
if ! ensure_libresign_setup; then
status=1
fi
fi
if [[ "${skip_indices}" != "1" ]]; then
if ! compose_cmd exec -T --user www-data app php occ db:add-missing-indices >/dev/null 2>&1; then
echo "Warning: occ db:add-missing-indices did not complete successfully."
status=1
fi
fi
exit "${status}"