199 lines
5.2 KiB
Go

package helpers
import (
"context"
"fmt"
"log/slog"
"slices"
"strconv"
"strings"
"git.maximotejeda.com/maximo/telegram-base-bot/config"
"git.maximotejeda.com/maximo/telegram-base-bot/internal/ports"
"github.com/go-telegram/bot"
"github.com/go-telegram/bot/models"
)
func IsUserRegistered() {}
func IsUserAuthorized() {}
func GetPendingAuthRequest() {}
func CreatePendingAuthRequest() {}
func DeletePendingAuthRequest() {}
func BanUSer() {}
func UnBanUser() {}
func Authenticate(ctx context.Context, log *slog.Logger, b *bot.Bot, update *models.Update, uSVC ports.UserService) bool {
var (
user models.User
)
// select user
if update.CallbackQuery != nil {
user = update.CallbackQuery.From
} else {
if update.MessageReaction != nil {
return true
}
user = *update.Message.From
}
// bot name
bn, _ := b.GetMe(ctx)
switch IsUserAdmin(user.ID) {
case true:
// theres an user env admin
// check if user exist on db
_, err := uSVC.Get(user.ID)
if err != nil {
log.Error("geting user", "error", err)
log.Debug("user seems to not exists")
if strings.Contains(err.Error(), "sql: no rows in result set") {
// if user does not exist create it
_, err := uSVC.Create(&user)
log.Debug("creating user")
if err != nil {
log.Error("creating new user for admnin", "err", err)
}
// add bot to user list
_, err = uSVC.AddBot(user.ID, bn.Username)
if err != nil {
log.Error("Adding bot to admin user list", "err", err)
}
}
}
return true
case false:
// user is not admin and need to be authorized
// check if user is on db
_, err := uSVC.Get(user.ID)
if err != nil {
// user need auth
log.Error("user not in db, authorization from an admin is required", "error", err)
// add user to manage it
if strings.Contains(err.Error(), "sql: no rows in result set") {
// check if theres an access request from the same user and bot
_, err := uSVC.Create(&user)
if err != nil {
log.Error("creating new user", "user", user.ID, "error", err)
}
// create access request
_, err = uSVC.CreateAccessRequest(user.ID, bn.Username)
if err != nil {
log.Error("creating access request for ", "user", user.ID, "error", err)
}
}
} else {
bots, err := uSVC.GetBots(user.ID)
if err != nil {
log.Error("checking bots on user access")
}
switch HasUserAccess(bots, bn.Username) {
case true:
return true
case false:
// check for banned user
buser, err := uSVC.GetAllBannedUsers(bn.Username)
if err != nil {
log.Error("error querying banned user")
}
for _, u := range buser.GetBans() {
if u.TgbId == user.ID {
b.SendMessage(ctx, &bot.SendMessageParams{
ChatID: u.TgbId,
Text: "user access is restricted, please ask for permission",
},)
return false
}
}
ac, err := uSVC.GetAccessRequest(user.ID)
acl := []string{}
for _, val := range ac.Access {
acl = append(acl, val.BotName)
}
if slices.Contains(acl, bn.Username) {
// create access request
log.Info("Access Request found returning early", "user", user.ID, "error", err)
return false
} else {
// create one
_, err = uSVC.CreateAccessRequest(user.ID, bn.Username)
if err != nil {
log.Error("creating access request", "err", err)
}
}
}
}
}
// get all admins
userL, _ := GetAdminFromEnv()
// send a mesage to all admins
for _, adm := range userL {
param := GenerateAccessRequestMessage(user, adm, b, update)
b.SendMessage(ctx, param)
}
return false
}
// GetAdminFromEnv
// will get an env variable that is a list of tgbID comma separated
// if the user trying to enter is admin auth the user
func GetAdminFromEnv() (adminList []int64, errList []error) {
adminsStrList := config.GetAdminsList()
list := strings.Split(adminsStrList, ",")
adminList = []int64{}
errList = []error{}
for _, item := range list {
adm, err := strconv.ParseInt(item, 10, 64)
if err != nil {
err = fmt.Errorf("parsing tgb admin id: %s\n err: %w", item, err)
fmt.Println(err)
errList = append(errList, err)
continue
}
adminList = append(adminList, adm)
}
return
}
// IsUserAdmin
// check if userID is admin on bot
func IsUserAdmin(userID int64) bool {
userL, errl := GetAdminFromEnv()
if len(errl) > 0 {
fmt.Printf("error no admin in var %v", errl)
}
return slices.Contains(userL, userID)
}
func HasUserAccess(bots []string, botName string) bool {
return slices.Contains(bots, botName)
}
func GenerateAccessRequestMessage(up models.User, adm int64, b *bot.Bot, update *models.Update) *bot.SendMessageParams {
txt := fmt.Sprintf(`User %s is requesting access
ID: %d
FirstName: %s
LastName: %s
ChatID: %d
`, up.Username, up.ID, up.FirstName, up.LastName, up.ID)
msg := &bot.SendMessageParams{
ChatID: adm,
Text: txt,
}
bn, _ := b.GetMe(context.Background())
options := [][]string{
{"Grant", fmt.Sprintf("operation=grant&userID=%d&bot=%s", up.ID, bn.Username)},
{"Deny", fmt.Sprintf("operation=deny&userID=%d&bot=%s", up.ID, bn.Username)},
// {"Deny", fmt.Sprintf("operation=ignore&userID=%d&bot=%s", up.ID, bn.Username)},
}
kbd := KeyboardWithCancel(options, 2, false)
msg.ReplyMarkup = kbd
return msg
}