From b535f3e68b71dfa959ae5673db518cffcc2ed307 Mon Sep 17 00:00:00 2001 From: Jasper Mayone Date: Sat, 27 Dec 2025 15:13:11 -0500 Subject: [PATCH 1/4] Improve invite command --- README.md | 2 +- pdsadmin/create-invite-code.sh | 17 -------- pdsadmin/help.sh | 13 +++++- pdsadmin/invite.sh | 72 ++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 20 deletions(-) delete mode 100644 pdsadmin/create-invite-code.sh create mode 100644 pdsadmin/invite.sh 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/create-invite-code.sh b/pdsadmin/create-invite-code.sh deleted file mode 100644 index 2e3d1c83..00000000 --- a/pdsadmin/create-invite-code.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -set -o errexit -set -o nounset -set -o pipefail - -PDS_ENV_FILE=${PDS_ENV_FILE:-"/pds/pds.env"} -source "${PDS_ENV_FILE}" - -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' diff --git a/pdsadmin/help.sh b/pdsadmin/help.sh index 99935234..e31319b7 100644 --- a/pdsadmin/help.sh +++ b/pdsadmin/help.sh @@ -35,9 +35,18 @@ request-crawl [] Request a crawl from a relay host. e.g. pdsadmin request-crawl bsky.network +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 - Create a new invite code. - e.g. pdsadmin create-invite-code + Removed. Use 'pdsadmin invite create' instead. help Display this help information. diff --git a/pdsadmin/invite.sh b/pdsadmin/invite.sh new file mode 100644 index 00000000..0cccb2ad --- /dev/null +++ b/pdsadmin/invite.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -o errexit +set -o nounset +set -o pipefail + +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' + else + # Show all codes + JQ_FILTER='.codes[] | [.code, (.uses | length | tostring), (if .disabled then "disabled" else "active" end)] | @tsv' + fi + + echo -e "Code\tUses\tStatus" + echo "${CODES_JSON}" | jq --raw-output "${JQ_FILTER}" | column --table + +# +# invite create [use_count] +# +elif [[ "${SUBCOMMAND}" == "create" ]]; then + USE_COUNT="${2:-1}" + + 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 From 1e9980ee5c6f725e605b34db6c378770699e7c37 Mon Sep 17 00:00:00 2001 From: Jasper Mayone Date: Mon, 29 Dec 2025 12:58:48 -0500 Subject: [PATCH 2/4] Add backwards compatibility for create-invite-code --- pdsadmin/create-invite-code.sh | 19 +++++++++++++++++++ pdsadmin/help.sh | 6 ++++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 pdsadmin/create-invite-code.sh diff --git a/pdsadmin/create-invite-code.sh b/pdsadmin/create-invite-code.sh new file mode 100644 index 00000000..27d04b36 --- /dev/null +++ b/pdsadmin/create-invite-code.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -o errexit +set -o nounset +set -o pipefail + +# Backwards compatibility wrapper for the old create-invite-code command. +# Delegates to 'pdsadmin invite create'. + +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 e31319b7..4138b441 100644 --- a/pdsadmin/help.sh +++ b/pdsadmin/help.sh @@ -45,8 +45,10 @@ invite e.g. pdsadmin invite create e.g. pdsadmin invite create 5 -create-invite-code - Removed. Use 'pdsadmin invite create' instead. +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. From d6ed09f98114e1167ac972ebe6d4c461f0a083b9 Mon Sep 17 00:00:00 2001 From: Jasper Mayone Date: Mon, 29 Dec 2025 13:02:25 -0500 Subject: [PATCH 3/4] Add goat notice to help and all commands --- pdsadmin/account.sh | 2 ++ pdsadmin/help.sh | 3 +++ pdsadmin/invite.sh | 2 ++ pdsadmin/request-crawl.sh | 2 ++ pdsadmin/update.sh | 2 ++ 5 files changed, 11 insertions(+) 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/help.sh b/pdsadmin/help.sh index 4138b441..2e59a638 100644 --- a/pdsadmin/help.sh +++ b/pdsadmin/help.sh @@ -7,6 +7,9 @@ set -o pipefail cat </dev/stderr + PDS_ENV_FILE=${PDS_ENV_FILE:-"/pds/pds.env"} source "${PDS_ENV_FILE}" 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" From 2f8f2c61ce8d77cf6c048f0d13aea0df2ab6254c Mon Sep 17 00:00:00 2001 From: Jasper Mayone Date: Mon, 29 Dec 2025 13:06:26 -0500 Subject: [PATCH 4/4] Improve invite command UX: validate inputs and handle empty results --- pdsadmin/invite.sh | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/pdsadmin/invite.sh b/pdsadmin/invite.sh index 1bef027a..f5f70f87 100644 --- a/pdsadmin/invite.sh +++ b/pdsadmin/invite.sh @@ -41,13 +41,26 @@ if [[ "${SUBCOMMAND}" == "list" ]]; then 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' - else - # Show all codes + 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 - echo -e "Code\tUses\tStatus" - echo "${CODES_JSON}" | jq --raw-output "${JQ_FILTER}" | column --table + 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] @@ -55,6 +68,13 @@ if [[ "${SUBCOMMAND}" == "list" ]]; then 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}}" \