#!/bin/bash
#
# metadata_begin
# recipe: Nextcloud
# tags: centos7,alma,rocky,oracle,fedora,debian10,debian11,debian12,ubuntu1804,ubuntu2004,ubuntu2204,ubuntu2204,alma_arm,rocky_arm,oracle_arm,ubuntu2004_arm,ubuntu2204_arm,debian10_arm,debian11_arm
# revision: 1
# description_ru: Рецепт установки Nextcloud
# description_en: Nextcloud installing recipe
# metadata_end
#

RNAME="Nextcloud"

set -x

LOG_PIPE=/tmp/log.pipe.$$
mkfifo ${LOG_PIPE}
LOG_FILE=/root/${RNAME}.log
touch ${LOG_FILE}
chmod 600 ${LOG_FILE}
tee < ${LOG_PIPE} ${LOG_FILE} &
exec > ${LOG_PIPE}
exec 2> ${LOG_PIPE}

killjobs() {
    test -n "$(jobs -p)" && kill $(jobs -p) || :
}
trap killjobs INT TERM EXIT

echo
echo "== Recipe ${RNAME} started at $(date) =="
echo

# Переменные
TN="directory"
NC_DIST="https://download.nextcloud.com/server/releases/latest-26.tar.bz2"
NC_DIR="/var/www/nextcloud"

# Пароли
# Пользователь и пароль панели
admUser="admin"
admPass=($ADMPASS)
# Если пароль пользователя Nextcloud не задан здесь, он буде сгенерирован в функцие config_nextcloud()

# Пароль пользователя root MySQL
mypwddb=""
#mypwddb=($MYSQLPASS)
# Если административный пароль MySQL не задан здесь, он буде сгенерирован в функцие config_mariadb()

# Пароль базы данных Nextcloud
mysqlNextcloudDB=""
#mysqlNextcloudDB=($NCDBPASS)
# Если пароль базы Nextcloud не задан здесь, он буде сгенерирован в функцие config_mariadb()

# Определение IP-адресов и сетевой карты
ipv4Addr=$(ip route get 1 | grep -Po '(?<=src )[^ ]+')

# Информация об ОС
. /etc/os-release
osLike="${ID_LIKE}"
[ "${ID}" = "debian" ] && osLike="debian"
echo ${ID_LIKE} | grep -q "rhel\|fedora" && osLike="rhel"
[ "${ID}" = "fedora" ] && osLike="rhel"
unaID=$(echo ${VERSION_ID} | sed -r 's/\..+//')

# Определение конфигурации демона Apache2
[ "${osLike}" = "debian" ] && { webServer="apache2" ; webServerSiteDir="/etc/apache2/sites-available/" ; }
[ "${osLike}" = "rhel" ] && { webServer="httpd" ; webServerSiteDir="/etc/httpd/conf.d/" ; }
[ -z "${webServer}" ] && exit 1
[ -z "${webServerSiteDir}" ] && exit 1
[ "${osLike}" = "debian" ] && webUser="www-data"
[ "${osLike}" = "rhel" ] && webUser="apache"
[ -z "${webUser}" ] && exit 1

# Определение имени демона и конфигурации Redis
[ "${osLike}" = "debian" ] && { redisServer="redis-server" ; redisSock="/run/redis/${redisServer}.sock" ; }
[ "${osLike}" = "rhel" ] && { redisServer="redis" ; redisSock="/var/run/redis/${redisServer}.sock" ; }
[ -z "${redisServer}" ] && exit 1
[ -z "${redisSock}" ] && exit 1
redisConf="/etc/redis/redis.conf"
([ "${osLike}" = "rhel" ] && [ ${unaID} -eq 7 -o ${unaID} -eq 8 ]) && redisConf="/etc/redis.conf"
[ -z "${redisConf}" ] && exit 1

# Определение SELinux
[ "${osLike}" = "rhel" ] && [ $(sestatus | grep 'SELinux status' | grep -q 'enabled') ] && selinux_enabled=yes

# Определение пакетного менеджера
DNF="/usr/bin/yum"
[ -f /usr/bin/dnf ] && DNF="/usr/bin/dnf"
[ -f /usr/bin/apt ] && { export DEBIAN_FRONTEND=noninteractive ; DNF="apt_Installer" ; }
[ -n "${DNF}" ] || exit 1

# Настройка /root/.my.cnf
RootMyCnf() {
touch /root/.my.cnf
chmod 600 /root/.my.cnf
echo "[client]" > /root/.my.cnf
echo "user=root" >> /root/.my.cnf
echo "password=${1}" >> /root/.my.cnf
}

# Финальный текст
final_text() {
cat > /root/${RNAME}-script-final.txt <<- EOF
=========================
Работа скрипта ${RNAME} успешно завершена.
Пароль MariaDB находится в файле /root/.my.cnf.
Пароль пользователя ${admUser} - ${admPass}
Журнал выполнения вы можете посмотреть в файле /root/${RNAME}.log
Внимание! В /root/${RNAME}.log может находиться пароль MariaDB в открытом виде, удалите его немедленно.
Панель ${RNAME} доступна по адресам:
http://${ipv4Addr}/
=========================

=========================
The ${RNAME} script completed successfully.
The MariaDB password is located in the /root/.my.cnf file.
The ${admUser} password - ${admPass}
You can see the execution log in /root/${RNAME}.log.
Attention! The /root/${RNAME}.log may contain the MariaDB password in clear text, remove it immediately.
The ${RNAME} panel is available at:
http://${ipv4Addr}/
=========================
EOF
}

# Определяем инсталятор apt и его опции. Обходим фоновые задачи установки и одновления ОС
apt_Installer() {
while ps uxaww | grep -v grep | grep -Eq 'apt|dpkg|unattended' ; do echo "waiting..." ; sleep 5 ; done && \
/usr/bin/apt -o Dpkg::Options::="--force-confold" -o Dpkg::Options::="--force-confdef" -q 	--allow-downgrades --allow-remove-essential --allow-change-held-packages $@
}

# Установка основных программ и подготовка базовых репозиториев
install_soft() {
if [ "${osLike}" = "debian" ]; then
	[ $(systemctl is-active unattended-upgrades.service 2>/dev/null) = "active" ] && { systemctl stop unattended-upgrades.service && unattServ="0" ; }
	${DNF} update && ${DNF} -y install lsb-release ca-certificates debian-archive-keyring gnupg2
fi
if [ "${osLike}" = "rhel" -a "${ID}" != "ol" -a "${ID}" != "fedora" ]; then
	${DNF} -y install epel-release elrepo-release
fi
if [ "${osLike}" = "rhel" -a "${ID}" = "ol" ]; then
	sed -i 's/oracle.com/hoztnode.net/' /etc/yum/vars/ocidomain
	${DNF} -y install oracle-epel-release-el${unaID}
fi
[ "${osLike}" = "rhel" ] && \
case ${unaID} in
"7")
	${DNF} -y install policycoreutils-python
	;;
*)
	${DNF} -y install policycoreutils-python-utils 
	${DNF} -y update libmodulemd
esac
${DNF} -y install bzip2 tar sudo pwgen curl
${DNF} -y install tuned
systemctl enable --now tuned 2>/dev/null
}

# Преднастройка ОС
config_system() {
[ "${osLike}" = "debian" -a ${VERSION_ID} -eq 10 ] && \
echo $(hostname -I | cut -d\  -f1) $(hostname) | tee -a /etc/hosts
}

# Настройка SELinux
config_selinux() {
semanage fcontext -a -t httpd_sys_rw_content_t "$1/data(/.*)?"
semanage fcontext -a -t httpd_sys_rw_content_t "$1/config(/.*)?"
semanage fcontext -a -t httpd_sys_rw_content_t "$1/apps(/.*)?"
semanage fcontext -a -t httpd_sys_rw_content_t "$1/.htaccess"
semanage fcontext -a -t httpd_sys_rw_content_t "$1/.user.ini"
semanage fcontext -a -t httpd_sys_rw_content_t "$1/3rdparty/aws/aws-sdk-php/src/data/logs(/.*)?"
restorecon -R $1
setsebool -P httpd_can_network_connect on
#setsebool httpd_unified on
setsebool -P httpd_unified on
}

# Определение и настройка фаервола
config_firewall() {
if [ -f /usr/sbin/ufw ] && $(ufw status | grep -i "Status" | grep -qi " active\|enable"); then
	ufw allow http
	ufw allow https
	ufw allow ssh
fi
if [ -f /usr/sbin/firewalld -a $(systemctl is-active firewalld.service 2>/dev/null) = "active" ]; then
	firewalldZone="$(firewall-cmd --get-default-zone)"
	firewall-cmd --permanent --zone=${firewalldZone} --remove-service=dhcpv6-client 2>&1 >/dev/null || return 0
	firewall-cmd --permanent --zone=${firewalldZone} --add-service=http
	firewall-cmd --permanent --zone=${firewalldZone} --add-service=https
	firewall-cmd --reload
fi
}

# Установка MySQL
install_mariadb() {
if [ "${osLike}" = "rhel" -a ${unaID} -eq 7 ]; then
	cat > /etc/yum.repos.d/MariaDB.repo <<- 'EOF'
[mariadb]
name = MariaDB
baseurl = https://mirror.hoztnode.net/mariadb/yum/10.10/centos7-amd64
gpgkey=https://mirror.hoztnode.net/mariadb/yum/RPM-GPG-KEY-MariaDB
gpgcheck=1
EOF
	[ "$(uname -m)" = "aarch64" ] && sed -i 's/centos7-amd64/centos7-aarch64/' /etc/yum.repos.d/MariaDB.repo
	${DNF} -y install MariaDB-server MariaDB-client
	mkdir -p /etc/my.cnf.d/
	cat > /etc/my.cnf.d/idb.cnf <<- 'EOF'
[mysqld]
innodb_read_only_compressed=OFF
EOF
elif [ "${ID}" = "ubuntu" -a ${unaID} -eq 18 ]; then
	${DNF} -y install software-properties-common
	apt-key adv --fetch-keys https://mirror.hoztnode.net/mariadb/PublicKey_v2
	echo "deb [arch=amd64] http://mirror.hoztnode.net/mariadb/repo/10.10/ubuntu ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/mariadb.list
	${DNF} update
	${DNF} -y install mariadb-server mariadb-client
else
	${DNF} -y install mariadb-server
fi
systemctl enable --now mariadb.service
systemctl restart mariadb.service
}

# Установка Apache2
install_web() {
${DNF} -y install ${webServer}
systemctl enable --now ${webServer}.service
}

# Установка PHP
install_php() {
[ "${osLike}" = "debian" ] && \
case ${VERSION_ID} in
	"18.04" )
		${DNF} -y install software-properties-common
		add-apt-repository -y ppa:ondrej/php
		${DNF} update
		;;
	"20.04" )
		${DNF} -y install software-properties-common
		add-apt-repository -y ppa:ondrej/php
		${DNF} update
		;;
	"10" | "11" )
		${DNF} -y install -y apt-transport-https
		wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
		echo "deb https://packages.sury.org/php/ ${VERSION_CODENAME} main" | tee /etc/apt/sources.list.d/php.list
		${DNF} update
		;;
esac
[ "${osLike}" = "debian" ] && ${DNF} -y install $(${DNF} search libmagickcore-*-extra | grep "libmagickcore" | grep -v "hdri" | sed -r 's/\/.+//')
[ "${osLike}" = "rhel" ] && \
case ${unaID} in
	"8" )
		${DNF} -y install dnf-utils https://mirror.hoztnode.net/remi/enterprise/remi-release-8.rpm
		sed -i 's/rpms.remirepo.net/mirror.hoztnode.net\/remi/' /etc/yum.repos.d/remi*.repo
		sed -i 's/^mirrorlist/#mirrorlist/' /etc/yum.repos.d/remi*.repo
		sed -i 's/^#baseurl/baseurl/' /etc/yum.repos.d/remi*.repo
		if [ "$(uname -m)" = "aarch64" ]; then
			${DNF} -y config-manager --set-disabled remi*
			${DNF} -y module list reset php
			${DNF} -y module enable php:8.0
		else
			${DNF} -y module list reset php
			${DNF} -y module enable php:remi-8.2
		fi
		;;
	"7" )
		${DNF} -y install yum-utils https://mirror.hoztnode.net/remi/enterprise/remi-release-7.rpm
		sed -i 's/rpms.remirepo.net/mirror.hoztnode.net\/remi/' /etc/yum.repos.d/remi*.repo
		sed -i 's/^mirrorlist/#mirrorlist/' /etc/yum.repos.d/remi*.repo
		sed -i 's/^#baseurl/baseurl/' /etc/yum.repos.d/remi*.repo
		yum-config-manager --disable remi-php* > /dev/null
		yum-config-manager --enable remi-php81 > /dev/null
		;;
esac
${DNF} -y install php php-gd php-curl php-mbstring php-intl php-gmp php-bcmath php-xml php-zip php-apcu php-bz2
${DNF} -y install php-imagick
[ "${osLike}" = "debian" ] && ${DNF} -y install php-mysql
[ "${osLike}" = "debian" -a ${unaID} != 11 ] && ${DNF} -y install php-mime-type
[ "${osLike}" = "rhel" ] && ${DNF} -y install php-mysqlnd php-opcache php-process
[ "${osLike}" = "rhel" ] && ${DNF} -y install php-sodium

# Узнаём версию php
PHP_VERSION=$(php -v | head -1 | cut -c5-7)
}

# Установка Redis
install_redis() {
${DNF} -y install ${redisServer}
${DNF} -y install php-redis
[ "$(uname -m)" = "aarch64" -a "${osLike}" = "rhel" -a ${unaID} -eq 8 ] && ${DNF} -y install http://repo.hoztnode.net/os/soft/RHEL/9/php-pecl-igbinary-3.2.14-1.el9.remi.8.0.aarch64.rpm http://repo.hoztnode.net/os/soft/RHEL/9/php-pecl-msgpack-2.1.2-4.el9.remi.8.0.aarch64.rpm http://repo.hoztnode.net/os/soft/RHEL/9/php-pecl-redis5-5.3.7-1.el9.remi.8.0.aarch64.rpm
systemctl enable --now ${redisServer}.service
}

# Установка Nextcloud
install_nextcloud() {
mkdir -p ${NC_DIR}
curl -s --connect-timeout 30 --retry 10 --retry-delay 5 -k -L -o - "${NC_DIST}" | tar -xj -C $(echo "${NC_DIR}" | sed 's/nextcloud//')
chown -R ${webUser}:${webUser} ${NC_DIR}
}

# Настройка MariaDB
config_mariadb() {
[ -z "${mypwddb}" -o "${mypwddb}" = "()" ] && local mypwddb="$(pwgen -s 32 1)"
[ ! -s /root/.my.cnf -a -z "$(echo "QUIT" | mysql -u root)" ] && case ${osLike} in
"rhel")
	/usr/bin/mysqladmin -u root password "${mypwddb}"
	RootMyCnf "${mypwddb}"
	echo "DELETE FROM user WHERE Password='';" | mysql --defaults-file=/root/.my.cnf -N mysql
	;;
"debian")
	/usr/bin/mysqladmin -u root password "${mypwddb}"
	RootMyCnf "${mypwddb}"
	echo "mariadb-server mariadb-server/root_password password ${mypwddb}" | debconf-set-selections
	echo "mariadb-server mariadb-server/root_password_again password ${mypwddb}" | debconf-set-selections
	systemctl restart mariadb.service
	;;
esac
systemctl restart mariadb.service
[ -z "${mysqlNextcloudDB}" -o "${mysqlNextcloudDB}" = "()" ] && mysqlNextcloudDB="$(pwgen -s 32 1)"
mysql --defaults-file=/root/.my.cnf -e "CREATE DATABASE IF NOT EXISTS nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci"
mysql --defaults-file=/root/.my.cnf -e "CREATE USER IF NOT EXISTS nextclouduser@localhost IDENTIFIED BY '${mysqlNextcloudDB}'"
mysql --defaults-file=/root/.my.cnf -e "ALTER USER 'nextclouduser'@'localhost' IDENTIFIED BY '${mysqlNextcloudDB}'"
mysql --defaults-file=/root/.my.cnf -e "GRANT ALL PRIVILEGES ON nextcloud.* TO nextclouduser@localhost IDENTIFIED BY '${mysqlNextcloudDB}'"
mysql --defaults-file=/root/.my.cnf -e "FLUSH PRIVILEGES"
}

# Настройка PHP
config_php() {
sed -i '/^memory_limit/cmemory_limit\ =\ 512M' $1
sed -i '/^;date.timezone/cdate.timezone' $1
sed -i '/^date.timezone/cdate.timezone\ =\ Europe\/Moscow' $1
sed -i '/^upload_max_filesize/cupload_max_filesize\ =\ 512M' $1
sed -i '/^upload_max_filesize/cupload_max_filesize\ =\ 4G' $1
sed -i '/^post_max_size/cpost_max_size\ =\ 4G' $1
sed -i '/^max_execution_time/cmax_execution_time\ =\ 300' $1
}

# Настройка PHP APCu
config_php_apcu() {
cp $1 $1.bak
cat > $1 <<- 'EOF'
extension=apcu.so
apc.enabled=1
apc.enable_cli=1
apc.mmap_file_mask=/tmp/apc.XXXXXX
EOF
}

# Настройка PHP Opcache
config_opcache() {
[ -f $1 ] && echo "opcache.interned_strings_buffer=32" >> $1
}

# Настройка Nextcloud Apache2
config_web_nextcloud() {
if [ "$TN" != "directory" ]; then
cat > $1 << EOF
<VirtualHost *:80>
  DocumentRoot ${NC_DIR}/
  ServerName ${SERVER_NAME}

  <Directory ${NC_DIR}/>
    Require all granted
    AllowOverride All
    Options FollowSymLinks MultiViews

    <IfModule mod_dav.c>
      Dav off
    </IfModule>
  </Directory>
</VirtualHost>
EOF
else
cat > $1 << EOF
Alias / "${NC_DIR}/"

<Directory ${NC_DIR}/>
  Require all granted
  AllowOverride All
  Options FollowSymLinks MultiViews

  <IfModule mod_dav.c>
    Dav off
  </IfModule>
</Directory>
EOF
fi
}

# Настрока Apache2
config_apache2() {
a2ensite nextcloud.conf
a2dissite 000-default.conf
a2enmod rewrite
a2enmod headers
a2enmod env
a2enmod dir
a2enmod mime
systemctl restart ${webServer}.service
}

# Настройка Redis
config_redis() {
sed -i "/#\ unixsocket\ /cunixsocket\ $redisSock" ${redisConf}
sed -i 's/#\ unixsocketperm\ 700/unixsocketperm\ 770/' ${redisConf}
usermod -a -G redis ${webUser}
systemctl restart ${redisServer}.service
}

# Настройка Nextcloud
config_nextcloud() {
cd ${NC_DIR}
[ -z "${admPass}" -o "${admPass}" = "()" ] && admPass="$(pwgen -s 32 1)"
sudo -u ${webUser} php occ maintenance:install --database \
"mysql" --database-name "nextcloud"  --database-user "nextclouduser" --database-pass \
"${mysqlNextcloudDB}" --admin-user "${admUser}" --admin-pass "${admPass}" || exit 1
sudo -u ${webUser} php occ config:system:set trusted_domains 0 --value=*
#sudo -u ${webUser} php occ config:system:set trusted_domains 0 --value=$HOSTNAME
#[ ${ipv4Addr} ] && sudo -u ${webUser} php occ config:system:set trusted_domains 1 --value=${ipv4Addr}
#[ ${ipv6Addr} ] && sudo -u ${webUser} php occ config:system:set trusted_domains 2 --value=${ipv6Addr}
#sudo -u ${webUser} php occ config:system:set default_phone_region --value=RU
sudo -u ${webUser} php occ config:system:set memcache.local --value='\OC\Memcache\APCu'
sudo -u ${webUser} php occ config:system:set memcache.locking --value='\OC\Memcache\Redis'
sudo -u ${webUser} php occ config:system:set memcache.distributed --value='\OC\Memcache\Redis'
sudo -u ${webUser} php occ config:system:set redis host --value=${redisSock}
sudo -u ${webUser} php occ config:system:set redis port --value=0
sudo -u ${webUser} php occ config:system:set redis dbindex --value=0
sudo -u ${webUser} php occ config:system:set redis timeout --value=1.5
sudo -u ${webUser} php occ background:cron
sudo -u ${webUser} php occ app:update --all
}

# Настрока планировщика Nextcloud
config_cron_nextcloud() {
cat > /etc/systemd/system/nextcloudcron.timer <<- 'EOF'
[Unit]
Description=Run Nextcloud cron.php every 5 minutes

[Timer]
OnBootSec=5min
OnUnitActiveSec=5min
Unit=nextcloudcron.service

[Install]
WantedBy=timers.target
EOF
cat > /etc/systemd/system/nextcloudcron.service <<- EOF
[Unit]
Description=Nextcloud cron.php job

[Service]
User=${webUser}
ExecStart=/usr/bin/php -f ${NC_DIR}/cron.php
KillMode=process
EOF
systemctl daemon-reload
systemctl enable --now nextcloudcron.timer
systemctl start nextcloudcron.service
}

install_soft
config_system
config_firewall
install_mariadb
install_web
install_php
install_redis
install_nextcloud
config_mariadb
config_redis
case ${osLike} in
	"rhel" )
		config_php /etc/php.ini
		config_php_apcu /etc/php.d/40-apcu.ini
		config_opcache /etc/php.d/10-opcache.ini
		config_web_nextcloud /etc/${webServer}/conf.d/nextcloud.conf
		systemctl restart ${webServer}.service
		[ "${osLike}" = "rhel" -a "${unaID}" != "7" ] && systemctl enable --now php-fpm.service
		[ "${selinux_enabled}" = "yes" ] && config_selinux ${NC_DIR}
		;;
	"debian" )
		config_php /etc/php/${PHP_VERSION}/apache2/php.ini
		config_php_apcu /etc/php/${PHP_VERSION}/mods-available/apcu.ini
		config_opcache /etc/php/${PHP_VERSION}/mods-available/opcache.ini
		config_web_nextcloud /etc/${webServer}/sites-available/nextcloud.conf
		config_apache2
		# Включаем обратно сервис самообновления Ubuntu
		[ -n "${unattServ}" ] && systemctl start unattended-upgrades.service
		;;
esac
config_nextcloud
config_cron_nextcloud

# Проверка
q=0
i=20
while [ $q -le $i ]; do
	curl -v --silent http://127.0.0.1/index.php/login 2>&1 | grep -q "Nextcloud" && final_text && exit 0
	q=$(($q + 1))
	sleep 2
done

exit 1