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