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