diff --git a/Cron/autoBackup.sh b/Cron/autoBackup.sh new file mode 100755 index 0000000..5430a1d --- /dev/null +++ b/Cron/autoBackup.sh @@ -0,0 +1,6 @@ +# cron-timing: 05 01 * * 1 +container_name="arbeitszeitmessung-main-db-1" +filename=backup-$(date '+%d%m%Y').sql +database_name=__DATABASE__ +docker exec $container_name pg_dump $database_name > /home/pi/arbeitszeitmessung-backup/$filename +echo "created backup file: "$filename diff --git a/Cron/autoHolidays.sh b/Cron/autoHolidays.sh new file mode 100755 index 0000000..50607b4 --- /dev/null +++ b/Cron/autoHolidays.sh @@ -0,0 +1,3 @@ +# Calls endpoint to write all public Holidays for the current year inside a database. +port=__PORT__ +curl localhost:$port/auto/feiertage diff --git a/Cron/autoLogout.sh b/Cron/autoLogout.sh new file mode 100755 index 0000000..75acb96 --- /dev/null +++ b/Cron/autoLogout.sh @@ -0,0 +1,4 @@ +# cron-timing: 55 23 * * * +# Calls endpoint to log out all users, still logged in for today +port=__PORT__ +curl localhost:$port/auto/logout diff --git a/Docker/env.example b/Docker/env.example index ab2147f..4d667fa 100644 --- a/Docker/env.example +++ b/Docker/env.example @@ -2,11 +2,10 @@ POSTGRES_USER=root # Postgres ADMIN Nutzername POSTGRES_PASSWORD=very_secure # Postgres ADMIN Passwort POSTGRES_API_USER=api_nutzer # Postgres API Nutzername (für Arbeitszeitmessung) POSTGRES_API_PASS=password # Postgres API Passwort (für Arbeitszeitmessung) -POSTGRES_PATH=../DB # Datebank Pfad (relativ zu Docker Ordner oder absoluter pfad mit /...) -LOG_PATH=../logs # Pfad für Logdatein +POSTGRES_PATH=__ROOT__/DB # Datebank Pfad (relativ zu Docker Ordner oder absoluter pfad mit /...) +LOG_PATH=__ROOT__/logs # Pfad für Audit Logs POSTGRES_DB=arbeitszeitmessung # Postgres Datenbank Name POSTGRES_PORT=127.0.0.1:5432 # Postgres Port will not be exposed by default. regex:^[0-9]{1,5}$ TZ=Europe/Berlin # Zeitzone API_TOKEN=dont_access # API Token für ESP Endpoints WEB_PORT=8000 # Port from which Arbeitszeitmessung should be accessable regex:^[0-9]{1,5}$ -TYPST_CONTAINER=arbeitszeitmessung-doc-creator # Name of the pdf compiler container diff --git a/DocumentCreator/Dockerfile b/DocumentCreator/Dockerfile deleted file mode 100644 index e132f75..0000000 --- a/DocumentCreator/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM ghcr.io/typst/typst:0.14.0 - -WORKDIR /app -COPY ./templates /app/templates -COPY ./static /app/static - -ENTRYPOINT ["sh", "-c", "while true; do sleep 3600; done"] diff --git a/DocumentCreator/static/logo.png b/DocumentCreator/static/logo.png deleted file mode 100644 index 53694f9..0000000 Binary files a/DocumentCreator/static/logo.png and /dev/null differ diff --git a/DocumentCreator/templates/abrechnung.typ b/DocumentCreator/templates/abrechnung.typ deleted file mode 100644 index 0735264..0000000 --- a/DocumentCreator/templates/abrechnung.typ +++ /dev/null @@ -1,97 +0,0 @@ -#let table-header(..headers) = { - table.header( - ..headers.pos().map(h => strong(h)) - ) -} - - -#let abrechnung(meta, days) = { - set page(paper: "a4", margin: (x:1.5cm, y:2.25cm), - footer:[#grid( - columns: (3fr, .65fr), - align: left + horizon, - inset: .5em, - [#meta.EmployeeName -- #meta.TimeRange], grid.cell(rowspan: 2)[#image("/static/logo.png")], - [Arbeitszeitrechnung maschinell erstellt am #meta.CurrentTimestamp], - ) - ]) - set text(font: "Noto Sans", size:10pt, fill: luma(10%)) - set table( - stroke: 0.5pt + luma(10%), - inset: .5em, - align: center + horizon, - ) - show text: it => { - if it.text == "0min"{ - text(oklch(70.8%, 0, 0deg))[#it] - }else if it.text.starts-with("-"){ - text(red)[#it] - }else{ - it - } - } - - - [= Abrechnung Arbeitszeit -- #meta.EmployeeName] - - [Zeitraum: #meta.TimeRange] - - table( - columns: (1fr, 1fr, 1fr, 1fr, 1fr, 1fr, .875fr, 1.25fr), - fill: (x, y) => - if y == 0 { oklch(87%, 0, 0deg) }, - table-header( - [Datum], [Kommen], [Gehen], [Arbeitsart], [Stunden], [Kurzarbeit], [Pause], [Überstunden] - ), - .. for day in days { - ( - [#day.Date], - if day.DayParts.len() == 0{ - table.cell(colspan: 3)[Keine Buchungen] - }else if day.DayParts.len() == 1 and not day.DayParts.first().IsWorkDay{ - table.cell(colspan: 3)[#day.DayParts.first().WorkType] - } - else { - table.cell(colspan: 3, inset: 0em)[ - #table( - columns: (1fr, 1fr, 1fr), - .. for Zeit in day.DayParts { - ( - if Zeit.IsWorkDay{ - ( - table.cell()[#Zeit.BookingFrom], - table.cell()[#Zeit.BookingTo], - table.cell()[#Zeit.WorkType], - ) - }else{ - (table.cell(colspan: 3)[#Zeit.WorkType],) - } - ) - }, - ) - ] - }, - [#day.Worktime], - [#day.Kurzarbeit], - [#day.Pausetime], - [#day.Overtime], - ) - if day.IsFriday { - ( table.cell(colspan: 8, fill: oklch(87%, 0, 0deg))[Wochenende], ) // note the trailing comma - } - } - ) - - table( - columns: (3fr, 1fr), - align: right, - inset: (x: .25em, y:.75em), - stroke: none, - table.hline(start: 0, end: 2, stroke: stroke(dash:"dashed", thickness:.5pt)), - [Arbeitszeit :], table.cell(align: left)[#meta.WorkTime], - [Kurzarbeit :], table.cell(align: left)[#meta.Kurzarbeit], - [Überstunden :], table.cell(align: left)[#meta.Overtime], - [Überstunden lfd. :],table.cell(align: left)[#meta.OvertimeTotal], - table.hline(start: 0, end: 2), -) -} diff --git a/install.sh b/install.sh index 114c7b5..c3c12e6 100755 --- a/install.sh +++ b/install.sh @@ -4,6 +4,10 @@ set -e envFile=Docker/.env envExample=Docker/env.example +autoBackupScript=Cron/autoBackup.sh +autoHolidaysScript=Cron/autoHolidays.sh +autoLogoutScript=Cron/autoLogout.sh + echo "Checking Docker installation..." if ! command -v docker >/dev/null 2>&1; then echo "Docker not found. Install Docker? [y/N]" @@ -18,12 +22,16 @@ else echo "Docker is already installed." fi +########################################################################### + echo "Checking Docker Compose..." if ! docker compose version >/dev/null 2>&1; then echo "Docker Compose plugin missing. You may need to update Docker." exit 1 fi +########################################################################### + echo "Preparing .env file..." if [ ! -f $envFile ]; then if [ -f $envExample ]; then @@ -44,6 +52,9 @@ if [ ! -f $envFile ]; then raw_val=$(printf "%s" "$rest" | sed 's/ *#.*//') default_value=$(printf "%s" "$raw_val" | sed 's/"//g') + # Replace __ROOT__ with script pwd + default_value="${default_value/__ROOT__/$(pwd)}" + regex="" if [[ "$comment" =~ regex:(.*)$ ]]; then regex="${BASH_REMATCH[1]}" @@ -96,13 +107,80 @@ else echo "Using existing .env. (found at $envFile)" fi +########################################################################### + +LOG_PATH=$(grep -E '^LOG_PATH=' $envFile | cut -d= -f2) +if [ -z "$LOG_PATH" ]; then + echo "LOG_PATH not found in .env using default $(pwd)/logs" + LOG_PATH=$(pwd)/logs +else + LOG_PATH=Docker/$LOG_PATH +fi +mkdir -p $LOG_PATH +echo "Created logs folder at $LOG_PATH" + +########################################################################### + +echo -e "\n\n" echo "Start containers with docker compose up -d? [y/N]" -read -r start_containers +read -r start_containersmkdi if [[ "$start_containers" =~ ^[Yy]$ ]]; then + cd Docker - mkdir ../logs docker compose up -d echo "Containers started." else echo "You can start them manually with: docker compose up -d" fi + +########################################################################### + +echo -e "\n\n" +echo "Setup Crontab for automatic logout, backup and holiday creation? [y/N]" +read -r setup_cron +if [[ "$setup_cron" =~ ^[Yy]$ ]]; then + WEB_PORT=$(grep -E '^WEB_PORT=' $envFile | cut -d= -f2) + if [ -z "$WEB_PORT" ]; then + echo "WEB_PORT not found in .env using default 8000" + WEB_PORT=8000 + fi + + POSTGRES_DB=$(grep -E '^POSTGRES_DB=' $envFile | cut -d= -f2) + if [ -z "$POSTGRES_DB" ]; then + echo "arbeitszeitmessung not found in .env using default arbeitszeitmessung" + POSTGRES_DB="arbeitszeitmessung" + fi + + sed -i "s/__PORT__/$WEB_PORT/" $autoHolidaysScript + sed -i "s/__PORT__/$WEB_PORT/" $autoLogoutScript + sed -i "s/__DATABASE__/$POSTGRES_DB/" $autoBackupScript + + chmod +x $autoBackupScript $autoHolidaysScript $autoLogoutScript + + # echo "Scripts build with PORT=$WEB_PORT and DATABSE=$POSTGRES_DB!" + echo "Adding rules to crontab." + + cron_commands=$(mktemp /tmp/arbeitszeitmessung-cron.XXX) + + for file in Cron/*; do + cron_timing=$(grep -E '^# cron-timing:' "$file" | sed 's/^# cron-timing:[[:space:]]*//') + + if [ -z "$cron_timing" ]; then + echo "No cron-timing found in $file, so it's not added to crontab." + continue + fi + + ( crontab -l ; echo "$cron_timing $(pwd)/$file" )| awk '!x[$0]++' | crontab - + echo "Added entry to crontab: $cron_timing $(pwd)/$file." + done + + if systemctl is-active --quiet cron.service ; then + echo "cron.service is running. Everything should be fine now." + else + echo "cron.service is not running. Please start and enable cron.service." + echo "For how to start a service, see: https://wiki.ubuntuusers.de/systemd/systemctl UNITNAME will be cron.service" + fi + +else + echo "Please setup cron manually by executing crontab -e and adding all files from inside the Cron directory!" +fi