#! /bin/bash
# -*- coding: utf-8 -*-
#
# Copyright (C) SHS-AV s.r.l. (<http://ww.zeroincombenze.it>)
# This software is free software under GNU Affero GPL3
# Bash general purpose library
#
#__version__=2.0.4

detached_login() {
# detached_login([path] [path2] [path3])
    if [ $opt_cron -gt 0 -a "$SHELL" == "/bin/sh" ]; then
      if [ $opt_dry_run -eq 0 ]; then
        fqcmd=$(readlink -f $0)
        wlog "Run $fqcmd in cron mode"
        SHELL=/bin/bash exec "$fqcmd" "$@"
      fi
    elif [ $opt_cron -gt 0 -a -f $HOME/.bash_profile ]; then
      wlog "Simulate login ($HOME/.bash_profile)"
      . $HOME/.bash_profile
    fi
    if [[ ":$PATH:" =~ /usr/local/bin ]]; then
      :
    else
      export PATH=/usr/local/bin:$PATH
    fi
    if [ -n "$1" ]; then
      if [ -d $1 ]; then
        if [[ ":$PATH:" =~ $1 ]]; then
          :
        else
          export PATH=$PATH:$1
        fi
      fi
    fi
    if [ -n "$2" ]; then
      if [ -d $2 ]; then
        if [[ ":$PATH:" =~ $2 ]]; then
          :
        else
          export PATH=$PATH:$2
        fi
      fi
    fi
    if [ -n "$3" ]; then
      if [ -d $3 ]; then
        if [[ ":$PATH:" =~ $3 ]]; then
          :
        else
          export PATH=$PATH:$3
        fi
      fi
    fi
    wlog "PATH=$PATH"
}

conf_default() {
    local sfx XDB
    ACTION=$1
    CFG_set "bckformat" "0"
    CFG_set "dbfilter" ".*"
    CFG_set "test_db" "test"
    CFG_set "tar_ext" ".gz .bz2 .tar"
    CFG_set "tar_opt" ""
    CFG_set "pg_dump_opt" ""
    CFG_set "db_user" "odoo"
    CFG_set "set_original_user" "1"
    CFG_set "pg_user" "postgres:postgres"
    CFG_set "excl_list" ""
    local DBFA="zi[0-9]+"
    for sfx in A B C D E F G H; do
      x=DBF$sfx
      XDB=${!x}
      CFG_set "DB${sfx}_filter" "$XDB"
      CFG_set "DB${sfx}_keep_recent" "7"
      CFG_set "DB${sfx}_keep_monthly" "3"
    done
    CFG_set "wait_4_prod" "60"
    CFG_set "odoo_rpc_host" "localhost"
    CFG_set "odoo_rpc_protocol" "xmlrpc"
    CFG_set "odoo_rpc_xmlport" "8069"
    CFG_set "odoo_version" "12.0"
    CFG_set "odoo_rpc_pwd" "admin"
    if [ "$DEV_ENVIRONMENT" == "$THIS" ]; then
      test_mode=1
    fi
    if [ ${test_mode:-0} -ne 0 ]; then
      opt_dry_run=1
      CFG_set "bckdir" "res/backups"
    fi
    if [ -n "$opt_conf" -a -f "$opt_conf" ]; then
      FCONF=$opt_conf
    elif [ ${test_mode:-0} -ne 0 ]; then
      FCONF=$TESTDIR/zar.conf
    else
      FCONF=$TDIR/zar.conf
    fi
    if [ ${test_mode:-0} -ne 0 ]; then
      publog=$TESTDIR/$1.log
    elif [ -z "$opt_log" ]; then
      publog="/var/log/zar/$1.log"
    else
      publog=$opt_log
    fi
    if [ ${opt_verbose:-0} -gt 0 -o ${opt_dry_run:-0} -gt 0  ]; then
      set_tlog_file "$publog" "" "echo"
    else
      set_tlog_file "$publog"
    fi
}

init_vars() {
#init_vars(dbsel)
    local x r
    dbsel=$1
    declare -g PGDIR RMTBCKDIR DBCKDIR HOST_PRD HOST_DEV URL_PRD URL_DEV
    declare -g BCKFORMAT TAR_EXT TAR_OPT PG_DUMP_OPT ORIG_OWN
    declare -g REST2 TEST_DB NEWDBS REDB OE_OWN PRD_OE_OWN DEV_OE_OWN
    declare -g DBA DBB DBC DBD DBE DBF DBG DBH
    declare -g NCA NCB NCC NCD NCE NCF NCG NCH
    declare -g NAA NAB NAC NAD NAE NAF NAG NAH
    declare -g EXCL_LIST
    local sfx selsfx XDB
    if [ ${test_mode:-0} -ne 0 ]; then
      PGDIR=$(findpkg "" "$TESTDIR")
    else
      PGDIR=$(findpkg "" "/var/lib" "postgresql  pgsql" "12.0 11.0 10.0 9.6 9.5 9.4 9.3 9.2 9.1 9.0 8.3 8.2")
      [[ -z $PGDIR ]] && PGDIR=$(findpkg "" "/var/lib" "postgresql  pgsql")
      if [ -z "$PGDIR" ]; then
        wlog "No postgres directory found!"
        exit 1
      fi
    fi
    HOST_PRD=$(get_cfg_value 0 production_host)
    HOST_DEV=$(get_cfg_value 0 development_host)
    URL_PRD=$(get_cfg_value 0 URL_production_host)
    if [ -z "$URL_PRD" ]; then
      URL_PRD=$HOST_PRD
    fi
    URL_DEV=$(get_cfg_value 0 URL_development_host)
    if [ -z "$URL_DEV" ]; then
      URL_DEV=$HOST_DEV
    fi
    x=$(get_cfg_value 0 bckdir)
    r=$(get_cfg_value 0 remote_bckdir)
    [ -z "$x" ] && x="$PGDIR/backups"
    DBCKDIR=$(readlink -f $x)
    [ -z "$r" ] && RMTBCKDIR=$DBCKDIR || RMTBCKDIR=$r
    BCKFORMAT="$(get_cfg_value 0 bckformat)"
    TAR_EXT=$(get_cfg_value 0 tar_ext)
    TAR_OPT=$(get_cfg_value 0 tar_opt)
    PG_DUMP_OPT=$(get_cfg_value 0 pg_dump_opt)
    REST2="$(get_cfg_value 0 enable_restore)"
    TEST_DB="$(get_cfg_value 0 test_db)"
    NEWDBS=$(get_cfg_value 0 bck_db)
    EXCL_LIST=$(get_cfg_value 0 excl_list)
    EXCL_LIST="${EXCL_LIST//,/ }"
    if [ -n "$NEWDBS" ]; then
      REDB="($TEST_DB|${NEWDBS//,/|})"
    else
      REDB="$TEST_DB"
    fi
    if [ -z $REDB ]; then
      REDB="test"
    fi
    OE_OWN=$(get_cfg_value 0 db_user)
    PRD_OE_OWN=$(get_cfg_value 0 PRD_db_user)
    DEV_OE_OWN=$(get_cfg_value 0 DEV_db_user)
    ORIGINAL_OWN=$(get_cfg_value 0 "set_original_user")
    PG_OWN=$(get_cfg_value 0 pg_user)
    ODOO_FILESTORE_ROOT="$(get_cfg_value 0 odoo_filestore_root)"
    [[ -z $ODOO_FILESTORE_ROOT && -d /home/odoo/.local/share ]] && ODOO_FILESTORE_ROOT="/home/odoo/.local/share"
    [[ -z $ODOO_FILESTORE_ROOT && -d /opt/odoo/.local/share ]] && ODOO_FILESTORE_ROOT="/opt/odoo/.local/share"
    ODOO_RPC_HOST="$(get_cfg_value 0 odoo_rpc_host)"
    ODOO_RPC_PROTOCOL="$(get_cfg_value 0 odoo_rpc_protocol)"
    ODOO_RPC_XMLPORT="$(get_cfg_value 0 odoo_rpc_xmlport)"
    ODOO_VERSION="$(get_cfg_value 0 odoo_version)"
    ODOO_RPC_PWD="$(get_cfg_value 0 odoo_rpc_pwd)"
    selsfx=
    for sfx in A B C D E F G H; do
      if [[ -n "$HOST_DEV" && ! $HOSTNAME =~ $HOST_DEV ]]; then
        eval DB$sfx="'$(get_cfg_value 0 PRD_DB${sfx}_filter)'"
        eval NC$sfx="$(get_cfg_value 0 PRD_DB${sfx}_keep_recent)"
        eval NA$sfx="$(get_cfg_value 0 PRD_DB${sfx}_keep_monthly)"
        BCK_ENV="PRD"
      elif [[ -n "$HOST_DEV" && "$HOST_DEV" != "$HOST_PRD" && $HOSTNAME =~ $HOST_DEV ]]; then
        eval DB$sfx="'$(get_cfg_value 0 DEV_DB${sfx}_filter)'"
        eval NC$sfx="$(get_cfg_value 0 DEV_DB${sfx}_keep_recent)"
        eval NA$sfx="$(get_cfg_value 0 DEV_DB${sfx}_keep_monthly)"
        BCK_ENV="DEV"
      else
        eval DB$sfx=""
        eval NC$sfx=""
        eval NA$sfx=""
        BCK_ENV="U1Q"
      fi
      x=DB$sfx
      XDB=${!x}
      x=NC${sfx}
      XNC=${!x}
      x=NA${sfx}
      XNA=${!x}
      [ -z "$XDB" ] && eval DB$sfx="'$(get_cfg_value 0 DB${sfx}_filter)'"
      [ -z "$XNC" ] && eval NC$sfx="$(get_cfg_value 0 DB${sfx}_keep_recent)"
      [ -z "$XNA" ] && eval NA$sfx="$(get_cfg_value 0 DB${sfx}_keep_monthly)"
      if [ "$ACTION" != "restdb" ] && [ -n "$dbsel" -o  ${opt_ex:-0} -ne 0 ]; then
        x=DB$sfx
        XDB=${!x}
        if [ -n "$dbsel" -a -n "$XDB" ] && [[ $dbsel =~ $XDB ]]; then
          selsfx=$sfx
        else
          eval DB$sfx=
          eval NC$sfx=
          eval NA$sfx=
        fi
      fi
    done
    if [ -n "$dbsel" -a -z "$selsfx" -a ${opt_ex:-0} -eq 0 ]; then
      DBA="'$(get_cfg_value 0 dbfilter)'"
      NCA=$(get_cfg_value 0 keep_recent)
      NAA=$(get_cfg_value 0 keep_monthly)
    fi
    if [ ${opt_ex:-0} -eq 0 -a "$ACTION" != "purgedb" ]; then
      DBSEL=
      for sfx in A B C D E F G H; do
        x=DB$sfx
        XDB=${!x}
        if [ -n "$XDB" ]; then
          if [ -z "$DBSEL" ]; then
            DBSEL="$XDB"
          elif [ "$DBSEL" != "$XDB" ]; then
            DBSEL=".*"
            break
          fi
        fi
      done
    else
      DBSEL=$dbsel
    fi
    if [[ "$opt_keep" =~ [0-9]+ ]]; then
      NCA=$opt_keep
    fi
    if [[ "$opt_km" =~ [0-9]+ ]]; then
      NAA=$opt_km
    fi
    if [ -z "$OE_OWN" ]; then
      if [ "$BCK_ENV" == "PRD" ]; then
        OE_OWN=$PRD_OE_OWN
      elif [ "$BCK_ENV" == "DEV" ]; then
        OE_OWN=$DEV_OE_OWN
      else
        OE_OWN="odoo"
      fi
    fi
    if [ -z "$OE_OWN" ]; then
      OE_OWN="odoo"
    fi
}

set_db_vars() {
#set_db_vars(db)
    dbsel=$1
    declare -g XDB XNC XNA
    local sfx x
    for sfx in A B C D E F G H; do
      x=DB${sfx}
      XDB=${!x}
      x=NC${sfx}
      XNC=${!x}
      x=NA${sfx}
      XNA=${!x}
      if [[ -n "$XDB" && $db =~ $XDB ]]; then
        break
      fi
   done
}

expand_tar() {
#expand_tar(db [sqlfname])
# current dir must be BCKDIR
    local src s x
    local db=$1
    if [ "$BCKFORMAT" != "0" ]; then
      for x in $TAR_EXT; do
        if [ -f "$db$x" ]; then
          src=$db$x
          break
        fi
      done
      if [ -n "$src" ]; then
        if [[ -f $src.bak ]]; then
          for x in "" z j J ""; do
            run_traced "tar $TAR_OPT -x${x}f $src.bak $2"
            [[ $? -eq 0 ]] && break
          done
          rm -f $src.bak
        fi
        if [ -f "$src" ]; then
          chown $PG_OWN $src
          if [[ "zjJ" =~ "$BCKFORMAT" ]]; then
            run_traced "tar $TAR_OPT -x${BCKFORMAT}f $src $2"
          else
            run_traced "tar $TAR_OPT -xf $src $2"
          fi
          if [ $? -ne 0 ]; then
            s=1
            for x in z j J ""; do
              if [ "$x" != "$BCKFORMAT" ]; then
                run_traced "tar $TAR_OPT -x${x}f $src $2"
                if [ $? -eq 0 ]; then
                  s=0
                  break
                fi
              fi
            done
            if [ $s -ne 0 ]; then
              run_traced "mv -f $src ${src}.bak"
            fi
          fi
        fi
      fi
    fi
}

compress_tar() {
#compress_tar(db sqlfname)
# current dir must be BCKDIR
    local src x sts fn
    local db=$1
    if [ -f "$db-*.sql" ]; then
      chown $PG_OWN $db-*.sql
    fi
    if [ "$BCKFORMAT" != "0" ]; then
      src=$db
      x=$(echo $TAR_EXT|awk '{print $1}')
      src=$db$x
      if [[ "zjJ" =~ "$BCKFORMAT" ]]; then
        run_traced "tar $TAR_OPT -c${BCKFORMAT}f $src $db-*.sql $db-filestore.gz"
      else
        run_traced "tar $TAR_OPT -cf $src $db-*.sql"
      fi
      sts=$?
      if [[ $sts -eq $STS_SUCCESS ]]; then
        wlog "removing archived files"
        for fn in $db-*.sql; do
          [[ $fn != "$2" ]] && rm -f $fn
        done
        [[ -f $db-filestore.gz ]] && rm -f $db-filestore.gz
      fi
    fi
}

create_db_list_from_pg() {
# create_db_list_from_pg(dbsel pgsql_dir bck_dir bck_db)
    local dblist=
    local PGDIR=$2
    local bckdir cmd dbsel f flst redb sfx x XDB
    if [ -z $3 ]; then
      bckdir="$DBCKDIR"
    else
      bckdir=$3
    fi
    flst="$HOME/db_pgsql.lst"
    dbsel=$1
    if [ -n "$dbsel" ]; then
      redb=$4
      if [ -z "$redb" ]; then
        redb="test"
      fi
      if [ $opt_dry_run -eq 0 -o ${test_mode:-0} -ne 0 ]; then
        slog "Select DB matches $dbsel in $bckdir"
      fi
      if [ ${test_mode:-0} -ne 0 ]; then
        cmd="echo -e "
        cmd="${cmd}invalid|postgres|UTF8|en_US.UTF-8|en_US.UTF-8|\\n"
        cmd="${cmd}zi01234567|postgres|UTF8|en_US.UTF-8|en_US.UTF-8|\\n"
        cmd="${cmd}zi01234589|postgres|UTF8|en_US.UTF-8|en_US.UTF-8|\\n"
        cmd="${cmd}test|postgres|UTF8|en_US.UTF-8|en_US.UTF-8|\\n"
      else
        cmd="psql -U$opt_user -Alt"
      fi
      for db in $($cmd|sort -f|awk -F"|" '{ print $1 }'); do
        if [[ $db =~ $redb ]]; then
          slog "DB $db is backup copy"
        else
          for sfx in A B C D E F G H; do
            x=DB$sfx
            XDB=${!x}
            f=0
            if [ -n "$XDB" ]; then
              if [[ $db =~ $XDB ]]; then
                if [ ${opt_ex:-0} -ne 0 ]; then
                  if [ "$BCK_ENV" == "PRD" ]; then
                    if [[ ! " $dblist " =~ [[:space:]]$dbsel[[:space:]] ]]; then
                      dblist="$dblist $dbsel"
                      f=1
                    fi
                    break
                  fi
                else
                  if [ "$BCK_ENV" == "PRD" ]; then
                    if [[ ! " $dblist " =~ [[:space:]]$db[[:space:]] ]]; then
                      dblist="$dblist $db"
                      f=1
                    fi
                    break
                  fi
                fi
              fi
            fi
          done
          if [ $f -eq 0 ]; then
            slog "DB $db is not classified"
          fi
        fi
      done
      rm -f $flst
    fi
    echo $dblist
}

create_db_list_from_file() {
# create_db_list_from_file(dbsel pgsql_dir bck_dir bck_db)
    local dbsel="$1"
    local dblist=""
    local files fn db dbf sfx f x
    local XDB bckdir redb valid passed
    if [ -z $3 ]; then
      bckdir="$DBCKDIR"
    else
      bckdir=$3
    fi
    files="$bckdir/*.sql"
    if [ "$BCKFORMAT" != "0" ]; then
      for x in $TAR_EXT; do
        files="$files $bckdir/*$x"
      done
    fi
    for fn in ${files/\~/$HOME}; do
      x="-$(echo $fn|awk -F- '{print $NF}')"
      dbf=${fn/$x/}
      x=$(basename $dbf)
      db=${x%.*}
      valid=0
      if [[ " $passed " =~ [[:space:]]$db[[:space:]] ]]; then
        :
      elif [ -z "$dbsel" ]; then
        valid=1
      elif [ ${opt_ex:-0} -ne 0 ]; then
        if [[ "$db" == "$dbsel" ]]; then
          valid=1
        fi
      else
        if [[ " $db " =~ [[:space:]]$dbsel[[:space:]] ]]; then
          valid=1
        fi
      fi
      [[ " $EXCL_LIST " =~ [[:space:]]$db[[:space:]] ]] && valid=0
      if [ $valid -ne 0 ]; then
        passed="$passed $db"
        for sfx in A B C D E F G H; do
          x=DB$sfx
          XDB=${!x}
          if [ -n "$XDB" ]; then
            if [[ $db =~ $XDB ]]; then
              if [ ${opt_ex:-0} -ne 0 ]; then
                if [[ " $dblist " =~ [[:space:]]$dbsel[[:space:]] ]]; then
                  :
                else
                  dblist="$dblist $dbsel"
                fi
              else
                if [[ " $dblist " =~ [[:space:]]$db[[:space:]] ]]; then
                  :
                else
                  dblist="$dblist $db"
                fi
              fi
            fi
          fi
        done
      fi
    done
    echo "$dblist"
}

reassign_owner() {
# reassign_owner(db old new)
    if [ -z "$1" -o -z "$3" ]; then
      echo $0 DB OLD_OWNER NEW_OWNER
      exit 1
    fi
    local DB=$1
    local OLD_OWNER=$2
    local NEW_OWNER=$3
    local tbl
    run_traced "psql -Upostgres -qc 'GRANT ALL PRIVILEGES ON DATABASE $DB TO $NEW_OWNER' $DB"
    run_traced "psql -Upostgres -qc 'ALTER DATABASE $DB OWNER TO $NEW_OWNER' $DB"
    run_traced "psql -Upostgres -qc 'GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO $NEW_OWNER' $DB"
    run_traced "psql -Upostgres -qc 'GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO $NEW_OWNER' $DB"
    run_traced "psql -Upostgres -qc 'GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO $NEW_OWNER' $DB"
    run_traced "psql -Upostgres -qc 'ALTER DEFAULT PRIVILEGES GRANT ALL ON TABLES TO $NEW_OWNER' $DB"
    run_traced "psql -Upostgres -qc 'ALTER DEFAULT PRIVILEGES GRANT ALL ON SEQUENCES TO $NEW_OWNER' $DB"
    if [ $opt_dry_run -eq 0 ]; then
      [ $opt_verbose -gt 0 ] && echo "Reassigning all tables ..."
      for tbl in $(psql -Upostgres -qAtc "select tablename from pg_tables where schemaname = 'public'" $DB); do
        psql -Upostgres -qc "ALTER TABLE \"$tbl\" OWNER TO $NEW_OWNER" $DB
        psql -Upostgres -qc "GRANT ALL PRIVILEGES ON TABLE \"$tbl\" TO $NEW_OWNER" $DB
      done
      for tbl in $(psql -Upostgres -qAtc "select sequence_name from information_schema.sequences where sequence_schema = 'public'" $DB); do
        psql -Upostgres -qc "ALTER SEQUENCE \"$tbl\" OWNER TO $NEW_OWNER" $DB
        psql -Upostgres -qc "GRANT ALL PRIVILEGES ON SEQUENCE \"$tbl\" TO $NEW_OWNER" $DB
      done
      for tbl in $(psql -qAtc "select table_name from information_schema.views where table_schema = 'public'" $DB); do
        psql -Upostgres -qc "ALTER VIEW \"$tbl\" OWNER TO $NEW_OWNER" $DB
        psql -Upostgres -qc "GRANT ALL PRIVILEGES ON TABLE \"$tbl\" TO $NEW_OWNER" $DB
      done
    fi
    [ -n "$OLD_OWNER" ] && run_traced "psql -Upostgres -qc 'GRANT $OLD_OWNER TO $NEW_OWNER;' $DB"
}

