Skip to main content

grammers_client/client/
chats.rs

1// Copyright 2020 - developers of the `grammers` project.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Methods related to users, groups and channels.
10
11use std::collections::HashMap;
12use std::collections::VecDeque;
13use std::future::Future;
14use std::sync::Arc;
15use std::time::Duration;
16
17use grammers_mtsender::{InvocationError, RpcError};
18use grammers_session::types::{PeerId, PeerKind, PeerRef};
19use grammers_tl_types as tl;
20
21use super::{Client, IterBuffer};
22use crate::media::Photo;
23use crate::message::Message;
24use crate::peer::ActionSender;
25use crate::peer::AdminRightsBuilder;
26use crate::peer::BannedRightsBuilder;
27use crate::peer::Participant;
28use crate::peer::Peer;
29use crate::peer::PeerMap;
30use crate::peer::User;
31use crate::peer::chats::AdminRightsBuilderInner;
32use crate::peer::chats::BannedRightsBuilderInner;
33
34const MAX_PARTICIPANT_LIMIT: usize = 200;
35const MAX_PHOTO_LIMIT: usize = 100;
36const KICK_BAN_DURATION: i32 = 60; // in seconds, in case the second request fails
37
38enum ParticipantIterInner {
39    Empty,
40    Chat {
41        client: Client,
42        chat_id: i64,
43        buffer: VecDeque<Participant>,
44        total: Option<usize>,
45    },
46    Channel(IterBuffer<tl::functions::channels::GetParticipants, Participant>),
47}
48
49/// Iterator returned by [`Client::iter_participants`].
50pub struct ParticipantIter(ParticipantIterInner);
51
52impl ParticipantIter {
53    fn new(client: &Client, peer: PeerRef) -> Self {
54        Self(if peer.id.kind() == PeerKind::Channel {
55            ParticipantIterInner::Channel(IterBuffer::from_request(
56                client,
57                MAX_PARTICIPANT_LIMIT,
58                tl::functions::channels::GetParticipants {
59                    channel: peer.into(),
60                    filter: tl::enums::ChannelParticipantsFilter::ChannelParticipantsRecent,
61                    offset: 0,
62                    limit: 0,
63                    hash: 0,
64                },
65            ))
66        } else if peer.id.kind() == PeerKind::Chat {
67            ParticipantIterInner::Chat {
68                client: client.clone(),
69                chat_id: peer.into(),
70                buffer: VecDeque::new(),
71                total: None,
72            }
73        } else {
74            ParticipantIterInner::Empty
75        })
76    }
77
78    /// Determines how many participants there are in total.
79    ///
80    /// This only performs a network call if `next` has not been called before.
81    pub async fn total(&mut self) -> Result<usize, InvocationError> {
82        match &self.0 {
83            ParticipantIterInner::Empty => Ok(0),
84            ParticipantIterInner::Chat { total, .. } => {
85                if let Some(total) = total {
86                    Ok(*total)
87                } else {
88                    self.fill_buffer().await
89                }
90            }
91            ParticipantIterInner::Channel(iter) => {
92                if let Some(total) = iter.total {
93                    Ok(total)
94                } else {
95                    self.fill_buffer().await
96                }
97            }
98        }
99    }
100
101    /// Fills the buffer, and returns the total count.
102    async fn fill_buffer(&mut self) -> Result<usize, InvocationError> {
103        match &mut self.0 {
104            ParticipantIterInner::Empty => Ok(0),
105            ParticipantIterInner::Chat {
106                client,
107                chat_id,
108                buffer,
109                total,
110            } => {
111                assert!(buffer.is_empty());
112                let tl::enums::messages::ChatFull::Full(full) = client
113                    .invoke(&tl::functions::messages::GetFullChat { chat_id: *chat_id })
114                    .await?;
115
116                let chat = match full.full_chat {
117                    tl::enums::ChatFull::Full(chat) => chat,
118                    tl::enums::ChatFull::ChannelFull(_) => panic!(
119                        "API returned ChannelFull even though messages::GetFullChat was used"
120                    ),
121                };
122
123                // Don't actually care for the chats, just the users.
124                let mut peers = client.build_peer_map(full.users, Vec::new()).await;
125
126                let participants = match chat.participants {
127                    tl::enums::ChatParticipants::Forbidden(c) => {
128                        if let Some(p) = c.self_participant {
129                            buffer.push_back(Participant::from_raw_chat(&mut peers, p));
130                        }
131                        return Ok(buffer.len());
132                    }
133                    tl::enums::ChatParticipants::Participants(c) => c.participants,
134                };
135
136                buffer.extend(
137                    participants
138                        .into_iter()
139                        .map(|p| Participant::from_raw_chat(&mut peers, p)),
140                );
141
142                *total = Some(buffer.len());
143                Ok(buffer.len())
144            }
145            ParticipantIterInner::Channel(iter) => {
146                assert!(iter.buffer.is_empty());
147                use tl::enums::channels::ChannelParticipants::*;
148
149                iter.request.limit = iter.determine_limit(MAX_PARTICIPANT_LIMIT);
150                let (count, participants, _, users) =
151                    match iter.client.invoke(&iter.request).await? {
152                        Participants(p) => (p.count, p.participants, p.chats, p.users),
153                        NotModified => {
154                            panic!("API returned Dialogs::NotModified even though hash = 0")
155                        }
156                    };
157
158                // Telegram can return less participants than asked for but the count being higher
159                // (for example, count=4825, participants=199, users=200). The missing participant
160                // was an admin bot account, not sure why it's not included.
161                //
162                // In any case we pick whichever size is highest to avoid weird cases like this.
163                iter.last_chunk =
164                    usize::max(participants.len(), users.len()) < iter.request.limit as usize;
165                iter.request.offset += participants.len() as i32;
166
167                // Don't actually care for the chats, just the users.
168                let mut peers = iter.client.build_peer_map(users, Vec::new()).await;
169
170                iter.buffer.extend(
171                    participants
172                        .into_iter()
173                        .map(|p| Participant::from_raw_channel(&mut peers, p)),
174                );
175
176                iter.total = Some(count as usize);
177                Ok(count as usize)
178            }
179        }
180    }
181
182    /// Return the next `Participant` from the internal buffer, filling the buffer previously if
183    /// it's empty.
184    ///
185    /// Returns `None` if the `limit` is reached or there are no participants left.
186    pub async fn next(&mut self) -> Result<Option<Participant>, InvocationError> {
187        // Need to split the `match` because `fill_buffer()` borrows mutably.
188        match &mut self.0 {
189            ParticipantIterInner::Empty => {}
190            ParticipantIterInner::Chat { buffer, .. } => {
191                if buffer.is_empty() {
192                    self.fill_buffer().await?;
193                }
194            }
195            ParticipantIterInner::Channel(iter) => {
196                if let Some(result) = iter.next_raw() {
197                    return result;
198                }
199                self.fill_buffer().await?;
200            }
201        }
202
203        match &mut self.0 {
204            ParticipantIterInner::Empty => Ok(None),
205            ParticipantIterInner::Chat { buffer, .. } => {
206                let result = buffer.pop_front();
207                if buffer.is_empty() {
208                    self.0 = ParticipantIterInner::Empty;
209                }
210                Ok(result)
211            }
212            ParticipantIterInner::Channel(iter) => Ok(iter.pop_item()),
213        }
214    }
215
216    /// apply a filter on fetched participants, note that this filter will apply only on large `Channel` and not small groups
217    pub fn filter(mut self, filter: tl::enums::ChannelParticipantsFilter) -> Self {
218        match self.0 {
219            ParticipantIterInner::Channel(ref mut c) => {
220                c.request.filter = filter;
221                self
222            }
223            _ => self,
224        }
225    }
226}
227
228enum ProfilePhotoIterInner {
229    User(IterBuffer<tl::functions::photos::GetUserPhotos, Photo>),
230    Chat(IterBuffer<tl::functions::messages::Search, Message>),
231}
232
233/// Iterator returned by [`Client::iter_profile_photos`].
234pub struct ProfilePhotoIter(ProfilePhotoIterInner);
235
236impl ProfilePhotoIter {
237    fn new(client: &Client, peer: PeerRef) -> Self {
238        Self(if matches!(peer.id.kind(), PeerKind::User) {
239            ProfilePhotoIterInner::User(IterBuffer::from_request(
240                client,
241                MAX_PHOTO_LIMIT,
242                tl::functions::photos::GetUserPhotos {
243                    user_id: peer.into(),
244                    offset: 0,
245                    max_id: 0,
246                    limit: 0,
247                },
248            ))
249        } else {
250            ProfilePhotoIterInner::Chat(
251                client
252                    .search_messages(peer)
253                    .filter(tl::enums::MessagesFilter::InputMessagesFilterChatPhotos),
254            )
255        })
256    }
257
258    /// Determines how many profile photos there are in total.
259    ///
260    /// This only performs a network call if `next` has not been called before.
261    pub async fn total(&mut self) -> Result<usize, InvocationError> {
262        match &mut self.0 {
263            ProfilePhotoIterInner::User(iter) => {
264                if let Some(total) = iter.total {
265                    Ok(total)
266                } else {
267                    self.fill_buffer().await
268                }
269            }
270            ProfilePhotoIterInner::Chat(iter) => iter.total().await,
271        }
272    }
273
274    /// Fills the buffer, and returns the total count.
275    async fn fill_buffer(&mut self) -> Result<usize, InvocationError> {
276        match &mut self.0 {
277            ProfilePhotoIterInner::User(iter) => {
278                use tl::enums::photos::Photos;
279
280                iter.request.limit = iter.determine_limit(MAX_PHOTO_LIMIT);
281                let (total, photos) = match iter.client.invoke(&iter.request).await? {
282                    Photos::Photos(p) => {
283                        iter.last_chunk = true;
284                        iter.total = Some(p.photos.len());
285                        (p.photos.len(), p.photos)
286                    }
287                    Photos::Slice(p) => {
288                        iter.last_chunk = p.photos.len() < iter.request.limit as usize;
289                        iter.total = Some(p.count as usize);
290                        (p.count as usize, p.photos)
291                    }
292                };
293
294                // Don't bother updating offsets if this is the last time stuff has to be fetched.
295                if !iter.last_chunk && !photos.is_empty() {
296                    iter.request.offset += photos.len() as i32;
297                }
298
299                iter.buffer.extend(photos.into_iter().map(Photo::from_raw));
300
301                Ok(total)
302            }
303            ProfilePhotoIterInner::Chat(_) => {
304                panic!("fill_buffer should not be called for Chat variant")
305            }
306        }
307    }
308
309    /// Return the next photo from the internal buffer, filling the buffer previously if it's
310    /// empty.
311    ///
312    /// Returns `None` if the `limit` is reached or there are no photos left.
313    pub async fn next(&mut self) -> Result<Option<Photo>, InvocationError> {
314        // Need to split the `match` because `fill_buffer()` borrows mutably.
315        match &mut self.0 {
316            ProfilePhotoIterInner::User(iter) => {
317                if let Some(result) = iter.next_raw() {
318                    return result;
319                }
320                self.fill_buffer().await?;
321            }
322            ProfilePhotoIterInner::Chat(iter) => {
323                while let Some(message) = iter.next().await? {
324                    if let Some(tl::enums::MessageAction::ChatEditPhoto(
325                        tl::types::MessageActionChatEditPhoto { photo },
326                    )) = message.action()
327                    {
328                        return Ok(Some(Photo::from_raw(photo.clone())));
329                    } else {
330                        continue;
331                    }
332                }
333            }
334        }
335
336        match &mut self.0 {
337            ProfilePhotoIterInner::User(iter) => Ok(iter.pop_item()),
338            ProfilePhotoIterInner::Chat(_) => Ok(None),
339        }
340    }
341}
342
343fn updates_to_chat(client: &Client, id: Option<i64>, updates: tl::enums::Updates) -> Option<Peer> {
344    use tl::enums::Updates;
345
346    let chats = match updates {
347        Updates::Combined(updates) => Some(updates.chats),
348        Updates::Updates(updates) => Some(updates.chats),
349        _ => None,
350    };
351
352    match chats {
353        Some(chats) => match id {
354            Some(id) => chats.into_iter().find(|chat| chat.id() == id),
355            None => chats.into_iter().next(),
356        },
357        None => None,
358    }
359    .map(|chat| Peer::from_raw(client, chat))
360}
361
362/// Method implementations related to dealing with peers.
363impl Client {
364    /// Resolves a username into the peer that owns it, if any.
365    ///
366    /// Note that this method is expensive to call, and can quickly cause long flood waits.
367    ///
368    /// # Examples
369    ///
370    /// ```
371    /// # async fn f(client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
372    /// if let Some(peer) = client.resolve_username("username").await? {
373    ///     println!("Found peer!: {:?}", peer.name());
374    /// }
375    /// # Ok(())
376    /// # }
377    /// ```
378    pub async fn resolve_username(&self, username: &str) -> Result<Option<Peer>, InvocationError> {
379        let tl::types::contacts::ResolvedPeer { peer, users, chats } = match self
380            .invoke(&tl::functions::contacts::ResolveUsername {
381                username: username.into(),
382                referer: None,
383            })
384            .await
385        {
386            Ok(tl::enums::contacts::ResolvedPeer::Peer(p)) => p,
387            Err(err) if err.is("USERNAME_NOT_OCCUPIED") => return Ok(None),
388            Err(err) => return Err(err),
389        };
390
391        let mut peers = self.build_peer_map(users, chats).await;
392        let peer_id = PeerId::from(peer);
393
394        Ok(peers.take(peer_id))
395    }
396
397    /// Fetch full information about the currently logged-in user.
398    ///
399    /// Although this method is cheap to call, you might want to cache the results somewhere.
400    ///
401    /// # Examples
402    ///
403    /// ```
404    /// # async fn f(client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
405    /// println!("Displaying full user information of the logged-in user:");
406    /// dbg!(client.get_me().await?);
407    /// # Ok(())
408    /// # }
409    /// ```
410    pub async fn get_me(&self) -> Result<User, InvocationError> {
411        let mut res = self
412            .invoke(&tl::functions::users::GetUsers {
413                id: vec![tl::enums::InputUser::UserSelf],
414            })
415            .await?;
416
417        if res.len() != 1 {
418            panic!("fetching only one user should exactly return one user");
419        }
420
421        Ok(User::from_raw(self, res.pop().unwrap()))
422    }
423
424    /// Iterate over the participants of a chat.
425    ///
426    /// The participants are returned in no particular order.
427    ///
428    /// When used to iterate the participants of "user", the iterator won't produce values.
429    ///
430    /// # Examples
431    ///
432    /// ```
433    /// # async fn f(chat: grammers_session::types::PeerRef, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
434    /// let mut participants = client.iter_participants(chat);
435    ///
436    /// while let Some(participant) = participants.next().await? {
437    ///     println!(
438    ///         "{} has role {:?}",
439    ///         participant.user.first_name().unwrap_or(&participant.user.id().to_string()),
440    ///         participant.role
441    ///     );
442    /// }
443    /// # Ok(())
444    /// # }
445    /// ```
446    pub fn iter_participants<C: Into<PeerRef>>(&self, chat: C) -> ParticipantIter {
447        ParticipantIter::new(self, chat.into())
448    }
449
450    /// Kicks the participant from the chat.
451    ///
452    /// This will fail if you do not have sufficient permissions to perform said operation,
453    /// or the target user is the logged-in account. Use [`Self::delete_dialog`] for the latter instead.
454    ///
455    /// The kicked user will be able to join after being kicked (they are not permanently banned).
456    ///
457    /// Kicking someone who was not in the chat prior to running this method will be able to join
458    /// after as well (effectively unbanning them).
459    ///
460    /// When used to kick users from "user" chat, nothing will be done.
461    ///
462    /// # Examples
463    ///
464    /// ```
465    /// # async fn f(chat: grammers_session::types::PeerRef, user: grammers_session::types::PeerRef, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
466    /// match client.kick_participant(chat, user).await {
467    ///     Ok(_) => println!("user is no more >:D"),
468    ///     Err(_) => println!("Kick failed! Are you sure you're admin?"),
469    /// };
470    /// # Ok(())
471    /// # }
472    /// ```
473    pub async fn kick_participant<C: Into<PeerRef>, U: Into<PeerRef>>(
474        &self,
475        chat: C,
476        user: U,
477    ) -> Result<(), InvocationError> {
478        let chat = chat.into();
479        let user = user.into();
480        if chat.id.kind() == PeerKind::Channel {
481            self.set_banned_rights(chat, user)
482                .view_messages(false)
483                .duration(Duration::from_secs(KICK_BAN_DURATION as u64))
484                .await?;
485
486            self.set_banned_rights(chat, user).await
487        } else if chat.id.kind() == PeerKind::Chat {
488            self.invoke(&tl::functions::messages::DeleteChatUser {
489                chat_id: chat.into(),
490                user_id: user.into(),
491                revoke_history: false,
492            })
493            .await
494            .map(drop)
495        } else {
496            Ok(())
497        }
498    }
499
500    /// Returns a builder to set the banned rights for a specific user.
501    ///
502    /// Nothing is done until it is awaited, at which point it might result in
503    /// error if you do not have sufficient permissions to ban the user in the input chat.
504    ///
505    /// By default, the user has all rights, and you need to revoke those you want to take away
506    /// from the user by setting the permissions to `false`. This means that not taking away any
507    /// permissions will effectively unban someone, granting them all default user permissions.
508    ///
509    /// By default, the ban is applied forever, but this can be changed to a shorter duration.
510    ///
511    /// The default group rights are respected, despite individual restrictions.
512    ///
513    /// # Example
514    ///
515    /// ```
516    /// # async fn f(chat: grammers_session::types::PeerRef, user: grammers_session::types::PeerRef, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
517    /// // This user keeps spamming pepe stickers, take the sticker permission away from them
518    /// let res = client
519    ///     .set_banned_rights(chat, user)
520    ///     .send_stickers(false)
521    ///     .await;
522    ///
523    /// match res {
524    ///     Ok(_) => println!("No more sticker spam!"),
525    ///     Err(_) => println!("Ban failed! Are you sure you're admin?"),
526    /// };
527    /// # Ok(())
528    /// # }
529    /// ```
530    pub fn set_banned_rights<C: Into<PeerRef>, U: Into<PeerRef>>(
531        &self,
532        channel: C,
533        user: U,
534    ) -> BannedRightsBuilder<impl Future<Output = Result<(), InvocationError>>> {
535        BannedRightsBuilder::new(
536            self.clone(),
537            channel.into(),
538            user.into(),
539            BannedRightsBuilderInner::invoke,
540        )
541    }
542
543    /// Returns a builder to set the administrator rights for a specific user.
544    ///
545    /// Nothing is done until it is awaited, at which point
546    /// it might result in error if you do not have sufficient permissions to grant those rights
547    /// to the other user.
548    ///
549    /// By default, no permissions are granted, and you need to specify those you want to grant by
550    /// setting the permissions to `true`. This means that not granting any permission will turn
551    /// the user into a normal user again, and they will no longer be an administrator.
552    ///
553    /// The change is applied forever and there is no way to set a specific duration. If the user
554    /// should only be an administrator for a set period of time, the administrator permissions
555    /// must be manually revoked at a later point in time.
556    ///
557    /// # Example
558    ///
559    /// ```
560    /// # async fn f(chat: grammers_session::types::PeerRef, user: grammers_session::types::PeerRef, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
561    /// // Let the user pin messages and ban other people
562    /// let res = client.set_admin_rights(chat, user)
563    ///     .load_current()
564    ///     .await?
565    ///     .pin_messages(true)
566    ///     .ban_users(true)
567    ///     .await?;
568    /// # Ok(())
569    /// # }
570    /// ```
571    pub fn set_admin_rights<C: Into<PeerRef>, U: Into<PeerRef>>(
572        &self,
573        channel: C,
574        user: U,
575    ) -> AdminRightsBuilder<impl Future<Output = Result<(), InvocationError>>> {
576        AdminRightsBuilder::new(
577            self.clone(),
578            channel.into(),
579            user.into(),
580            AdminRightsBuilderInner::invoke,
581        )
582    }
583
584    /// Iterate over the history of profile photos for the given peer.
585    ///
586    /// Note that the current photo might not be present in the history, and to avoid doing more
587    /// work when it's generally not needed (the photo history tends to be complete but in some
588    /// cases it might not be), it's up to you to fetch this photo from the full channel.
589    ///
590    /// Note that you cannot use these photos to send them as messages directly. They must be
591    /// downloaded first, then uploaded, and finally sent.
592    ///
593    /// # Examples
594    ///
595    /// ```
596    /// # async fn f(peer: grammers_session::types::PeerRef, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
597    /// let mut photos = client.iter_profile_photos(peer);
598    ///
599    /// while let Some(photo) = photos.next().await? {
600    ///     println!("Did you know peer has a photo with ID {}?", photo.id());
601    /// }
602    /// # Ok(())
603    /// # }
604    /// ```
605    pub fn iter_profile_photos<C: Into<PeerRef>>(&self, peer: C) -> ProfilePhotoIter {
606        ProfilePhotoIter::new(self, peer.into())
607    }
608
609    /// Convert a [`PeerRef`] back into a [`Peer`].
610    ///
611    /// # Example
612    ///
613    /// ```
614    /// # async fn f(peer: grammers_session::types::PeerRef, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
615    /// let peer = client.resolve_peer(peer).await?;
616    ///
617    /// println!("Found peer: {}", peer.name().unwrap_or(&peer.id().to_string()));
618    /// # Ok(())
619    /// # }
620    /// ```
621    pub async fn resolve_peer<C: Into<PeerRef>>(&self, peer: C) -> Result<Peer, InvocationError> {
622        let peer = peer.into();
623        let mut peers = match peer.id.kind() {
624            PeerKind::User => {
625                let res = self
626                    .invoke(&tl::functions::users::GetUsers {
627                        id: vec![peer.into()],
628                    })
629                    .await?;
630                if res.len() > 1 {
631                    panic!("fetching only one user should exactly return one user");
632                }
633                self.build_peer_map(res, Vec::new()).await
634            }
635            PeerKind::Chat => {
636                let res = match self
637                    .invoke(&tl::functions::messages::GetChats {
638                        id: vec![peer.into()],
639                    })
640                    .await?
641                {
642                    tl::enums::messages::Chats::Chats(chats) => chats.chats,
643                    tl::enums::messages::Chats::Slice(chat_slice) => chat_slice.chats,
644                };
645                if res.len() > 1 {
646                    panic!("fetching only one chat should exactly return one chat");
647                }
648                self.build_peer_map(Vec::new(), res).await
649            }
650            PeerKind::Channel => {
651                let res = match self
652                    .invoke(&tl::functions::channels::GetChannels {
653                        id: vec![peer.into()],
654                    })
655                    .await?
656                {
657                    tl::enums::messages::Chats::Chats(chats) => chats.chats,
658                    tl::enums::messages::Chats::Slice(chat_slice) => chat_slice.chats,
659                };
660                if res.len() > 1 {
661                    panic!("fetching only one channel should exactly return one chat");
662                }
663                self.build_peer_map(Vec::new(), res).await
664            }
665        };
666        peers.take(peer.id).ok_or(InvocationError::Dropped)
667    }
668
669    /// Get permissions of participant `user` from chat `chat`.
670    ///
671    /// # Example
672    ///
673    /// ```
674    /// # async fn f(chat: grammers_session::types::PeerRef, user: grammers_session::types::PeerRef, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
675    /// let permissions = client.get_permissions(chat, user).await?;
676    /// println!("The user {} an admin", if permissions.is_admin() { "is" } else { "is not" });
677    /// # Ok(())
678    /// # }
679    /// ```
680    pub async fn get_permissions<C: Into<PeerRef>, U: Into<PeerRef>>(
681        &self,
682        chat: C,
683        user: U,
684    ) -> Result<ParticipantPermissions, InvocationError> {
685        let chat = chat.into();
686        let user = user.into();
687
688        // Get by chat
689        if chat.id.kind() == PeerKind::Chat {
690            // Get user id
691            let user = user.into();
692            let user_id = match user {
693                tl::enums::InputUser::User(user) => user.user_id,
694                tl::enums::InputUser::FromMessage(user) => user.user_id,
695                tl::enums::InputUser::UserSelf => {
696                    let me = self.get_me().await?;
697                    me.id().bare_id_unchecked()
698                }
699                tl::enums::InputUser::Empty => return Err(InvocationError::Dropped),
700            };
701
702            // Get chat and find user
703            let chat = self
704                .invoke(&tl::functions::messages::GetFullChat {
705                    chat_id: chat.into(),
706                })
707                .await?;
708            let tl::enums::messages::ChatFull::Full(chat) = chat;
709            if let tl::enums::ChatFull::Full(chat) = chat.full_chat {
710                if let tl::enums::ChatParticipants::Participants(participants) = chat.participants {
711                    for participant in participants.participants {
712                        if participant.user_id() == user_id {
713                            return Ok(ParticipantPermissions(ParticipantPermissionsInner::Chat(
714                                participant,
715                            )));
716                        }
717                    }
718                }
719            }
720            return Err(InvocationError::Rpc(RpcError {
721                code: 400,
722                name: "USER_NOT_PARTICIPANT".to_string(),
723                value: None,
724                caused_by: None,
725            }));
726        }
727
728        // Get by channel
729        let participant = self
730            .invoke(&tl::functions::channels::GetParticipant {
731                channel: chat.into(),
732                participant: user.into(),
733            })
734            .await?;
735        let tl::enums::channels::ChannelParticipant::Participant(participant) = participant;
736        Ok(ParticipantPermissions(
737            ParticipantPermissionsInner::Channel(participant.participant),
738        ))
739    }
740
741    #[cfg(feature = "parse_invite_link")]
742    pub fn parse_invite_link(invite_link: &str) -> Option<String> {
743        let url_parse_result = url::Url::parse(invite_link);
744        if url_parse_result.is_err() {
745            return None;
746        }
747
748        let url_parse = url_parse_result.unwrap();
749        let scheme = url_parse.scheme();
750        let path = url_parse.path();
751        if url_parse.host_str().is_none() || !vec!["https", "http"].contains(&scheme) {
752            return None;
753        }
754        let host = url_parse.host_str().unwrap();
755        let hosts = [
756            "t.me",
757            "telegram.me",
758            "telegram.dog",
759            "tg.dev",
760            "telegram.me",
761            "telesco.pe",
762        ];
763
764        if !hosts.contains(&host) {
765            return None;
766        }
767        let paths = path.split("/").skip(1).collect::<Vec<&str>>();
768
769        if paths.len() == 1 {
770            if paths[0].starts_with("+") {
771                return Some(paths[0].replace("+", ""));
772            }
773            return None;
774        }
775
776        if paths.len() > 1 {
777            if paths[0].starts_with("joinchat") {
778                return Some(paths[1].to_string());
779            }
780            if paths[0].starts_with("+") {
781                return Some(paths[0].replace("+", ""));
782            }
783            return None;
784        }
785
786        None
787    }
788
789    /// Accept an invite link to join the corresponding private chat.
790    ///
791    /// If the chat is public (has a public username), [`Client::join_chat`](Client::join_chat) should be used instead.
792    #[cfg(feature = "parse_invite_link")]
793    pub async fn accept_invite_link(
794        &self,
795        invite_link: &str,
796    ) -> Result<Option<Peer>, InvocationError> {
797        match Self::parse_invite_link(invite_link) {
798            Some(hash) => Ok(
799                if let tl::enums::messages::ChatInviteJoinResult::Ok(ok) = self
800                    .invoke(&tl::functions::messages::ImportChatInvite { hash })
801                    .await?
802                {
803                    updates_to_chat(self, None, ok.updates)
804                } else {
805                    None
806                },
807            ),
808            None => Err(InvocationError::Rpc(RpcError {
809                code: 400,
810                name: "INVITE_HASH_INVALID".to_string(),
811                value: None,
812                caused_by: None,
813            })),
814        }
815    }
816
817    #[cfg_attr(
818        not(feature = "parse_invite_link"),
819        allow(rustdoc::broken_intra_doc_links)
820    )]
821    /// Join a public group or channel.
822    ///
823    /// A channel is public if it has a username.
824    /// To join private chats, [`Client::accept_invite_link`](Client::accept_invite_link) should be used instead.
825    pub async fn join_chat<C: Into<PeerRef>>(
826        &self,
827        chat: C,
828    ) -> Result<Option<Peer>, InvocationError> {
829        let chat: PeerRef = chat.into();
830        let channel = chat.into();
831        Ok(
832            if let tl::enums::messages::ChatInviteJoinResult::Ok(ok) = self
833                .invoke(&tl::functions::channels::JoinChannel { channel })
834                .await?
835            {
836                updates_to_chat(self, chat.id.bare_id(), ok.updates)
837            } else {
838                None
839            },
840        )
841    }
842
843    /// Send a message action (such as typing, uploading photo, or viewing an emoji interaction)
844    ///
845    /// # Examples
846    ///
847    /// **Do a one-shot pulse and let it fade away**
848    /// ```
849    /// # async fn f(peer: grammers_session::types::PeerRef, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
850    /// use grammers_tl_types::enums::SendMessageAction;
851    ///
852    /// client
853    ///     .action(peer)
854    ///     .oneshot(SendMessageAction::SendMessageTypingAction)
855    ///     .await?;
856    /// # Ok(())
857    /// # }
858    /// ```
859    ///
860    /// **Repeat request until the future is done**
861    /// ```
862    /// # use std::time::Duration;
863    ///
864    /// # async fn f(peer: grammers_session::types::PeerRef, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
865    /// use grammers_tl_types as tl;
866    ///
867    /// let heavy_task = async {
868    ///     tokio::time::sleep(Duration::from_secs(10)).await;
869    ///
870    ///     42
871    /// };
872    ///
873    /// tokio::pin!(heavy_task);
874    ///
875    /// let (task_result, _) = client
876    ///     .action(peer)
877    ///     .repeat(
878    ///         // most clients doesn't actually show progress of an action
879    ///         || tl::types::SendMessageUploadDocumentAction { progress: 0 },
880    ///         heavy_task
881    ///     )
882    ///     .await;
883    ///
884    /// // Note: repeat function does not cancel actions automatically, they will just fade away
885    ///
886    /// assert_eq!(task_result, 42);
887    /// # Ok(())
888    /// # }
889    /// ```
890    ///
891    /// **Cancel any actions**
892    /// ```
893    /// # async fn f(peer: grammers_session::types::PeerRef, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
894    /// client.action(peer).cancel().await?;
895    /// # Ok(())
896    /// # }
897    /// ```
898    pub fn action<C: Into<PeerRef>>(&self, peer: C) -> ActionSender {
899        ActionSender::new(self, peer)
900    }
901
902    pub(crate) async fn build_peer_map(
903        &self,
904        users: Vec<tl::enums::User>,
905        chats: Vec<tl::enums::Chat>,
906    ) -> PeerMap {
907        let map = users
908            .into_iter()
909            .map(|user| Peer::from_user(self, user))
910            .chain(chats.into_iter().map(|chat| Peer::from_raw(self, chat)))
911            .map(|peer| (peer.id(), peer))
912            .collect::<HashMap<_, _>>();
913
914        if self.0.configuration.auto_cache_peers {
915            for peer in map.values() {
916                if peer.auth().is_some() {
917                    if let Err(e) = self.0.session.cache_peer(&peer.into()).await {
918                        log::warn!("cache_peer fail: {:?}", e)
919                    }
920                }
921            }
922        }
923
924        PeerMap {
925            map: Arc::new(map),
926            session: Arc::clone(&self.0.session),
927        }
928    }
929
930    pub(crate) fn empty_peer_map(&self) -> PeerMap {
931        PeerMap {
932            map: Arc::new(HashMap::new()),
933            session: Arc::clone(&self.0.session),
934        }
935    }
936}
937
938#[derive(Debug, Clone)]
939enum ParticipantPermissionsInner {
940    Channel(tl::enums::ChannelParticipant),
941    Chat(tl::enums::ChatParticipant),
942}
943
944/// Permissions returned by [`Client::get_permissions`].
945#[derive(Debug, Clone)]
946pub struct ParticipantPermissions(ParticipantPermissionsInner);
947
948impl ParticipantPermissions {
949    /// Whether the user is the creator of the chat or not.
950    pub fn is_creator(&self) -> bool {
951        matches!(
952            self.0,
953            ParticipantPermissionsInner::Channel(tl::enums::ChannelParticipant::Creator(_))
954                | ParticipantPermissionsInner::Chat(tl::enums::ChatParticipant::Creator(_))
955        )
956    }
957
958    /// Whether the user is an administrator of the chat or not. The creator also counts as begin an administrator, since they have all permissions.
959    pub fn is_admin(&self) -> bool {
960        self.is_creator()
961            || matches!(
962                self.0,
963                ParticipantPermissionsInner::Channel(tl::enums::ChannelParticipant::Admin(_))
964                    | ParticipantPermissionsInner::Chat(tl::enums::ChatParticipant::Admin(_))
965            )
966    }
967
968    /// Whether the user is banned in the chat.
969    pub fn is_banned(&self) -> bool {
970        matches!(
971            self.0,
972            ParticipantPermissionsInner::Channel(tl::enums::ChannelParticipant::Banned(_))
973        )
974    }
975
976    /// Whether the user left the chat.
977    pub fn has_left(&self) -> bool {
978        matches!(
979            self.0,
980            ParticipantPermissionsInner::Channel(tl::enums::ChannelParticipant::Left(_))
981        )
982    }
983
984    /// Whether the user is a normal user of the chat (not administrator, but not banned either, and has no restrictions applied).
985    pub fn has_default_permissions(&self) -> bool {
986        matches!(
987            self.0,
988            ParticipantPermissionsInner::Channel(tl::enums::ChannelParticipant::Participant(_))
989                | ParticipantPermissionsInner::Channel(
990                    tl::enums::ChannelParticipant::ParticipantSelf(_)
991                )
992                | ParticipantPermissionsInner::Chat(tl::enums::ChatParticipant::Participant(_))
993        )
994    }
995
996    /// Whether the administrator can add new administrators with the same or less permissions than them.
997    pub fn can_add_admins(&self) -> bool {
998        if !self.is_admin() {
999            return false;
1000        }
1001        match &self.0 {
1002            ParticipantPermissionsInner::Channel(tl::enums::ChannelParticipant::Admin(
1003                participant,
1004            )) => {
1005                let tl::enums::ChatAdminRights::Rights(rights) = &participant.admin_rights;
1006                rights.add_admins
1007            }
1008            ParticipantPermissionsInner::Channel(tl::enums::ChannelParticipant::Creator(_)) => true,
1009            ParticipantPermissionsInner::Chat(_) => self.is_creator(),
1010            _ => false,
1011        }
1012    }
1013}