diff --git a/main.go b/main.go
index 6418a6e..2b8970a 100644
--- a/main.go
+++ b/main.go
@@ -3,6 +3,7 @@ package main
import (
"fmt"
"log"
+ "strconv"
"strings"
"time"
@@ -10,9 +11,9 @@ import (
)
const (
- AdminJoinRequestMsg = "New join #request from _%s_\n\nJoin reason: %s"
- AdminApprovedMsg = "✅ Join #request approved for _%s_\n\nJoin reason: %s\nApproved by: %s\nApproved at: %s"
- AdminRejectedMsg = "❌ Join #request rejected for _%s_\n\nJoin reason: %s\nRejected by: %s\nRejected at: %s"
+ AdminJoinRequestMsg = "New join #request from %s [%d]\n\nJoin reason: %s"
+ AdminApprovedMsg = "✅ Join #request approved for %s [%d]\n\nJoin reason: %s\nApproved by: %s\nApproved at: %s"
+ AdminDeclinedMsg = "❌ Join #request declined for %s [%d]\n\nJoin reason: %s\nDeclined by: %s\nDeclined at: %s\nDeclined reason: %s"
)
type ExtendedChatJoinRequest struct {
@@ -51,7 +52,9 @@ func main() {
for update := range updatesChannel {
if update.ChatJoinRequest != nil {
- b.handleJoinRequest(update.ChatJoinRequest)
+ if update.ChatJoinRequest.Chat.ID == b.Config.TargetChatId {
+ b.handleJoinRequest(update.ChatJoinRequest)
+ }
continue
}
@@ -69,12 +72,33 @@ func main() {
b.handleJoinRequestResponse(user, update.Message)
}
}
+
+ if update.Message.Chat.ID == b.Config.AdminChatId && update.Message.ReplyToMessage != nil {
+ // handle admin declineion reason
+ repliedMsg := update.Message.ReplyToMessage
+ if strings.Contains(repliedMsg.Text, "(no reason provided, reply to this to send one)") {
+ // now we need to make sure the one that declined it is the one replying
+ lines := strings.Split(repliedMsg.Text, "\n")
+ if strings.TrimPrefix(lines[3], "Declined by: ") == update.Message.From.String() {
+
+ edit := api.NewEditMessageText(b.Config.AdminChatId, repliedMsg.MessageID,
+ strings.Replace(repliedMsg.Text, "(no reason provided, reply to this to send one)",
+ escapeHTML(update.Message.Text), 1))
+ edit.ParseMode = api.ModeHTML
+ b.API.Send(edit)
+ userID := GetUserIDFromMessage(repliedMsg.Text)
+ m := api.NewMessage(userID, fmt.Sprintf("Your join request was declined for the following reason:\n\n%s",
+ update.Message.Text))
+ b.API.Send(m)
+ }
+ }
+ }
}
}
func (bot *Bot) handleJoinRequestResponse(user *ExtendedChatJoinRequest, update *api.Message) {
if user.JoinReason == "" {
- user.JoinReason = escapeMarkdown(update.Text)
+ user.JoinReason = escapeHTML(update.Text)
userString := ""
if user.From.UserName != "" {
@@ -84,10 +108,10 @@ func (bot *Bot) handleJoinRequestResponse(user *ExtendedChatJoinRequest, update
}
edit := api.NewEditMessageText(bot.Config.AdminChatId, user.JoinRequestMessageID,
fmt.Sprintf(AdminJoinRequestMsg,
- userString, user.JoinReason))
+ userString, user.From.ID, user.JoinReason))
keyboard := newApprovalKeyboard(user.From.ID)
edit.ReplyMarkup = &keyboard
- edit.ParseMode = api.ModeMarkdown
+ edit.ParseMode = api.ModeHTML
bot.API.Send(edit)
ack := api.NewMessage(update.From.ID, "Thank you! Your request has been sent to the admins for review.")
@@ -99,31 +123,29 @@ func (bot *Bot) handleJoinRequestResponse(user *ExtendedChatJoinRequest, update
}
func (bot *Bot) handleJoinRequest(request *api.ChatJoinRequest) {
- if bot.Config.TargetChatId == request.Chat.ID {
- bot.WaitingForApproval[request.From.ID] = &ExtendedChatJoinRequest{
- ChatJoinRequest: request,
- JoinReason: "",
- }
- m := api.NewMessage(request.From.ID, bot.Config.EntryMessage)
- m.ParseMode = api.ModeMarkdown
- bot.API.Send(m)
-
- userString := ""
- if request.From.UserName != "" {
- userString = "@" + request.From.UserName
- } else {
- userString = fmt.Sprintf("%s %s (no username)", request.From.FirstName, request.From.LastName)
- }
- m = api.NewMessage(bot.Config.AdminChatId,
- fmt.Sprintf(AdminJoinRequestMsg, userString, "(awaiting user response)"))
- m.ReplyMarkup = newApprovalKeyboard(request.From.ID)
- m.ParseMode = api.ModeMarkdown
- if bot.Config.AdminChatTopicId != 0 {
- m.MessageThreadID = bot.Config.AdminChatTopicId
- }
- r, _ := bot.API.Send(m)
- bot.WaitingForApproval[request.From.ID].JoinRequestMessageID = r.MessageID
+ bot.WaitingForApproval[request.From.ID] = &ExtendedChatJoinRequest{
+ ChatJoinRequest: request,
+ JoinReason: "",
}
+ m := api.NewMessage(request.From.ID, bot.Config.EntryMessage)
+ m.ParseMode = api.ModeHTML
+ bot.API.Send(m)
+
+ userString := ""
+ if request.From.UserName != "" {
+ userString = "@" + request.From.UserName
+ } else {
+ userString = fmt.Sprintf("%s %s (no username)", request.From.FirstName, request.From.LastName)
+ }
+ m = api.NewMessage(bot.Config.AdminChatId,
+ fmt.Sprintf(AdminJoinRequestMsg, userString, request.From.ID, "(awaiting user response)"))
+ m.ReplyMarkup = newApprovalKeyboard(request.From.ID)
+ m.ParseMode = api.ModeHTML
+ if bot.Config.AdminChatTopicId != 0 {
+ m.MessageThreadID = bot.Config.AdminChatTopicId
+ }
+ r, _ := bot.API.Send(m)
+ bot.WaitingForApproval[request.From.ID].JoinRequestMessageID = r.MessageID
}
func (bot *Bot) handleCallbackQuery(query *api.CallbackQuery) {
@@ -162,17 +184,20 @@ func (bot *Bot) handleCallbackQuery(query *api.CallbackQuery) {
}
edit := api.NewEditMessageText(bot.Config.AdminChatId, user.JoinRequestMessageID,
fmt.Sprintf(AdminApprovedMsg,
- userString, user.JoinReason, query.From.String(), time.Now().Format("2006-01-02 15:04:05")))
- edit.ParseMode = api.ModeMarkdown
+ userString, user.From.ID, user.JoinReason, query.From.String(), time.Now().Format("2006-01-02 15:04:05")))
+ edit.ParseMode = api.ModeHTML
bot.API.Send(edit)
if bot.Config.ApprovalMessage != "" {
m := api.NewMessage(user.From.ID, bot.Config.ApprovalMessage)
- m.ParseMode = api.ModeMarkdown
+ m.ParseMode = api.ModeHTML
bot.API.Send(m)
}
- case "reject":
+ callback := api.NewCallback(query.ID, "Join request approved.")
+ bot.API.Request(callback)
+
+ case "decline":
r := api.DeclineChatJoinRequest{
ChatConfig: api.ChatConfig{
ChatID: user.ChatJoinRequest.Chat.ID,
@@ -188,10 +213,13 @@ func (bot *Bot) handleCallbackQuery(query *api.CallbackQuery) {
userString = fmt.Sprintf("%s %s (no username)", user.From.FirstName, user.From.LastName)
}
edit := api.NewEditMessageText(bot.Config.AdminChatId, user.JoinRequestMessageID,
- fmt.Sprintf(AdminRejectedMsg,
- userString, user.JoinReason, query.From.String(), time.Now().Format("2006-01-02 15:04:05")))
- edit.ParseMode = api.ModeMarkdown
+ fmt.Sprintf(AdminDeclinedMsg,
+ userString, user.From.ID, user.JoinReason, query.From.String(), time.Now().Format("2006-01-02 15:04:05"), "(no reason provided, reply to this to send one)"))
+ edit.ParseMode = api.ModeHTML
bot.API.Send(edit)
+
+ callback := api.NewCallback(query.ID, "Join request declined.")
+ bot.API.Request(callback)
}
delete(bot.WaitingForApproval, userId)
@@ -210,8 +238,28 @@ func escapeMarkdown(s string) string {
return replacer.Replace(s)
}
-func newApprovalKeyboard(userID int64) api.InlineKeyboardMarkup {
- approveBtn := api.NewInlineKeyboardButtonData("✅ Approve", fmt.Sprintf("approve_%d", userID))
- rejectBtn := api.NewInlineKeyboardButtonData("❌ Reject", fmt.Sprintf("reject_%d", userID))
- return api.NewInlineKeyboardMarkup([]api.InlineKeyboardButton{approveBtn, rejectBtn})
+func escapeHTML(s string) string {
+ toEscape := []string{"&", "<", ">", "\"", "'"}
+
+ replacements := make([]string, 0, len(toEscape)*2)
+ replacements = append(replacements, "&", "&")
+ replacements = append(replacements, "<", "<")
+ replacements = append(replacements, ">", ">")
+ replacements = append(replacements, "\"", """)
+
+ replacer := strings.NewReplacer(replacements...)
+ return replacer.Replace(s)
+}
+
+func newApprovalKeyboard(userID int64) api.InlineKeyboardMarkup {
+ approveBtn := api.NewInlineKeyboardButtonData("Approve", fmt.Sprintf("approve_%d", userID))
+ declineBtn := api.NewInlineKeyboardButtonData("Decline", fmt.Sprintf("decline_%d", userID))
+ return api.NewInlineKeyboardMarkup([]api.InlineKeyboardButton{approveBtn, declineBtn})
+}
+
+func GetUserIDFromMessage(msg string) int64 {
+ start := strings.Index(msg, "[")
+ end := strings.Index(msg, "]")
+ num, _ := strconv.Atoi(msg[start+1 : end])
+ return int64(num)
}