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}