Configuration Options

Create/edit the project .env

mkdir -p /home/websites/atlas/requests
cd /home/websites/atlas/requests

nano .env

Here’s a list of the config values that should be set.

DATABASE_URL="postgresql://web_user:1234_with_single_quotes@localhost:5432/atlas-requests"
SESSION_SECRET="03efg9241c4fc6bc9b98529f69bfj5ce"

# saml sso configuration.
SAML_IDP_METADATA="http://localhost:7000/metadata"
SAML_SP_AUTHNREQUESTSSIGNED=false
SAML_SP_WANTMESSAGESIGNED=false
SAML_SP_WANTASSERTIONSIGNED=false
SAML_SP_WANTLOGOUTREQUESTSIGNED=false
SAML_PRIVATE_KEY="/etc/certs/idp-private-key.pem"
SAML_PRIVATE_KEY_PASS=""
SAML_ENC_PRIVATE_KEY="/etc/certs/idp-private-key.pem"
SAML_SP_ISASSERTIONENCRYPTED=false

# ldap settings.
LDAP_HOST=ldap://localhost
LDAP_START_TLS=false
LDAP_USERNAME=cn=admin,dc=example,dc=org
LDAP_PASSWORD=adminpassword
LDAP_BASE_DN=dc=example,dc=org
LDAP_GROUP_SEARCH=(objectClass=groupOfNames)
LDAP_USER_SEARCH=(&(objectClass=inetOrgPerson)(sn=*)(givenName=*)(displayName=*))
LDAP_EMAIL_FIELD=sn
LDAP_GROUP_NAME=cn
LDAP_FIRSTNAME=givenName
LDAP_LASTNAME=displayName
LDAP_PHOTO_FIELD=jpegPhoto
LDAP_USER_GROUP=memberOf

# email box settings
SMTP_HOST=localhost
SMTP_PORT=25
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_TLS=false
SMTP_SENDER_NAME=Atlas Requests | Riverside Healthcare Analytics
SMTP_SENDER_EMAIL=[email protected]
IMAP_HOST=localhost
IMAP_PORT=143

# the URL your site will be accessed at.
HOSTNAME=https://requests.atlas.bi

Configure

If this is a new install proceed to the install guide.

Update the app with your new configuration by running:

curl -sSL https://atlas.bi/installers/requests.sh | bash -s -- --configure

#!/usr/bin/env bash
# Setup global variables.
APP=atlas-requests
SOURCE=https://api.github.com/repos/atlas-bi/Requests/releases/latest
NGINX_FILE="$APP.conf"
PM2_PREFIX="$APP"
if [[ -f "installer.conf" ]]; then
. installer.conf
fi
# Setup basic colors
color() {
  YELLOW=$(printf '\033[1m\033[33m')
  BLUE=$(printf '\033[1m\033[34m')
  RED=$(printf '\033[1m\033[31m')
  RESET=$(printf '\033[0m') # No Color
  GREEN=$(printf '\033[1m\033[32m')
  CYAN=$(printf '\033[1m\033[36m')
  BOLD=$(printf '\033[1m')
}

color

fmt_yellow() {
  echo "${YELLOW}$1${RESET}"
}
fmt_red() {
  echo "${RED}$1${RESET}"
}
fmt_blue() {
  echo "${BLUE}$1${RESET}"
}
fmt_green() {
  echo "${GREEN}$1${RESET}"
}
fmt_cyan() {
  echo "${BLUE}$1${RESET}"
}
check_command() {
  if ! [ -x "$(command -v $1)" ]; then
    fmt_red "Error: $1 is not installed. ${GREEN}See https://atlas.bi/docs/" >&2
    exit 1
  fi
}

warn_command() {
  if ! [ -x "$(command -v $1)" ]; then
    fmt_cyan "$2" >&2
  fi
}

check_file() {
  if ! [[ -n $(compgen -G $1) ]]; then
    fmt_red "File $1 must be created before running this script. ${GREEN}See https://atlas.bi/docs/" >&2
    exit 1
  fi
}

exporter() {
  echo $1 | tee -a .env .env.local >/dev/null
}
random_number() {
  floor=3000
  range=3999
  number=0
  while [ "$number" -le $floor ]
  do
    number=$RANDOM
    let "number %= $range"
  done
  echo $number
}

get_port() {
  PORT=$(random_number)
  while [[ $(lsof -i -P -n | grep :$PORT) ]]
  do
    PORT=$(random_number)
  done
  echo $PORT
}
# from https://dev.to/justincy/blue-green-node-js-deploys-with-nginx-bkc
nginx_workers() {
  echo $(ps -ef | grep "nginx: worker process" | grep -v grep | wc -l)
}

nginx_reload() {
  numWorkerProcesses=$(nginx_workers)
  nginx -s reload

  # Wait for the old nginx workers to be retired before we kill the old server.
  while [ $(nginx_workers) -ne $numWorkerProcesses ]
  do
    sleep 1;
  done;
}
set -Eeuo pipefail
trap cleanup SIGINT SIGTERM ERR EXIT

configure(){
    check_file .env

    fmt_yellow "Update .env file in site.."
    pm2 list | grep -oP "$PM2_PREFIX-((quirrel|meili)-)?\d+" | uniq | grep -oP "\d+" | uniq  | while IFS=$'\n' read DIRECTORY; do
      if [ -d "$DIRECTORY" ]; then
        cp .env $DIRECTORY
        cat .env.local >> .env 2>&1 >/dev/null
      fi
    done

    fmt_yellow "Restarting processes.."
    pm2 list | grep -oP "$PM2_PREFIX-((quirrel|meili)-)?\d+" | uniq | while IFS=$'\n' read process; do
      pm2 restart $process
    done
}

usage() {
  cat << EOF

${BOLD}Usage: $(basename "${BASH_SOURCE[0]}") [-h, -b, -c, -u]

${BLUE}Atlas Requests Installer.${RESET}

Available options:

    -h, --help               Print this help and exit
    -c, --configure          Reconfigure Atlas Requests
    -i, --install [DEFAULT]  Install or Upgrade Atlas Requests

Additional Altas Requests Help at https://atlas.bi/docs/requests

EOF
  exit
}

install() {
  # Check if commands and files exist.
check_command node
check_command npm
check_command curl
check_command pm2
check_command nginx
check_command lsof
check_command dotenv
check_command grep
check_file .env
check_file "/etc/nginx/**/$NGINX_FILE"


# Get free internal ports.
fmt_yellow "Finding a free port.."

PORT=$(get_port)
QUIRREL_PORT=$(get_port)
MEILI_PORT=$(get_port)

fmt_blue "Using web port $PORT"
fmt_blue "Using quirrel port $QUIRREL_PORT"
fmt_blue "Using meilsearch port $MEILI_PORT"

# Download the latest release.
fmt_yellow "Downloading latest version into $(pwd)/$PORT.."

mkdir "$PORT"
curl -sSL $(curl -sSL "$SOURCE" | grep browser_download_url | cut -d : -f 2,3 | tr -d \") | tar zxf - -C "$PORT"
cd "$PORT"

fmt_blue "Downloaded version $(npm pkg get version | tr -d '"')"

# Copy in the .env file.
fmt_yellow "Setting up website.."
cp ../.env .

# Install dependencies.
npm i --omit=dev --loglevel error --no-fund --no-audit --legacy-peer-deps

# Apply database migrations.
fmt_yellow "Applying database migrations.."
npx prisma migrate deploy
npx prisma generate


# Set a few process names.
APP_PROCESS="$APP-$PORT"
QUIRREL_PROCESS="$APP-quirrel-$QUIRREL_PORT"
MEILI_PROCESS="$APP-meili-$MEILI_PORT"

exporter NODE_ENV=production
exporter WEB_PORT=$PORT
exporter QUIRREL_PORT=$QUIRREL_PORT
exporter MEILI_PORT=$MEILI_PORT

exporter APP_PROCESS=$APP_PROCESS
exporter QUIRREL_PROCESS=$QUIRREL_PROCESS
exporter MEILI_PROCESS=$MEILI_PROCESS

# Download meilisearch.
fmt_yellow "Installing meilisearch.."
curl -L https://install.meilisearch.com | sh

fmt_yellow "Starting new services.."

exporter PASSPHRASES=$QUIRREL_PROCESS
exporter DISABLE_TELEMETRY=1
exporter SESSION_SECRET=$APP_PROCESS

# Start quirrel and get a token.
# this is now down in the app's server.js file
# so that the correct token can be used on a restart.
# dotenv -v PORT=$QUIRREL_PORT -- pm2 start node --name="$QUIRREL_PROCESS" -- node_modules/quirrel/dist/cjs/src/api/main.js

# Set quirrel env vars.
# set in server.ts now.
# exporter QUIRREL_TOKEN=$(curl --retry 5 --retry-delay 3 --retry-all-errors --connect-timeout 10 --user ignored:$QUIRREL_PROCESS -X PUT "localhost:$QUIRREL_PORT/tokens/prod")
exporter QUIRREL_API_URL=http://localhost:$QUIRREL_PORT
exporter QUIRREL_BASE_URL=http://localhost:$PORT

# Load quirrel cron jobs.
# now done in server.js
# npm run quirrel:ci

# Add a few env vars to get meilisearch running
exporter MEILI_NO_ANALYTICS=true
exporter MEILI_DB_PAT=$(pwd)/$PORT/data.ms/
exporter MEILI_ENV=production
exporter MEILI_MASTER_KEY=$MEILI_PROCESS
exporter MEILISEARCH_URL=http://localhost:$MEILI_PORT
exporter MEILI_HTTP_ADDR=localhost:$MEILI_PORT

# Start web process.
dotenv -v PORT=$PORT -- pm2 start node --name="$APP_PROCESS" --merge-logs -- ./build/server.js

# Start meili process.
dotenv -- pm2 start meilisearch --name="$MEILI_PROCESS"

fmt_blue "Done setting up."
cd ..

fmt_yellow "Updating nginx.."
sed -i "s/localhost:3[0-9]*/localhost:${PORT}/" `find -L /etc/nginx -name "$NGINX_FILE"`

fmt_yellow "Gracefully reloading nginx..."
nginx_reload

fmt_yellow "Removing old pm2 processes.."

# gnu grep
pm2 list | grep -oP "$APP-((quirrel|meili)-)?\d+" | uniq | while IFS=$'\n' read process; do
  if [[ $process != $APP_PROCESS && $process != $QUIRREL_PROCESS && $process != $MEILI_PROCESS ]];
  then
    fmt_yellow "Removing $process"
    pm2 delete $process || true
  fi
done

pm2 save

fmt_yellow "Archiving old installs.."

for olddir in $(ls -d 3*); do
  if [[ $olddir != $PORT ]];
  then
    fmt_yellow "Moving $olddir"
    mv -f $olddir "backup-$olddir"
  fi
done;

fmt_blue "Finished cleaning up."
echo ""
echo ${YELLOW}Back folders can be manually removed. ${BLUE}rm -r $(pwd)/backup-*
echo ""
fmt_green "Thanks for installing Atlas Requests!"
echo ""
fmt_green "Read the full install guide at https://atlas.bi/docs/requests/"
echo ""
fmt_blue "Next Steps"

cat <<EOF
${CYAN}Current Configuration

${YELLOW}$(cat $PORT/.env.local)

${YELLOW}Web process was started with ${BLUE}dotenv -v PORT=$PORT -- pm2 start node --name="$APP_PROCESS" --merge-logs -- ./build/server.js
${YELLOW}Quirrel process was started with ${BLUE}dotenv -v PORT=$QUIRREL_PORT -- pm2 start node --name="$QUIRREL_PROCESS" -- node_modules/quirrel/dist/cjs/src/api/main.js
${YELLOW}Meilisearch process was started with ${BLUE}dotenv -- pm2 start meilisearch --name="$MEILI_PROCESS"

${CYAN}Updating App Settings

${YELLOW}1. Update user configuration file ${BLUE}nano $(pwd)/.env
${YELLOW}2. Copy config into app ${BLUE}cp $(pwd)/.env $(pwd)/$PORT/.env
${YELLOW}3. Restart the apps:
${BLUE}   pm2 restart $APP_PROCESS
${BLUE}   pm2 restart $MEILI_PROCESS
${BLUE}   pm2 restart $QUIRREL_PROCESS

${CYAN}Updating Nginx Settings

${YELLOW}1. Update configuration file ${BLUE}nano $(find -L /etc/nginx -name "$NGINX_FILE")
${YELLOW}2. Reload nginx ${BLUE}nginx -s reload


${CYAN}Monitoring and Viewing Logs

${YELLOW}Live Logging ${BLUE}pm2 monit

${RESET}
EOF

warn_command ufw "Recommendation: secure your server with ufw."
echo ""

}

cleanup() {
  trap - SIGINT SIGTERM ERR EXIT
}

die() {
  echo >&2 -e "${1-}"
  exit 1
}

# https://betterdev.blog/minimal-safe-bash-script-template/
parse_params() {
  while :; do
    case "${1-}" in
    -h | --help) usage;break ;;

    -c | --configure) configure;break ;;
    -i | --install) install;break ;;
    -?*) die "${RED}Unknown option: $1. Run $(basename "${BASH_SOURCE[0]}") -h for help.${RESET}";break ;;
    *)  install;break ;;
    esac
    shift
  done

  return 0
}

parse_params "$@"