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