#!/bin/bash
# Script de manipulation d'un cloud'
# init /versions / restart ...
#

KAZ_ROOT=$(cd "$(dirname $0)"/..; pwd)
. $KAZ_ROOT/bin/.commonFunctions.sh
setKazVars
. $DOCKERS_ENV

#GLOBAL VARS
PRG=$(basename $0)

availableOrga=($(getList "${KAZ_CONF_DIR}/container-orga.list"))
AVAILABLE_ORGAS=${availableOrga[*]//-orga/}

# CLOUD
APPLIS_PAR_DEFAUT="tasks calendar contacts bookmarks mail richdocuments external drawio ransomware_protection" #rainloop richdocumentscode 
QUIET="1"
ONNAS=

CLOUDCOMMUN="OUI_PAR_DEFAUT"
DockerServName=${nextcloudServName}

usage() {
echo "${PRG} [OPTION] [COMMANDES] [ORGA]
Manipulation d'un cloud

OPTIONS 
 -h|--help          Cette aide :-)
 -n|--simu          SIMULATION
 -q|--quiet         On ne parle pas (utile avec le -n pour avoir que les commandes)
 --nas              L'orga se trouve sur le NAS !
 
COMMANDES (on peut en mettre plusieurs dans l'ordre souhaité)
 -I|--install       L'initialisation du cloud
 -v|--version       Donne la version du cloud et signale les MàJ

 --optim            Lance la procédure Nextcloud pour optimiser les performances          **               **
 -occ \"command\"     Envoie une commande via occ                                           **               **
 -u                 Mets à jour les applis                                                **  SPECIFIQUES  **
 -i                 Install des applis                                                    **      CLOUD    **
 -a \"app1 app2 ...\"  Choix des appli à installer ou mettre à jour (entre guillemets)      **               **
 -U|--upgrade       Upgrade des clouds                                                    **               **
 -O|--officeURL      MAJ le office de ce nextcloud                                         **               **

ORGA                parmi : ${AVAILABLE_ORGAS}
                    ou vide si cloud commun
"
}


##################################
############### CLOUD ############
##################################

Init(){
    NOM=$ORGA
    [ -n "${CLOUDCOMMUN}" ] && NOM="commun"
    if [ -z "${LISTE_APPS}" ]; then
        printKazMsg "Aucune appli n'est précisée, j'installerais les applis par défaut : ${APPLIS_PAR_DEFAUT}" >& $QUIET
        LISTE_APPS="${APPLIS_PAR_DEFAUT}"
    fi

    checkDockerRunning "$DockerServName" "$NOM" 
    [ $? -ne 0 ] && echo "${CYAN}\n  $DockerServName est down : impossible de terminer l'install${NC}" && return 1 >& $QUIET

    CONF_FILE="${DOCK_VOL}/orga_${ORGA}-cloudConfig/_data/config.php"
    CLOUD_URL="https://${ORGA}-${cloudHost}.${domain}"
    if [ -n "$CLOUDCOMMUN" ]; then 
        CONF_FILE="${DOCK_VOL}/cloud-cloudConfig/_data/config.php"
        CLOUD_URL="https://${cloudHost}.${domain}"
    elif [ -n "${ONNAS}" ]; then 
        CONF_FILE="${NAS_VOL}/orga_${ORGA}-cloudConfig/_data/config.php"
    fi

    firstInstall "$CLOUD_URL" "$CONF_FILE" "$NOM"
    updatePhpConf "$CONF_FILE"
    InstallApplis
    echo "${CYAN}  *** Paramétrage richdocuments pour $ORGA${NC}" >& $QUIET
    setOfficeUrl
    occCommand "config:app:set --value 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 richdocuments wopi_allowlist"
    occCommand "config:system:set overwrite.cli.url --value=$CLOUD_URL"
    occCommand "config:system:set disable_certificate_verification --value=true"

    if [ -n "$CLOUDCOMMUN" ]; then initLdap "$NOM" ; fi
}

Version(){
    VERSION=$(docker exec -u 33 ${DockerServName} /var/www/html/occ status | grep -i version:) 
    VERSION_UPDATE=$(docker exec -u 33 ${DockerServName} /var/www/html/occ update:check | grep -i "available\." | cut -c 1-17)
    versionSTR="Version ${DockerServName} : ${GREEN}${VERSION}${NC}"
    [ -n "${VERSION_UPDATE}" ] && versionSTR="$versionSTR   --   Disponible : ${RED} ${VERSION_UPDATE} ${NC}"
    echo "$versionSTR"
}

firstInstall(){
    # $1 CLOUD_URL
    # $2 phpConfFile
    # $3 orga
    if ! grep -q "'installed' => true," "$2" 2> /dev/null; then

        printKazMsg "\n  *** Premier lancement nextcloud $3" >& $QUIET
        _getPasswords

        ${SIMU} waitUrl "$1"

        ${SIMU} curl -X POST \
            -d "install=true" \
            -d "adminlogin=${NEXTCLOUD_ADMIN_USER}" \
            -d "adminpass=${NEXTCLOUD_ADMIN_PASSWORD}" \
            -d "directory=/var/www/html/data" \
            -d "dbtype=mysql" \
            -d "dbuser=${MYSQL_USER}" \
            -d "dbpass=${MYSQL_PASSWORD}" \
            -d "dbname=${MYSQL_DATABASE}" \
            -d "dbhost=${MYSQL_HOST}" \
            -d "install-recommended-apps=true" \
            "$1"
    fi
}

_getPasswords(){
    if [ -n "$CLOUDCOMMUN" ]; then 
        . $KAZ_KEY_DIR/env-nextcloudServ
        . $KAZ_KEY_DIR/env-nextcloudDB
    else
        . $KAZ_KEY_DIR/orgas/$ORGA/env-nextcloudServ
        . $KAZ_KEY_DIR/orgas/$ORGA/env-nextcloudDB
    fi
}


setOfficeUrl(){
    # Did le 25 mars les offices sont tous normalisé sur les serveurs https://${site}-${officeHost}.${domain}
    #OFFICE_URL="https://${officeHost}.${domain}"
    #if [ ! "${site}" = "prod1" ]; then
    OFFICE_URL="https://${site}-${officeHost}.${domain}"
    #fi 
    occCommand "config:app:set --value $OFFICE_URL richdocuments public_wopi_url"
    occCommand "config:app:set --value $OFFICE_URL richdocuments wopi_url"
    occCommand "config:app:set --value $OFFICE_URL richdocuments disable_certificate_verification"
}

initLdap(){
    . $KAZ_KEY_DIR/env-ldapServ
    # $1 Nom du cloud
    echo "${CYAN}  *** Installation LDAP pour $1${NC}" >& $QUIET
    occCommand "app:enable user_ldap" "${DockerServName}"
    occCommand "ldap:delete-config s01" "${DockerServName}"
    occCommand "ldap:create-empty-config" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapAgentName cn=cloud,ou=applications,${ldap_root}" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapAgentPassword ${LDAP_CLOUD_PASSWORD}" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapBase ${ldap_root}" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapBaseGroups ${ldap_root}" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapBaseUsers ou=users,${ldap_root}" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapExpertUsernameAttr identifiantKaz" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapHost ${ldapServName}" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapPort 389" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapTLS 0" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapLoginFilter \"(&(objectclass=nextcloudAccount)(|(cn=%uid)(identifiantKaz=%uid)))\"" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapQuotaAttribute nextcloudQuota" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapUserFilter \"(&(objectclass=nextcloudAccount)(nextcloudEnabled=TRUE))\"" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapUserFilterObjectclass nextcloudAccount" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapEmailAttribute mail" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapUserDisplayName cn" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapUserFilterMode 1" "${DockerServName}"
    occCommand "ldap:set-config s01 ldapConfigurationActive 1" "${DockerServName}"

    # Dans le mariadb, pour permettre au ldap de reprendre la main : delete from oc_users where uid<>'admin';
    # docker exec -i nextcloudDB mysql --user=<user> --password=<password> <db> <<< "delete from oc_users where uid<>'admin';"

    # Doc : https://help.nextcloud.com/t/migration-to-ldap-keeping-users-and-data/13205

    # Exemple de table/clés :
    # +-------------------------------+----------------------------------------------------------+
    # | Configuration                 | s01                                                      |
    # +-------------------------------+----------------------------------------------------------+
    # | hasMemberOfFilterSupport      | 0                                                        |
    # | homeFolderNamingRule          |                                                          |
    # | lastJpegPhotoLookup           | 0                                                        |
    # | ldapAgentName                 | cn=cloud,ou=applications,dc=kaz,dc=sns                   |
    # | ldapAgentPassword             | ***                                                      |
    # | ldapAttributesForGroupSearch  |                                                          |
    # | ldapAttributesForUserSearch   |                                                          |
    # | ldapBackgroundHost            |                                                          |
    # | ldapBackgroundPort            |                                                          |
    # | ldapBackupHost                |                                                          |
    # | ldapBackupPort                |                                                          |
    # | ldapBase                      | ou=users,dc=kaz,dc=sns                                   |
    # | ldapBaseGroups                | ou=users,dc=kaz,dc=sns                                   |
    # | ldapBaseUsers                 | ou=users,dc=kaz,dc=sns                                   |
    # | ldapCacheTTL                  | 600                                                      |
    # | ldapConfigurationActive       | 1                                                        |
    # | ldapConnectionTimeout         | 15                                                       |
    # | ldapDefaultPPolicyDN          |                                                          |
    # | ldapDynamicGroupMemberURL     |                                                          |
    # | ldapEmailAttribute            | mail                                                     |
    # | ldapExperiencedAdmin          | 0                                                        |
    # | ldapExpertUUIDGroupAttr       |                                                          |
    # | ldapExpertUUIDUserAttr        |                                                          |
    # | ldapExpertUsernameAttr        | uid                                                      |
    # | ldapExtStorageHomeAttribute   |                                                          |
    # | ldapGidNumber                 | gidNumber                                                |
    # | ldapGroupDisplayName          | cn                                                       |
    # | ldapGroupFilter               |                                                          |
    # | ldapGroupFilterGroups         |                                                          |
    # | ldapGroupFilterMode           | 0                                                        |
    # | ldapGroupFilterObjectclass    |                                                          |
    # | ldapGroupMemberAssocAttr      |                                                          |
    # | ldapHost                      | ldap                                                     |
    # | ldapIgnoreNamingRules         |                                                          |
    # | ldapLoginFilter               | (&(|(objectclass=nextcloudAccount))(cn=%uid))            |
    # | ldapLoginFilterAttributes     |                                                          |
    # | ldapLoginFilterEmail          | 0                                                        |
    # | ldapLoginFilterMode           | 0                                                        |
    # | ldapLoginFilterUsername       | 1                                                        |
    # | ldapMatchingRuleInChainState  | unknown                                                  |
    # | ldapNestedGroups              | 0                                                        |
    # | ldapOverrideMainServer        |                                                          |
    # | ldapPagingSize                | 500                                                      |
    # | ldapPort                      | 389                                                      |
    # | ldapQuotaAttribute            | nextcloudQuota                                           |
    # | ldapQuotaDefault              |                                                          |
    # | ldapTLS                       | 0                                                        |
    # | ldapUserAvatarRule            | default                                                  |
    # | ldapUserDisplayName           | cn                                                       |
    # | ldapUserDisplayName2          |                                                          |
    # | ldapUserFilter                | (&(objectclass=nextcloudAccount)(nextcloudEnabled=TRUE)) |
    # | ldapUserFilterGroups          |                                                          |
    # | ldapUserFilterMode            | 1                                                        |
    # | ldapUserFilterObjectclass     | nextcloudAccount                                         |
    # | ldapUuidGroupAttribute        | auto                                                     |
    # | ldapUuidUserAttribute         | auto                                                     |
    # | turnOffCertCheck              | 0                                                        |
    # | turnOnPasswordChange          | 0                                                        |
    # | useMemberOfToDetectMembership | 1                                                        |
    # +-------------------------------+----------------------------------------------------------+
}

updatePhpConf(){
    # $1 php_conf_file
    if [ $# -ne 1 ]; then
        echo "${RED}#Je ne sais pas ou écrire la conf php !${NC}"
        return 1
    fi

    echo "${CYAN}  *** Maj de la conf $1${NC}" >& $QUIET
    PHPCONF="$1"
    _addVarAfterInConf "default_language" " 'default_language' => 'fr'," "CONFIG = array (" "${PHPCONF}"
    _addVarAfterInConf "theme" " 'theme' => ''," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "default_phone_region" " 'default_phone_region' => 'FR'," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "loglevel" " 'loglevel' => 2," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "maintenance" " 'maintenance' => false," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "app_install_overwrite" " 'app_install_overwrite' => \n  array (\n    0 => 'documents',\n  )," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "overwriteprotocol" " 'overwriteprotocol' => 'https'," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "mail_domain" " 'mail_domain' => '${domain}'," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "mail_from_address" " 'mail_from_address' => 'admin'," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "mail_smtpport" " 'mail_smtpport' => '25'," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "mail_sendmailmode" " 'mail_sendmailmode' => 'smtp'," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "mail_smtphost" " 'mail_smtphost' => '${smtpHost}.${domain}'," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "mail_smtpmode" " 'mail_smtpmode' => 'smtp'," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "enable_previews" " 'enable_previews' => true," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "trashbin_retention_obligation" " 'trashbin_retention_obligation' => 'auto, 30'," "'installed' => true," "${PHPCONF}"
    #pour supprimer le message "obtenir un compte gratuit" dans le footer
    _addVarAfterInConf "simpleSignUpLink.shown" " 'simpleSignUpLink.shown' => false," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "trusted_proxies" " 'trusted_proxies' => array( 0 => '10.0.0.0/8', 1 => '172.16.0.0/12', 2 => '192.168.0.0/16' )," "'installed' => true," "${PHPCONF}"
    _addVarAfterInConf "maintenance_window_start" " 'maintenance_window_start' => 1," "'installed' => true," "${PHPCONF}"
}

UpgradeClouds() {
    echo "${NC}--------------------------------------------------------" >& $QUIET
    echo "UPGRADE des cloud" >& $QUIET
    echo "--------------------------------------------------------" >& $QUIET
    occCommand "upgrade"
}

OptimiseClouds() {
    occCommand "db:add-missing-indices" "db:convert-filecache-bigint --no-interaction"
}


UpdateApplis() {
    printKazMsg "UPDATE DES APPLIS du cloud ${DockerServName} : ${LISTE_APPS}" >& $QUIET
    if [ -z "${LISTE_APPS}" ]; then
        occCommand "app:update --all"
        return
    fi
    echo "Mise à jour de ${LISTE_APPS}" >& $QUIET
    for app in ${LISTE_APPS}
    do
        occCommand "app:update ${app}"
    done
}

InstallApplis(){
    if [ -z "${LISTE_APPS}" ]; then
        printKazMsg "Aucune appli n'est précisée, j'installe les applis par défaut : ${APPLIS_PAR_DEFAUT}" >& $QUIET
        LISTE_APPS="${APPLIS_PAR_DEFAUT}"
    fi
    apps=$LISTE_APPS

    if ! [[ "$(docker ps -f name=${DockerServName} | grep -w ${DockerServName})" ]]; then
        printKazError "${RED}# ${DockerServName} not running... impossible d'installer les applis${NC}" >& $QUIET
        return 1
    fi
    LIST_ALL=$(docker exec -ti -u 33 "${DockerServName}" /var/www/html/occ app:list |
            awk 'BEGIN     {cp=0}
            /Enabled:/   {cp=1 ; next};
            /Disabled:/  {cp=0; next};
            {if (cp) print $0};')

    for app in $apps
    do
        grep -wq "${app}" <<<"${LIST_ALL}" 2>/dev/null && echo "${app} dejà installée" >& $QUIET && continue
        echo "  install ${app}" >& $QUIET
        occCommand "app:install ${app}"
    done
}

occCommand(){
    # $1 Command
    ${SIMU} docker exec -u 33 $DockerServName /var/www/html/occ $1
}

_addVarAfterInConf(){
    # $1 key
    # $2 val
    # $3 where
    # $4 confFile
    if ! grep -q "$1" "${4}" ; then
    echo -n " ${CYAN}${BOLD}$1${NC}" >& $QUIET
    ${SIMU} sed -i -e "/$3/a\ $2" "$4"
    fi
}

########## Main #################
for ARG in "$@"; do
    if [ -n "${GETOCCCOMAND}" ]; then # après un -occ
        OCCCOMAND="${ARG}"
        GETOCCCOMAND=
    elif [ -n  "${GETAPPS}" ]; then  # après un -a
        LISTE_APPS="${LISTE_APPS} ${ARG}"
        GETAPPS=""
    else 
        case "${ARG}" in
            '-h' | '--help' )
            usage && exit ;;
            '-n' | '--simu')
            SIMU="echo" ;;
            '-q' )
            QUIET="/dev/null" ;;
            '--nas' | '-nas' )
            ONNAS="SURNAS" ;; 
            '-v' | '--version')
            COMMANDS="$(echo "${COMMANDS} VERSION" | sed "s/\s/\n/g" | sort | uniq)" ;; 
            '-I' | '--install' )
            COMMANDS="$(echo "${COMMANDS} INIT" | sed "s/\s/\n/g" | sort | uniq)" ;; # le sed sort uniq, c'est pour pas l'avoir en double
            '-U' | '--upgrade')
            COMMANDS="$(echo "${COMMANDS} UPGRADE" | sed "s/\s/\n/g" | sort | uniq)" ;;
            '-O' | '--officeURL')
            COMMANDS="$(echo "${COMMANDS} OFFICEURL" | sed "s/\s/\n/g" | sort | uniq)" ;; 
            '--optim' | '-optim' )
            COMMANDS="$(echo "${COMMANDS} OPTIMISE-CLOUD" | sed "s/\s/\n/g" | sort | uniq)" ;;
            '-u' )
            COMMANDS="$(echo "${COMMANDS} UPDATE-CLOUD-APP" | sed "s/\s/\n/g" | sort | uniq)" ;;
            '-i' )
            COMMANDS="$(echo "${COMMANDS} INSTALL-CLOUD-APP" | sed "s/\s/\n/g" | sort | uniq)" ;;
            '-a' )
            GETAPPS="now" ;;
            '--occ' | '-occ' )
            COMMANDS="$(echo "${COMMANDS} RUN-CLOUD-OCC" | sed "s/\s/\n/g" | sort | uniq)"
            GETOCCCOMAND="now" ;;
            '-*' ) # ignore
            ;; 
            *)
            ORGA="${ARG%-orga}"
            DockerServName="${ORGA}-${nextcloudServName}"
            CLOUDCOMMUN=
            ;;
        esac
    fi
done

if [ -z "${COMMANDS}" ]; then 
    usage && exit 
fi

for COMMAND in ${COMMANDS}; do
    case "${COMMAND}" in
        'VERSION' )
         Version && exit ;;
        'OPTIMISE-CLOUD' )
         OptimiseClouds ;;
        'UPDATE-CLOUD-APP' )
         UpdateApplis ;;
        'UPGRADE' )
         UpgradeClouds ;;
        'INIT' )
         Init ;;
        'INSTALL-CLOUD-APP' )
         InstallApplis ;;
        'OFFICEURL' )
         setOfficeUrl ;;
        'RUN-CLOUD-OCC' )
         occCommand "${OCCCOMAND}";;
    esac
done
