botapi: getChatMemberCount, getChatMember, and a fuller getChat
- getChatMemberCount: channel/supergroup participant count (numeric chat_id). - getChatMember: resolves a member via GetParticipant, projected to a Bot API ChatMember (creator/administrator/restricted/member/left/kicked with the matching rights); a user simply not in an accessible chat returns "left". - getChat now uses the full channel view and adds permissions (from the default restrictions), slow_mode_delay, linked_chat_id and pinned_message. Channel-only methods reject user chat_ids; private chats the bot cannot access return CHAT_NOT_FOUND.
This commit is contained in:
parent
f5a0e770c7
commit
22846e340f
5 changed files with 336 additions and 15 deletions
|
|
@ -70,7 +70,7 @@ func (r *Router) BotAPIChat(ctx context.Context, botID, chatID int64) (domain.Bo
|
|||
if r.deps.Channels == nil {
|
||||
return domain.BotAPIChat{}, errors.New("CHAT_NOT_FOUND")
|
||||
}
|
||||
view, err := r.deps.Channels.ResolveChannel(ctx, botID, peer.ID)
|
||||
view, err := r.deps.Channels.GetChannel(ctx, botID, peer.ID)
|
||||
if err != nil {
|
||||
return domain.BotAPIChat{}, botAPIChatErr(err)
|
||||
}
|
||||
|
|
@ -79,21 +79,91 @@ func (r *Router) BotAPIChat(ctx context.Context, botID, chatID int64) (domain.Bo
|
|||
if ch.Broadcast && !ch.Megagroup {
|
||||
typ = "channel"
|
||||
}
|
||||
return domain.BotAPIChat{
|
||||
Peer: peer,
|
||||
Type: typ,
|
||||
Title: ch.Title,
|
||||
Username: ch.Username,
|
||||
Description: ch.About,
|
||||
IsForum: ch.Forum,
|
||||
Verified: ch.Verified,
|
||||
Scam: ch.Scam,
|
||||
Fake: ch.Fake,
|
||||
}, nil
|
||||
out := domain.BotAPIChat{
|
||||
Peer: peer,
|
||||
Type: typ,
|
||||
Title: ch.Title,
|
||||
Username: ch.Username,
|
||||
Description: ch.About,
|
||||
IsForum: ch.Forum,
|
||||
Verified: ch.Verified,
|
||||
Scam: ch.Scam,
|
||||
Fake: ch.Fake,
|
||||
SlowModeDelay: ch.SlowmodeSeconds,
|
||||
LinkedChatID: ch.LinkedChatID,
|
||||
}
|
||||
if typ == "supergroup" {
|
||||
perms := ch.DefaultBannedRights
|
||||
out.Permissions = &perms
|
||||
}
|
||||
if ch.PinnedMessageID > 0 {
|
||||
if hist, msgErr := r.deps.Channels.GetMessages(ctx, botID, peer.ID, []int{ch.PinnedMessageID}); msgErr == nil && len(hist.Messages) > 0 {
|
||||
pinned := botAPIMessageFromChannel(botID, hist.Messages[0])
|
||||
out.PinnedMessage = &pinned
|
||||
out.PinnedMessageUsers = hist.Users
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
return domain.BotAPIChat{}, errors.New("CHAT_ID_INVALID")
|
||||
}
|
||||
|
||||
// BotAPIChatMemberCount resolves getChatMemberCount. Channels/supergroups only.
|
||||
func (r *Router) BotAPIChatMemberCount(ctx context.Context, botID, chatID int64) (int, error) {
|
||||
if r == nil || botID == 0 {
|
||||
return 0, errors.New("BOT_INVALID")
|
||||
}
|
||||
peer, ok := botAPIPeerFromChatID(chatID)
|
||||
if !ok || peer.Type != domain.PeerTypeChannel {
|
||||
return 0, errors.New("CHAT_ID_INVALID")
|
||||
}
|
||||
if r.deps.Channels == nil {
|
||||
return 0, errors.New("CHAT_NOT_FOUND")
|
||||
}
|
||||
view, err := r.deps.Channels.ResolveChannel(ctx, botID, peer.ID)
|
||||
if err != nil {
|
||||
return 0, botAPIChatErr(err)
|
||||
}
|
||||
return view.Channel.ParticipantsCount, nil
|
||||
}
|
||||
|
||||
// BotAPIChatMember resolves getChatMember. Channels/supergroups only.
|
||||
func (r *Router) BotAPIChatMember(ctx context.Context, botID, chatID, userID int64) (domain.BotAPIChatMember, error) {
|
||||
if r == nil || botID == 0 {
|
||||
return domain.BotAPIChatMember{}, errors.New("BOT_INVALID")
|
||||
}
|
||||
if userID <= 0 {
|
||||
return domain.BotAPIChatMember{}, errors.New("USER_ID_INVALID")
|
||||
}
|
||||
peer, ok := botAPIPeerFromChatID(chatID)
|
||||
if !ok || peer.Type != domain.PeerTypeChannel {
|
||||
return domain.BotAPIChatMember{}, errors.New("CHAT_ID_INVALID")
|
||||
}
|
||||
if r.deps.Channels == nil {
|
||||
return domain.BotAPIChatMember{}, errors.New("CHAT_NOT_FOUND")
|
||||
}
|
||||
member, err := r.deps.Channels.GetParticipant(ctx, botID, peer.ID, userID)
|
||||
switch {
|
||||
case err == nil:
|
||||
case errors.Is(err, domain.ErrUserNotParticipant):
|
||||
// Bot API returns a "left" member for a user who is simply not in the
|
||||
// chat, as long as the chat itself is accessible.
|
||||
member = domain.ChannelMember{ChannelID: peer.ID, UserID: userID, Role: domain.ChannelRoleMember, Status: domain.ChannelMemberLeft}
|
||||
default:
|
||||
return domain.BotAPIChatMember{}, botAPIChatErr(err)
|
||||
}
|
||||
out := domain.BotAPIChatMember{Member: member}
|
||||
if r.deps.Users != nil {
|
||||
if u, found, uErr := r.deps.Users.ByID(ctx, botID, userID); uErr == nil && found {
|
||||
out.User = u
|
||||
}
|
||||
}
|
||||
if out.User.ID == 0 {
|
||||
out.User = domain.User{ID: userID}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func botAPIChatErr(err error) error {
|
||||
switch {
|
||||
case errors.Is(err, domain.ErrChannelInvalid),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue