# Script

The following script executes commands against the rules service.

Set `RULE_SERVICE_TOKEN` to the PAT before you execute the script: `export RULE_SERVICE_TOKEN="my token"`

To delete a object add a `delete-after` annotation that is a date. To the date of execution is after that date then the rule is removed instead of updated. Once the rule is confirmed to have been deleted it can be removed from the file system.

```bash
#!/bin/bash

RULE_SERVICE_URL=https://rules.app.gomboc.ai

if ! which curl > /dev/null; then
    echo "curl is not installed"
    exit 1
fi

if ! which yq > /dev/null;
then
    echo "yq is not installed"
    exit 1
fi

if [[ -z "$RULE_SERVICE_TOKEN" ]]; then
    echo "RULE_SERVICE_TOKEN is not set"
    exit 1
fi

list_classifications() {
  echo "Listing classifications $@"
  local page=1
  while true; do
    local response=$(curl -s "$RULE_SERVICE_URL/api/v1/classifications/search" \
      -G \
      -H "Authorization: Bearer $RULE_SERVICE_TOKEN" \
      -H "Content-Type: application/json" \
      -d "query=(not%20(eq%20%24.name%20%22%22))&page=$page")

    echo "$response" | jq -r '.data'
    local classifications=$(echo "$response" | jq -r '.data.classifications')

    if [[ "$classifications" == "[]" ]]; then
      break
    fi

    page=$((page + 1))
  done
}

list_channels() {
  echo "Listing channels"
  local page=1
  while true; do
    local response=$(curl -s "$RULE_SERVICE_URL/api/v1/channels/search" \
      -G \
      -H "Authorization: Bearer $RULE_SERVICE_TOKEN" \
      -H "Content-Type: application/json" \
      -d "query=(not%20(eq%20%24.name%20%22%22))&page=$page")

    echo "$response" | jq -r '.'
    local channels=$(echo "$response" | jq -r '.data.channels')

    if [[ "$channels" == "[]" ]]; then
      break
    fi

    page=$((page + 1))
  done
}

list_rules() {
  echo "Listing rules"
  local page=1
  while true; do
    local response=$(curl -s "$RULE_SERVICE_URL/api/v1/rules/search" \
      -G \
      -H "Authorization: Bearer $RULE_SERVICE_TOKEN" \
      -H "Content-Type: application/json" \
      -d "query=(not%20(eq%20%24.name%20%22%22))&page=$page")

    echo "$response" | jq -r '.data'
    local rules=$(echo "$response" | jq -r '.data.rules')

    if [[ "$rules" == "[]" ]]; then
      break
    fi

    page=$((page + 1))
  done
}

# upsert_raw <type> <directory>
# can only upsert raw rules service object from yaml files
upsert_raw() {
  local type=$1
  shift 1

  # List all yaml files in the provided directory, 1 level deep
  local files=$(find "$1" -maxdepth 1 -type f -name '*.yaml' | sort)

  # Loop through each file
  for file in $files; do
      echo "Upserting $file"

      # if rule contains "delete-after" annotation then check the date and if it is in the past and ignore the rule
      if yq -e '.annotations["delete-after"]' "$file" > /dev/null 2>&1; then
        delete_after=$(yq -e '.annotations["delete-after"]' "$file")
        if [[ "$(date +%Y-%m-%d)" > "$delete_after" ]]; then
          echo -e "\tIgnoring $file because it is in the past ($delete_after)"
          continue
        fi
      fi

      # convert to json
      json=$(yq -o=json "$file")

      # Because updates are more common we try to update first, then fall back to create
      local response=$(curl -w "%{http_code}" -X PUT "$RULE_SERVICE_URL/api/v1/$type/update" \
              -H "Authorization: Bearer $RULE_SERVICE_TOKEN" \
              -H "Content-Type: application/json" \
              -d "$json" -o /dev/null 2>/dev/null)
      if [[ "$response" -ne 200 ]]; then
          echo -e "\tcouldn't update, trying create (response: $response)"

          response=$(curl -w "%{http_code}" -X POST "$RULE_SERVICE_URL/api/v1/$type/create" \
            -H "Authorization: Bearer $RULE_SERVICE_TOKEN" \
            -H "Content-Type: application/json" \
            -d "$json" -o /dev/null 2>/dev/null)

          if [[ "$response" -ne 200 ]]; then
              echo -e "\tFailed to create (response: $response)"
              exit 1
          fi
      fi

      echo -e "\tSuccessfully upserted $type $file"
  done

  # recurse
  local dirs=$(find "$1" -mindepth 1 -maxdepth 1 -type d | sort)
  for dir in $dirs; do
    upsert_raw "$type" "$dir"
  done
}

# delete_raw <type> <directory>
# can only delete raw rules service object from yaml files
# if the `delete-after` annotation is in the past
delete_raw() {
  local type=$1
  shift 1
  echo "Deleting $type"

  local glob="*.yaml"

  if [[ "$type" == "rules" ]]; then
    glob="*.orl"
  fi

  local files=$(find "$1" -mindepth 1 -maxdepth 1 -type f,l -name "$glob" | sort)

  # Loop through each file
  for file in $files; do
      echo "Processing $file"

      # if rule contains "delete-after" annotation then check the date and if it is in the past and ignore the rule
      delete_after=$(yq -e '.metadata.annotations["delete-after"]' "$file" 2>/dev/null)
      if [[ "$delete_after" == "null" || "$delete_after" == "" ]]; then
        echo "No delete-after annotation found in $file, skipping"
        continue
      fi
      if [[ "$delete_after" > "$(date +%Y-%m-%d)" ]]; then
        echo "Ignoring $file because it should not be deleted until $delete_after"
        continue
      fi

      local name=$(yq -e '.metadata.name' "$file" 2>/dev/null)
      echo "Name: '$name'"

      local response=$(curl -w "%{http_code}" "$RULE_SERVICE_URL/api/v1/$type/delete" \
          -X DELETE \
          -G \
          -H "Authorization: Bearer $RULE_SERVICE_TOKEN" \
          --data-urlencode "name=$name" -o /dev/null 2>/dev/null)
      if [[ "$response" -ne 200 && "$response" -ne 404 ]]; then
          echo -e "\tFailed to delete $name in $file ($response)"
          exit 1
      fi

      echo -e "\tSuccessfully deleted $type $name in $file"
  done
}

main() {
  local command=$1
  local type=$2
  shift 2

  case "${command} ${type}" in
    "delete channels")
      delete_raw "channels" "$@"
      ;;
    "delete classifications")
      delete_raw "classifications" "$@"
      ;;
    "delete rules")
      delete_raw "rules" "$@"
      ;;
    "list classifications")
      list_classifications "$@"
      ;;
    "list channels")
      list_channels "$@"
      ;;
    "list rules")
      list_rules "$@"
      ;;
    "upsert channels")
      upsert_raw "channels" "$@"
      ;;
    "upsert classifications")
      upsert_raw "classifications" "$@"
      ;;
    *)
      echo "Invalid command: ${command} ${type}"
      echo "Usage: $0 <command> <type> [<args>...]"
      echo "Valid commands:"
      echo "  delete channels <path of channel yamls>"
      echo "  delete classifications <path of classification yamls>"
      echo "  delete rules <path of rule yamls>"
      echo "  list classifications"
      echo "  list channels"
      echo "  list rules"
      echo "  upsert channels <path of channel yamls>"
      echo "  upsert classifications <path of classification yamls>"
      echo
      echo "NOTE: delete and upsert check for the delete-after annotation in the yaml file"
      echo "upsert will not update an item past the delete-after date"
      echo "delete will only delete items if the delete-after date is in the past"
      exit 1
      ;;
  esac
}

main "$@"
```
