botapi: implement getChat

Adds the getChat method to the HTTP Bot API gateway. Numeric chat_id only (no
@username). Resolution goes through the shared peer resolvers:

- user: ByID; unknown -> CHAT_NOT_FOUND
- channel/supergroup: ResolveChannel, so a public one resolves even when the bot
  is not a member (projected as a preview); a private one the bot cannot access
  -> CHAT_NOT_FOUND, a banned bot likewise

The Chat projection returns id (bot-api encoded), type ("channel" for a
broadcast, "supergroup" for a megagroup, "private" for a user), title, username,
first/last name, description, is_forum, and the scam/fake/verified flags.
This commit is contained in:
Astra 2026-09-09 16:14:49 +01:00
parent 3229bfa6b3
commit 578eb5a1f6
5 changed files with 221 additions and 0 deletions

View file

@ -356,6 +356,45 @@ func apiMediaUsesCaption(media map[string]any) bool {
return false
}
// apiChatFull projects a getChat result. The bot-api chat-id encoding is applied
// here: users keep their positive id, channels/supergroups become
// -1000000000000 - channelID.
func apiChatFull(chat domain.BotAPIChat) map[string]any {
id := chat.Peer.ID
if chat.Peer.Type == domain.PeerTypeChannel {
id = -1000000000000 - chat.Peer.ID
}
out := map[string]any{"id": id, "type": chat.Type}
if chat.Title != "" {
out["title"] = chat.Title
}
if chat.Username != "" {
out["username"] = chat.Username
}
if chat.FirstName != "" {
out["first_name"] = chat.FirstName
}
if chat.LastName != "" {
out["last_name"] = chat.LastName
}
if chat.Description != "" {
out["description"] = chat.Description
}
if chat.IsForum {
out["is_forum"] = true
}
if chat.Verified {
out["is_verified"] = true
}
if chat.Scam {
out["is_scam"] = true
}
if chat.Fake {
out["is_fake"] = true
}
return out
}
func apiChat(peer domain.Peer, users map[int64]domain.User) map[string]any {
switch peer.Type {
case domain.PeerTypeUser: