Update telegram-approval-join submodule and apply branding patches
This commit is contained in:
parent
4e71c09c5a
commit
015f99dc83
10 changed files with 263 additions and 7 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "telegram-approval-join"]
|
||||||
|
path = telegram-approval-join
|
||||||
|
url = ssh://git@git.zio.sh:2222/astra/telegram-join-approval-bot.git
|
||||||
2
go.mod
2
go.mod
|
|
@ -1,4 +1,4 @@
|
||||||
module git.zio.sh/astra/telegram-approval-join
|
module git.zio.sh/astra/telegram-approval-join-nuzzles
|
||||||
|
|
||||||
go 1.25.3
|
go 1.25.3
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
utils "git.zio.sh/astra/telegram-approval-join/pkg/utils"
|
utils "git.zio.sh/astra/telegram-approval-join-nuzzles/pkg/utils"
|
||||||
api "github.com/OvyFlash/telegram-bot-api"
|
api "github.com/OvyFlash/telegram-bot-api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
utils "git.zio.sh/astra/telegram-approval-join/pkg/utils"
|
utils "git.zio.sh/astra/telegram-approval-join-nuzzles/pkg/utils"
|
||||||
api "github.com/OvyFlash/telegram-bot-api"
|
api "github.com/OvyFlash/telegram-bot-api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package handlers
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
config "git.zio.sh/astra/telegram-approval-join/config"
|
config "git.zio.sh/astra/telegram-approval-join-nuzzles/config"
|
||||||
api "github.com/OvyFlash/telegram-bot-api"
|
api "github.com/OvyFlash/telegram-bot-api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
utils "git.zio.sh/astra/telegram-approval-join/pkg/utils"
|
utils "git.zio.sh/astra/telegram-approval-join-nuzzles/pkg/utils"
|
||||||
api "github.com/OvyFlash/telegram-bot-api"
|
api "github.com/OvyFlash/telegram-bot-api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
4
main.go
4
main.go
|
|
@ -3,8 +3,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"git.zio.sh/astra/telegram-approval-join/config"
|
"git.zio.sh/astra/telegram-approval-join-nuzzles/config"
|
||||||
"git.zio.sh/astra/telegram-approval-join/handlers"
|
"git.zio.sh/astra/telegram-approval-join-nuzzles/handlers"
|
||||||
api "github.com/OvyFlash/telegram-bot-api"
|
api "github.com/OvyFlash/telegram-bot-api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
169
patches/0002-nuzzles.patch
Normal file
169
patches/0002-nuzzles.patch
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
--- a/config/config.go
|
||||||
|
+++ b/config/config.go
|
||||||
|
@@ -8,14 +8,15 @@ import (
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
- BotToken *string `yaml:"bot_token"`
|
||||||
|
- AdminChatId *int64 `yaml:"admin_chat_id"`
|
||||||
|
- AdminChatTopicId *int `yaml:"admin_chat_topic_id"`
|
||||||
|
- TargetChatId *int64 `yaml:"target_chat_id"`
|
||||||
|
- EntryMessage string `yaml:"entry_message"`
|
||||||
|
- ApprovalMessage string `yaml:"approval_message"`
|
||||||
|
- SendApprovalMessage bool `yaml:"send_approval_message"`
|
||||||
|
- DeleteRequestAfterDecision bool `yaml:"delete_request_after_decision"`
|
||||||
|
+ BotToken *string `yaml:"bot_token"`
|
||||||
|
+ AdminChatId *int64 `yaml:"admin_chat_id"`
|
||||||
|
+ AdminChatTopicId *int `yaml:"admin_chat_topic_id"`
|
||||||
|
+ TargetChatId *int64 `yaml:"target_chat_id"`
|
||||||
|
+ EntryMessage string `yaml:"entry_message"`
|
||||||
|
+ ApprovalMessage string `yaml:"approval_message"`
|
||||||
|
+ SendApprovalMessage bool `yaml:"send_approval_message"`
|
||||||
|
+ DeleteRequestAfterDecision bool `yaml:"delete_request_after_decision"`
|
||||||
|
+ CannedDeclineResponses []string `yaml:"canned_decline_responses"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) LoadConfig() error {
|
||||||
|
@@ -47,6 +48,7 @@ func (c *Config) CreateConfig() error {
|
||||||
|
ApprovalMessage: "",
|
||||||
|
SendApprovalMessage: false,
|
||||||
|
DeleteRequestAfterDecision: false,
|
||||||
|
+ CannedDeclineResponses: []string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder := yaml.NewEncoder(f)
|
||||||
|
|
||||||
|
--- a/handlers/callbacks.go
|
||||||
|
+++ b/handlers/callbacks.go
|
||||||
|
@@ -36,6 +36,7 @@ func (bot *Bot) HandleCallbackQuery(query *api.CallbackQuery) {
|
||||||
|
switch action {
|
||||||
|
case "approve":
|
||||||
|
bot.handleApproveRequest(query, user, userString, adminUserString)
|
||||||
|
+ bot.DeletePendingUser(args)
|
||||||
|
case "decline":
|
||||||
|
bot.handleDeclineRequest(query, user, userString, adminUserString)
|
||||||
|
case "ban":
|
||||||
|
@@ -44,10 +45,19 @@ func (bot *Bot) HandleCallbackQuery(query *api.CallbackQuery) {
|
||||||
|
return
|
||||||
|
case "banc":
|
||||||
|
bot.handleBanRequest(query, user, userString, adminUserString)
|
||||||
|
+ bot.DeletePendingUser(args)
|
||||||
|
+ case "cannedrespsel":
|
||||||
|
+ parts := strings.Split(query.Data, "_")
|
||||||
|
+ if len(parts) >= 3 {
|
||||||
|
+ var respIdx int
|
||||||
|
+ fmt.Sscanf(parts[2], "%d", &respIdx)
|
||||||
|
+ bot.sendCannedResponse(query, user, respIdx)
|
||||||
|
+ }
|
||||||
|
+ bot.DeletePendingUser(args)
|
||||||
|
+ bot.API.Request(api.NewCallback(query.ID, ""))
|
||||||
|
+ return
|
||||||
|
}
|
||||||
|
|
||||||
|
- bot.DeletePendingUser(args)
|
||||||
|
-
|
||||||
|
if bot.Config.DeleteRequestAfterDecision {
|
||||||
|
go bot.scheduleMessageDeletion(query.Message.Chat.ID, query.Message.MessageID, 10*time.Second)
|
||||||
|
}
|
||||||
|
@@ -93,14 +103,39 @@ func (bot *Bot) handleDeclineRequest(query *api.CallbackQuery, user *ExtendedCha
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
- utils.EditMessage(bot.API, query.Message.Chat.ID, query.Message.MessageID,
|
||||||
|
- fmt.Sprintf(AdminDeclinedMsg,
|
||||||
|
- userString, user.From.ID, user.JoinReason, adminUserString,
|
||||||
|
- time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
- defaultReason,
|
||||||
|
- ),
|
||||||
|
+ messageText := fmt.Sprintf(AdminDeclinedMsg,
|
||||||
|
+ userString, user.From.ID, user.JoinReason, adminUserString,
|
||||||
|
+ time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
+ defaultReason,
|
||||||
|
)
|
||||||
|
|
||||||
|
+ edit := api.NewEditMessageText(query.Message.Chat.ID, query.Message.MessageID, messageText)
|
||||||
|
+ edit.ParseMode = api.ModeHTML
|
||||||
|
+ edit.Entities = query.Message.Entities
|
||||||
|
+
|
||||||
|
+ if len(bot.Config.CannedDeclineResponses) > 0 {
|
||||||
|
+ var rows [][]api.InlineKeyboardButton
|
||||||
|
+ for i, response := range bot.Config.CannedDeclineResponses {
|
||||||
|
+ // Clean up the response text for button display
|
||||||
|
+ snippet := strings.TrimSpace(response)
|
||||||
|
+ snippet = strings.ReplaceAll(snippet, "\n", " ")
|
||||||
|
+ // Remove multiple consecutive spaces
|
||||||
|
+ for strings.Contains(snippet, " ") {
|
||||||
|
+ snippet = strings.ReplaceAll(snippet, " ", " ")
|
||||||
|
+ }
|
||||||
|
+ // Truncate to 30 chars for button text
|
||||||
|
+ if len(snippet) > 30 {
|
||||||
|
+ snippet = snippet[:30] + "..."
|
||||||
|
+ }
|
||||||
|
+ btn := api.NewInlineKeyboardButtonData(snippet, fmt.Sprintf("cannedrespsel_%d_%d", user.From.ID, i))
|
||||||
|
+ rows = append(rows, []api.InlineKeyboardButton{btn})
|
||||||
|
+ }
|
||||||
|
+ keyboard := api.NewInlineKeyboardMarkup(rows...)
|
||||||
|
+ edit.ReplyMarkup = &keyboard
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ bot.API.Send(edit)
|
||||||
|
+
|
||||||
|
bot.API.Request(api.NewCallback(query.ID, "Join request declined."))
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -175,12 +210,14 @@ func (bot *Bot) HandleDeclineReason(update *api.Update) {
|
||||||
|
userID, username, joinReason, declinedBy, declinedAt := utils.GetInfoFromMsg(repliedMsg.Text)
|
||||||
|
|
||||||
|
reason := utils.EscapeHTML(update.Message.Text)
|
||||||
|
- if strings.HasPrefix(update.Message.Text, "+") {
|
||||||
|
- reason = utils.EscapeHTML(update.Message.Text[1:])
|
||||||
|
+ if !strings.HasPrefix(update.Message.Text, "/") {
|
||||||
|
+ reason = utils.EscapeHTML(update.Message.Text)
|
||||||
|
utils.SendMessage(bot.API, userID, 0,
|
||||||
|
fmt.Sprintf("Your join request was declined for the following reason:\n\n%s", reason))
|
||||||
|
}
|
||||||
|
|
||||||
|
+ reason = strings.TrimPrefix(reason, "/")
|
||||||
|
+
|
||||||
|
utils.EditMessage(bot.API, update.Message.Chat.ID, repliedMsg.MessageID,
|
||||||
|
fmt.Sprintf(AdminDeclinedMsg, username, userID, joinReason, declinedBy, declinedAt, reason))
|
||||||
|
|
||||||
|
@@ -188,6 +225,26 @@ func (bot *Bot) HandleDeclineReason(update *api.Update) {
|
||||||
|
bot.API.Send(api.NewDeleteMessage(update.Message.Chat.ID, update.Message.MessageID))
|
||||||
|
}
|
||||||
|
|
||||||
|
+// sendCannedResponse sends a canned decline response to the declined user.
|
||||||
|
+func (bot *Bot) sendCannedResponse(query *api.CallbackQuery, user *ExtendedChatJoinRequest, respIdx int) {
|
||||||
|
+ if respIdx < 0 || respIdx >= len(bot.Config.CannedDeclineResponses) {
|
||||||
|
+ return
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ reason := utils.EscapeHTML(bot.Config.CannedDeclineResponses[respIdx])
|
||||||
|
+ utils.SendMessage(bot.API, user.From.ID, 0,
|
||||||
|
+ fmt.Sprintf("Your join request was declined for the following reason:\n\n%s", reason))
|
||||||
|
+
|
||||||
|
+ // Extract user info from original message and reformat with the canned response
|
||||||
|
+ userID, username, joinReason, declinedBy, declinedAt := utils.GetInfoFromMsg(query.Message.Text)
|
||||||
|
+
|
||||||
|
+ edit := api.NewEditMessageText(query.Message.Chat.ID, query.Message.MessageID,
|
||||||
|
+ fmt.Sprintf(AdminDeclinedMsg, username, userID, joinReason, declinedBy, declinedAt, reason))
|
||||||
|
+ edit.ParseMode = api.ModeHTML
|
||||||
|
+ edit.Entities = query.Message.Entities
|
||||||
|
+ bot.API.Send(edit)
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
// parseCallbackData parses the action and user ID from a callback query's data string.
|
||||||
|
func parseCallbackData(data string) (action string, userID int64, err error) {
|
||||||
|
normalized := strings.Join(strings.Split(data, "_"), " ")
|
||||||
|
|
||||||
|
--- a/handlers/handlers.go
|
||||||
|
+++ b/handlers/handlers.go
|
||||||
|
@@ -13,7 +13,7 @@ const (
|
||||||
|
AdminDeclinedMsg = "❌ Join #request declined for %s [<code>%d</code>]\n\n<b>Join reason</b>: %s\n<b>Declined by</b>: %s\n<b>Declined at</b>: %s\n<b>Declined reason</b>: %s"
|
||||||
|
AdminBannedMsg = "🚫 Join #request banned for %s [<code>%d</code>]\n\n<b>Join reason</b>: %s\n<b>Banned by</b>: %s\n<b>Banned at</b>: %s\n<b>Banned until</b>: %s"
|
||||||
|
AdminFailedMsg = "⚠️ Join #request failed for %s [<code>%d</code>]\n\n<b>Join reason</b>: %s\n<b>Failure reason</b>: %s"
|
||||||
|
- defaultReason = "(no reason provided, reply to this to set one, prepend with + to also send to user)"
|
||||||
|
+ defaultReason = "(no reason provided, reply to this message to send one to the user, prepend with / to just set it)"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Types shared by handler files
|
||||||
83
scripts/sync.sh
Executable file
83
scripts/sync.sh
Executable file
|
|
@ -0,0 +1,83 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# sync.sh — Copy telegram-approval-join submodule into internal/, then apply branding patches.
|
||||||
|
# Usage: ./scripts/sync.sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
|
||||||
|
SUBMODULE_DIR="$ROOT_DIR/telegram-approval-join"
|
||||||
|
PATCH_FILE="$ROOT_DIR/patches/0001-nuzzles.patch"
|
||||||
|
|
||||||
|
# ── 1. Ensure submodule is initialised ────────────────────────────────────────
|
||||||
|
echo "→ Updating submodule..."
|
||||||
|
|
||||||
|
# Capture the submodule commit before update
|
||||||
|
OLD_COMMIT=$(git -C "$SUBMODULE_DIR" rev-parse HEAD 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
# Update the submodule
|
||||||
|
git -C "$ROOT_DIR" submodule update --init --recursive --remote
|
||||||
|
|
||||||
|
# Capture the submodule commit after update
|
||||||
|
NEW_COMMIT=$(git -C "$SUBMODULE_DIR" rev-parse HEAD 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
# Check if there were any changes
|
||||||
|
# if [[ "$OLD_COMMIT" == "$NEW_COMMIT" ]] && [[ -n "$OLD_COMMIT" ]]; then
|
||||||
|
# echo " Submodule is already up to date. Nothing to do."
|
||||||
|
# exit 0
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# ── 2. Wipe and re-copy the submodule source ──────────────────────────────────
|
||||||
|
echo "→ Copying telegram-approval-join source to root..."
|
||||||
|
# Clean up directories that will be replaced
|
||||||
|
rm -rf "$ROOT_DIR/cmd" "$ROOT_DIR/internal" "$ROOT_DIR/Dockerfile" "$ROOT_DIR/go.mod" "$ROOT_DIR/go.sum" "$ROOT_DIR/config.yaml.example"
|
||||||
|
|
||||||
|
# Copy source files, excluding .git and keeping patches/ and scripts/
|
||||||
|
rsync -a --stats --exclude='.git' --exclude='internal/telegram-approval-join' \
|
||||||
|
"$SUBMODULE_DIR/" "$ROOT_DIR/" \
|
||||||
|
--exclude='patches' --exclude='scripts' --exclude='README.md'
|
||||||
|
|
||||||
|
# Remove scripts/ from .gitignore so we can track our sync script
|
||||||
|
sed -i '/^scripts\/$/d' "$ROOT_DIR/.gitignore"
|
||||||
|
|
||||||
|
# ── 3. Rewrite the Go module path inside the copied source ────────────────────
|
||||||
|
# Change the module from telegram-approval-join to telegram-approval-join-nuzzles
|
||||||
|
echo "→ Rewriting module path in go.mod ..."
|
||||||
|
sed -i "s|^module git\.zio\.sh/astra/telegram-approval-join|module git.zio.sh/astra/telegram-approval-join-nuzzles|" "$ROOT_DIR/go.mod"
|
||||||
|
|
||||||
|
# Fix all import references in the copied source
|
||||||
|
echo "→ Rewriting import paths in .go files ..."
|
||||||
|
find "$ROOT_DIR" -name '*.go' -not -path "*/telegram-approval-join/*" | xargs sed -i 's|git\.zio\.sh/astra/telegram-approval-join|git.zio.sh/astra/telegram-approval-join-nuzzles|g'
|
||||||
|
|
||||||
|
# ── 4. Apply branding string patch ────────────────────────────────────────────
|
||||||
|
if [[ -f "$PATCH_FILE" ]]; then
|
||||||
|
echo "→ Applying branding patch ..."
|
||||||
|
# Check if patch applies cleanly first (dry run)
|
||||||
|
if patch --dry-run -p1 -d "$ROOT_DIR" < "$PATCH_FILE" &>/dev/null; then
|
||||||
|
patch -p1 --no-backup-if-mismatch -d "$ROOT_DIR" < "$PATCH_FILE"
|
||||||
|
echo " Patch applied successfully."
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo "⚠️ Patch did not apply cleanly — telegram-approval-join may have changed."
|
||||||
|
echo " Run the following to see conflicts:"
|
||||||
|
echo " patch --dry-run -p1 -d $ROOT_DIR < $PATCH_FILE"
|
||||||
|
echo ""
|
||||||
|
echo " Update patches/branding.patch to match the new source, then re-run sync."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " No patch file found at patches/branding.patch — skipping."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 5. Verify it builds ───────────────────────────────────────────────────────
|
||||||
|
echo "→ Verifying build ..."
|
||||||
|
go build ./... 2>&1 && echo " Build OK." || { echo "❌ Build failed."; exit 1; }
|
||||||
|
|
||||||
|
# ── 6. Commit changes ─────────────────────────────────────────────────────────
|
||||||
|
echo "→ Committing changes..."
|
||||||
|
git -C "$ROOT_DIR" add -A
|
||||||
|
git -C "$ROOT_DIR" commit -m "Update telegram-approval-join submodule and apply branding patches" || true
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Sync complete. Root directory is up to date with telegram-approval-join (patched)."
|
||||||
1
telegram-approval-join
Submodule
1
telegram-approval-join
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 4e71c09c5a6a3f93bd4f0702b0e6f417b6e9e995
|
||||||
Loading…
Add table
Add a link
Reference in a new issue