#!/bin/sh
# Copyright (c) 2026 Athan Clark. SPDX-License-Identifier: GPL-3.0-only
# Sets up OpenChronology after the FreeBSD package is installed (#116), as the Linux packages'
# installation does: the configuration, PostgreSQL (initialized and enabled when it is not
# yet), the role and database with pgmp, the migration and the service. An installation that
# has its configuration and database already (an upgrade) is left alone, with advice.
# Usage, as root: openchronology-setup   (safe to run again)
# The package runs it with "upgrade" when upgrading, to advise only: it starts nothing then,
# since pkg ends what its scripts leave running.
set -e
PG_MAJOR=@PG_MAJOR@
CONFIG_DIR=/usr/local/etc/openchronology
CONFIG=$CONFIG_DIR/openchronology.env
EXAMPLES=/usr/local/share/openchronology
DOCS=/usr/local/share/doc/openchronology-server/README.FreeBSD
PGDATA=/var/db/postgres/data$PG_MAJOR
if [ "$(id -u)" -ne 0 ]; then
  echo "Run as root: openchronology-setup" >&2
  exit 1
fi
existing=
if [ -e "$CONFIG" ]; then existing=1; fi
advise_only=
if [ "${1:-}" = upgrade ]; then advise_only=1; fi

install -d -m 0750 -o openchronology -g openchronology /var/db/openchronology
install -d -m 0750 -o root -g openchronology "$CONFIG_DIR"
# Configuration files are created once and then belong to the administrator: upgrades never
# rewrite them (each version's templates stay in /usr/local/share/openchronology to compare).
new_config() {
  [ -e "$1" ] && return 0
  sed "$2" "$3" >"$1.new"
  chown root:openchronology "$1.new"
  chmod 0640 "$1.new"
  mv "$1.new" "$1"
}
key=$(od -An -tx1 -N32 /dev/random | tr -d ' \n')
new_config "$CONFIG" "s|^AUTH_ENCRYPTION_KEY=\$|AUTH_ENCRYPTION_KEY=$key|" \
  "$EXAMPLES/openchronology.env.example"
new_config "$CONFIG_DIR/syslog.env" "" "$EXAMPLES/syslog.env.example"

# SQL as the postgres user, over the local socket (peer authentication).
pg() {
  db=$1
  shift
  printf '%s\n' "$*" | su -l postgres -c "psql -X -q -At -v ON_ERROR_STOP=1 -d $db"
}
reachable() { pg postgres 'SELECT 1' >/dev/null 2>&1; }
if [ -z "$advise_only" ] && ! reachable; then
  if [ ! -s "$PGDATA/PG_VERSION" ]; then
    su -l postgres -c "initdb -D $PGDATA -E UTF8 --locale=C --auth-local=peer --auth-host=scram-sha-256" \
      >/dev/null
  fi
  sysrc -q postgresql_enable=YES >/dev/null
  service postgresql start >/dev/null 2>&1 || true
  for _ in $(seq 30); do
    reachable && break
    sleep 1
  done
fi
running=
if reachable; then running=1; fi
installed=
if [ -n "$existing" ] && [ -n "$running" ] &&
  [ -n "$(pg postgres "SELECT 1 FROM pg_database WHERE datname='openchronology'")" ]; then
  installed=1
fi
# Upgrading with PostgreSQL stopped: the same advice, without looking at the database.
if [ -n "$advise_only" ] && [ -n "$existing" ]; then installed=1; fi
if [ -n "$installed" ]; then
  # Settings the new template has that this installation's configuration does not.
  missing=$(sed -n 's/^\([A-Z][A-Z0-9_]*\)=.*/\1/p' "$EXAMPLES/openchronology.env.example" |
    while read -r name; do grep -q "^$name=" "$CONFIG" || echo "  $name"; done)
  version=$(pkg query '%v' openchronology-server 2>/dev/null || true)
  cat <<MSG

OpenChronology $version is installed over an earlier version (its configuration and database
are kept). The server starts again once the database is migrated to this version:

  1. Review the configuration in $CONFIG against this version's template:
       diff -u $CONFIG $EXAMPLES/openchronology.env.example
MSG
  if [ -n "$missing" ]; then
    echo "     New settings to consider (their defaults apply until you add them):"
    echo "$missing" | sed 's/^/     /'
  fi
  cat <<MSG
  2. Back up the database:   su -l postgres -c 'pg_dump openchronology' > openchronology.sql
  3. Migrate and restart:    openchronology-migrate

See $DOCS.

MSG
  exit 0
fi

if [ -n "$advise_only" ]; then exit 0; fi
if [ -z "$running" ]; then
  cat <<MSG

OpenChronology is installed, but PostgreSQL is not running, so the database was not created.
Start it, then finish the setup (as root):

  service postgresql start
  openchronology-setup

See $DOCS.

MSG
  exit 0
fi
if [ -z "$(pg postgres "SELECT 1 FROM pg_roles WHERE rolname='openchronology'")" ]; then
  pg postgres 'CREATE ROLE openchronology LOGIN'
fi
if [ -z "$(pg postgres "SELECT 1 FROM pg_database WHERE datname='openchronology'")" ]; then
  pg postgres 'CREATE DATABASE openchronology OWNER openchronology'
fi
# pgmp is not a trusted extension: the superuser creates it once for the application's role.
pg openchronology 'CREATE EXTENSION IF NOT EXISTS pgmp'
openchronology-migrate --no-restart
sysrc -q openchronology_enable=YES >/dev/null
service openchronology restart >/dev/null 2>&1 || service openchronology start >/dev/null
origin=$(sed -n 's/^APP_ORIGIN=//p' "$CONFIG")
cat <<MSG

OpenChronology is installed and running at $origin.

Next steps:
  - Set APP_ORIGIN, email, an administrator and sign-in providers in $CONFIG,
    then: openchronology-migrate (creates the administrator) or
          service openchronology restart
  - Put an HTTPS reverse proxy in front of it for public use.
  - Back up AUTH_ENCRYPTION_KEY from $CONFIG separately from the database.

See $DOCS.

MSG
