Files
mautrix-telegram/pkg/gotd/telegram/peers/user.go
T
2025-06-27 20:03:37 -07:00

270 lines
6.2 KiB
Go

package peers
import (
"context"
"fmt"
"github.com/go-faster/errors"
"go.mau.fi/mautrix-telegram/pkg/gotd/constant"
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
)
// User is user peer.
type User struct {
raw *tg.User
m *Manager
}
// User creates new User, attached to this manager.
func (m *Manager) User(u *tg.User) User {
m.needsUpdate(userPeerID(u.ID))
return User{
raw: u,
m: m,
}
}
// GetUser gets User using given tg.InputUserClass.
func (m *Manager) GetUser(ctx context.Context, p tg.InputUserClass) (User, error) {
user, err := m.getUser(ctx, p)
if err != nil {
return User{}, err
}
return m.User(user), nil
}
// Raw returns raw *tg.User.
func (u User) Raw() *tg.User {
return u.raw
}
// ID returns entity ID.
func (u User) ID() int64 {
return u.raw.GetID()
}
// TDLibPeerID returns TDLibPeerID for this entity.
func (u User) TDLibPeerID() constant.TDLibPeerID {
return userPeerID(u.raw.GetID())
}
// VisibleName returns visible name of peer.
//
// It returns FirstName + " " + LastName for users, and title for chats and channels.
func (u User) VisibleName() string {
firstName := u.raw.FirstName
lastName := u.raw.LastName
if lastName == "" {
return firstName
}
return fmt.Sprintf("%s %s", firstName, lastName)
}
// Username returns peer username, if any.
func (u User) Username() (string, bool) {
return u.raw.GetUsername()
}
// Restricted whether this user/chat/channel is restricted.
func (u User) Restricted() ([]tg.RestrictionReason, bool) {
reason, ok := u.raw.GetRestrictionReason()
return reason, ok || u.raw.GetRestricted()
}
// Verified whether this user/chat/channel is verified by Telegram.
func (u User) Verified() bool {
return u.raw.Verified
}
// Scam whether this user/chat/channel is probably a scam.
func (u User) Scam() bool {
return u.raw.Scam
}
// Fake whether this user/chat/channel was reported by many users as a fake or scam: be
// careful when interacting with it.
func (u User) Fake() bool {
return u.raw.Fake
}
// InputPeer returns input peer for this peer.
func (u User) InputPeer() tg.InputPeerClass {
if u.Self() {
return &tg.InputPeerSelf{}
}
return &tg.InputPeerUser{
UserID: u.raw.ID,
AccessHash: u.raw.AccessHash,
}
}
// Sync updates current object.
func (u User) Sync(ctx context.Context) error {
raw, err := u.m.updateUser(ctx, u.InputUser())
if err != nil {
return errors.Wrap(err, "get user")
}
*u.raw = *raw
return nil
}
// Manager returns attached Manager.
func (u User) Manager() *Manager {
return u.m
}
// Report reports a peer for violation of telegram's Terms of Service.
func (u User) Report(ctx context.Context, reason tg.ReportReasonClass, message string) error {
if _, err := u.m.api.AccountReportPeer(ctx, &tg.AccountReportPeerRequest{
Peer: u.InputPeer(),
Reason: reason,
Message: message,
}); err != nil {
return errors.Wrap(err, "report")
}
return nil
}
// Photo returns peer photo, if any.
func (u User) Photo(ctx context.Context) (*tg.Photo, bool, error) {
r, err := u.m.api.PhotosGetUserPhotos(ctx, &tg.PhotosGetUserPhotosRequest{
UserID: u.InputUser(),
Offset: 0,
Limit: 1,
})
if err != nil {
return nil, false, errors.Wrap(err, "get user photos")
}
if err := u.m.applyUsers(ctx, r.GetUsers()...); err != nil {
return nil, false, errors.Wrap(err, "apply users")
}
photos := r.GetPhotos()
if len(photos) < 1 {
return nil, false, nil
}
p, ok := photos[0].AsNotEmpty()
return p, ok, nil
}
// FullRaw returns *tg.UserFull for this User.
func (u User) FullRaw(ctx context.Context) (*tg.UserFull, error) {
return u.m.getUserFull(ctx, u.InputUser())
}
// ToBot tries to convert this User to Bot.
func (u User) ToBot() (Bot, bool) {
if !u.raw.Bot {
return Bot{}, false
}
return Bot{
User: u,
}, true
}
// Self whether this user indicates the currently logged-in user.
func (u User) Self() bool {
// TODO(tdakkota): return helper instead?
return u.raw.Self
}
// Contact whether this user is a contact.
func (u User) Contact() bool {
return u.raw.Contact
}
// MutualContact whether this user is a mutual contact.
func (u User) MutualContact() bool {
return u.raw.MutualContact
}
// Deleted whether the account of this user was deleted.
func (u User) Deleted() bool {
return u.raw.Deleted
}
// Support whether this is an official support user.
func (u User) Support() bool {
return u.raw.Support
}
// FirstName returns first name.
func (u User) FirstName() (string, bool) {
return u.raw.GetFirstName()
}
// LastName returns last name.
func (u User) LastName() (string, bool) {
return u.raw.GetLastName()
}
// Phone returns phone, if any.
func (u User) Phone() (string, bool) {
return u.raw.GetPhone()
}
// Status returns user status, if any.
func (u User) Status() (tg.UserStatusClass, bool) {
return u.raw.GetStatus()
}
// LangCode returns users lang code, if any.
func (u User) LangCode() (string, bool) {
return u.raw.GetLangCode()
}
// InputUser returns input user for this user.
func (u User) InputUser() tg.InputUserClass {
if u.Self() {
return &tg.InputUserSelf{}
}
return &tg.InputUser{
UserID: u.raw.ID,
AccessHash: u.raw.AccessHash,
}
}
// ReportSpam reports a new incoming chat for spam, if the peer settings of the chat allow us to do that.
func (u User) ReportSpam(ctx context.Context) error {
if _, err := u.m.api.MessagesReportSpam(ctx, u.InputPeer()); err != nil {
return errors.Wrap(err, "report spam")
}
return nil
}
// Block blocks this user.
func (u User) Block(ctx context.Context) error {
if _, err := u.m.api.ContactsBlock(ctx, &tg.ContactsBlockRequest{
ID: u.InputPeer(),
}); err != nil {
return errors.Wrap(err, "block")
}
return nil
}
// Unblock unblocks this user.
func (u User) Unblock(ctx context.Context) error {
if _, err := u.m.api.ContactsUnblock(ctx, &tg.ContactsUnblockRequest{
ID: u.InputPeer(),
}); err != nil {
return errors.Wrap(err, "unblock")
}
return nil
}
// InviteTo invites User to given channel.
func (u User) InviteTo(ctx context.Context, ch tg.InputChannelClass) error {
if _, err := u.m.api.ChannelsInviteToChannel(ctx, &tg.ChannelsInviteToChannelRequest{
Channel: ch,
Users: []tg.InputUserClass{u.InputUser()},
}); err != nil {
return errors.Wrap(err, "invite to channel")
}
return nil
}
// TODO(tdakkota): add more getters, helpers and convertors