Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(peers): add admin helpers #688

Merged
merged 10 commits into from Mar 10, 2022
45 changes: 23 additions & 22 deletions telegram/peers/channel.go
Expand Up @@ -100,6 +100,11 @@ func (c Channel) Sync(ctx context.Context) error {
return nil
}

// Manager returns attached Manager.
func (c Channel) Manager() *Manager {
return c.m
}

// Report reports a peer for violation of telegram's Terms of Service.
func (c Channel) Report(ctx context.Context, reason tg.ReportReasonClass, message string) error {
if _, err := c.m.api.AccountReportPeer(ctx, &tg.AccountReportPeerRequest{
Expand Down Expand Up @@ -130,24 +135,34 @@ func (c Channel) FullRaw(ctx context.Context) (*tg.ChannelFull, error) {

// ToBroadcast tries to convert this Channel to Broadcast.
func (c Channel) ToBroadcast() (Broadcast, bool) {
if !c.raw.Broadcast {
if !c.IsBroadcast() {
return Broadcast{}, false
}
return Broadcast{
Channel: c,
}, true
}

// IsBroadcast whether this Channel is Broadcast.
func (c Channel) IsBroadcast() bool {
return c.raw.Broadcast
}

// ToSupergroup tries to convert this Channel to Supergroup.
func (c Channel) ToSupergroup() (Supergroup, bool) {
if !c.raw.Megagroup {
if !c.IsSupergroup() {
return Supergroup{}, false
}
return Supergroup{
Channel: c,
}, true
}

// IsSupergroup whether this Channel is Supergroup.
func (c Channel) IsSupergroup() bool {
return c.raw.Megagroup
}

// InviteLinks returns InviteLinks for this peer.
func (c Channel) InviteLinks() InviteLinks {
return InviteLinks{
Expand Down Expand Up @@ -203,20 +218,23 @@ func (c Channel) NoForwards() bool {
//
// See https://core.telegram.org/api/rights.
func (c Channel) AdminRights() (tg.ChatAdminRights, bool) {
// TODO(tdakkota): add wrapper for raw object?
return c.raw.GetAdminRights()
}

// BannedRights returns banned rights of the user in this channel.
//
// See https://core.telegram.org/api/rights.
func (c Channel) BannedRights() (tg.ChatBannedRights, bool) {
// TODO(tdakkota): add wrapper for raw object?
return c.raw.GetBannedRights()
}

// DefaultBannedRights returns default chat rights.
//
// See https://core.telegram.org/api/rights.
func (c Channel) DefaultBannedRights() (tg.ChatBannedRights, bool) {
// TODO(tdakkota): add wrapper for raw object?
return c.raw.GetDefaultBannedRights()
}

Expand Down Expand Up @@ -263,36 +281,19 @@ func (c Channel) SetTitle(ctx context.Context, title string) error {

// SetDescription sets new description for this Chat.
func (c Channel) SetDescription(ctx context.Context, about string) error {
if _, err := c.m.api.MessagesEditChatAbout(ctx, &tg.MessagesEditChatAboutRequest{
Peer: c.InputPeer(),
About: about,
}); err != nil {
return errors.Wrap(err, "edit channel about")
}
return nil
return c.m.editAbout(ctx, c.InputPeer(), about)
}

// SetReactions sets list of available reactions.
//
// Empty list disables reactions at all.
func (c Channel) SetReactions(ctx context.Context, reactions ...string) error {
return c.setReactions(ctx, reactions...)
return c.m.editReactions(ctx, c.InputPeer(), reactions...)
}

// DisableReactions disables reactions.
func (c Channel) DisableReactions(ctx context.Context) error {
return c.setReactions(ctx)
}

func (c Channel) setReactions(ctx context.Context, reactions ...string) error {
if _, err := c.m.api.MessagesSetChatAvailableReactions(ctx, &tg.MessagesSetChatAvailableReactionsRequest{
Peer: c.InputPeer(),
AvailableReactions: reactions,
}); err != nil {
return errors.Wrap(err, "set reactions")
}

return nil
return c.m.editReactions(ctx, c.InputPeer())
}

// TODO(tdakkota): add more getters, helpers and convertors
54 changes: 54 additions & 0 deletions telegram/peers/channel_test.go
Expand Up @@ -73,6 +73,24 @@ func TestChannelGetters(t *testing.T) {
a.Equal(b.raw.Broadcast, ok)
a.Equal(b.raw.Signatures, b.Signatures())
}
{
v, ok := u.AdminRights()
v2, ok2 := u.raw.GetAdminRights()
a.Equal(ok, ok2)
a.Equal(v2, v)
}
{
v, ok := u.BannedRights()
v2, ok2 := u.raw.GetBannedRights()
a.Equal(ok, ok2)
a.Equal(v2, v)
}
{
v, ok := u.DefaultBannedRights()
v2, ok2 := u.raw.GetDefaultBannedRights()
a.Equal(ok2, ok)
a.Equal(v2, v)
}
}

func TestChannel_Leave(t *testing.T) {
Expand Down Expand Up @@ -134,3 +152,39 @@ func TestChannel_SetDescription(t *testing.T) {
}).ThenTrue()
a.NoError(ch.SetDescription(ctx, about))
}

func TestChannel_Join(t *testing.T) {
a := require.New(t)
ctx := context.Background()
mock, m := testManager(t)

ch := m.Channel(getTestChannel())

mock.ExpectCall(&tg.ChannelsJoinChannelRequest{
Channel: ch.InputChannel(),
}).ThenRPCErr(getTestError())
a.Error(ch.Join(ctx))

mock.ExpectCall(&tg.ChannelsJoinChannelRequest{
Channel: ch.InputChannel(),
}).ThenResult(&tg.Updates{})
a.NoError(ch.Join(ctx))
}

func TestChannel_Delete(t *testing.T) {
a := require.New(t)
ctx := context.Background()
mock, m := testManager(t)

ch := m.Channel(getTestChannel())

mock.ExpectCall(&tg.ChannelsDeleteChannelRequest{
Channel: ch.InputChannel(),
}).ThenRPCErr(getTestError())
a.Error(ch.Delete(ctx))

mock.ExpectCall(&tg.ChannelsDeleteChannelRequest{
Channel: ch.InputChannel(),
}).ThenResult(&tg.Updates{})
a.NoError(ch.Delete(ctx))
}
74 changes: 41 additions & 33 deletions telegram/peers/chat.go
Expand Up @@ -96,6 +96,11 @@ func (c Chat) Sync(ctx context.Context) error {
return nil
}

// Manager returns attached Manager.
func (c Chat) Manager() *Manager {
return c.m
}

// Report reports a peer for violation of telegram's Terms of Service.
func (c Chat) Report(ctx context.Context, reason tg.ReportReasonClass, message string) error {
if _, err := c.m.api.AccountReportPeer(ctx, &tg.AccountReportPeerRequest{
Expand Down Expand Up @@ -139,12 +144,22 @@ func (c Chat) InviteLinks() InviteLinks {

// ToBroadcast tries to convert this Chat to Broadcast.
func (c Chat) ToBroadcast() (Broadcast, bool) {
return Broadcast{}, false
return Broadcast{}, c.IsBroadcast()
}

// IsBroadcast whether this Chat is Broadcast.
func (c Chat) IsBroadcast() bool {
return false
}

// ToSupergroup tries to convert this Chat to Supergroup.
func (c Chat) ToSupergroup() (Supergroup, bool) {
return Supergroup{}, false
return Supergroup{}, c.IsSupergroup()
}

// IsSupergroup whether this Chat is Supergroup.
func (c Chat) IsSupergroup() bool {
return false
}

// Creator whether the current user is the creator of this group.
Expand Down Expand Up @@ -196,13 +211,15 @@ func (c Chat) ParticipantsCount() int {
//
// See https://core.telegram.org/api/rights.
func (c Chat) AdminRights() (tg.ChatAdminRights, bool) {
// TODO(tdakkota): add wrapper for raw object?
return c.raw.GetAdminRights()
}

// DefaultBannedRights returns default chat rights.
//
// See https://core.telegram.org/api/rights.
func (c Chat) DefaultBannedRights() (tg.ChatBannedRights, bool) {
// TODO(tdakkota): add wrapper for raw object?
return c.raw.GetDefaultBannedRights()
}

Expand Down Expand Up @@ -240,51 +257,42 @@ func (c Chat) SetTitle(ctx context.Context, title string) error {

// SetDescription sets new description for this Chat.
func (c Chat) SetDescription(ctx context.Context, about string) error {
if _, err := c.m.api.MessagesEditChatAbout(ctx, &tg.MessagesEditChatAboutRequest{
Peer: c.InputPeer(),
About: about,
}); err != nil {
return errors.Wrap(err, "edit chat about")
}
return nil
}

// LeaveAndDelete leaves this chat and removes the entire chat history of this user in this chat.
func (c Chat) LeaveAndDelete(ctx context.Context) error {
return c.deleteMe(ctx, true)
}

func (c Chat) deleteMe(ctx context.Context, revokeHistory bool) error {
if _, err := c.m.api.MessagesDeleteChatUser(ctx, &tg.MessagesDeleteChatUserRequest{
RevokeHistory: revokeHistory,
ChatID: c.raw.GetID(),
UserID: &tg.InputUserSelf{},
}); err != nil {
return errors.Wrapf(err, "leave (revoke: %v)", revokeHistory)
}
return nil
return c.m.editAbout(ctx, c.InputPeer(), about)
}

// SetReactions sets list of available reactions.
//
// Empty list disables reactions at all.
func (c Chat) SetReactions(ctx context.Context, reactions ...string) error {
return c.setReactions(ctx, reactions...)
return c.m.editReactions(ctx, c.InputPeer(), reactions...)
}

// DisableReactions disables reactions.
func (c Chat) DisableReactions(ctx context.Context) error {
return c.setReactions(ctx)
return c.m.editReactions(ctx, c.InputPeer())
}

// LeaveAndDelete leaves this chat and removes the entire chat history of this user in this chat.
func (c Chat) LeaveAndDelete(ctx context.Context) error {
return c.deleteMe(ctx, true)
}

func (c Chat) deleteMe(ctx context.Context, revokeHistory bool) error {
return c.deleteUser(ctx, &tg.InputUserSelf{}, revokeHistory)
}

func (c Chat) setReactions(ctx context.Context, reactions ...string) error {
if _, err := c.m.api.MessagesSetChatAvailableReactions(ctx, &tg.MessagesSetChatAvailableReactionsRequest{
Peer: c.InputPeer(),
AvailableReactions: reactions,
func (c Chat) deleteUser(ctx context.Context, user tg.InputUserClass, revokeHistory bool) error {
if _, err := c.m.api.MessagesDeleteChatUser(ctx, &tg.MessagesDeleteChatUserRequest{
RevokeHistory: revokeHistory,
ChatID: c.raw.GetID(),
UserID: user,
}); err != nil {
return errors.Wrap(err, "set reactions")
_, self := user.(*tg.InputUserSelf)
if self {
return errors.Wrapf(err, "leave (revoke: %v)", revokeHistory)
}
return errors.Wrapf(err, "delete user (revoke: %v)", revokeHistory)
}

return nil
}

Expand Down
74 changes: 74 additions & 0 deletions telegram/peers/id.go
@@ -0,0 +1,74 @@
package peers

import (
"context"

"github.com/go-faster/errors"

"github.com/gotd/td/constant"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
)

// ResolveTDLibID creates Peer using given constant.TDLibPeerID.
func (m *Manager) ResolveTDLibID(ctx context.Context, peerID constant.TDLibPeerID) (p Peer, err error) {
switch {
case peerID.IsUser():
p, err = m.ResolveUserID(ctx, peerID.ToPlain())
case peerID.IsChat():
p, err = m.ResolveChatID(ctx, peerID.ToPlain())
case peerID.IsChannel():
p, err = m.ResolveChannelID(ctx, peerID.ToPlain())
default:
return nil, errors.Errorf("invalid ID %d", peerID)
}
return p, err
}

// ResolveUserID creates User using given id.
func (m *Manager) ResolveUserID(ctx context.Context, id int64) (User, error) {
v, ok, err := m.storage.Find(ctx, Key{
Prefix: usersPrefix,
ID: id,
})
if err != nil {
return User{}, err
}
u, err := m.GetUser(ctx, &tg.InputUser{
UserID: id,
AccessHash: v.AccessHash,
})
if !ok && tgerr.Is(err, tg.ErrUserIDInvalid) {
return User{}, &PeerNotFoundError{
Peer: &tg.PeerUser{UserID: id},
}
}
return u, err
}

// ResolveChatID creates Chat using given id.
func (m *Manager) ResolveChatID(ctx context.Context, id int64) (Chat, error) {
c, err := m.GetChat(ctx, id)
return c, err
}

// ResolveChannelID creates Channel using given id.
func (m *Manager) ResolveChannelID(ctx context.Context, id int64) (Channel, error) {
v, ok, err := m.storage.Find(ctx, Key{
Prefix: channelPrefix,
ID: id,
})
if err != nil {
return Channel{}, err
}
c, err := m.GetChannel(ctx, &tg.InputChannel{
ChannelID: id,
AccessHash: v.AccessHash,
})
if !ok && tgerr.Is(err, tg.ErrChannelInvalid) {
return Channel{}, &PeerNotFoundError{
Peer: &tg.PeerChannel{ChannelID: id},
}
}
return c, err
}
5 changes: 5 additions & 0 deletions telegram/peers/manager.go
Expand Up @@ -39,3 +39,8 @@ func (m *Manager) Init(ctx context.Context) error {
}
return nil
}

// API returns used Client.
func (m *Manager) API() *tg.Client {
return m.api
}