From f0c74cd154573541b06dd9137dc202d445ca9cf9 Mon Sep 17 00:00:00 2001 From: Seva Luchianov Date: Thu, 19 Feb 2026 19:20:09 -0500 Subject: [PATCH] feat: CLI Invite Manager Signed-off-by: Seva Luchianov --- README.md | 29 ++++++++++++++- invite_manager.sh | 95 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 invite_manager.sh diff --git a/README.md b/README.md index f31174e..52ffef6 100644 --- a/README.md +++ b/README.md @@ -372,17 +372,42 @@ services: Enable invite-only mode by setting `invite_only` in `Revolt.toml` to `true`. -Create an invite: +You can use the interactive invite manager to create, view, and delete invite codes. +```bash +chmod +x invite_manager.sh +./invite_manager.sh +``` + +Or you can manage the invites db by hand: ```bash # drop into mongo shell docker compose exec database mongosh -# create the invite +# connect to the db use revolt +``` + +Then you are able to... + +Create an invite: + +```bash db.invites.insertOne({ _id: "enter_an_invite_code_here" }) ``` +View all pending invites: + +```bash +db.invites.find() +``` + +Delete a pending invite: + +```bash +db.invites.deleteOne({ _id: "invite_code_to_be_deleted" }) +``` + ## Notices > [!IMPORTANT] diff --git a/invite_manager.sh b/invite_manager.sh new file mode 100644 index 0000000..40959f2 --- /dev/null +++ b/invite_manager.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ ! -f "compose.yml" || ! -f "Revolt.toml" ]]; then + echo "Error: This script needs to be run from your stoat config directory." >&2 + exit 1 +fi + +run_mongosh() { + sudo docker compose exec -T database mongosh --quiet --eval "$1" +} + +create_invite() { + local code + code="$(openssl rand -hex 16)" + + if run_mongosh "use(\"revolt\"); db.invites.insertOne({ _id: \"${code}\" });" > /dev/null 2>&1; then + echo "Successfully created invite: ${code}" + else + echo "Error: Failed to create invite" >&2 + fi +} + +view_invites() { + local output + output="$(run_mongosh "use(\"revolt\"); db.invites.find().forEach(doc => print(doc._id));")" + + if [[ -z "$output" ]]; then + echo "No active invites found" + else + echo "Active invites:" + while IFS= read -r line; do + echo " - ${line}" + done <<< "$output" + fi +} + +delete_invite() { + local output + output="$(run_mongosh "use(\"revolt\"); db.invites.find().forEach(doc => print(doc._id));")" + + if [[ -z "$output" ]]; then + echo "No active invites to delete" + return + fi + + local invites=() + while IFS= read -r line; do + invites+=("$line") + done <<< "$output" + + echo "Active invites:" + for i in "${!invites[@]}"; do + echo " $((i + 1))) ${invites[$i]}" + done + + local choice + read -rp "Enter the number of the invite to delete (1-${#invites[@]}, or 'c' to cancel): " choice + + if [[ "$choice" =~ ^[Cc](ancel)?$ ]]; then + echo "Delete cancelled" + return + fi + + if ! [[ "$choice" =~ ^[0-9]+$ ]] || (( choice < 1 || choice > ${#invites[@]} )); then + echo "Error: Invalid selection" >&2 + return + fi + + local target="${invites[$((choice - 1))]}" + + if run_mongosh "use(\"revolt\"); db.invites.deleteOne({ _id: \"${target}\" });" > /dev/null 2>&1; then + echo "Successfully deleted invite: ${target}" + else + echo "Error: Failed to delete invite" >&2 + fi +} + +while true; do + echo "" + echo "Stoat Invite Manager" + echo "1) Create a new invite" + echo "2) View active invites" + echo "3) Delete a pending invite" + echo "4) Exit" + read -rp "Choose an option: " option + + case "$option" in + 1) create_invite ;; + 2) view_invites ;; + 3) delete_invite ;; + 4) exit 0 ;; + *) echo "Invalid option." ;; + esac +done