diff --git a/README.md b/README.md index 0b8c07a6..0ef997ee 100644 --- a/README.md +++ b/README.md @@ -234,7 +234,7 @@ sudo pdsadmin account create If needed, use `pdsadmin` to create an invite code: ```bash -sudo pdsadmin create-invite-code +sudo pdsadmin invite create ``` When creating an account using the app, enter this invite code. diff --git a/pdsadmin/account.sh b/pdsadmin/account.sh index d87c4a6d..5b391565 100644 --- a/pdsadmin/account.sh +++ b/pdsadmin/account.sh @@ -3,6 +3,8 @@ set -o errexit set -o nounset set -o pipefail +echo "NOTE: pdsadmin is not actively maintained. Consider using goat: https://github.com/bluesky-social/goat" >/dev/stderr + PDS_ENV_FILE=${PDS_ENV_FILE:-"/pds/pds.env"} source "${PDS_ENV_FILE}" diff --git a/pdsadmin/create-invite-code.sh b/pdsadmin/create-invite-code.sh index 2e3d1c83..27d04b36 100644 --- a/pdsadmin/create-invite-code.sh +++ b/pdsadmin/create-invite-code.sh @@ -3,15 +3,17 @@ set -o errexit set -o nounset set -o pipefail -PDS_ENV_FILE=${PDS_ENV_FILE:-"/pds/pds.env"} -source "${PDS_ENV_FILE}" +# Backwards compatibility wrapper for the old create-invite-code command. +# Delegates to 'pdsadmin invite create'. -curl \ - --fail \ - --silent \ - --show-error \ - --request POST \ - --user "admin:${PDS_ADMIN_PASSWORD}" \ - --header "Content-Type: application/json" \ - --data '{"useCount": 1}' \ - "https://${PDS_HOSTNAME}/xrpc/com.atproto.server.createInviteCode" | jq --raw-output '.code' +PDSADMIN_BASE_URL="https://raw.githubusercontent.com/bluesky-social/pds/main/pdsadmin" + +SCRIPT_URL="${PDSADMIN_BASE_URL}/invite.sh" +SCRIPT_FILE="$(mktemp /tmp/pdsadmin.invite.XXXXXX)" + +curl --fail --silent --show-error --location --output "${SCRIPT_FILE}" "${SCRIPT_URL}" +chmod +x "${SCRIPT_FILE}" + +if "${SCRIPT_FILE}" create "$@"; then + rm -f "${SCRIPT_FILE}" +fi diff --git a/pdsadmin/help.sh b/pdsadmin/help.sh index 99935234..2e59a638 100644 --- a/pdsadmin/help.sh +++ b/pdsadmin/help.sh @@ -7,6 +7,9 @@ set -o pipefail cat <] Request a crawl from a relay host. e.g. pdsadmin request-crawl bsky.network -create-invite-code - Create a new invite code. +invite + list [FILTER] + List invite codes. Filter: used, disabled, free + e.g. pdsadmin invite list + e.g. pdsadmin invite list free + create [COUNT] + Create a new invite code with optional use count (default: 1) + e.g. pdsadmin invite create + e.g. pdsadmin invite create 5 + +create-invite-code [COUNT] + Create a new invite code (deprecated, use 'pdsadmin invite create' instead) e.g. pdsadmin create-invite-code + e.g. pdsadmin create-invite-code 5 help Display this help information. diff --git a/pdsadmin/invite.sh b/pdsadmin/invite.sh new file mode 100644 index 00000000..f5f70f87 --- /dev/null +++ b/pdsadmin/invite.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +set -o errexit +set -o nounset +set -o pipefail + +echo "NOTE: pdsadmin is not actively maintained. Consider using goat: https://github.com/bluesky-social/goat" >/dev/stderr + +PDS_ENV_FILE=${PDS_ENV_FILE:-"/pds/pds.env"} +source "${PDS_ENV_FILE}" + +# curl a URL and fail if the request fails. +function curl_cmd_get { + curl --fail --silent --show-error "$@" +} + +# curl a URL and fail if the request fails. +function curl_cmd_post { + curl --fail --silent --show-error --request POST --header "Content-Type: application/json" "$@" +} + +# The subcommand to run. +SUBCOMMAND="${1:-}" + +# +# invite list [filter] +# +if [[ "${SUBCOMMAND}" == "list" ]]; then + FILTER="${2:-}" + + CODES_JSON="$(curl_cmd_get \ + --user "admin:${PDS_ADMIN_PASSWORD}" \ + "https://${PDS_HOSTNAME}/xrpc/com.atproto.admin.getInviteCodes" + )" + + if [[ "${FILTER}" == "used" ]]; then + # Show codes that have been used + JQ_FILTER='.codes[] | select(.uses != []) | [.code, (.uses | length | tostring), (if .disabled then "disabled" else "active" end)] | @tsv' + elif [[ "${FILTER}" == "disabled" ]]; then + # Show disabled codes + JQ_FILTER='.codes[] | select(.disabled == true) | [.code, (.uses | length | tostring), "disabled"] | @tsv' + elif [[ "${FILTER}" == "free" ]]; then + # Show codes that are not used and not disabled + JQ_FILTER='.codes[] | select(.uses == [] and .disabled == false) | [.code, "0", "active"] | @tsv' + elif [[ -z "${FILTER}" ]]; then + # No filter provided: show all codes + JQ_FILTER='.codes[] | [.code, (.uses | length | tostring), (if .disabled then "disabled" else "active" end)] | @tsv' + else + echo "Unknown filter: ${FILTER}" >/dev/stderr + echo "Valid filters: used, disabled, free" >/dev/stderr + exit 1 + fi + + RESULTS="$(echo "${CODES_JSON}" | jq --raw-output "${JQ_FILTER}")" + if [[ -z "${RESULTS}" ]]; then + if [[ -n "${FILTER}" ]]; then + echo "No invite codes found matching filter: ${FILTER}" + else + echo "No invite codes found." + fi + else + echo -e "Code\tUses\tStatus" + echo "${RESULTS}" | column --table + fi + +# +# invite create [use_count] +# +elif [[ "${SUBCOMMAND}" == "create" ]]; then + USE_COUNT="${2:-1}" + + # Validate that USE_COUNT is a positive integer to avoid invalid JSON payloads. + if ! [[ "${USE_COUNT}" =~ ^[1-9][0-9]*$ ]]; then + echo "Error: USE_COUNT must be a positive integer (got: '${USE_COUNT}')." >/dev/stderr + echo "Usage: pdsadmin invite create [count]" >/dev/stderr + exit 1 + fi + + CODE="$(curl_cmd_post \ + --user "admin:${PDS_ADMIN_PASSWORD}" \ + --data "{\"useCount\": ${USE_COUNT}}" \ + "https://${PDS_HOSTNAME}/xrpc/com.atproto.server.createInviteCode" | jq --raw-output '.code' + )" + + echo "${CODE}" + +else + echo "Unknown subcommand: ${SUBCOMMAND}" >/dev/stderr + echo "Usage: pdsadmin invite " >/dev/stderr + echo "" >/dev/stderr + echo "Commands:" >/dev/stderr + echo " list [filter] List invite codes (filter: used, disabled, free)" >/dev/stderr + echo " create [count] Create a new invite code (default: 1 use)" >/dev/stderr + exit 1 +fi diff --git a/pdsadmin/request-crawl.sh b/pdsadmin/request-crawl.sh index fe83d2b1..772ca436 100644 --- a/pdsadmin/request-crawl.sh +++ b/pdsadmin/request-crawl.sh @@ -3,6 +3,8 @@ set -o errexit set -o nounset set -o pipefail +echo "NOTE: pdsadmin is not actively maintained. Consider using goat: https://github.com/bluesky-social/goat" >/dev/stderr + PDS_ENV_FILE=${PDS_ENV_FILE:-"/pds/pds.env"} source "${PDS_ENV_FILE}" diff --git a/pdsadmin/update.sh b/pdsadmin/update.sh index a360d6ac..8f8dfcc9 100644 --- a/pdsadmin/update.sh +++ b/pdsadmin/update.sh @@ -3,6 +3,8 @@ set -o errexit set -o nounset set -o pipefail +echo "NOTE: pdsadmin is not actively maintained. Consider using goat: https://github.com/bluesky-social/goat" >/dev/stderr + PDS_DATADIR="/pds" COMPOSE_FILE="${PDS_DATADIR}/compose.yaml" COMPOSE_URL="https://raw.githubusercontent.com/bluesky-social/pds/main/compose.yaml"