#!/usr/bin/env bash
#
#   Copyright © 2021,2022 IsardVDI S.L.
#
#   This file is part of DD
#
#   DD is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or (at your
#   option) any later version.
#
#   DD is distributed in the hope that it will be useful, but WITHOUT ANY
#   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
#   FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
#   details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with DD. If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later

OPERATION="$1"
shift

# We need docker-compose >= 1.28 to catch configuration variables
REQUIRED_DOCKER_COMPOSE_VERSION="1.28"

docker_compose_version(){
	docker-compose --version --short | sed 's/^docker-compose version \([^,]\+\),.*$/\1/'
}

check_docker_compose_version(){
	# We cannot use sort -C because is not included in BusyBox v1.33.1 of docker:dind image
	{
		echo "$REQUIRED_DOCKER_COMPOSE_VERSION"
		docker_compose_version
	} | sort -c -V 2> /dev/null
}

get_os(){
	if grep -q ^DISTRIB_ID=Ubuntu /etc/lsb-release 2>/dev/null; then
	   echo ubuntu
	elif [ -f /etc/debian_version ]; then
	   echo debian
	fi
}

help() {
	cat <<-EOF
	 Example: ./dd.ctl [operation] [arguments]

	  For a new installation, you usually will want to run:
	    ./dd-ctl prerequisites
	    ./dd-ctl securize
	    ./dd-ctl all
	    ./dd-ctl saml


	              Generate adminer.yml to access DBs: ./dd-ctl adminer
	                    Bring the current project up: ./dd-ctl all
	              Branding (custom/img, custom/menu): ./dd-ctl branding
	                         Build the compose files: ./dd-ctl build
	                   Build the devel compose files: ./dd-ctl build-devel
	                            Apply customizations: ./dd-ctl customize
	                   Stop the project when started: ./dd-ctl down
   Show external files in repo, their license and source: ./dd-ctl listpatches
Generate .orig and .patch files to compare with upstream: ./dd-ctl genpatches
	                   Rescan nextcloud data folders: ./dd-ctl nextcloud-scan
	      Install all prerequisites for installation: ./dd-ctl prerequisites
	                     Update DD to latest version: ./dd-ctl update [branch-name] (defaults to main)
	    Restart api if changes applied (development): ./dd-ctl restart-api
	                        Update SAML certificates: ./dd-ctl saml
	                 Set secure passwords in dd.conf: ./dd-ctl securize
	                Set a config variable in dd.conf: ./dd-ctl setconf VARIABLE [VALUE]
	                  Start the project when stopped: ./dd-ctl up
	                                 Upgrade plugins: ./dd-ctl upgrade-plugins
	         Regenerate docker-compose.yml from conf: ./dd-ctl yml
	EOF
}

# Help messages
if [ -z "$OPERATION" ] || [ "$OPERATION" = "-h" ] || [ "$OPERATION" = "--help" ]; then
	test -n "$OPERATION" || printf "Missing command.\n\n"
	help
	exit
fi

# Sanity checks
if [ -z "$(get_os)" ]; then
	cat >&2 <<-EOF
	*****************************************************************
	Your OS doesn't seem to be Debian or Ubuntu and is not supported!
	Things might still work, please report back.
	*****************************************************************
	EOF
fi
if [ "$OPERATION" != "prerequisites" ]; then
	if [ ! -d "custom" ]; then
		echo "You need to copy custom.sample to custom folder and adapt it to your needs." >&2
		exit 1
	fi
	if [ ! -f "dd.conf" ]; then
		echo "You need to copy dd.conf.sample to dd.conf and adapt" >&2
		exit 1
	fi
	if ! check_docker_compose_version; then
		echo "ERROR: Please use docker-compose greather than or equal to $REQUIRED_DOCKER_COMPOSE_VERSION." >&2
		exit 1
	fi
fi

REPO_BRANCH="${1:-main}"


CUSTOM_PATH=$(pwd)
if [ -f dd.conf ]; then
	cp dd.conf .env
	. ./.env
fi

prerequisites_docker(){
	# Remove uncompatible docker packages
	for pkg in docker docker-engine docker.io containerd runc; do
		if dpkg -s "${pkg}" >/dev/null; then
			apt-get remove -y "${pkg}"
		fi
	done

	# Install upstream-docker repo pre-requisites
	apt-get install -y \
		apt-transport-https \
		ca-certificates \
		curl \
		gnupg-agent \
		software-properties-common \
		git \
		unzip \
		libffi-dev

	os="$(get_os)"
	curl -fsSL "https://download.docker.com/linux/${os:?}/gpg" | \
		apt-key add -
	add-apt-repository \
		"deb [arch=amd64] https://download.docker.com/linux/${os:?} \
		 $(lsb_release -cs) \
		stable"
	apt-get update -y
	# docker-ce must be used instead of the one from the distro
	apt-get install -y docker-ce docker-ce-cli containerd.io

	apt-get install -y python3-pip
	# docker-compose > 1.28 is required, latest will be installed
	pip3 install docker-compose
}
prerequisites_pwd(){
	apt-get install -y dictionaries-common wamerican
}

ddupdate(){
	# Bring down services
	./dd-ctl down
	# Switch to latest version
	git fetch && git checkout "$REPO_BRANCH"
	git pull --rebase --autostash
	# Needed for dd-apps submodules...
	git submodule update --init --recursive
	case "${1}" in
		--full)
			# Rebuild containers
			./dd-ctl build
			# Upgrade plugins
			./dd-ctl upgrade-plugins
			# Reapply customisations if needed
			./dd-ctl customize
		;;
	esac
}

build_compose(){
	DD_DEFAULT_BUILD="$(git rev-parse --short=8 HEAD)"
	export DD_BUILD="${DD_BUILD:-${DD_DEFAULT_BUILD}}"
	setconf DD_BUILD "${DD_BUILD}" .env

	setconf CUSTOM_PATH "$CUSTOM_PATH" .env

	setconf BUILD_APPS_ROOT_PATH "$CUSTOM_PATH/dd-apps" .env
	setconf BUILD_SSO_ROOT_PATH "$CUSTOM_PATH/dd-sso" .env

	# SMTP (needed for e.g. Nextcloud's more granular settings)
	SMTP_LOCAL_PART="$(echo "${SMTP_USER:-}" | cut -d '@' -f 1)"
	export SMTP_LOCAL_PART
	SMTP_DOMAIN="$(echo "${SMTP_USER:-}" | cut -d '@' -f 2)"
	export SMTP_DOMAIN
	setconf SMTP_LOCAL_PART "${SMTP_LOCAL_PART}" .env
	setconf SMTP_DOMAIN "${SMTP_DOMAIN}" .env

	# Choose HAProxy configuration flavour
	if [ "${PROXY_PROTOCOL:-false}" = "true" ]; then
		HAPROXY_YML="haproxy.proxy.yml"
		HAPROXY_PROXY="proxy"
	else
		# Default
		HAPROXY_YML="haproxy.yml"
		HAPROXY_PROXY="no-proxy"
	fi
	# Enable or disable WAF
	if [ "${DISABLE_WAF:-true}" = "true" ]; then
		# Current default (might change)
		WAF_YML="waf-modsecurity.disabled.yml"
		HAPROXY_WAF="no-waf"
	else
		WAF_YML="waf-modsecurity.yml"
		HAPROXY_WAF="waf"
	fi

	# Persist resulting HAProxy config
	export HAPROXY_CFG="haproxy.${HAPROXY_WAF}.${HAPROXY_PROXY}.cfg"
	setconf HAPROXY_CFG "${HAPROXY_CFG}"
	setconf HAPROXY_CFG "${HAPROXY_CFG}" .env

	# Enable or disable ClamAV's container
	if [ "${DISABLE_CLAMAV:-true}" = "true" ]; then
		# Current default (might change)
		CLAMAV_YML="clamav.disabled.yml"
	else
		CLAMAV_YML="clamav.yml"
	fi

	# Clean up redundant .env files
	for f in	dd-apps \
			dd-apps/docker/postgresql dd-apps/docker/mariadb \
			dd-apps/docker/moodle dd-apps/docker/nextcloud \
			dd-apps/docker/wordpress dd-apps/docker/etherpad \
			dd-sso dd-sso/docker-compose-parts; do
		if [ -f "${f}/.env" ]; then
			rm "${f}/.env"
		fi
	done

	# Clean up older custom data
	rm -rf custom/system/keycloak-themes
	rmdir custom/system 2>/dev/null || true

	# Build compose ymls
	docker-compose \
			--env-file "${CUSTOM_PATH}/.env" \
					\
			-f "dd-sso/docker-compose-parts/$WAF_YML" \
			-f "dd-sso/docker-compose-parts/$HAPROXY_YML"\
			-f dd-sso/docker-compose-parts/api.yml \
			-f dd-sso/docker-compose-parts/keycloak.yml \
			-f dd-sso/docker-compose-parts/avatars.yml \
			-f dd-sso/docker-compose-parts/admin.yml \
					\
			-f dd-apps/docker/moodle/moodle.yml \
			-f dd-apps/docker/nextcloud/nextcloud.yml \
			-f dd-apps/docker/wordpress/wordpress.yml \
			-f dd-apps/docker/etherpad/etherpad.yml \
			-f dd-apps/docker/onlyoffice/onlyoffice.yml \
			-f dd-apps/docker/redis/redis.yml \
			-f dd-apps/docker/postgresql/postgresql.yml \
			-f dd-apps/docker/mariadb/mariadb.yml \
			-f "dd-apps/docker/clamav/${CLAMAV_YML}" \
			-f dd-apps/docker/network.yml \
			config > docker-compose.yml
}

listpatches(){
	cat <<-EOM
	# Generate .orig and .patch files with ./dd-ctl genpatches
	# file	license	author	url
	EOM
	# shellcheck disable=SC2044  # TODO: Get rid of this for X in find
	for patchfile in $(find . -name 'dd-patch'); do
		patchdir="$(dirname "${patchfile}")"
		grep -vE '^#' "${patchfile}" | awk "{print \"${patchdir}/\" \$0}"
	done
}

genpatches(){
	CD="$(pwd)"
	# shellcheck disable=SC2044  # TODO: Get rid of this for X in find
	for patchfile in $(find . -name 'dd-patch'); do
		# shellcheck disable=SC2164  # We got the dir from find
		cd "$(dirname "${patchfile}")"
		echo "IN DIR $(pwd)"
		grep -vE '^#' dd-patch | while IFS= read -r line; do
			fn="$(echo "${line}" | cut -f 1)"
			url="$(echo "${line}" | cut -f 4)"
			wget "${url}" -O "${fn}.orig"
			diff "${fn}.orig" "${fn}" > "${fn}.patch"
		done
		# shellcheck disable=SC2164  # This was previous working dir
		cd "${CD}"
	done
}

build(){
	build_compose
	docker-compose pull --ignore-pull-failures --include-deps
	docker-compose build
}

build_compose_develop(){
	build_compose

	## Prepare sso environment
	setconf CUSTOM_PATH "$CUSTOM_PATH" .env
	setconf BUILD_SSO_ROOT_PATH "$CUSTOM_PATH/dd-sso" .env

	ln -sf "${CUSTOM_PATH}/.env" dd-sso/.env
	ln -sf "${CUSTOM_PATH}/.env" dd-sso/docker-compose-parts/.env

	docker-compose	-f docker-compose.yml \
			-f dd-sso/docker-compose-parts/api.devel.yml \
			-f dd-sso/docker-compose-parts/admin.devel.yml \
			config > devel.yml
}

up(){
	docker-compose up -d
}

down(){
	docker-compose down
}

nextcloud_scan(){
	# The folders shown as 'not writeable' are empty user folders. Not a problem.
	docker exec -u www-data dd-apps-nextcloud-app php occ files:scan --all
}

setup_moodle(){
	echo " --> Applying custom settings in moodle"
	# TODO: check why admin/cli/cfg can't be read with -u nobody
	docker exec -i dd-apps-moodle sh -s <<-EOF
	php7 admin/cli/cfg.php --name=guestloginbutton --set=0
	php7 admin/cli/cfg.php --name=enrol_plugins_enabled --set=manual
	php7 admin/cli/cfg.php --name=enablemobilewebservice --set=0
	php7 admin/cli/cfg.php --name=enablebadges --set=0
	php7 admin/cli/cfg.php --name=timezone --set="${MOODLE_TIMEZONE-Europe/Madrid}"
	php7 admin/cli/cfg.php --name=cookiehttponly --set=1
	# Add operator custom CSS
	php7 admin/cli/cfg.php --component=theme_cbe --name=scss \
		--set="\$(cat <<-eof
		$(sed -E "s/DOMAIN/${DOMAIN}/g" custom/css/custom.css 2>/dev/null || true)
		eof
		)"
	php7 admin/cli/purge_caches.php
	EOF
}

setup_wordpress(){
	echo " --> Applying custom settings in wordpress"
	chown -R 33:33 "${DATA_FOLDER}/wordpress"
	docker exec -i --user=33 dd-apps-wordpress sh -s <<-EOF
	wp core install --path="/var/www/html" \
		--url=wp.${DOMAIN} --title="${TITLE}" \
		--admin_user=${WORDPRESS_ADMIN_USER} \
		--admin_password=${WORDPRESS_ADMIN_PASSWORD} \
		--admin_email=${SMTP_USER}
	wp core multisite-convert

	wp plugin activate onelogin-saml-sso
	wp plugin install generateblocks --activate
	wp plugin activate generateblocks --network

	wp theme install generatepress --activate
	wp theme enable generatepress --network
	wp theme delete twentynineteen
	wp theme delete twentytwenty
	wp theme delete twentytwentyone

	wp option set WPLANG ca
	wp option set date_format "d/m/Y"
	EOF
}

setup_keycloak(){
	echo " --> Setting up SAML: Keycloak realm and client_scopes"
	docker exec -i dd-sso-admin sh -s <<-EOF
	export PYTHONWARNINGS='ignore:Unverified HTTPS request'
	cd /admin/saml_scripts/ && python3 keycloak_config.py
	EOF
}

saml_generate_certificates(){
	saml_dir="${DATA_FOLDER}/saml"
	mkdir -p "${saml_dir}/public"

	# Moodle generates its own certificate earlier, only NC and Wp
	for saml_info in nextcloud:82 wordpress:33; do
		saml_sp="$(echo "${saml_info}" | cut -d ':' -f 1)"
		sp_uid="$(echo "${saml_info}" | cut -d ':' -f 2)"
		sp_dir="${saml_dir}/${saml_sp}"
		mkdir -p "${sp_dir}"
		C=CA
		L=Barcelona
		O=localdomain
		CN_CA=$O
		# Generate certificate
		echo " --> Generating SAML certificates for SP: ${saml_sp}"
		openssl req -nodes -new -x509 \
			-keyout "${sp_dir}/private.key" \
			-out "${sp_dir}/public.crt" \
			-subj "/C=$C/L=$L/O=$O/CN=$CN_CA" -days 3650
		# Fix permissions
		chown -R "${sp_uid}:${sp_uid}" "${sp_dir}"
		chmod 0550 "${sp_dir}"
		# Propagate public part
		cp "${sp_dir}/public.crt" "${saml_dir}/public/${saml_sp}.crt"
	done
	# TODO: Rework wordpress_saml.py so we can get rid of this
	cp "${saml_dir}/wordpress/private.key" "${saml_dir}/public/wordpress.key"

	chmod 0555 "${saml_dir}/public"
	find "${saml_dir}/public" -type f -exec chmod 0444 '{}' '+'
}

saml_register_sps_with_idp(){
	wait_for_moodle

	# Setup SAML for each SP
	for saml_sp in moodle nextcloud wordpress email; do
		echo " --> Registering SAML SP '${saml_sp}' in IDP"
		docker exec -i dd-sso-admin sh -s <<-EOF
		export PYTHONWARNINGS='ignore:Unverified HTTPS request'
		cd /admin/saml_scripts/ && python3 ${saml_sp}_saml.py
		EOF
		test $? == 0 || printf "\tError setting up SAML for %s...\n" "${saml_sp}" >&2
	done

	# Purge cache for moodle
	docker exec -i dd-apps-moodle php7 admin/cli/purge_caches.php
}

saml_setup_idp_in_sps(){
	# We need to support this for newer Nextcloud versions
	saml_info="dd-apps-nextcloud-app:82"
	saml_sp="$(echo "${saml_info}" | cut -d ':' -f 1)"
	sp_uid="$(echo "${saml_info}" | cut -d ':' -f 2)"
	echo " --> Setting up SAML IDP in ${saml_sp}"
	docker exec -i -u "${sp_uid}" "${saml_sp}" /saml.sh
}

saml(){
	if [ "${1:-}" != "--no-up" ]; then
		up
		wait_for_moodle
	fi
	# Ensure realm is OK and write public IDP cert
	setup_keycloak
	# Make sure each SP has its own certs and fix permissions if needed
	saml_generate_certificates
	# Register all SPs with the IDP
	saml_register_sps_with_idp
	# Setup IDP in each SP
	saml_setup_idp_in_sps
}

wait_for_moodle(){
	echo "Waiting for system to be fully up before customizing... It can take some minutes..."
	echo " (you can monitorize install with: docker logs dd-apps-moodle --follow"
	# This previously waited for the container to be 'healthy',
	# but that was not what is actually required here, which is:
	#  - Is moodle installed?
	#  - Is the web service up?
	# That is now checked in /is_moodle_ready.sh
	while ! docker exec dd-apps-moodle /is_moodle_ready.sh; do
		sleep 2;
	done
}

upgrade_moodle(){
	docker exec -i dd-apps-moodle php7 admin/cli/maintenance.php --enable
	docker exec -i dd-apps-moodle php7 admin/cli/upgrade.php --non-interactive --allow-unstable
	docker exec -i dd-apps-moodle php7 admin/cli/maintenance.php --disable
}

extras_adminer(){
	docker-compose 	-f dd-apps/docker/network.yml \
					-f dd-sso/docker-compose-parts/adminer.yml config > adminer.yml
	echo " --> Generated adminer.yml"
	echo "     Bring it up: docker-compose -f adminer.yml up -d"
	echo "     Connect to: https://sso.$DOMAIN/dd-sso-adminer/"
	echo "     Parameters:"
	echo "       - System: PostgreSQL (or Mysql for wordpress db)"
	echo "         Server: dd-apps-postgresql (or dd-apps-mariadb for wordpress db)"
	echo "         User/Pass/Database from dd.conf"
}

extras_pgtuner(){
	docker-compose  -f dd-apps/docker/network.yml \
					-f dd-sso/docker-compose-parts/pgtuner.yml config > pgtuner.yml
	echo " --> Generated pgtuner.yml"
}

extras_dump_keycloak_client(){
	docker exec -i dd-sso-keycloak sh -s <<-EOF
	/opt/jboss/keycloak/bin/kcadm.sh config credentials --server http://localhost:8080/auth --realm master --user admin --password keycloakkeycloak \
	&& /opt/jboss/keycloak/bin/kcadm.sh get clients/bef873f0-2079-4876-8657-067de27d01b7 -r master
	EOF
}
upgrade_plugins_moodle(){
	wait_for_moodle
	rm -rf /tmp/moodle

	mkdir -p /tmp/moodle/mod
	mkdir -p /tmp/moodle/mod/assign/submission
	mkdir -p /tmp/moodle/auth/saml2
	mkdir -p /tmp/moodle/theme/cbe
	mkdir -p /tmp/moodle/blocks
	mkdir -p /tmp/moodle/lib/editor/atto/plugins/tipnc

	curl --location "${MOODLE_PLUGIN_JITSI_OVERRIDE:-https://moodle.org/plugins/download.php/27002/mod_jitsi_moodle40_2022070602.zip}" > jitsi.zip
	unzip -q jitsi.zip -d /tmp/moodle/mod/
	rm jitsi.zip
	
	curl --location "${MOODLE_PLUGIN_BBB_OVERRIDE:-https://moodle.org/plugins/download.php/26792/mod_bigbluebuttonbn_moodle311_2019101014.zip}" > bbb.zip
	unzip -q bbb.zip -d /tmp/moodle/mod/
	rm bbb.zip
	
	# curl --location https://github.com/isard-vdi/moodle-auth_saml2/archive/refs/heads/role_map.zip > auth_saml2.zip
	# curl --location https://moodle.org/plugins/download.php/24556/auth_saml2_moodle311_2021062900.zip > auth_saml2.zip
	curl --location "${MOODLE_PLUGIN_SAML_OVERRIDE:-https://github.com/isard-vdi/moodle-auth_saml2/archive/refs/heads/role_map.zip}" > auth_saml2.zip
	unzip -q auth_saml2.zip -d /tmp/moodle/auth/
	mv /tmp/moodle/auth/moodle-auth_saml2-role_map/* /tmp/moodle/auth/saml2/
	rm -rf /tmp/moodle/auth/moodle-auth_saml2-role_map
	rm auth_saml2.zip
	M3IPSHARE="https://github.com/3iPunt/moodle_mod_tresipuntshare/archive/refs/heads/master.zip"

	if [[ "${MOODLE_PLUGIN_TRESIPUNTSHARE_OVERRIDE:-${M3IPSHARE}}" == *"develop"* ]]; then
		PLUGIN_BRANCH=develop
	else
		PLUGIN_BRANCH=master
	fi
	curl --location "${MOODLE_PLUGIN_TRESIPUNTSHARE_OVERRIDE:-${M3IPSHARE}}" > tresipuntshare.zip
	unzip -q tresipuntshare.zip -d /tmp/moodle/mod/
	mv /tmp/moodle/mod/moodle_mod_tresipuntshare-$PLUGIN_BRANCH /tmp/moodle/mod/tresipuntshare
	rm tresipuntshare.zip
	M3IPVIDEO="https://github.com/3iPunt/moodle_mod_tresipuntvideo/archive/refs/heads/master.zip"

	if [[ "${MOODLE_PLUGIN_TRESIPUNTVIDEO_OVERRIDE:-${M3IPVIDEO}}" == *"develop"* ]]; then
		PLUGIN_BRANCH=develop
	else
		PLUGIN_BRANCH=master
	fi
	curl --location "${MOODLE_PLUGIN_TRESIPUNTVIDEO_OVERRIDE:-${M3IPVIDEO}}" > tresipuntvideo.zip
	unzip -q tresipuntvideo.zip -d /tmp/moodle/mod/
	mv /tmp/moodle/mod/moodle_mod_tresipuntvideo-$PLUGIN_BRANCH /tmp/moodle/mod/tresipuntvideo
	rm tresipuntvideo.zip
	M3IPAUDIO="https://github.com/3iPunt/moodle_mod_tresipuntaudio/archive/refs/heads/master.zip"

	if [[ "${MOODLE_PLUGIN_TRESIPUNTAUDIO_OVERRIDE:-${M3IPAUDIO}}" == *"develop"* ]]; then
		PLUGIN_BRANCH=develop
	else
		PLUGIN_BRANCH=master
	fi
	curl --location "${MOODLE_PLUGIN_TRESIPUNTAUDIO_OVERRIDE:-${M3IPAUDIO}}" > tresipuntaudio.zip
	unzip -q tresipuntaudio.zip -d /tmp/moodle/mod/
	mv /tmp/moodle/mod/moodle_mod_tresipuntaudio-$PLUGIN_BRANCH /tmp/moodle/mod/tresipuntaudio
	rm tresipuntaudio.zip
	M3IPSUBMISSION="https://github.com/3iPunt/moodle_assignsubmission_tipnc/archive/refs/heads/master.zip"

	if [[ "${MOODLE_PLUGIN_ASSIGNSUBMISSION_OVERRIDE:-${M3IPSUBMISSION}}" == *"develop"* ]]; then
		PLUGIN_BRANCH=develop
	else
		PLUGIN_BRANCH=master
	fi
	curl --location "${MOODLE_PLUGIN_ASSIGNSUBMISSION_OVERRIDE:-${M3IPSUBMISSION}}" > assignsubmission_tipnc.zip
	unzip -q assignsubmission_tipnc.zip -d /tmp/moodle/mod/assign/submission/
	mv /tmp/moodle/mod/assign/submission/moodle_assignsubmission_tipnc-$PLUGIN_BRANCH /tmp/moodle/mod/assign/submission/tipnc
	rm assignsubmission_tipnc.zip
	M3IPSPEND="https://github.com/3iPunt/moodle_block_tresipuntmodspend/archive/refs/heads/master.zip"

	curl --location "${MOODLE_PLUGIN_TRESIPUNTMODSPEND_OVERRIDE:-${M3IPSPEND}}" > block_tresipuntmodspend.zip
	unzip -q block_tresipuntmodspend.zip -d /tmp/moodle/blocks/
	rm block_tresipuntmodspend.zip
	M3IPCBE="https://github.com/3iPunt/moodle_theme_cbe/archive/refs/heads/master.zip"

	if [[ "${MOODLE_THEME_CBE_OVERRIDE:-${M3IPCBE}}" == *"develop"* ]]; then
		PLUGIN_BRANCH=develop
	else
		PLUGIN_BRANCH=master
	fi
	curl --location "${MOODLE_THEME_CBE_OVERRIDE:-${M3IPCBE}}" > tresipunt_theme_cbe.zip
	unzip -q tresipunt_theme_cbe.zip -d /tmp/moodle/theme/cbe/
	mv /tmp/moodle/theme/cbe/moodle_theme_cbe-$PLUGIN_BRANCH/* /tmp/moodle/theme/cbe/
	rm tresipunt_theme_cbe.zip

	# mod_tipnextcloud
	M3IPTN="https://github.com/3iPunt/mod_tipnextcloud/archive/refs/heads/master.zip"
	if [[ "${MOODLE_MOD_TN_OVERRIDE:-${M3IPTN}}" == *"develop"* ]]; then
		PLUGIN_BRANCH=develop
	else
		PLUGIN_BRANCH=master
	fi
	
	curl --location "${MOODLE_MOD_TN_OVERRIDE:-${M3IPTN}}" > tresipunt_mod_tn.zip
	unzip -q tresipunt_mod_tn.zip -d /tmp/moodle/mod/tipnextcloud/
	mv /tmp/moodle/mod/tipnextcloud/mod_tipnextcloud-$PLUGIN_BRANCH/* /tmp/moodle/mod/tipnextcloud/
	rm tresipunt_mod_tn.zip


	# atto_tipnc https://github.com/3iPunt/atto_tipnc
	M3ATTOTIPTN="https://github.com/3iPunt/atto_tipnc/archive/refs/heads/master.zip"
	if [[ "${MOODLE_ATTOTIPTN_OVERRIDE:-${M3ATTOTIPTN}}" == *"develop"* ]]; then
		PLUGIN_BRANCH=develop
	else
		PLUGIN_BRANCH=master
	fi

	curl --location "${MOODLE_ATTOTIPTN_OVERRIDE:-https://github.com/3iPunt/atto_tipnc/archive/refs/heads/master.zip}" > tresipunt_atto_tipnc.zip
	unzip -q tresipunt_atto_tipnc.zip -d /tmp/moodle/lib/editor/atto/plugins/tipnc/
	mv /tmp/moodle/lib/editor/atto/plugins/tipnc/atto_tipnc-$PLUGIN_BRANCH/* /tmp/moodle/lib/editor/atto/plugins/tipnc/
	rm tresipunt_atto_tipnc.zip
	
	# local_mail
	curl --location "${MOODLE_PLUGIN_MAIL_OVERRIDE:-https://moodle.org/plugins/download.php/26393/local_mail_moodle40_2017121407.zip}" > mail.zip
	unzip -q mail.zip -d /tmp/moodle/local/
	rm mail.zip
	#mkdir -p /tmp/moodle/local/tresipuntimportgc
	#cp -R local_plugins/moodle/tresipuntimportgc/* /tmp/moodle/local/tresipuntimportgc/

	curl --location https://github.com/danmarsden/moodle-mod_attendance/archive/refs/heads/MOODLE_311_STABLE.zip > mod_attendance.zip
    unzip -q mod_attendance.zip -d /tmp/moodle/mod/
    mv /tmp/moodle/mod/moodle-mod_attendance-MOODLE_311_STABLE /tmp/moodle/mod/attendance
    rm mod_attendance.zip

	curl --location https://github.com/projectestac/moodle-mod_geogebra/archive/refs/heads/MOODLE_39_STABLE.zip > mod_geogebra.zip
    unzip -q mod_geogebra.zip -d /tmp/moodle/mod/
    mv /tmp/moodle/mod/moodle-mod_geogebra-MOODLE_39_STABLE /tmp/moodle/mod/geogebra
    rm mod_geogebra.zip

	cp -R /tmp/moodle/* "$SRC_FOLDER/moodle/"
	rm -rf /tmp/moodle
	docker exec -i dd-apps-moodle php7 admin/cli/purge_caches.php
}

upgrade_plugins_wp(){
	cp -R dd-apps/docker/wordpress/src/* "$SRC_FOLDER/wordpress/"

	if [ ! -d "$SRC_FOLDER/wordpress/wp-content/mu-plugins" ]; then
		git clone https://gitlab.com/muplugins-multiste1/muplugins-google-sites.git "$SRC_FOLDER/wordpress/wp-content/mu-plugins"
	fi
	if [ ! -d "$SRC_FOLDER/wordpress/wp-content/mu-plugins/.git" ]; then
		echo "WARNING: $SRC_FOLDER/wordpress/wp-content/mu-plugins is not a git repository."
		echo "         This could be due to old installation. To bring all new mu-plugins code for WP"
		echo "         remove that folder and it will be cloned and mantained with git from now on."
	else
		sh -c "cd $SRC_FOLDER/wordpress/wp-content/mu-plugins; git pull"
	fi
	chown -R 33:33 "${SRC_FOLDER}/wordpress/wp-content/mu-plugins"
	# TODO: Fix this, check https://gitlab.com/DD-workspace/DD/-/issues/16
	##install plugin gsite
	docker exec -i dd-apps-wordpress sh -s <<-EOF
	apt-get update
	apt-get install -y git
	apt install -y zlib1g-dev libjpeg-dev libpng-dev
	apt-get install -y python3 python3-click python3-scrapy python3-unidecode python3-pillow python3-slugify
	apt-get install -y curl
	git clone https://gitlab.com/isard/gsite2wordpress
	mv /var/www/html/gsite2wordpress /var/www
	curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
	chmod +x wp-cli.phar
	mv wp-cli.phar /usr/local/bin/wp
	EOF
}

update_logos_and_menu(){
	docker exec -i --user root dd-sso-keycloak sh -c 'rm -rf /opt/jboss/keycloak/standalone/tmp/kc-gzip-cache/*'
	docker-compose build dd-sso-api && docker-compose up -d dd-sso-api
}

genpwd() {
	if [ ! -f /usr/share/dict/words ]; then
		prerequisites_pwd > /dev/null
	fi
	shuf -n3 /usr/share/dict/words | tr -d "\n" | tr -d "'"
}

securize() {
	for dd_var in \
			ADMINAPP_PASSWORD \
			DDADMIN_PASSWORD \
			KEYCLOAK_PASSWORD \
			KEYCLOAK_DB_PASSWORD \
			POSTGRES_PASSWORD \
			MARIADB_PASSWORD \
			MOODLE_POSTGRES_PASSWORD \
			MOODLE_ADMIN_PASSWORD \
			NEXTCLOUD_POSTGRES_PASSWORD \
			NEXTCLOUD_ADMIN_PASSWORD \
			ETHERPAD_POSTGRES_PASSWORD \
			ETHERPAD_ADMIN_PASSWORD \
			WORDPRESS_MARIADB_PASSWORD \
			WORDPRESS_ADMIN_PASSWORD; do
		setconf "${dd_var}" "$(genpwd)"
	done
	setconf "API_SECRET" "$(openssl rand -base64 32)"
}

setconf() {
	dd_var="$(echo "$1" | tr "[:lower:]" "[:upper:]")"
	dd_val="$2"
	dd_line="$(printf '%s="%s"' "${dd_var:?}" "${dd_val}")"
	conf_file="${3:-dd.conf}"
	if grep -qE "^${dd_var:?}=" "${conf_file}"; then
		# Found uncommented, replace in-place
		sed -i'' -E "s!^${dd_var:?}=.*\$!${dd_line}!" "${conf_file}"
	elif grep -qE "^#[[:space:]]*${dd_var:?}=" "${conf_file}"; then
		# Found commented, replace in-place
		sed -i'' -E "s!^#[[:space:]]*${dd_var:?}=.*\$!${dd_line}!" "${conf_file}"
	else
		# Not found, append
		echo "${dd_line}" >> "${conf_file}"
	fi
}

special_image_tags() {
	# Special image tags that apply to this build
	head="$(git rev-parse HEAD)"
	# loop through BRANCH:TAG1[:TAG2:...:TAG_N] items
	for tag_info in develop:latest main:stable; do
		branch="$(echo "${tag_info}" | cut -d ':' -f 1)"
		upstream="$(git rev-parse "${DD_REMOTE:-origin}/${branch}" 2>/dev/null || true)"
		if [ "${head}" = "${upstream}" ]; then
			# If head and upstream match, use these tags
			special_tags="$(echo "${tag_info}" | cut -d ':' -f 2- | tr ':' ' ')"
			echo "${special_tags}"
		fi
	done
}

push_images() {
	#
	# Note this requires docker login on the registry
	# (Runs on CI)
	#
	# Get images that are using the registry
	images="$(docker ps --format '{{ .Names }}\t{{ .Image }}' | grep "${DD_REGISTRY:-registry.dd-work.space}")"
	for extra_tag in $(special_image_tags); do
		# And apply the special tags on them
		for image in $(echo "${images}" | cut -f 2); do
			docker tag "${image}" "${image%:*}:${extra_tag}"
		done
	done
	image_names="$(echo "${images}" | cut -f 1 | tr '\n' '\t')"
	# Finally, actually push all tags to the registry
	# shellcheck disable=SC2086  # We do want multiple arguments
	docker-compose push ${image_names:?}
}

# Argument handling
case "$OPERATION" in
	build)
		build
	;;
	build-devel)
		build_compose_develop
	;;
	adminer)
		extras_adminer
	;;
	all)
		build
		up

		wait_for_moodle
		upgrade_plugins_moodle
		upgrade_plugins_wp

		setup_moodle
		setup_wordpress

		saml --no-up

		cat <<-EOF

		 #### After install ####
		 - SSO in moodle should be active. You can go to: https://moodle.$DOMAIN
		   If it fails, regenerate and lock certificate in moodle SAML2 connector as a local admin.
		   After that run ./dd-ctl saml
		 - SSO in nextcloud should be active. You can go to: https://nextcloud.$DOMAIN
		 - SSO in wordpress should be active. You should go to https://wp.$DOMAIN/wp-admin//plugins.php

		 #### Update customizations ####
		 - ./dd-ctl customize
		EOF
	;;
	branding)
		up
		wait_for_moodle
		update_logos_and_menu
	;;
	customize)
		up
		wait_for_moodle
		setup_wordpress
		setup_moodle
	;;
	down)
		down
	;;
	nextcloud-scan)
		nextcloud_scan
	;;
	pgtuner)
		extras_pgtuner
	;;
	prerequisites)
		prerequisites_docker
		prerequisites_pwd
	;;
	update)
		ddupdate --full
	;;
	repo-update)
		ddupdate
	;;
	reset-data|reset-1714)
		cat <<-EOF
		# Following commands RESET ALL DATA except for certificates
		# execute them only if you know what you are doing
		# This *will* result in DATA LOSS
		 "$0" down
		 rm -rf /opt/DD/data/*
		 rm -rf /opt/DD/db/*
		 rm -rf '$SRC_FOLDER/avatars'
		 rm -rf '$SRC_FOLDER/moodle'
		 rm -rf '$SRC_FOLDER/nextcloud'
		 rm -rf '$SRC_FOLDER/wordpress'
		EOF
	;;
	restart-api)
		up
		wait_for_moodle
		docker restart dd-sso-api
	;;
	saml)
		saml "$@"
	;;
	securize)
		securize
	;;
	setconf)
		setconf "$@"
	;;
	up)
		up
	;;
	upgrade-plugins)
		up
		wait_for_moodle
		upgrade_plugins_moodle
		upgrade_plugins_wp
	;;
	yml)
		cp dd.conf .env
		CUSTOM_PATH=$(pwd)
		. ./.env
		build_compose
	;;
	listpatches)
		listpatches
	;;
	push-images)
		push_images
	;;
	failing-containers)
		fc="$(docker ps --format '{{.Names}}' -f 'health=unhealthy')"
		if [ -n "${fc}" ]; then
			cat >&2  <<-EOF
			Failing containers:
			${fc}
			EOF
			exit 1
		fi
	;;
	genpatches)
		genpatches
	;;
	*)
		printf "Unknown command '%s'\n\n" "$OPERATION" >&2
		help >&2
		exit 1
	;;
esac
