apiVersion: v1
kind: ConfigMap
metadata:
    name: file-backup-script
    namespace: docspell
data:
    export-files.sh: |
        #!/usr/bin/env bash
        #
        # Simple script for downloading all your files. It goes through all
        # items visible to the logged in user and downloads the attachments
        # (the original files).
        #
        # The item's metadata are stored next to the files to provide more
        # information about the item: tags, dates, custom fields etc. This
        # contains most of your user supplied data.
        #
        # This script is intended for having your data outside and independent
        # of docspell. Another good idea for a backup strategy is to take
        # database dumps *and* storing the releases of docspell next to this
        # dump.
        #
        # Usage:
        #
        # export-files.sh <docspell-base-url> <target-directory>
        #
        # The docspell base url is required as well as a directory to store
        # all the files into.
        #
        # Example:
        #
        #    export-files.sh http://localhost:7880 /tmp/ds-download
        #
        # The script then asks for username and password and starts
        # downloading. Files are downloaded into the following structure
        # (below the given target directory):
        #
        # - yyyy-mm (item date)
        #   - A3…XY (item id)
        #     - somefile.pdf (attachments with name)
        #     - metadata.json (json file with items metadata)
        #
        # By default, files are not overwritten, it stops if existing files
        # are encountered. Configuration can be specified using environment
        # variables:
        #
        # - OVERWRITE_FILE= if `y` then overwriting existing files is ok.
        # - SKIP_FILE= if `y` then existing files are skipped (supersedes
        #   OVERWRITE_FILE).
        # - DROP_ITEM= if `y` the item folder is removed before attempting to
        #   download it. If this is set to `y` then the above options don't
        #   make sense, since they operate on the files inside the item folder
        #
        # Docspell sends with each file its sha256 checksum via the ETag
        # header. This is used to do a integrity check after downloading.


        if [ -z "$1" ]; then
            echo "The base-url to docspell is required."
            exit 1
        else
            BASE_URL="$1"
            shift
        fi

        if [ -z "$1" ]; then
            echo "A directory is required to store the files into."
            exit 1
        else
            TARGET="$1"
            shift
        fi

        set -o errexit -o pipefail -o noclobber -o nounset

        LOGIN_URL="$BASE_URL/api/v1/open/auth/login"
        SEARCH_URL="$BASE_URL/api/v1/sec/item/searchWithTags"
        INSIGHT_URL="$BASE_URL/api/v1/sec/collective/insights"
        DETAIL_URL="$BASE_URL/api/v1/sec/item"
        ATTACH_URL="$BASE_URL/api/v1/sec/attachment"

        OVERWRITE_FILE=${OVERWRITE_FILE:-n}
        DROP_ITEM=${DROP_ITEM:-n}

        errout() {
            >&2 echo "$@"
        }

        trap "{ rm -f ${TMPDIR-:/tmp}/ds-export.*; }" EXIT

        mcurl() {
            tmpfile1=$(mktemp -t "ds-export.XXXXX")
            tmpfile2=$(mktemp -t "ds-export.XXXXX")
            set +e
            curl -# --fail --stderr "$tmpfile1" -o "$tmpfile2" -H "X-Docspell-Auth: $auth_token" "$@"
            status=$?
            set -e
            if [ $status -ne 0 ]; then
                errout "curl -H 'X-Docspell-Auth: …' $@"
                errout "Curl command failed (rc=$status)! Output is below."
                cat "$tmpfile1" >&2
                cat "$tmpfile2" >&2
                rm -f "$tmpfile1" "$tmpfile2"
                return 2
            else
                ret=$(cat "$tmpfile2")
                rm "$tmpfile2" "$tmpfile1"
                echo $ret
            fi
        }


        errout "Login to Docspell."
        errout "Using url: $BASE_URL"
        if [ -z "$DS_USER" ]; then
            errout -n "Account: "
            read DS_USER
        fi
        if [ -z "$DS_PASS" ]; then
            errout -n "Password: "
            read -s DS_PASS
        fi
        echo

        declare auth
        declare auth_token
        declare auth_time


        login() {
            auth=$(curl -s --fail -XPOST \
                         --data-binary "{\"account\":\"$DS_USER\", \"password\":\"$DS_PASS\"}" "$LOGIN_URL")

            if [ "$(echo $auth | jq .success)" == "true" ]; then
                errout "Login successful"
                auth_token=$(echo $auth | jq -r .token)
                auth_time=$(date +%s)
            else
                errout "Login failed."
                exit 1
            fi
        }

        checkLogin() {
            elapsed=$((1000 * ($(date +%s) - $auth_time)))
            maxtime=$(echo $auth | jq .validMs)

            elapsed=$(($elapsed + 1000))
            if [ $elapsed -gt $maxtime ]; then
                errout "Need to re-login $elapsed > $maxtime"
                login
            fi
        }

        listItems() {
            OFFSET="${1:-0}"
            LIMIT="${2:-50}"
            errout "Get next items with offset=$OFFSET, limit=$LIMIT"
            REQ="{\"offset\":$OFFSET, \"limit\":$LIMIT, \"tagsInclude\":[],\"tagsExclude\":[],\"tagCategoriesInclude\":[], \"tagCategoriesExclude\":[],\"customValues\":[],\"inbox\":false}"

            mcurl -XPOST -H 'ContentType: application/json' -d "$REQ" "$SEARCH_URL" | jq -r '.groups[].items[]|.id'
        }

        fetchItemCount() {
            mcurl -XGET "$INSIGHT_URL" | jq '[.incomingCount, .outgoingCount] | add'
        }

        fetchItem() {
            mcurl -XGET "$DETAIL_URL/$1"
        }

        downloadAttachment() {
            attachId="$1"
            errout " - Download '$attachName' ($attachId)"

            if [ -f "$attachOut" ] && [ "$SKIP_FILE" == "y" ]; then
                errout " - Skipping file '$attachOut' since it already exists"
            else
                if [ -f "$attachOut" ] && [ "$OVERWRITE_FILE" == "y" ]; then
                    errout " - Removing attachment file as requested: $attachOut"
                    rm -f "$attachOut"
                fi

                checksum1=$(curl -s -I -H "X-Docspell-Auth: $auth_token" "$ATTACH_URL/$attachId/original" | \
                                grep -i 'etag' | cut -d' ' -f2 | jq -r)
                curl -s -o "$attachOut" -H "X-Docspell-Auth: $auth_token" "$ATTACH_URL/$attachId/original"
                checksum2=$(sha256sum "$attachOut" | cut -d' ' -f1 | xargs)
                if [ "$checksum1" == "$checksum2" ]; then
                    errout " - Checksum ok."
                else
                    errout " - WARNING: Checksum mismatch! Server: $checksum1 Downloaded: $checksum2"
                    return 3
                fi
            fi
        }

        downloadItem() {
            checkLogin
            itemData=$(fetchItem "$1")
            errout "Get item $(echo $itemData | jq -r .id)"
            created=$(echo $itemData|jq '.created')
            created=$((($(echo $itemData|jq '.created') + 500) / 1000))
            itemId=$(echo $itemData | jq -r '.id')
            out="$TARGET/$(date -d @$created +%Y-%m)/$itemId"

            if [ -d "$out" ] && [ "$DROP_ITEM" == "y" ]; then
                errout "Removing item folder as requested: $out"
                rm -rf "$out"
            fi

            mkdir -p "$out"
            if [ -f "$out/metadata.json" ] && [ "$SKIP_FILE" == "y" ]; then
                errout " - Skipping file 'metadata.json' since it already exists"
            else
                if [ -f "$out/metadata.json" ] && [ "$OVERWRITE_FILE" == "y" ]; then
                    errout " - Removing metadata.json as requested"
                    rm -f "$out/metadata.json"
                fi
                echo $itemData | jq > "$out/metadata.json"
            fi

            while read attachId attachName; do
                attachOut="$out/$attachName"
                checkLogin
                downloadAttachment "$attachId"
            done < <(echo $itemData | jq -r '.sources[] | [.id,.name] | join(" ")')

        }

        login

        allCount=$(fetchItemCount)
        errout "Downloading $allCount items…"

        allCounter=0 innerCounter=0 limit=100 offset=0 done=n

        while [ "$done" = "n" ]; do
            checkLogin

            innerCounter=0
            while read id; do
                downloadItem "$id"
                innerCounter=$(($innerCounter + 1))
            done < <(listItems $offset $limit)

            allCounter=$(($allCounter + $innerCounter))
            offset=$(($offset + $limit))


            if [ $innerCounter -lt $limit ]; then
                done=y
            fi

        done
        errout "Downloaded $allCounter/$allCount items"
        if [[ $allCounter < $allCount ]]; then
            errout
            errout "  Downloaded less items than were reported as available. This"
            errout "  may be due to items in folders that you cannot see. Or it"
            errout "  may be a bug."
            errout
        fi
