Backup and restore strategies

Simple: Make backup of server app and data dir (H2 database)

#!/bin/bash
BUP_PATH="/backup/teedy/"
mkdir -p $BUP_PATH
rsync -lrptR /var/docs $BUP_PATH
rsync -lrptR /opt/jetty-home-11.0.15/jetty-base/webapps $BUP_PATH
cd $BUP_PATH
FILENAME=$(date +%Y-%m-%d)-teedy.tar.gz
tar -zcvf $FILENAME $BUP_PATH/var/
chown TARGETUSER:TARGETUSER $FILENAME

Simple: Restore backup data dir (H2 database)

sudo systemctl stop jetty11.service
sudo rm -rf /vardocs/
sudo mkdir -p /var/docs/
sudocp /backup/teedy/2018-12-30-teedy.tar.gz /var/docs
sudo cd /var/docs/
sudo tar -xvzf 2018-12-30-teedy.tar.gz
sudo chmod 777 /var/docs/
sudo systemctl start jetty11.service

Simple: Backup PostgreSQL (not if you are using H2)

sudo -iu postgres bash -c "pg_dump YOURDATABASE > YOURDATABASE.sql" && mv /var/lib/postgresql/YOURDATABASE.sql "$BUP_POSTGRES"/YOURDATABASE.sql

Simple: Restore PostgreSQL dump

The database you want to restore must exis in your psql instancet! If you move your DB from one server to another you need to recreate an empty DB first. See Teedy with PostgreSQL.

#move the database dump file to a location where postgres user can read it, for example /var/lib/postgres/
chown postgres /var/lib/postgresql/teedy_db.sql
su - postgres
 
#drop old database and create a new one
psql
drop database teedy_inventory_db;
CREATE DATABASE teedy_db WITH ENCODING 'UNICODE' LC_COLLATE 'C' LC_CTYPE 'C' TEMPLATE template0;
GRANT ALL PRIVILEGES ON DATABASE teedy_inventory_db TO teedy_inventory;
 
#now import the backup db dump
psql teedy_inventory_db < teedy_inventory_db.sql

API Use: Bash script for API export of all documents (of the last 2 years) and all tags with cURL

This requires database access!

#!/bin/bash
BASE_URL="https://dms.yourdomain.de"
DB_USER="YOUR_DB_USER"
DB_NAME="YOUR_DB_NAME"
TEEDY_USER="YOUR_TEEDY_USER"
AUTH_TOKEN=$(psql -t -U$DB_USER $DB_NAME --command="SELECT aut_id_c FROM t_authentication_token AS A JOIN t_user AS U ON U.use_id_c = A.aut_iduser_c WHERE use_username_c = '$TEEDY_USER' AND aut_lastconnectiondate_d IS NOT NULL LIMIT 1;")
#AUTH_TOKEN=$(curl -i -X POST -d username="admin" -d password="bJ3VsrK0BkeTL6fx74Ur" "$BASE_URL/api/user/login" -k|grep "auth_token"|cut -c24-59)
BACKUP_DIR="/opt/sismics-data-bup"
TARGET_JSON_FILE=$BACKUP_DIR"/documentlist.json"
TARGET_JSON_FILE_PARSED=$BACKUP_DIR"/documentlist.txt"
TARGET_JSON_FILE_SORTED=$BACKUP_DIR"/documentlist.sorted.txt"
DIR_ZIP=$BACKUP_DIR/"ZIP"
DIR_PDF=$BACKUP_DIR/"PDF"

#teedy api limit per request - max is 100!
LIMIT=100

FILTER_DATE_MIN=$(date --date='-2 year' +%Y-01-01)

#create backup directory
mkdir -p "$BACKUP_DIR"
mkdir -p "$DIR_ZIP"
mkdir -p "$DIR_PDF"

echo "Checking token ..."
STATE=$(curl --silent -X GET -H "Cookie: auth_token=$AUTH_TOKEN" "$BASE_URL/api/document/list" -k)
substring="You don't have access to this resource"
if [[ "$STATE" =~ "$substring" ]]; then
	echo "Error: $STATE - Please create a permanent token for user $TEEDY_USER and try again!"
	exit 1
fi

echo "Getting tags list ..."
curl --silent -X GET -H "Cookie: auth_token=$AUTH_TOKEN" "$BASE_URL/api/tag/list?limit=0" -k | jq . > "$BACKUP_DIR"/taglist.json

echo "Filtering date >= $FILTER_DATE_MIN ..."

TOTAL=$(curl --silent -X GET -H "Cookie: auth_token=$AUTH_TOKEN" "$BASE_URL/api/document/list?&search=after:$FILTER_DATE_MIN" -k | jq '.|.total')
echo "Getting document count: $TOTAL ..."

echo "Getting documents list ..."
CURRENT=0
echo "{\"total\": $TOTAL, \"documents\": [], \"suggestions\": []}" | jq . > "$TARGET_JSON_FILE"
while [ $CURRENT -le $TOTAL ]; do
	echo "Next chunk of $LIMIT@$CURRENT ..."
	curl --silent -X GET -H "Cookie: auth_token=$AUTH_TOKEN" "$BASE_URL/api/document/list?&limit=$LIMIT&offset=$CURRENT&search=after:$FILTER_DATE_MIN" -k | jq '.' > /tmp/cumu.json

	# Merge the current iteration file into the cumulative file
	jq -s '.[0] as $old | .[1] as $new | {"total": $new.total, "documents": ($old.documents + $new.documents), "suggestions": ($old.suggestions + $new.suggestions)}' /tmp/cumu.json "$TARGET_JSON_FILE" > /tmp/cumu2.json
	mv /tmp/cumu2.json "$TARGET_JSON_FILE"
    ((CURRENT += $LIMIT))
done

echo "Reading list of documents ..."
jq -c '.|{documents}|.[]|.[]|{id}+{title}+{create_date}+{tags}' "$TARGET_JSON_FILE" > "$TARGET_JSON_FILE_PARSED"

echo "Making sorted list which shows number of duplicates ..."
jq -c '.|{documents}|.[]|.[]|{title}' "$TARGET_JSON_FILE" | sort | uniq -c | sort > "$TARGET_JSON_FILE_SORTED"

COUNT=0
echo "Parsing each document ..."
jq -c '.|{documents}|.[]|.[]|{id}+{title}+{create_date}' "$TARGET_JSON_FILE" | while read -r i; do
	COUNT=$((COUNT + 1))
    #parse the line and get parameters from the line
    DOC_ID=$(jq -c '.|{id}|.id' <<< $(printf '%s\n' "$i"))
    DOC_NAME=$(jq -c '.|{title}|.title' <<< $(printf '%s\n' "$i"))
    DOC_DATE=$(jq -c '.|{create_date}|.create_date' <<< $(printf '%s\n' "$i"))

    #EXPORT_FILE_NAME=$(date -d@${DOC_DATE:0:-3} +%Y-%m-%d)_${DOC_ID:1:-1}_${DOC_NAME:1:-1}.zip
    EXPORT_FILE_NAME=$(date -d@${DOC_DATE:0:-3} +%Y-%m-%d)_${DOC_ID:1:-1}
    echo $COUNT OF $TOTAL = $EXPORT_FILE_NAME ____ ${DOC_NAME:1:-1}

    curl --silent -X GET -H "Cookie: auth_token=$AUTH_TOKEN" "$BASE_URL"/api/file/zip?id="${DOC_ID:1:-1}" -k -o "$DIR_ZIP"/"$EXPORT_FILE_NAME".zip
    curl --silent -X GET -H "Cookie: auth_token=$AUTH_TOKEN" "$BASE_URL"/api/document/"${DOC_ID:1:-1}"/pdf?margin=10\&metadata=false\&comments=true\&fitimagetopage=true -k -o "$DIR_PDF"/"$EXPORT_FILE_NAME".pdf
done

#logout if finished
#curl --silent -X POST -H "Cookie: auth_token=$AUTH_TOKEN" "$BASE_URL/api/user/logout" -k #we do not logout to keep the token alive

API Use: Flat Hirarchy Export + File List Overview

#!/bin/bash
 
BASE_URL="https://dms.yourdomain.de"
AUTH_TOKEN=$(curl -i -X POST -d username="THEUSER" -d password="THEPASSWORD" "$BASE_URL/api/user/login" -k|grep "auth_token"|cut -c24-59)
BACKUP_DIR="/backup/teedy"
TARGET_DOCLIST_JSON=$BACKUP_DIR"/documentlist_forfiles.json"
TARGET_FILELIST_JSON=$BACKUP_DIR"/filelist.json"
 
mkdir -p "$BACKUP_DIR"
rm $TARGET_DOCLIST_JSON
rm $TARGET_FILELIST_JSON
 
echo "Retrieving document list"
#curl --silent -X GET -H "Cookie: auth_token=$AUTH_TOKEN" "$BASE_URL/api/document/list?limit=0" -k | jq . > "$TARGET_DOCLIST_JSON"
curl --silent -X POST -H "Cookie: auth_token=$AUTH_TOKEN" "$BASE_URL/api/document/list" -d "limit=999999" -k | jq . > "$TARGET_JSON_FILE"
 
echo "Retrieving file list based on document list"
COUNT=0
jq -c '.|{documents}|.[]|.[]|{id}+{title}+{create_date}' "$TARGET_DOCLIST_JSON" | while read -r i; do
    COUNT=$((COUNT + 1))
    DOC_ID=$(jq -c '.|{id}|.id' <<< $(printf '%s\n' $i))
    DOC_ID=${DOC_ID:1:-1}
    curl --silent -X GET -H "Cookie: auth_token=$AUTH_TOKEN" "$BASE_URL/api/file/list?id=$DOC_ID" >> "$TARGET_FILELIST_JSON"
    #echo -e "\n" >> "TARGET_JSON_FILE"
    echo Getting $COUNT : $DOC_ID
done
 
echo "Dumping files into flat hirarchy"
mkdir "$BACKUP_DIR"/flat_hirarchy/
COUNT=0
jq -c '.[]|.[]|{create_date}+{name}+{id}+{document_id}+{mimetype}' "$TARGET_FILELIST_JSON" | while read -r i; do
    COUNT=$((COUNT + 1))
    DOC_ID=$(jq -c '.|{document_id}|.document_id' <<< $(printf '%s\n' "$i"))
    DOC_ID=${DOC_ID:1:-1}
    FILE_NAME=$(jq -c '.|{name}|.name' <<< $(printf '%s\n' "$i"))
    FILE_NAME=${FILE_NAME:1:-1}
    FILE_DATE=$(jq -c '.|{create_date}|.create_date' <<< $(printf '%s\n' "$i"))
    FILE_ID=$(jq -c '.|{id}|.id' <<< $(printf '%s\n' "$i"))
    FILE_ID=${FILE_ID:1:-1}
    #MIMETYPE=$(jq -c '.|{mimetype}|.mimetype' <<< $(printf '%s\n' "$i")|sed 's#/#_#g')
    #MIMETYPE=${MIMETYPE:1:-1}
    #FILE_TYPE=$(echo "$FILE_NAME"|awk -F. '{print $(NF)}')
    #FILE_TYPE=${FILE_TYPE:0:-1}
    #EXPORT_FILE_NAME=$(date -d@${FILE_DATE:0:-3} +%Y-%m-%d)_"$FILE_ID"."$FILE_ID"."$MIMETYPE"."$FILETYPE"
    EXPORT_FILE_NAME=$(date -d@${FILE_DATE:0:-3} +%Y-%m-%d)_"$FILE_ID"."$FILE_ID"."$FILE_NAME"
    echo Getting $COUNT : $EXPORT_FILE_NAME
    curl --silent -X GET -H "Cookie: auth_token=$AUTH_TOKEN" "$BASE_URL/api/file/$FILE_ID/data" -o "$BACKUP_DIR"/flat_hirarchy/"$EXPORT_FILE_NAME"
done
  
#logout if finished
curl --silent -X POST -H "Cookie: auth_token=$AUTH_TOKEN" "$BASE_URL/api/user/logout" -k

Version #2
Erstellt: 2025-05-14 13:53:04 CEST von Mario Voigt
Zuletzt aktualisiert: 2026-06-13 12:18:49 CEST von Mario Voigt