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