188 lines
4.8 KiB
Go
188 lines
4.8 KiB
Go
package handlers
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"log/slog"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"github.com/theorift/white-zone-bot/bot"
|
||
"github.com/theorift/white-zone-bot/repositories"
|
||
"github.com/theorift/white-zone-bot/services"
|
||
"gopkg.in/telebot.v4"
|
||
)
|
||
|
||
const (
|
||
genericErrorMsg = "⚠️ Oops! Something went wrong. Please try again later."
|
||
welcomeMessage = "Welcome to VIP Group Portal!\n\nExplore using the buttons below:"
|
||
welcomeBackMessage = "Welcome back! Your options:"
|
||
inviteButtonText = "🔗 Get Invite Link"
|
||
pointsButtonText = "💰 Check Points"
|
||
)
|
||
|
||
func HandleStart(b bot.Bot, userRepo repositories.UserRepository) {
|
||
instance := b.GetInstance()
|
||
|
||
instance.Handle("/start", func(ctx telebot.Context) error {
|
||
sender := ctx.Sender()
|
||
msg := ctx.Message()
|
||
|
||
slog.Info("User started bot",
|
||
"userID", sender.ID,
|
||
"payload", msg.Payload,
|
||
"chatID", msg.Chat.ID,
|
||
)
|
||
|
||
referrerID, parseErr := parseReferrerID(msg.Payload)
|
||
if parseErr != nil {
|
||
sendParseError(ctx, sender.ID)
|
||
return nil
|
||
}
|
||
|
||
userService := services.NewUserService(sender.ID, userRepo)
|
||
|
||
err := userService.ProcessStart(referrerID)
|
||
if err != nil {
|
||
return handleStartError(ctx, err, sender.ID, referrerID)
|
||
}
|
||
|
||
slog.Info("Start processed successfully",
|
||
"userID", sender.ID,
|
||
"referrerID", referrerID)
|
||
|
||
return sendWelcomeMessage(ctx, false)
|
||
})
|
||
}
|
||
|
||
func parseReferrerID(payload string) (int64, error) {
|
||
trimmed := strings.TrimSpace(payload)
|
||
if trimmed == "" {
|
||
return 0, nil
|
||
}
|
||
|
||
id, err := strconv.ParseInt(trimmed, 10, 64)
|
||
if err != nil {
|
||
return 0, fmt.Errorf("invalid referrer format: %w", err)
|
||
}
|
||
return id, nil
|
||
}
|
||
|
||
func sendParseError(ctx telebot.Context, userID int64) {
|
||
msg := "❌ Invalid referral code format! Please use numeric codes."
|
||
if err := ctx.Send(msg); err != nil {
|
||
slog.Error("Failed to send parse error",
|
||
"userID", userID,
|
||
"error", err)
|
||
}
|
||
}
|
||
|
||
func handleStartError(ctx telebot.Context, err error, userID, referrerID int64) error {
|
||
var userMsg string
|
||
|
||
switch {
|
||
case errors.Is(err, services.ErrSelfReferral):
|
||
userMsg = "❌ Self-referrals are not allowed!"
|
||
slog.Warn("Self-referral blocked",
|
||
"userID", userID,
|
||
"referrerID", referrerID)
|
||
|
||
case errors.Is(err, services.ErrInvalidReferrer):
|
||
userMsg = "❌ Invalid referral code! Please check and try again."
|
||
slog.Warn("Invalid referral attempt",
|
||
"userID", userID,
|
||
"referrerID", referrerID)
|
||
|
||
case errors.Is(err, services.ErrAlreadyReferred):
|
||
userMsg = "ℹ️ You already have an active referral!"
|
||
slog.Info("Duplicate referral ignored",
|
||
"userID", userID,
|
||
"referrerID", referrerID)
|
||
|
||
case errors.Is(err, services.ErrLateReferralAttempt):
|
||
userMsg = "ℹ️ Referrals must happen during first use!"
|
||
slog.Info("Late attempt referral blocked",
|
||
"userID", userID,
|
||
"referrerID", referrerID)
|
||
|
||
case errors.Is(err, services.ErrCircularReference):
|
||
userMsg = "❌ Circular referrals are not allowed!"
|
||
slog.Info("Circular referral blocked",
|
||
"userID", userID,
|
||
"referrerID", referrerID)
|
||
|
||
case errors.Is(err, services.ErrDuplicateUser):
|
||
slog.Info("Duplicate user creation attempt", "userID", userID)
|
||
if sendErr := sendWelcomeMessage(ctx, true); sendErr != nil {
|
||
// Attempt fallback message
|
||
if backupErr := ctx.Send("Welcome back! Please use the menu buttons."); backupErr != nil {
|
||
slog.Error("Failed to send welcome messages",
|
||
"userID", userID,
|
||
"welcomeError", sendErr,
|
||
"fallbackError", backupErr)
|
||
}
|
||
}
|
||
return nil
|
||
|
||
case errors.Is(err, services.ErrReferralChainTooLong):
|
||
userMsg = "❌ Invalid referral chain detected!"
|
||
slog.Warn("Long referral chain blocked",
|
||
"userID", userID,
|
||
"referrerID", referrerID)
|
||
|
||
default:
|
||
userMsg = genericErrorMsg
|
||
slog.Error("Start handler failed",
|
||
"userID", userID,
|
||
"referrerID", referrerID,
|
||
"error", err)
|
||
}
|
||
|
||
if sendErr := ctx.Send(userMsg); sendErr != nil {
|
||
slog.Error("Failed to send error message",
|
||
"userID", userID,
|
||
"originalError", err,
|
||
"sendError", sendErr)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func sendWelcomeMessage(ctx telebot.Context, isReturning bool) error {
|
||
msg := welcomeMessage
|
||
if isReturning {
|
||
msg = welcomeBackMessage
|
||
}
|
||
|
||
markup := &telebot.ReplyMarkup{
|
||
InlineKeyboard: [][]telebot.InlineButton{
|
||
{
|
||
{
|
||
Text: inviteButtonText,
|
||
InlineQueryChosenChat: &telebot.SwitchInlineQuery{
|
||
Query: "invite",
|
||
AllowUserChats: true,
|
||
AllowBotChats: false,
|
||
AllowGroupChats: true,
|
||
AllowChannelChats: true,
|
||
},
|
||
},
|
||
},
|
||
{
|
||
{
|
||
Unique: "check_points",
|
||
Text: pointsButtonText,
|
||
},
|
||
},
|
||
},
|
||
}
|
||
|
||
err := ctx.Send(msg, markup)
|
||
if err != nil {
|
||
slog.Error("Failed to send welcome message",
|
||
"userID", ctx.Sender().ID,
|
||
"error", err)
|
||
return err
|
||
}
|
||
return nil
|
||
}
|