261 lines
8.3 KiB
Go
261 lines
8.3 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
|
|
"github.com/gotd/td/tg"
|
|
|
|
"telesrv/internal/domain"
|
|
)
|
|
|
|
func (r *Router) onMessagesGetAttachMenuBots(ctx context.Context, hash int64) (tg.AttachMenuBotsClass, error) {
|
|
userID, _, err := r.currentUserID(ctx)
|
|
if err != nil {
|
|
return nil, internalErr()
|
|
}
|
|
if userID == 0 || r.deps.Bots == nil {
|
|
return &tg.AttachMenuBots{Hash: 0, Bots: []tg.AttachMenuBot{}, Users: []tg.UserClass{}}, nil
|
|
}
|
|
items, err := r.deps.Bots.ListAttachMenuBots(ctx)
|
|
if err != nil {
|
|
return nil, internalErr()
|
|
}
|
|
stateByBot := make(map[int64]domain.BotAttachMenuState, len(items))
|
|
for _, item := range items {
|
|
if state, found, err := r.deps.Bots.GetAttachMenuState(ctx, userID, item.BotUserID); err == nil && found {
|
|
stateByBot[item.BotUserID] = state
|
|
} else if err != nil {
|
|
return nil, internalErr()
|
|
}
|
|
}
|
|
outHash := attachMenuBotsHash(userID, items, stateByBot)
|
|
if hash != 0 && hash == outHash {
|
|
return &tg.AttachMenuBotsNotModified{}, nil
|
|
}
|
|
bots := make([]tg.AttachMenuBot, 0, len(items))
|
|
userIDs := make([]int64, 0, len(items))
|
|
for _, item := range items {
|
|
state := stateByBot[item.BotUserID]
|
|
bots = append(bots, r.tgAttachMenuBot(ctx, item, state))
|
|
userIDs = append(userIDs, item.BotUserID)
|
|
}
|
|
return &tg.AttachMenuBots{
|
|
Hash: outHash,
|
|
Bots: bots,
|
|
Users: r.attachMenuUsers(ctx, userID, userIDs, stateByBot),
|
|
}, nil
|
|
}
|
|
|
|
func (r *Router) onMessagesGetAttachMenuBot(ctx context.Context, bot tg.InputUserClass) (*tg.AttachMenuBotsBot, error) {
|
|
userID, target, err := r.attachMenuBotTarget(ctx, bot)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
item, found, err := r.deps.Bots.GetAttachMenuBot(ctx, target.ID)
|
|
if err != nil {
|
|
return nil, internalErr()
|
|
}
|
|
if !found {
|
|
return nil, botInvalidErr()
|
|
}
|
|
var state domain.BotAttachMenuState
|
|
if st, found, err := r.deps.Bots.GetAttachMenuState(ctx, userID, target.ID); err == nil && found {
|
|
state = st
|
|
} else if err != nil {
|
|
return nil, internalErr()
|
|
}
|
|
stateByBot := map[int64]domain.BotAttachMenuState{target.ID: state}
|
|
return &tg.AttachMenuBotsBot{
|
|
Bot: r.tgAttachMenuBot(ctx, item, state),
|
|
Users: r.attachMenuUsers(ctx, userID, []int64{target.ID}, stateByBot),
|
|
}, nil
|
|
}
|
|
|
|
func (r *Router) onMessagesToggleBotInAttachMenu(ctx context.Context, req *tg.MessagesToggleBotInAttachMenuRequest) (bool, error) {
|
|
if req == nil {
|
|
return false, botInvalidErr()
|
|
}
|
|
userID, target, err := r.attachMenuBotTarget(ctx, req.Bot)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if _, found, err := r.deps.Bots.GetAttachMenuBot(ctx, target.ID); err != nil {
|
|
return false, internalErr()
|
|
} else if !found {
|
|
return false, botInvalidErr()
|
|
}
|
|
prev, found, err := r.deps.Bots.GetAttachMenuState(ctx, userID, target.ID)
|
|
if err != nil {
|
|
return false, internalErr()
|
|
}
|
|
next := domain.BotAttachMenuState{
|
|
UserID: userID,
|
|
BotUserID: target.ID,
|
|
Enabled: req.Enabled,
|
|
WriteAllowed: prev.WriteAllowed || req.WriteAllowed,
|
|
}
|
|
if _, err := r.deps.Bots.SetAttachMenuState(ctx, next); err != nil {
|
|
return false, botInvalidErr()
|
|
}
|
|
if req.WriteAllowed && !prev.WriteAllowed {
|
|
if _, err := r.deps.Bots.AllowSendMessage(ctx, userID, target.ID, true); err != nil {
|
|
return false, botInvalidErr()
|
|
}
|
|
res, err := r.sendBotAllowedServiceMessageWith(ctx, userID, target.ID, domain.MessageBotAllowedAction{AttachMenu: true})
|
|
if err != nil {
|
|
return false, internalErr()
|
|
}
|
|
if !res.Duplicate {
|
|
senderUsers := r.usersForMessageUpdate(ctx, userID, res.SenderMessage)
|
|
senderChats := r.chatsForMessageUpdate(ctx, userID, res.SenderMessage)
|
|
r.pushUserMessage(ctx, userID, "push attach menu bot allowed", tgPrivateMessageUpdates(res.SenderEvent, res.SenderMessage, 0, false, senderUsers, senderChats))
|
|
}
|
|
}
|
|
if !found || prev.Enabled != next.Enabled || prev.WriteAllowed != next.WriteAllowed {
|
|
r.pushUserMessageTransient(ctx, userID, "push attach menu bots changed", &tg.Updates{
|
|
Updates: []tg.UpdateClass{&tg.UpdateAttachMenuBots{}},
|
|
Date: int(r.clock.Now().Unix()),
|
|
})
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (r *Router) attachMenuBotTarget(ctx context.Context, bot tg.InputUserClass) (int64, domain.User, error) {
|
|
userID, _, err := r.currentUserID(ctx)
|
|
if err != nil {
|
|
return 0, domain.User{}, internalErr()
|
|
}
|
|
if userID == 0 || r.deps.Bots == nil || bot == nil {
|
|
return 0, domain.User{}, botInvalidErr()
|
|
}
|
|
u, found, err := r.userFromInput(ctx, userID, bot)
|
|
if err != nil {
|
|
return 0, domain.User{}, internalErr()
|
|
}
|
|
if !found || !u.Bot {
|
|
return 0, domain.User{}, botInvalidErr()
|
|
}
|
|
return userID, u, nil
|
|
}
|
|
|
|
func (r *Router) tgAttachMenuBot(ctx context.Context, item domain.BotAttachMenuBot, state domain.BotAttachMenuState) tg.AttachMenuBot {
|
|
out := tg.AttachMenuBot{
|
|
Inactive: item.Inactive || !state.Enabled,
|
|
HasSettings: item.HasSettings,
|
|
RequestWriteAccess: item.RequestWriteAccess,
|
|
ShowInAttachMenu: item.ShowInAttachMenu,
|
|
ShowInSideMenu: item.ShowInSideMenu,
|
|
SideMenuDisclaimerNeeded: item.SideMenuDisclaimerNeeded,
|
|
BotID: item.BotUserID,
|
|
ShortName: item.ShortName,
|
|
PeerTypes: tgAttachMenuPeerTypes(item.PeerTypes),
|
|
Icons: r.tgAttachMenuIcons(ctx, item.Icons),
|
|
}
|
|
if len(out.PeerTypes) == 0 {
|
|
out.PeerTypes = []tg.AttachMenuPeerTypeClass{&tg.AttachMenuPeerTypePM{}, &tg.AttachMenuPeerTypeChat{}, &tg.AttachMenuPeerTypeBroadcast{}}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (r *Router) tgAttachMenuIcons(ctx context.Context, icons []domain.BotAttachMenuIcon) []tg.AttachMenuBotIcon {
|
|
if len(icons) == 0 {
|
|
return []tg.AttachMenuBotIcon{}
|
|
}
|
|
out := make([]tg.AttachMenuBotIcon, 0, len(icons))
|
|
for _, icon := range icons {
|
|
if icon.Name == "" || icon.DocumentID == 0 || r.deps.Files == nil {
|
|
continue
|
|
}
|
|
doc, found, err := r.deps.Files.GetDocument(ctx, icon.DocumentID)
|
|
if err != nil || !found {
|
|
continue
|
|
}
|
|
tgIcon := tg.AttachMenuBotIcon{Name: icon.Name, Icon: tgDocument(doc)}
|
|
if len(icon.Colors) > 0 {
|
|
colors := make([]tg.AttachMenuBotIconColor, 0, len(icon.Colors))
|
|
for _, color := range icon.Colors {
|
|
if color.Name != "" {
|
|
colors = append(colors, tg.AttachMenuBotIconColor{Name: color.Name, Color: color.Color})
|
|
}
|
|
}
|
|
if len(colors) > 0 {
|
|
tgIcon.SetColors(colors)
|
|
}
|
|
}
|
|
out = append(out, tgIcon)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func tgAttachMenuPeerTypes(in []string) []tg.AttachMenuPeerTypeClass {
|
|
out := make([]tg.AttachMenuPeerTypeClass, 0, len(in))
|
|
seen := map[string]bool{}
|
|
for _, typ := range in {
|
|
if seen[typ] {
|
|
continue
|
|
}
|
|
seen[typ] = true
|
|
switch typ {
|
|
case "same_bot_pm":
|
|
out = append(out, &tg.AttachMenuPeerTypeSameBotPM{})
|
|
case "bot_pm":
|
|
out = append(out, &tg.AttachMenuPeerTypeBotPM{})
|
|
case "pm":
|
|
out = append(out, &tg.AttachMenuPeerTypePM{})
|
|
case "chat", "megagroup":
|
|
out = append(out, &tg.AttachMenuPeerTypeChat{})
|
|
case "broadcast", "channel":
|
|
out = append(out, &tg.AttachMenuPeerTypeBroadcast{})
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (r *Router) attachMenuUsers(ctx context.Context, viewerID int64, ids []int64, states map[int64]domain.BotAttachMenuState) []tg.UserClass {
|
|
if len(ids) == 0 || r.deps.Users == nil {
|
|
return []tg.UserClass{}
|
|
}
|
|
users, err := r.deps.Users.ByIDs(ctx, viewerID, ids)
|
|
if err != nil {
|
|
return []tg.UserClass{}
|
|
}
|
|
out := make([]tg.UserClass, 0, len(users))
|
|
for _, user := range users {
|
|
tgUser := r.withBotProfileFlags(ctx, r.tgUser(user))
|
|
if state, ok := states[user.ID]; ok && state.Enabled {
|
|
tgUser.SetAttachMenuEnabled(true)
|
|
}
|
|
out = append(out, tgUser)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func attachMenuBotsHash(userID int64, items []domain.BotAttachMenuBot, states map[int64]domain.BotAttachMenuState) int64 {
|
|
if len(items) == 0 {
|
|
return 0
|
|
}
|
|
parts := []string{"attach-menu", strconv.FormatInt(userID, 10)}
|
|
for _, item := range items {
|
|
state := states[item.BotUserID]
|
|
parts = append(parts,
|
|
strconv.FormatInt(item.BotUserID, 10),
|
|
item.ShortName,
|
|
strconv.FormatBool(item.Inactive),
|
|
strconv.FormatBool(item.HasSettings),
|
|
strconv.FormatBool(item.RequestWriteAccess),
|
|
strconv.FormatBool(item.ShowInAttachMenu),
|
|
strconv.FormatBool(item.ShowInSideMenu),
|
|
strconv.FormatBool(item.SideMenuDisclaimerNeeded),
|
|
strconv.FormatBool(state.Enabled),
|
|
strconv.FormatBool(state.WriteAllowed),
|
|
)
|
|
for _, typ := range item.PeerTypes {
|
|
parts = append(parts, typ)
|
|
}
|
|
for _, icon := range item.Icons {
|
|
parts = append(parts, icon.Name, strconv.FormatInt(icon.DocumentID, 10))
|
|
}
|
|
}
|
|
return stableBotAppInt64(parts...)
|
|
}
|