Go-Filter-Bot / plugins /forcesub.go
Thaimozhi's picture
first commit
891b1b2
Raw History Blame Contribute Delete
3.71 kB
// Force Subscribe middleware - checks if a user has joined all required channels
// before the bot responds. Channels are configured via FORCE_SUB env var (stored in DB).
package plugins
import (
"fmt"
"github.com/Jisin0/Go-Filter-Bot/utils"
"github.com/PaulSonOfLars/gotgbot/v2"
"github.com/PaulSonOfLars/gotgbot/v2/ext"
)
// forceSubText is the message sent when a user hasn't joined required channels.
const forceSubText = `⚠️ <b>Sᴜʙsᴄʀɪʙᴇ Rᴇǫᴜɪʀᴇᴅ!</b>
You must join the channels below before using this bot.
After joining, click the <b>✅ I've Joined</b> button.`
// CheckForceSub verifies the user has joined all force-sub channels.
// Returns true if the user is allowed (subscribed / admin / no force sub set).
// Returns false and sends a join-prompt message if the user hasn't subscribed.
func CheckForceSub(bot *gotgbot.Bot, ctx *ext.Context) bool {
user := ctx.EffectiveUser
if user == nil || user.Id == 0 {
return true // anonymous admin – let through
}
// Bot admins bypass force-sub
if utils.IsAdmin(user.Id) {
return true
}
channels := DB.GetForceSubChannels()
if len(channels) == 0 {
return true
}
var notJoined []int64
for _, chanID := range channels {
member, err := bot.GetChatMember(chanID, user.Id, nil)
if err != nil {
// Channel not accessible to bot – skip rather than block user
continue
}
status := member.GetStatus()
if status == "left" || status == "kicked" {
notJoined = append(notJoined, chanID)
}
}
if len(notJoined) == 0 {
return true // user is subscribed to all channels
}
// Build one button per unjoined channel + verify button
var rows [][]gotgbot.InlineKeyboardButton
for _, chanID := range notJoined {
invite := buildInviteLink(bot, chanID)
if invite == "" {
continue
}
chat, err := bot.GetChat(chanID, nil)
title := fmt.Sprintf("Channel %d", chanID)
if err == nil {
title = chat.Title
}
rows = append(rows, []gotgbot.InlineKeyboardButton{{
Text: "📢 Join " + title,
Url: invite,
}})
}
rows = append(rows, []gotgbot.InlineKeyboardButton{{
Text: "✅ I've Joined",
CallbackData: "checksub",
}})
if ctx.EffectiveMessage != nil {
ctx.EffectiveMessage.Reply(bot, forceSubText, &gotgbot.SendMessageOpts{ //nolint:errcheck
ParseMode: gotgbot.ParseModeHTML,
ReplyMarkup: gotgbot.InlineKeyboardMarkup{InlineKeyboard: rows},
})
}
return false
}
// buildInviteLink returns a public or exported invite link for a channel.
func buildInviteLink(bot *gotgbot.Bot, chanID int64) string {
chat, err := bot.GetChat(chanID, nil)
if err != nil {
return ""
}
if chat.Username != "" {
return "https://t.me/" + chat.Username
}
link, err := bot.ExportChatInviteLink(chanID, nil)
if err != nil {
return ""
}
return link
}
// CbCheckSub handles the "✅ I've Joined" callback button.
//
//nolint:errcheck
func CbCheckSub(bot *gotgbot.Bot, ctx *ext.Context) error {
update := ctx.CallbackQuery
userID := update.From.Id
channels := DB.GetForceSubChannels()
var notJoined []int64
for _, chanID := range channels {
member, err := bot.GetChatMember(chanID, userID, nil)
if err != nil {
continue
}
status := member.GetStatus()
if status == "left" || status == "kicked" {
notJoined = append(notJoined, chanID)
}
}
if len(notJoined) == 0 {
update.Answer(bot, &gotgbot.AnswerCallbackQueryOpts{
Text: "✅ Verified! You can now use the bot.",
ShowAlert: true,
})
update.Message.Delete(bot, nil)
} else {
update.Answer(bot, &gotgbot.AnswerCallbackQueryOpts{
Text: "❌ You haven't joined all required channels yet!",
ShowAlert: true,
})
}
return nil
}