code refactor
This commit is contained in:
parent
7275b93666
commit
d157f9b2c9
6 changed files with 187 additions and 193 deletions
|
|
@ -19,12 +19,10 @@ func (bot *Bot) HandleAdminCommands(update *api.Update) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_, e := utils.SendMessage(bot.API, bot.API.Self.ID, 0, update.Message.CommandArguments())
|
_, e := utils.SendMessage(bot.API, bot.API.Self.ID, 0, update.Message.CommandArguments())
|
||||||
if e != nil {
|
if e != nil && strings.HasPrefix(e.Error(), "Bad Request:") {
|
||||||
if strings.HasPrefix(e.Error(), "Bad Request:") {
|
utils.SendMessage(bot.API, update.Message.Chat.ID, update.Message.MessageThreadID,
|
||||||
utils.SendMessage(bot.API, update.Message.Chat.ID, update.Message.MessageThreadID,
|
fmt.Sprintf("Unable to set entry message: <code>%s</code>", e))
|
||||||
fmt.Sprintf("Unable to set entry message: <code>%s</code>", e))
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.Config.EntryMessage = update.Message.CommandArguments()
|
bot.Config.EntryMessage = update.Message.CommandArguments()
|
||||||
|
|
@ -57,23 +55,19 @@ func (bot *Bot) HandleAdminCommands(update *api.Update) {
|
||||||
update.Message.Chat.ID, topicID))
|
update.Message.Chat.ID, topicID))
|
||||||
|
|
||||||
case "togglesendapproval":
|
case "togglesendapproval":
|
||||||
if bot.Config.ApprovalMessage != "" {
|
if bot.Config.ApprovalMessage == "" {
|
||||||
switch bot.Config.SendApprovalMessage {
|
|
||||||
case true:
|
|
||||||
bot.Config.SendApprovalMessage = false
|
|
||||||
case false:
|
|
||||||
bot.Config.SendApprovalMessage = true
|
|
||||||
}
|
|
||||||
if err := bot.Config.SaveConfig(); err != nil {
|
|
||||||
log.Printf("Failed to save config: %v", err)
|
|
||||||
}
|
|
||||||
utils.SendMessage(bot.API, update.Message.Chat.ID, update.Message.MessageThreadID,
|
|
||||||
fmt.Sprintf("Send approval message: %v", bot.Config.SendApprovalMessage))
|
|
||||||
} else {
|
|
||||||
utils.SendMessage(bot.API, update.Message.Chat.ID, update.Message.MessageThreadID,
|
utils.SendMessage(bot.API, update.Message.Chat.ID, update.Message.MessageThreadID,
|
||||||
"Please set an approval message with <code>/setapprovalmessage</code>")
|
"Please set an approval message with <code>/setapprovalmessage</code>")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bot.Config.SendApprovalMessage = !bot.Config.SendApprovalMessage
|
||||||
|
if err := bot.Config.SaveConfig(); err != nil {
|
||||||
|
log.Printf("Failed to save config: %v", err)
|
||||||
|
}
|
||||||
|
utils.SendMessage(bot.API, update.Message.Chat.ID, update.Message.MessageThreadID,
|
||||||
|
fmt.Sprintf("Send approval message: %v", bot.Config.SendApprovalMessage))
|
||||||
|
|
||||||
case "setapprovalmessage":
|
case "setapprovalmessage":
|
||||||
if update.Message.CommandArguments() == "" {
|
if update.Message.CommandArguments() == "" {
|
||||||
utils.SendMessage(bot.API, update.Message.Chat.ID, update.Message.MessageThreadID,
|
utils.SendMessage(bot.API, update.Message.Chat.ID, update.Message.MessageThreadID,
|
||||||
|
|
@ -93,12 +87,14 @@ func (bot *Bot) HandleAdminCommands(update *api.Update) {
|
||||||
if *bot.Config.TargetChatId != 0 {
|
if *bot.Config.TargetChatId != 0 {
|
||||||
targetChatID = fmt.Sprintf("%d", *bot.Config.TargetChatId)
|
targetChatID = fmt.Sprintf("%d", *bot.Config.TargetChatId)
|
||||||
}
|
}
|
||||||
infoMsg := fmt.Sprintf("%s\n%s\n%s\n%s\n%s",
|
utils.SendMessage(bot.API, update.Message.Chat.ID, update.Message.MessageThreadID,
|
||||||
fmt.Sprintf("Admin Chat ID: <b>%d</b>", update.Message.Chat.ID),
|
fmt.Sprintf(
|
||||||
fmt.Sprintf("Admin Topic ID: <b>%d</b>", *bot.Config.AdminChatTopicId),
|
"Admin Chat ID: <b>%d</b>\nAdmin Topic ID: <b>%d</b>\nTarget Chat ID: <b>%s</b>\nEntry Message: %s\nApproval Message: %s",
|
||||||
fmt.Sprintf("Target Chat ID: <b>%s</b>", targetChatID),
|
update.Message.Chat.ID,
|
||||||
fmt.Sprintf("Entry Message: %s", bot.Config.EntryMessage),
|
*bot.Config.AdminChatTopicId,
|
||||||
fmt.Sprintf("Approval Message: %s", bot.Config.ApprovalMessage))
|
targetChatID,
|
||||||
utils.SendMessage(bot.API, update.Message.Chat.ID, update.Message.MessageThreadID, infoMsg)
|
bot.Config.EntryMessage,
|
||||||
|
bot.Config.ApprovalMessage,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,37 +12,21 @@ import (
|
||||||
|
|
||||||
// HandleCallbackQuery processes inline button callbacks (approve/decline/leave).
|
// HandleCallbackQuery processes inline button callbacks (approve/decline/leave).
|
||||||
func (bot *Bot) HandleCallbackQuery(query *api.CallbackQuery) {
|
func (bot *Bot) HandleCallbackQuery(query *api.CallbackQuery) {
|
||||||
data := strings.Join(strings.Split(query.Data, "_"), " ")
|
action, args, err := parseCallbackData(query.Data)
|
||||||
var action string
|
|
||||||
var args int64
|
|
||||||
_, err := fmt.Sscanf(data, "%s %d", &action, &args)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to parse callback data: %v", err)
|
log.Printf("Failed to parse callback data: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if action == "leave" {
|
if action == "leave" {
|
||||||
utils.LeaveChatRequest(bot.API, []int64{args})
|
bot.handleLeaveAction(query, args)
|
||||||
utils.EditMessage(bot.API, query.Message.Chat.ID, query.Message.MessageID,
|
|
||||||
fmt.Sprintf("We have left chat <i>%d</i>", args))
|
|
||||||
callback := api.NewCallback(query.ID, "")
|
|
||||||
bot.API.Request(callback)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user := bot.GetPendingUser(args)
|
user := bot.GetPendingUser(args)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
log.Printf("No pending request for user ID %d", args)
|
log.Printf("No pending request for user ID %d", args)
|
||||||
msg := api.NewMessage(query.Message.Chat.ID, "Unable to find user, bot may have restarted")
|
bot.handleMissingUser(query)
|
||||||
msg.ReplyParameters = api.ReplyParameters{MessageID: query.Message.MessageID, ChatID: query.Message.Chat.ID}
|
|
||||||
r, _ := bot.API.Send(msg)
|
|
||||||
|
|
||||||
edit := api.NewEditMessageText(query.Message.Chat.ID, r.ReplyToMessage.MessageID, r.ReplyToMessage.Text)
|
|
||||||
edit.Entities = r.ReplyToMessage.Entities
|
|
||||||
bot.API.Send(edit)
|
|
||||||
|
|
||||||
callback := api.NewCallback(query.ID, "")
|
|
||||||
bot.API.Request(callback)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,98 +40,83 @@ func (bot *Bot) HandleCallbackQuery(query *api.CallbackQuery) {
|
||||||
bot.handleDeclineRequest(query, user, userString, adminUserString)
|
bot.handleDeclineRequest(query, user, userString, adminUserString)
|
||||||
}
|
}
|
||||||
|
|
||||||
if bot.Config.DeleteRequestAfterDecision {
|
|
||||||
deleteTimer := time.NewTimer(10 * time.Second)
|
|
||||||
go func() {
|
|
||||||
defer deleteTimer.Stop()
|
|
||||||
<-deleteTimer.C
|
|
||||||
del := api.NewDeleteMessage(query.Message.Chat.ID, query.Message.MessageID)
|
|
||||||
bot.API.Send(del)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.DeletePendingUser(args)
|
bot.DeletePendingUser(args)
|
||||||
|
|
||||||
|
if bot.Config.DeleteRequestAfterDecision {
|
||||||
|
go bot.scheduleMessageDeletion(query.Message.Chat.ID, query.Message.MessageID, 10*time.Second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleApproveRequest approves a join request and sends approval callback.
|
// handleApproveRequest approves a join request and sends an approval callback.
|
||||||
func (bot *Bot) handleApproveRequest(query *api.CallbackQuery, user *ExtendedChatJoinRequest, userString, adminUserString string) {
|
func (bot *Bot) handleApproveRequest(query *api.CallbackQuery, user *ExtendedChatJoinRequest, userString, adminUserString string) {
|
||||||
r := api.ApproveChatJoinRequestConfig{
|
r := api.ApproveChatJoinRequestConfig{
|
||||||
ChatConfig: api.ChatConfig{
|
ChatConfig: api.ChatConfig{ChatID: user.ChatJoinRequest.Chat.ID},
|
||||||
ChatID: user.ChatJoinRequest.Chat.ID,
|
UserID: user.ChatJoinRequest.From.ID,
|
||||||
},
|
|
||||||
UserID: user.ChatJoinRequest.From.ID,
|
|
||||||
}
|
}
|
||||||
_, e := bot.API.Request(r)
|
|
||||||
if e != nil {
|
if _, err := bot.API.Request(r); err != nil {
|
||||||
log.Println(e.Error())
|
log.Println(err)
|
||||||
edit := api.NewEditMessageText(query.Message.Chat.ID, query.Message.MessageID, query.Message.Text)
|
bot.restoreMessage(query)
|
||||||
edit.Entities = query.Message.Entities
|
|
||||||
bot.API.Send(edit)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.EditMessage(bot.API, query.Message.Chat.ID, query.Message.MessageID,
|
utils.EditMessage(bot.API, query.Message.Chat.ID, query.Message.MessageID,
|
||||||
fmt.Sprintf(AdminApprovedMsg,
|
fmt.Sprintf(AdminApprovedMsg,
|
||||||
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"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
if bot.Config.SendApprovalMessage {
|
if bot.Config.SendApprovalMessage {
|
||||||
utils.SendMessage(bot.API, user.From.ID, 0, bot.Config.ApprovalMessage)
|
utils.SendMessage(bot.API, user.From.ID, 0, bot.Config.ApprovalMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
callback := api.NewCallback(query.ID, "Join request approved.")
|
bot.API.Request(api.NewCallback(query.ID, "Join request approved."))
|
||||||
bot.API.Request(callback)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleDeclineRequest declines a join request and sends decline callback.
|
// handleDeclineRequest declines a join request and sends a decline callback.
|
||||||
func (bot *Bot) handleDeclineRequest(query *api.CallbackQuery, user *ExtendedChatJoinRequest, userString, adminUserString string) {
|
func (bot *Bot) handleDeclineRequest(query *api.CallbackQuery, user *ExtendedChatJoinRequest, userString, adminUserString string) {
|
||||||
r := api.DeclineChatJoinRequest{
|
r := api.DeclineChatJoinRequest{
|
||||||
ChatConfig: api.ChatConfig{
|
ChatConfig: api.ChatConfig{ChatID: user.ChatJoinRequest.Chat.ID},
|
||||||
ChatID: user.ChatJoinRequest.Chat.ID,
|
UserID: user.ChatJoinRequest.From.ID,
|
||||||
},
|
|
||||||
UserID: user.ChatJoinRequest.From.ID,
|
|
||||||
}
|
}
|
||||||
_, e := bot.API.Request(r)
|
|
||||||
if e != nil {
|
if _, err := bot.API.Request(r); err != nil {
|
||||||
log.Println(e.Error())
|
log.Println(err)
|
||||||
edit := api.NewEditMessageText(query.Message.Chat.ID, query.Message.MessageID, query.Message.Text)
|
bot.restoreMessage(query)
|
||||||
edit.Entities = query.Message.Entities
|
|
||||||
bot.API.Send(edit)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.EditMessage(bot.API, query.Message.Chat.ID, query.Message.MessageID,
|
utils.EditMessage(bot.API, query.Message.Chat.ID, query.Message.MessageID,
|
||||||
fmt.Sprintf(AdminDeclinedMsg, userString, user.From.ID, user.JoinReason, adminUserString,
|
fmt.Sprintf(AdminDeclinedMsg,
|
||||||
|
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"),
|
||||||
"(no reason provided, reply to this to set one, prepend with + to also send to user)"),
|
defaultReason,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
callback := api.NewCallback(query.ID, "Join request declined.")
|
bot.API.Request(api.NewCallback(query.ID, "Join request declined."))
|
||||||
bot.API.Request(callback)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleDeclineReason allows admins to provide a decline reason by replying to decline messages.
|
// HandleDeclineReason allows admins to provide a decline reason by replying to decline messages.
|
||||||
func (bot *Bot) HandleDeclineReason(update *api.Update) {
|
func (bot *Bot) HandleDeclineReason(update *api.Update) {
|
||||||
repliedMsg := update.Message.ReplyToMessage
|
repliedMsg := update.Message.ReplyToMessage
|
||||||
if !strings.Contains(repliedMsg.Text,
|
if !strings.Contains(repliedMsg.Text, defaultReason) {
|
||||||
"(no reason provided, reply to this to set one, prepend with + to also send to user)") {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := strings.Split(repliedMsg.Text, "\n")
|
lines := strings.Split(repliedMsg.Text, "\n")
|
||||||
userString := utils.BuildUserString(update.Message.From)
|
userString := utils.BuildUserString(update.Message.From)
|
||||||
|
|
||||||
if strings.TrimPrefix(lines[3], "Declined by: ") != userString {
|
if strings.TrimPrefix(lines[3], "Declined by: ") != userString {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
reason := utils.EscapeHTML(update.Message.Text)
|
|
||||||
userID, username, joinReason, declinedBy, declinedAt := utils.GetInfoFromMsg(repliedMsg.Text)
|
userID, username, joinReason, declinedBy, declinedAt := utils.GetInfoFromMsg(repliedMsg.Text)
|
||||||
entities, _ := utils.FilterEntitiesByTypeWithContext(repliedMsg, "italic")
|
if entities, _ := utils.FilterEntitiesByTypeWithContext(repliedMsg, "italic"); len(entities) >= 1 {
|
||||||
if len(entities) >= 1 {
|
|
||||||
username = fmt.Sprintf("<i>%s</i>", entities[0].Text)
|
username = fmt.Sprintf("<i>%s</i>", entities[0].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[1:])
|
||||||
utils.SendMessage(bot.API, userID, 0,
|
utils.SendMessage(bot.API, userID, 0,
|
||||||
|
|
@ -157,3 +126,49 @@ func (bot *Bot) HandleDeclineReason(update *api.Update) {
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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, "_"), " ")
|
||||||
|
_, err = fmt.Sscanf(normalized, "%s %d", &action, &userID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleLeaveAction handles the "leave" callback by leaving the specified chat.
|
||||||
|
func (bot *Bot) handleLeaveAction(query *api.CallbackQuery, chatID int64) {
|
||||||
|
utils.LeaveChatRequest(bot.API, []int64{chatID})
|
||||||
|
utils.EditMessage(bot.API, query.Message.Chat.ID, query.Message.MessageID,
|
||||||
|
fmt.Sprintf("We have left chat <i>%d</i>", chatID))
|
||||||
|
bot.API.Request(api.NewCallback(query.ID, ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleMissingUser notifies the admin that the user's pending request could not be found.
|
||||||
|
func (bot *Bot) handleMissingUser(query *api.CallbackQuery) {
|
||||||
|
msg := api.NewMessage(query.Message.Chat.ID, "Unable to find user, bot may have restarted")
|
||||||
|
msg.ReplyParameters = api.ReplyParameters{
|
||||||
|
MessageID: query.Message.MessageID,
|
||||||
|
ChatID: query.Message.Chat.ID,
|
||||||
|
}
|
||||||
|
r, _ := bot.API.Send(msg)
|
||||||
|
|
||||||
|
edit := api.NewEditMessageText(query.Message.Chat.ID, r.ReplyToMessage.MessageID, r.ReplyToMessage.Text)
|
||||||
|
edit.Entities = r.ReplyToMessage.Entities
|
||||||
|
bot.API.Send(edit)
|
||||||
|
|
||||||
|
bot.API.Request(api.NewCallback(query.ID, ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
// restoreMessage restores a message to its original state after a failed API request.
|
||||||
|
func (bot *Bot) restoreMessage(query *api.CallbackQuery) {
|
||||||
|
edit := api.NewEditMessageText(query.Message.Chat.ID, query.Message.MessageID, query.Message.Text)
|
||||||
|
edit.Entities = query.Message.Entities
|
||||||
|
bot.API.Send(edit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scheduleMessageDeletion deletes a message after a given delay.
|
||||||
|
func (bot *Bot) scheduleMessageDeletion(chatID int64, messageID int, delay time.Duration) {
|
||||||
|
timer := time.NewTimer(delay)
|
||||||
|
defer timer.Stop()
|
||||||
|
<-timer.C
|
||||||
|
bot.API.Send(api.NewDeleteMessage(chatID, messageID))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ const (
|
||||||
AdminApprovedMsg = "✅ Join #request approved for %s [<code>%d</code>]\n\n<b>Join reason</b>: %s\n<b>Approved by</b>: %s\n<b>Approved at</b>: %s"
|
AdminApprovedMsg = "✅ Join #request approved for %s [<code>%d</code>]\n\n<b>Join reason</b>: %s\n<b>Approved by</b>: %s\n<b>Approved at</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"
|
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"
|
||||||
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)"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Types shared by handler files
|
// Types shared by handler files
|
||||||
|
|
@ -32,20 +33,13 @@ type Bot struct {
|
||||||
func (bot *Bot) GetPendingUser(userID int64) *ExtendedChatJoinRequest {
|
func (bot *Bot) GetPendingUser(userID int64) *ExtendedChatJoinRequest {
|
||||||
bot.mu.RLock()
|
bot.mu.RLock()
|
||||||
defer bot.mu.RUnlock()
|
defer bot.mu.RUnlock()
|
||||||
user := bot.WaitingForApproval[userID]
|
return bot.WaitingForApproval[userID]
|
||||||
if user == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return user
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPendingUser stores a pending user request (write-safe).
|
// SetPendingUser stores a pending user request (write-safe).
|
||||||
func (bot *Bot) SetPendingUser(userID int64, user *ExtendedChatJoinRequest) {
|
func (bot *Bot) SetPendingUser(userID int64, user *ExtendedChatJoinRequest) {
|
||||||
bot.mu.Lock()
|
bot.mu.Lock()
|
||||||
defer bot.mu.Unlock()
|
defer bot.mu.Unlock()
|
||||||
if _, ok := bot.WaitingForApproval[userID]; !ok {
|
|
||||||
bot.WaitingForApproval = make(map[int64]*ExtendedChatJoinRequest)
|
|
||||||
}
|
|
||||||
bot.WaitingForApproval[userID] = user
|
bot.WaitingForApproval[userID] = user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,35 +10,23 @@ import (
|
||||||
|
|
||||||
// HandleJoinRequestResponse records the user's join reason and notifies admins.
|
// HandleJoinRequestResponse records the user's join reason and notifies admins.
|
||||||
func (bot *Bot) HandleJoinRequestResponse(user *ExtendedChatJoinRequest, update *api.Message) {
|
func (bot *Bot) HandleJoinRequestResponse(user *ExtendedChatJoinRequest, update *api.Message) {
|
||||||
if user.JoinReason == "" {
|
if user.JoinReason != "" {
|
||||||
user.JoinReason = utils.EscapeHTML(update.Text)
|
|
||||||
userString := utils.BuildUserString(&user.From)
|
|
||||||
|
|
||||||
keyboard := utils.NewApprovalKeyboard(user.From.ID)
|
|
||||||
utils.EditMessageWithKeyboard(bot.API, *bot.Config.AdminChatId, user.JoinRequestMessageID,
|
|
||||||
fmt.Sprintf(AdminJoinRequestMsg,
|
|
||||||
userString, user.From.ID, user.JoinReason), &keyboard)
|
|
||||||
|
|
||||||
utils.SendMessage(bot.API, update.From.ID, 0, "Thank you! Your request has been sent to the admins for review.")
|
|
||||||
} else {
|
|
||||||
utils.SendMessage(bot.API, update.From.ID, 0, "Your request is already pending approval.")
|
utils.SendMessage(bot.API, update.From.ID, 0, "Your request is already pending approval.")
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleJoinRequest initiates join approval flow by sending entry message and admin notification.
|
|
||||||
func (bot *Bot) HandleJoinRequest(request *api.ChatJoinRequest) {
|
|
||||||
// if chat is not in config, ignore
|
|
||||||
if *bot.Config.TargetChatId != request.Chat.ID {
|
|
||||||
m := api.NewMessage(*bot.Config.AdminChatId,
|
|
||||||
fmt.Sprintf("Received join request for chat %s (<code>%d</code>), but it's not in config, ignoring",
|
|
||||||
request.Chat.Title, request.Chat.ID))
|
|
||||||
leaveBtn := api.NewInlineKeyboardButtonData("Leave Chat", fmt.Sprintf("leave_%d", request.Chat.ID))
|
|
||||||
m.ReplyMarkup = api.NewInlineKeyboardMarkup([]api.InlineKeyboardButton{leaveBtn})
|
|
||||||
m.ParseMode = api.ModeHTML
|
|
||||||
bot.API.Send(m)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user.JoinReason = utils.EscapeHTML(update.Text)
|
||||||
|
userString := utils.BuildUserString(&user.From)
|
||||||
|
|
||||||
|
keyboard := utils.NewApprovalKeyboard(user.From.ID)
|
||||||
|
utils.EditMessageWithKeyboard(bot.API, *bot.Config.AdminChatId, user.JoinRequestMessageID,
|
||||||
|
fmt.Sprintf(AdminJoinRequestMsg, userString, user.From.ID, user.JoinReason), &keyboard)
|
||||||
|
|
||||||
|
utils.SendMessage(bot.API, update.From.ID, 0, "Thank you! Your request has been sent to the admins for review.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleJoinRequest initiates the join approval flow by sending the entry message and admin notification.
|
||||||
|
func (bot *Bot) HandleJoinRequest(request *api.ChatJoinRequest) {
|
||||||
utils.SendMessage(bot.API, request.From.ID, 0, bot.Config.EntryMessage)
|
utils.SendMessage(bot.API, request.From.ID, 0, bot.Config.EntryMessage)
|
||||||
userString := utils.BuildUserString(&request.From)
|
userString := utils.BuildUserString(&request.From)
|
||||||
|
|
||||||
|
|
@ -49,6 +37,7 @@ func (bot *Bot) HandleJoinRequest(request *api.ChatJoinRequest) {
|
||||||
if topic := *bot.Config.AdminChatTopicId; topic != 0 {
|
if topic := *bot.Config.AdminChatTopicId; topic != 0 {
|
||||||
m.MessageThreadID = topic
|
m.MessageThreadID = topic
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := bot.API.Send(m)
|
r, err := bot.API.Send(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to send join request to admin chat: %v", err)
|
log.Printf("Failed to send join request to admin chat: %v", err)
|
||||||
|
|
@ -66,7 +55,5 @@ func (bot *Bot) HandleJoinRequest(request *api.ChatJoinRequest) {
|
||||||
func (bot *Bot) SendFailureMessage(user *ExtendedChatJoinRequest, query *api.CallbackQuery, userString string) {
|
func (bot *Bot) SendFailureMessage(user *ExtendedChatJoinRequest, query *api.CallbackQuery, userString string) {
|
||||||
utils.EditMessage(bot.API, *bot.Config.AdminChatId, user.JoinRequestMessageID,
|
utils.EditMessage(bot.API, *bot.Config.AdminChatId, user.JoinRequestMessageID,
|
||||||
fmt.Sprintf(AdminFailedMsg, userString, user.From.ID, utils.EscapeHTML(user.JoinReason), "User not found in requests."))
|
fmt.Sprintf(AdminFailedMsg, userString, user.From.ID, utils.EscapeHTML(user.JoinReason), "User not found in requests."))
|
||||||
|
bot.API.Request(api.NewCallback(query.ID, "Join request failed."))
|
||||||
callback := api.NewCallback(query.ID, "Join request failed.")
|
|
||||||
bot.API.Request(callback)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
85
main.go
85
main.go
|
|
@ -9,58 +9,63 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
b := &handlers.Bot{}
|
cfg := config.Config{}
|
||||||
b.Config = config.Config{}
|
if err := cfg.LoadConfig(); err != nil {
|
||||||
err := b.Config.LoadConfig()
|
log.Fatal(err)
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err.Error())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.Config.BotToken == nil {
|
if cfg.BotToken == nil {
|
||||||
log.Fatal("Edit config.yaml and fill out bot token")
|
log.Fatal("Edit config.yaml and fill out bot token")
|
||||||
}
|
}
|
||||||
bot, err := api.NewBotAPI(*b.Config.BotToken)
|
|
||||||
|
bot, err := api.NewBotAPI(*cfg.BotToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.API = bot
|
b := &handlers.Bot{
|
||||||
b.WaitingForApproval = make(map[int64]*handlers.ExtendedChatJoinRequest)
|
API: bot,
|
||||||
|
Config: cfg,
|
||||||
|
WaitingForApproval: make(map[int64]*handlers.ExtendedChatJoinRequest),
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("Authorized on account %s", bot.Self.UserName)
|
log.Printf("Authorized on account %s", bot.Self.UserName)
|
||||||
|
|
||||||
updateConfig := api.NewUpdate(0)
|
updateConfig := api.NewUpdate(0)
|
||||||
updateConfig.Timeout = 60
|
updateConfig.Timeout = 60
|
||||||
updatesChannel := b.API.GetUpdatesChan(updateConfig)
|
|
||||||
|
|
||||||
for update := range updatesChannel {
|
for update := range b.API.GetUpdatesChan(updateConfig) {
|
||||||
if update.ChatJoinRequest != nil {
|
processUpdate(b, update)
|
||||||
if update.ChatJoinRequest.Chat.ID == *b.Config.TargetChatId {
|
}
|
||||||
b.HandleJoinRequest(update.ChatJoinRequest)
|
}
|
||||||
}
|
|
||||||
continue
|
func processUpdate(b *handlers.Bot, update api.Update) {
|
||||||
}
|
if update.ChatJoinRequest != nil {
|
||||||
|
if update.ChatJoinRequest.Chat.ID == *b.Config.TargetChatId {
|
||||||
if update.CallbackQuery != nil {
|
b.HandleJoinRequest(update.ChatJoinRequest)
|
||||||
b.HandleCallbackQuery(update.CallbackQuery)
|
}
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if update.Message == nil {
|
if update.CallbackQuery != nil {
|
||||||
continue
|
b.HandleCallbackQuery(update.CallbackQuery)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
if user, ok := b.WaitingForApproval[update.Message.From.ID]; ok {
|
|
||||||
if update.Message.Chat.ID == update.Message.From.ID {
|
if update.Message == nil || update.Message.From == nil {
|
||||||
b.HandleJoinRequestResponse(user, update.Message)
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if user := b.GetPendingUser(update.Message.From.ID); user != nil {
|
||||||
if update.Message.Chat.ID == *b.Config.AdminChatId {
|
if update.Message.Chat.ID == update.Message.From.ID {
|
||||||
if update.Message.ReplyToMessage != nil {
|
b.HandleJoinRequestResponse(user, update.Message)
|
||||||
b.HandleDeclineReason(&update)
|
}
|
||||||
}
|
}
|
||||||
b.HandleAdminCommands(&update)
|
|
||||||
}
|
if update.Message.Chat.ID == *b.Config.AdminChatId {
|
||||||
|
if update.Message.ReplyToMessage != nil {
|
||||||
|
b.HandleDeclineReason(&update)
|
||||||
|
}
|
||||||
|
b.HandleAdminCommands(&update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,27 +10,28 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func EscapeMarkdown(s string) string {
|
func EscapeMarkdown(s string) string {
|
||||||
toEscape := []string{"*", "_", "`", "[", "]", "(", ")", "\\", "#", "-"}
|
replacer := strings.NewReplacer(
|
||||||
|
"\\", "\\\\",
|
||||||
replacements := make([]string, 0, len(toEscape)*2)
|
"*", "\\*",
|
||||||
for _, char := range toEscape {
|
"_", "\\_",
|
||||||
replacements = append(replacements, char, "\\"+char)
|
"`", "\\`",
|
||||||
}
|
"[", "\\[",
|
||||||
|
"]", "\\]",
|
||||||
replacer := strings.NewReplacer(replacements...)
|
"(", "\\(",
|
||||||
|
")", "\\)",
|
||||||
|
"#", "\\#",
|
||||||
|
"-", "\\-",
|
||||||
|
)
|
||||||
return replacer.Replace(s)
|
return replacer.Replace(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func EscapeHTML(s string) string {
|
func EscapeHTML(s string) string {
|
||||||
toEscape := []string{"&", "<", ">", "\"", "'"}
|
replacer := strings.NewReplacer(
|
||||||
|
"&", "&",
|
||||||
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)
|
return replacer.Replace(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,7 +110,7 @@ func BuildUserString(user *api.User) string {
|
||||||
return name.String()
|
return name.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendMessage(botAPI *api.BotAPI, chatID int64, topicID int, text string) (resp api.Message, err error) {
|
func SendMessage(botAPI *api.BotAPI, chatID int64, topicID int, text string) (api.Message, error) {
|
||||||
msg := api.NewMessage(chatID, text)
|
msg := api.NewMessage(chatID, text)
|
||||||
msg.ParseMode = api.ModeHTML
|
msg.ParseMode = api.ModeHTML
|
||||||
if topicID != 0 {
|
if topicID != 0 {
|
||||||
|
|
@ -118,22 +119,20 @@ func SendMessage(botAPI *api.BotAPI, chatID int64, topicID int, text string) (re
|
||||||
return botAPI.Send(msg)
|
return botAPI.Send(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func EditMessage(botAPI *api.BotAPI, chatID int64, messageID int, text string) (resp api.Message, err error) {
|
func EditMessage(botAPI *api.BotAPI, chatID int64, messageID int, text string) (api.Message, error) {
|
||||||
edit := api.NewEditMessageText(chatID, messageID, text)
|
edit := api.NewEditMessageText(chatID, messageID, text)
|
||||||
edit.ParseMode = api.ModeHTML
|
edit.ParseMode = api.ModeHTML
|
||||||
return botAPI.Send(edit)
|
return botAPI.Send(edit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func LeaveChatRequest(botAPI *api.BotAPI, chatIDs []int64) error {
|
func LeaveChatRequest(botAPI *api.BotAPI, chatIDs []int64) error {
|
||||||
var err error
|
|
||||||
for _, chatID := range chatIDs {
|
for _, chatID := range chatIDs {
|
||||||
leaveChatConfig := api.LeaveChatConfig{ChatConfig: api.ChatConfig{ChatID: chatID}}
|
_, err := botAPI.Request(api.LeaveChatConfig{ChatConfig: api.ChatConfig{ChatID: chatID}})
|
||||||
_, err = botAPI.Request(leaveChatConfig)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func EditMessageWithKeyboard(botAPI *api.BotAPI, chatID int64, messageID int, text string, keyboard *api.InlineKeyboardMarkup) {
|
func EditMessageWithKeyboard(botAPI *api.BotAPI, chatID int64, messageID int, text string, keyboard *api.InlineKeyboardMarkup) {
|
||||||
|
|
@ -145,8 +144,7 @@ func EditMessageWithKeyboard(botAPI *api.BotAPI, chatID int64, messageID int, te
|
||||||
botAPI.Send(edit)
|
botAPI.Send(edit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseIntArg parses a string argument as int, returns (value, error message).
|
// ParseIntArg parses a string argument as int. Returns (value, errMsg); errMsg is empty on success.
|
||||||
// Error message is empty on success.
|
|
||||||
func ParseIntArg(arg string) (int, string) {
|
func ParseIntArg(arg string) (int, string) {
|
||||||
val, err := strconv.Atoi(arg)
|
val, err := strconv.Atoi(arg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -155,8 +153,7 @@ func ParseIntArg(arg string) (int, string) {
|
||||||
return val, ""
|
return val, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseInt64Arg parses a string argument as int64, returns (value, error message).
|
// ParseInt64Arg parses a string argument as int64. Returns (value, errMsg); errMsg is empty on success.
|
||||||
// Error message is empty on success.
|
|
||||||
func ParseInt64Arg(arg string) (int64, string) {
|
func ParseInt64Arg(arg string) (int64, string) {
|
||||||
val, err := strconv.ParseInt(arg, 10, 64)
|
val, err := strconv.ParseInt(arg, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue