Update telegram-approval-join submodule and apply branding patches

This commit is contained in:
Astra 2026-03-09 20:53:04 +00:00
parent 015f99dc83
commit 8aa8521304
5 changed files with 80 additions and 21 deletions

View file

@ -8,14 +8,15 @@ import (
) )
type Config struct { type Config struct {
BotToken *string `yaml:"bot_token"` BotToken *string `yaml:"bot_token"`
AdminChatId *int64 `yaml:"admin_chat_id"` AdminChatId *int64 `yaml:"admin_chat_id"`
AdminChatTopicId *int `yaml:"admin_chat_topic_id"` AdminChatTopicId *int `yaml:"admin_chat_topic_id"`
TargetChatId *int64 `yaml:"target_chat_id"` TargetChatId *int64 `yaml:"target_chat_id"`
EntryMessage string `yaml:"entry_message"` EntryMessage string `yaml:"entry_message"`
ApprovalMessage string `yaml:"approval_message"` ApprovalMessage string `yaml:"approval_message"`
SendApprovalMessage bool `yaml:"send_approval_message"` SendApprovalMessage bool `yaml:"send_approval_message"`
DeleteRequestAfterDecision bool `yaml:"delete_request_after_decision"` DeleteRequestAfterDecision bool `yaml:"delete_request_after_decision"`
CannedDeclineResponses []string `yaml:"canned_decline_responses"`
} }
func (c *Config) LoadConfig() error { func (c *Config) LoadConfig() error {
@ -47,6 +48,7 @@ func (c *Config) CreateConfig() error {
ApprovalMessage: "", ApprovalMessage: "",
SendApprovalMessage: false, SendApprovalMessage: false,
DeleteRequestAfterDecision: false, DeleteRequestAfterDecision: false,
CannedDeclineResponses: []string{},
} }
encoder := yaml.NewEncoder(f) encoder := yaml.NewEncoder(f)

View file

@ -36,6 +36,7 @@ func (bot *Bot) HandleCallbackQuery(query *api.CallbackQuery) {
switch action { switch action {
case "approve": case "approve":
bot.handleApproveRequest(query, user, userString, adminUserString) bot.handleApproveRequest(query, user, userString, adminUserString)
bot.DeletePendingUser(args)
case "decline": case "decline":
bot.handleDeclineRequest(query, user, userString, adminUserString) bot.handleDeclineRequest(query, user, userString, adminUserString)
case "ban": case "ban":
@ -44,10 +45,19 @@ func (bot *Bot) HandleCallbackQuery(query *api.CallbackQuery) {
return return
case "banc": case "banc":
bot.handleBanRequest(query, user, userString, adminUserString) 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 { if bot.Config.DeleteRequestAfterDecision {
go bot.scheduleMessageDeletion(query.Message.Chat.ID, query.Message.MessageID, 10*time.Second) 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 return
} }
utils.EditMessage(bot.API, query.Message.Chat.ID, query.Message.MessageID, messageText := fmt.Sprintf(AdminDeclinedMsg,
fmt.Sprintf(AdminDeclinedMsg, userString, user.From.ID, user.JoinReason, adminUserString,
userString, user.From.ID, user.JoinReason, adminUserString, time.Now().Format("2006-01-02 15:04:05"),
time.Now().Format("2006-01-02 15:04:05"), defaultReason,
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.")) 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) userID, username, joinReason, declinedBy, declinedAt := utils.GetInfoFromMsg(repliedMsg.Text)
reason := utils.EscapeHTML(update.Message.Text) reason := utils.EscapeHTML(update.Message.Text)
if strings.HasPrefix(update.Message.Text, "+") { if !strings.HasPrefix(update.Message.Text, "/") {
reason = utils.EscapeHTML(update.Message.Text[1:]) reason = utils.EscapeHTML(update.Message.Text)
utils.SendMessage(bot.API, userID, 0, utils.SendMessage(bot.API, userID, 0,
fmt.Sprintf("Your join request was declined for the following reason:\n\n%s", reason)) 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, utils.EditMessage(bot.API, update.Message.Chat.ID, repliedMsg.MessageID,
fmt.Sprintf(AdminDeclinedMsg, username, userID, joinReason, declinedBy, declinedAt, reason)) 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)) 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. // parseCallbackData parses the action and user ID from a callback query's data string.
func parseCallbackData(data string) (action string, userID int64, err error) { func parseCallbackData(data string) (action string, userID int64, err error) {
normalized := strings.Join(strings.Split(data, "_"), " ") normalized := strings.Join(strings.Split(data, "_"), " ")

View file

@ -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" 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" 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" 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 // Types shared by handler files

View file

@ -63,11 +63,11 @@ if [[ -f "$PATCH_FILE" ]]; then
echo " Run the following to see conflicts:" echo " Run the following to see conflicts:"
echo " patch --dry-run -p1 -d $ROOT_DIR < $PATCH_FILE" echo " patch --dry-run -p1 -d $ROOT_DIR < $PATCH_FILE"
echo "" echo ""
echo " Update patches/branding.patch to match the new source, then re-run sync." echo " Update patches/0001-nuzzles.patch to match the new source, then re-run sync."
exit 1 exit 1
fi fi
else else
echo " No patch file found at patches/branding.patch — skipping." echo " No patch file found at patches/0001-nuzzles.patch — skipping."
fi fi
# ── 5. Verify it builds ─────────────────────────────────────────────────────── # ── 5. Verify it builds ───────────────────────────────────────────────────────