1use std::collections::VecDeque;
6
7use layer_tl_types as tl;
8use layer_tl_types::{Cursor, Deserializable};
9
10use crate::{Client, InvocationError, PeerRef};
11
12#[derive(Debug, Clone)]
16pub struct Participant {
17 pub user: tl::types::User,
19 pub status: ParticipantStatus,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq)]
25pub enum ParticipantStatus {
26 Member,
28 Creator,
30 Admin,
32 Restricted,
34 Left,
36 Banned,
38}
39
40impl Client {
43 pub async fn get_participants(
50 &self,
51 peer: impl Into<PeerRef>,
52 limit: i32,
53 ) -> Result<Vec<Participant>, InvocationError> {
54 let peer = peer.into().resolve(self).await?;
55 match &peer {
56 tl::enums::Peer::Channel(c) => {
57 let cache = self.inner.peer_cache.read().await;
58 let access_hash = cache.channels.get(&c.channel_id).copied().unwrap_or(0);
59 drop(cache);
60 self.get_channel_participants(c.channel_id, access_hash, limit)
61 .await
62 }
63 tl::enums::Peer::Chat(c) => self.get_chat_participants(c.chat_id).await,
64 _ => Err(InvocationError::Deserialize(
65 "get_participants: peer must be a chat or channel".into(),
66 )),
67 }
68 }
69
70 async fn get_channel_participants(
71 &self,
72 channel_id: i64,
73 access_hash: i64,
74 limit: i32,
75 ) -> Result<Vec<Participant>, InvocationError> {
76 let limit = if limit <= 0 { 200 } else { limit };
77 let req = tl::functions::channels::GetParticipants {
78 channel: tl::enums::InputChannel::InputChannel(tl::types::InputChannel {
79 channel_id,
80 access_hash,
81 }),
82 filter: tl::enums::ChannelParticipantsFilter::ChannelParticipantsRecent,
83 offset: 0,
84 limit,
85 hash: 0,
86 };
87 let body = self.rpc_call_raw_pub(&req).await?;
88 let mut cur = Cursor::from_slice(&body);
89 let raw = match tl::enums::channels::ChannelParticipants::deserialize(&mut cur)? {
90 tl::enums::channels::ChannelParticipants::ChannelParticipants(p) => p,
91 tl::enums::channels::ChannelParticipants::NotModified => return Ok(vec![]),
92 };
93
94 let user_map: std::collections::HashMap<i64, tl::types::User> = raw
96 .users
97 .into_iter()
98 .filter_map(|u| match u {
99 tl::enums::User::User(u) => Some((u.id, u)),
100 _ => None,
101 })
102 .collect();
103
104 {
106 let mut cache = self.inner.peer_cache.write().await;
107 for u in user_map.values() {
108 if let Some(h) = u.access_hash {
109 cache.users.insert(u.id, h);
110 }
111 }
112 }
113
114 let mut result = Vec::new();
115 for p in raw.participants {
116 let (user_id, status) = match &p {
117 tl::enums::ChannelParticipant::ChannelParticipant(x) => {
118 (x.user_id, ParticipantStatus::Member)
119 }
120 tl::enums::ChannelParticipant::ParticipantSelf(x) => {
121 (x.user_id, ParticipantStatus::Member)
122 }
123 tl::enums::ChannelParticipant::Creator(x) => {
124 (x.user_id, ParticipantStatus::Creator)
125 }
126 tl::enums::ChannelParticipant::Admin(x) => (x.user_id, ParticipantStatus::Admin),
127 tl::enums::ChannelParticipant::Banned(x) => {
128 (x.peer.user_id_or(0), ParticipantStatus::Banned)
129 }
130 tl::enums::ChannelParticipant::Left(x) => {
131 (x.peer.user_id_or(0), ParticipantStatus::Left)
132 }
133 };
134 if let Some(user) = user_map.get(&user_id).cloned() {
135 result.push(Participant { user, status });
136 }
137 }
138 Ok(result)
139 }
140
141 async fn get_chat_participants(
142 &self,
143 chat_id: i64,
144 ) -> Result<Vec<Participant>, InvocationError> {
145 let req = tl::functions::messages::GetFullChat { chat_id };
146 let body = self.rpc_call_raw_pub(&req).await?;
147 let mut cur = Cursor::from_slice(&body);
148 let tl::enums::messages::ChatFull::ChatFull(full) =
149 tl::enums::messages::ChatFull::deserialize(&mut cur)?;
150
151 let user_map: std::collections::HashMap<i64, tl::types::User> = full
152 .users
153 .into_iter()
154 .filter_map(|u| match u {
155 tl::enums::User::User(u) => Some((u.id, u)),
156 _ => None,
157 })
158 .collect();
159
160 {
161 let mut cache = self.inner.peer_cache.write().await;
162 for u in user_map.values() {
163 if let Some(h) = u.access_hash {
164 cache.users.insert(u.id, h);
165 }
166 }
167 }
168
169 let participants = match &full.full_chat {
170 tl::enums::ChatFull::ChatFull(cf) => match &cf.participants {
171 tl::enums::ChatParticipants::ChatParticipants(p) => p.participants.clone(),
172 tl::enums::ChatParticipants::Forbidden(_) => vec![],
173 },
174 tl::enums::ChatFull::ChannelFull(_) => {
175 return Err(InvocationError::Deserialize(
176 "get_chat_participants: peer is a channel, use get_participants with a Channel peer instead".into()
177 ));
178 }
179 };
180
181 let mut result = Vec::new();
182 for p in participants {
183 let (user_id, status) = match p {
184 tl::enums::ChatParticipant::ChatParticipant(x) => {
185 (x.user_id, ParticipantStatus::Member)
186 }
187 tl::enums::ChatParticipant::Creator(x) => (x.user_id, ParticipantStatus::Creator),
188 tl::enums::ChatParticipant::Admin(x) => (x.user_id, ParticipantStatus::Admin),
189 };
190 if let Some(user) = user_map.get(&user_id).cloned() {
191 result.push(Participant { user, status });
192 }
193 }
194 Ok(result)
195 }
196
197 pub async fn kick_participant(
199 &self,
200 chat_id: i64,
201 user_id: i64,
202 ) -> Result<(), InvocationError> {
203 let cache = self.inner.peer_cache.read().await;
204 let access_hash = cache.users.get(&user_id).copied().unwrap_or(0);
205 drop(cache);
206 let req = tl::functions::messages::DeleteChatUser {
207 revoke_history: false,
208 chat_id,
209 user_id: tl::enums::InputUser::InputUser(tl::types::InputUser {
210 user_id,
211 access_hash,
212 }),
213 };
214 self.rpc_call_raw_pub(&req).await?;
215 Ok(())
216 }
217
218 pub async fn ban_participant(
222 &self,
223 channel: impl Into<PeerRef>,
224 user_id: i64,
225 until_date: i32,
226 ) -> Result<(), InvocationError> {
227 let channel = channel.into().resolve(self).await?;
228 let (channel_id, ch_hash) = match &channel {
229 tl::enums::Peer::Channel(c) => {
230 let h = self
231 .inner
232 .peer_cache
233 .read()
234 .await
235 .channels
236 .get(&c.channel_id)
237 .copied()
238 .unwrap_or(0);
239 (c.channel_id, h)
240 }
241 _ => {
242 return Err(InvocationError::Deserialize(
243 "ban_participant: peer must be a channel".into(),
244 ));
245 }
246 };
247 let user_hash = self
248 .inner
249 .peer_cache
250 .read()
251 .await
252 .users
253 .get(&user_id)
254 .copied()
255 .unwrap_or(0);
256
257 let req = tl::functions::channels::EditBanned {
258 channel: tl::enums::InputChannel::InputChannel(tl::types::InputChannel {
259 channel_id,
260 access_hash: ch_hash,
261 }),
262 participant: tl::enums::InputPeer::User(tl::types::InputPeerUser {
263 user_id,
264 access_hash: user_hash,
265 }),
266 banned_rights: tl::enums::ChatBannedRights::ChatBannedRights(
267 tl::types::ChatBannedRights {
268 view_messages: true,
269 send_messages: true,
270 send_media: true,
271 send_stickers: true,
272 send_gifs: true,
273 send_games: true,
274 send_inline: true,
275 embed_links: true,
276 send_polls: true,
277 change_info: true,
278 invite_users: true,
279 pin_messages: true,
280 manage_topics: false,
281 send_photos: false,
282 send_videos: false,
283 send_roundvideos: false,
284 send_audios: false,
285 send_voices: false,
286 send_docs: false,
287 send_plain: false,
288 edit_rank: false,
289 until_date,
290 },
291 ),
292 };
293 self.rpc_call_raw_pub(&req).await?;
294 Ok(())
295 }
296
297 pub async fn promote_participant(
301 &self,
302 channel: impl Into<PeerRef>,
303 user_id: i64,
304 promote: bool,
305 ) -> Result<(), InvocationError> {
306 let channel = channel.into().resolve(self).await?;
307 let (channel_id, ch_hash) = match &channel {
308 tl::enums::Peer::Channel(c) => {
309 let h = self
310 .inner
311 .peer_cache
312 .read()
313 .await
314 .channels
315 .get(&c.channel_id)
316 .copied()
317 .unwrap_or(0);
318 (c.channel_id, h)
319 }
320 _ => {
321 return Err(InvocationError::Deserialize(
322 "promote_participant: peer must be a channel".into(),
323 ));
324 }
325 };
326 let user_hash = self
327 .inner
328 .peer_cache
329 .read()
330 .await
331 .users
332 .get(&user_id)
333 .copied()
334 .unwrap_or(0);
335
336 let rights = if promote {
337 tl::types::ChatAdminRights {
338 change_info: true,
339 post_messages: true,
340 edit_messages: true,
341 delete_messages: true,
342 ban_users: true,
343 invite_users: true,
344 pin_messages: true,
345 add_admins: false,
346 anonymous: false,
347 manage_call: true,
348 other: false,
349 manage_topics: false,
350 post_stories: false,
351 edit_stories: false,
352 delete_stories: false,
353 manage_direct_messages: false,
354 manage_ranks: false,
355 }
356 } else {
357 tl::types::ChatAdminRights {
358 change_info: false,
359 post_messages: false,
360 edit_messages: false,
361 delete_messages: false,
362 ban_users: false,
363 invite_users: false,
364 pin_messages: false,
365 add_admins: false,
366 anonymous: false,
367 manage_call: false,
368 other: false,
369 manage_topics: false,
370 post_stories: false,
371 edit_stories: false,
372 delete_stories: false,
373 manage_direct_messages: false,
374 manage_ranks: false,
375 }
376 };
377
378 let req = tl::functions::channels::EditAdmin {
379 channel: tl::enums::InputChannel::InputChannel(tl::types::InputChannel {
380 channel_id,
381 access_hash: ch_hash,
382 }),
383 user_id: tl::enums::InputUser::InputUser(tl::types::InputUser {
384 user_id,
385 access_hash: user_hash,
386 }),
387 admin_rights: tl::enums::ChatAdminRights::ChatAdminRights(rights),
388 rank: None,
389 };
390 self.rpc_call_raw_pub(&req).await?;
391 Ok(())
392 }
393
394 pub async fn get_profile_photos(
398 &self,
399 peer: impl Into<PeerRef>,
400 limit: i32,
401 ) -> Result<Vec<tl::enums::Photo>, InvocationError> {
402 let peer = peer.into().resolve(self).await?;
403 let input_peer = {
404 let cache = self.inner.peer_cache.read().await;
405 cache.peer_to_input(&peer)
406 };
407
408 let req = tl::functions::photos::GetUserPhotos {
409 user_id: match &input_peer {
410 tl::enums::InputPeer::User(u) => {
411 tl::enums::InputUser::InputUser(tl::types::InputUser {
412 user_id: u.user_id,
413 access_hash: u.access_hash,
414 })
415 }
416 tl::enums::InputPeer::PeerSelf => tl::enums::InputUser::UserSelf,
417 _ => {
418 return Err(InvocationError::Deserialize(
419 "get_profile_photos: peer must be a user".into(),
420 ));
421 }
422 },
423 offset: 0,
424 max_id: 0,
425 limit,
426 };
427 let body = self.rpc_call_raw_pub(&req).await?;
428 let mut cur = Cursor::from_slice(&body);
429 match tl::enums::photos::Photos::deserialize(&mut cur)? {
430 tl::enums::photos::Photos::Photos(p) => Ok(p.photos),
431 tl::enums::photos::Photos::Slice(p) => Ok(p.photos),
432 }
433 }
434
435 pub async fn iter_profile_photos(
455 &self,
456 peer: impl Into<PeerRef>,
457 chunk_size: i32,
458 ) -> Result<ProfilePhotoIter, InvocationError> {
459 let chunk_size = if chunk_size <= 0 { 100 } else { chunk_size };
460 let peer = peer.into().resolve(self).await?;
461 let input_peer = {
462 let cache = self.inner.peer_cache.read().await;
463 cache.peer_to_input(&peer)
464 };
465 let input_user = match &input_peer {
466 tl::enums::InputPeer::User(u) => {
467 tl::enums::InputUser::InputUser(tl::types::InputUser {
468 user_id: u.user_id,
469 access_hash: u.access_hash,
470 })
471 }
472 tl::enums::InputPeer::PeerSelf => tl::enums::InputUser::UserSelf,
473 _ => {
474 return Err(InvocationError::Deserialize(
475 "iter_profile_photos: peer must be a user".into(),
476 ));
477 }
478 };
479
480 Ok(ProfilePhotoIter {
481 client: self.clone(),
482 input_user,
483 chunk_size,
484 offset: 0,
485 buffer: VecDeque::new(),
486 done: false,
487 })
488 }
489
490 pub async fn search_peer(&self, query: &str) -> Result<Vec<tl::enums::Peer>, InvocationError> {
494 let req = tl::functions::contacts::Search {
495 q: query.to_string(),
496 limit: 20,
497 };
498 let body = self.rpc_call_raw_pub(&req).await?;
499 let mut cur = Cursor::from_slice(&body);
500 let tl::enums::contacts::Found::Found(found) =
501 tl::enums::contacts::Found::deserialize(&mut cur)?;
502
503 self.cache_users_slice_pub(&found.users).await;
504 self.cache_chats_slice_pub(&found.chats).await;
505
506 let mut peers = Vec::new();
507 for r in found.my_results.iter().chain(found.results.iter()) {
508 peers.push(r.clone());
509 }
510 Ok(peers)
511 }
512
513 pub async fn send_reaction(
529 &self,
530 peer: impl Into<PeerRef>,
531 message_id: i32,
532 reaction: impl Into<crate::reactions::InputReactions>,
533 ) -> Result<(), InvocationError> {
534 let peer = peer.into().resolve(self).await?;
535 let input_peer = {
536 let cache = self.inner.peer_cache.read().await;
537 cache.peer_to_input(&peer)
538 };
539
540 let r: crate::reactions::InputReactions = reaction.into();
541 let req = tl::functions::messages::SendReaction {
542 big: r.big,
543 add_to_recent: r.add_to_recent,
544 peer: input_peer,
545 msg_id: message_id,
546 reaction: if r.reactions.is_empty() {
547 None
548 } else {
549 Some(r.reactions)
550 },
551 };
552 self.rpc_call_raw_pub(&req).await?;
553 Ok(())
554 }
555}
556
557trait PeerUserIdExt {
560 fn user_id_or(&self, default: i64) -> i64;
561}
562
563impl PeerUserIdExt for tl::enums::Peer {
564 fn user_id_or(&self, default: i64) -> i64 {
565 match self {
566 tl::enums::Peer::User(u) => u.user_id,
567 _ => default,
568 }
569 }
570}
571
572#[derive(Debug, Clone, Default)]
586pub struct BannedRightsBuilder {
587 pub view_messages: bool,
588 pub send_messages: bool,
589 pub send_media: bool,
590 pub send_stickers: bool,
591 pub send_gifs: bool,
592 pub send_games: bool,
593 pub send_inline: bool,
594 pub embed_links: bool,
595 pub send_polls: bool,
596 pub change_info: bool,
597 pub invite_users: bool,
598 pub pin_messages: bool,
599 pub until_date: i32,
600}
601
602impl BannedRightsBuilder {
603 pub fn new() -> Self {
604 Self::default()
605 }
606 pub fn view_messages(mut self, v: bool) -> Self {
607 self.view_messages = v;
608 self
609 }
610 pub fn send_messages(mut self, v: bool) -> Self {
611 self.send_messages = v;
612 self
613 }
614 pub fn send_media(mut self, v: bool) -> Self {
615 self.send_media = v;
616 self
617 }
618 pub fn send_stickers(mut self, v: bool) -> Self {
619 self.send_stickers = v;
620 self
621 }
622 pub fn send_gifs(mut self, v: bool) -> Self {
623 self.send_gifs = v;
624 self
625 }
626 pub fn send_games(mut self, v: bool) -> Self {
627 self.send_games = v;
628 self
629 }
630 pub fn send_inline(mut self, v: bool) -> Self {
631 self.send_inline = v;
632 self
633 }
634 pub fn embed_links(mut self, v: bool) -> Self {
635 self.embed_links = v;
636 self
637 }
638 pub fn send_polls(mut self, v: bool) -> Self {
639 self.send_polls = v;
640 self
641 }
642 pub fn change_info(mut self, v: bool) -> Self {
643 self.change_info = v;
644 self
645 }
646 pub fn invite_users(mut self, v: bool) -> Self {
647 self.invite_users = v;
648 self
649 }
650 pub fn pin_messages(mut self, v: bool) -> Self {
651 self.pin_messages = v;
652 self
653 }
654 pub fn until_date(mut self, ts: i32) -> Self {
656 self.until_date = ts;
657 self
658 }
659
660 pub fn full_ban() -> Self {
662 Self {
663 view_messages: true,
664 send_messages: true,
665 send_media: true,
666 send_stickers: true,
667 send_gifs: true,
668 send_games: true,
669 send_inline: true,
670 embed_links: true,
671 send_polls: true,
672 change_info: true,
673 invite_users: true,
674 pin_messages: true,
675 until_date: 0,
676 }
677 }
678
679 pub(crate) fn into_tl(self) -> tl::enums::ChatBannedRights {
680 tl::enums::ChatBannedRights::ChatBannedRights(tl::types::ChatBannedRights {
681 view_messages: self.view_messages,
682 send_messages: self.send_messages,
683 send_media: self.send_media,
684 send_stickers: self.send_stickers,
685 send_gifs: self.send_gifs,
686 send_games: self.send_games,
687 send_inline: self.send_inline,
688 embed_links: self.embed_links,
689 send_polls: self.send_polls,
690 change_info: self.change_info,
691 invite_users: self.invite_users,
692 pin_messages: self.pin_messages,
693 manage_topics: false,
694 send_photos: false,
695 send_videos: false,
696 send_roundvideos: false,
697 send_audios: false,
698 send_voices: false,
699 send_docs: false,
700 send_plain: false,
701 edit_rank: false,
702 until_date: self.until_date,
703 })
704 }
705}
706
707#[derive(Debug, Clone, Default)]
711pub struct AdminRightsBuilder {
712 pub change_info: bool,
713 pub post_messages: bool,
714 pub edit_messages: bool,
715 pub delete_messages: bool,
716 pub ban_users: bool,
717 pub invite_users: bool,
718 pub pin_messages: bool,
719 pub add_admins: bool,
720 pub anonymous: bool,
721 pub manage_call: bool,
722 pub manage_topics: bool,
723 pub rank: Option<String>,
724}
725
726impl AdminRightsBuilder {
727 pub fn new() -> Self {
728 Self::default()
729 }
730 pub fn change_info(mut self, v: bool) -> Self {
731 self.change_info = v;
732 self
733 }
734 pub fn post_messages(mut self, v: bool) -> Self {
735 self.post_messages = v;
736 self
737 }
738 pub fn edit_messages(mut self, v: bool) -> Self {
739 self.edit_messages = v;
740 self
741 }
742 pub fn delete_messages(mut self, v: bool) -> Self {
743 self.delete_messages = v;
744 self
745 }
746 pub fn ban_users(mut self, v: bool) -> Self {
747 self.ban_users = v;
748 self
749 }
750 pub fn invite_users(mut self, v: bool) -> Self {
751 self.invite_users = v;
752 self
753 }
754 pub fn pin_messages(mut self, v: bool) -> Self {
755 self.pin_messages = v;
756 self
757 }
758 pub fn add_admins(mut self, v: bool) -> Self {
759 self.add_admins = v;
760 self
761 }
762 pub fn anonymous(mut self, v: bool) -> Self {
763 self.anonymous = v;
764 self
765 }
766 pub fn manage_call(mut self, v: bool) -> Self {
767 self.manage_call = v;
768 self
769 }
770 pub fn manage_topics(mut self, v: bool) -> Self {
771 self.manage_topics = v;
772 self
773 }
774 pub fn rank(mut self, r: impl Into<String>) -> Self {
776 self.rank = Some(r.into());
777 self
778 }
779
780 pub fn full_admin() -> Self {
782 Self {
783 change_info: true,
784 post_messages: true,
785 edit_messages: true,
786 delete_messages: true,
787 ban_users: true,
788 invite_users: true,
789 pin_messages: true,
790 add_admins: false,
791 anonymous: false,
792 manage_call: true,
793 manage_topics: true,
794 rank: None,
795 }
796 }
797
798 pub(crate) fn into_tl_rights(self) -> tl::enums::ChatAdminRights {
799 tl::enums::ChatAdminRights::ChatAdminRights(tl::types::ChatAdminRights {
800 change_info: self.change_info,
801 post_messages: self.post_messages,
802 edit_messages: self.edit_messages,
803 delete_messages: self.delete_messages,
804 ban_users: self.ban_users,
805 invite_users: self.invite_users,
806 pin_messages: self.pin_messages,
807 add_admins: self.add_admins,
808 anonymous: self.anonymous,
809 manage_call: self.manage_call,
810 other: false,
811 manage_topics: self.manage_topics,
812 post_stories: false,
813 edit_stories: false,
814 delete_stories: false,
815 manage_direct_messages: false,
816 manage_ranks: false,
817 })
818 }
819}
820
821#[derive(Debug, Clone)]
825pub struct ParticipantPermissions {
826 pub is_creator: bool,
827 pub is_admin: bool,
828 pub is_banned: bool,
829 pub is_left: bool,
830 pub can_send_messages: bool,
831 pub can_send_media: bool,
832 pub can_pin_messages: bool,
833 pub can_add_admins: bool,
834 pub admin_rank: Option<String>,
835}
836
837impl ParticipantPermissions {
838 pub fn is_creator(&self) -> bool {
839 self.is_creator
840 }
841 pub fn is_admin(&self) -> bool {
842 self.is_admin
843 }
844 pub fn is_banned(&self) -> bool {
845 self.is_banned
846 }
847 pub fn is_member(&self) -> bool {
848 !self.is_banned && !self.is_left
849 }
850}
851
852impl Client {
855 pub async fn set_banned_rights(
861 &self,
862 channel: impl Into<PeerRef>,
863 user_id: i64,
864 build: impl FnOnce(BannedRightsBuilder) -> BannedRightsBuilder,
865 ) -> Result<(), InvocationError> {
866 let rights = build(BannedRightsBuilder::new()).into_tl();
867 let channel = channel.into().resolve(self).await?;
868 let (channel_id, ch_hash) = match &channel {
869 tl::enums::Peer::Channel(c) => {
870 let h = self
871 .inner
872 .peer_cache
873 .read()
874 .await
875 .channels
876 .get(&c.channel_id)
877 .copied()
878 .unwrap_or(0);
879 (c.channel_id, h)
880 }
881 _ => {
882 return Err(InvocationError::Deserialize(
883 "set_banned_rights: must be a channel".into(),
884 ));
885 }
886 };
887 let user_hash = self
888 .inner
889 .peer_cache
890 .read()
891 .await
892 .users
893 .get(&user_id)
894 .copied()
895 .unwrap_or(0);
896 let req = tl::functions::channels::EditBanned {
897 channel: tl::enums::InputChannel::InputChannel(tl::types::InputChannel {
898 channel_id,
899 access_hash: ch_hash,
900 }),
901 participant: tl::enums::InputPeer::User(tl::types::InputPeerUser {
902 user_id,
903 access_hash: user_hash,
904 }),
905 banned_rights: rights,
906 };
907 self.rpc_call_raw_pub(&req).await?;
908 Ok(())
909 }
910
911 pub async fn set_admin_rights(
917 &self,
918 channel: impl Into<PeerRef>,
919 user_id: i64,
920 build: impl FnOnce(AdminRightsBuilder) -> AdminRightsBuilder,
921 ) -> Result<(), InvocationError> {
922 let b = build(AdminRightsBuilder::new());
923 let rank = b.rank.clone();
924 let rights = b.into_tl_rights();
925 let channel = channel.into().resolve(self).await?;
926 let (channel_id, ch_hash) = match &channel {
927 tl::enums::Peer::Channel(c) => {
928 let h = self
929 .inner
930 .peer_cache
931 .read()
932 .await
933 .channels
934 .get(&c.channel_id)
935 .copied()
936 .unwrap_or(0);
937 (c.channel_id, h)
938 }
939 _ => {
940 return Err(InvocationError::Deserialize(
941 "set_admin_rights: must be a channel".into(),
942 ));
943 }
944 };
945 let user_hash = self
946 .inner
947 .peer_cache
948 .read()
949 .await
950 .users
951 .get(&user_id)
952 .copied()
953 .unwrap_or(0);
954 let req = tl::functions::channels::EditAdmin {
955 channel: tl::enums::InputChannel::InputChannel(tl::types::InputChannel {
956 channel_id,
957 access_hash: ch_hash,
958 }),
959 user_id: tl::enums::InputUser::InputUser(tl::types::InputUser {
960 user_id,
961 access_hash: user_hash,
962 }),
963 admin_rights: rights,
964 rank,
965 };
966 self.rpc_call_raw_pub(&req).await?;
967 Ok(())
968 }
969
970 pub async fn iter_participants(
976 &self,
977 peer: impl Into<PeerRef>,
978 filter: Option<tl::enums::ChannelParticipantsFilter>,
979 limit: i32,
980 ) -> Result<Vec<Participant>, InvocationError> {
981 let peer = peer.into().resolve(self).await?;
982 match &peer {
983 tl::enums::Peer::Channel(c) => {
984 let access_hash = self
985 .inner
986 .peer_cache
987 .read()
988 .await
989 .channels
990 .get(&c.channel_id)
991 .copied()
992 .unwrap_or(0);
993 let filter = filter
994 .unwrap_or(tl::enums::ChannelParticipantsFilter::ChannelParticipantsRecent);
995 let limit = if limit <= 0 { 200 } else { limit };
996 let req = tl::functions::channels::GetParticipants {
997 channel: tl::enums::InputChannel::InputChannel(tl::types::InputChannel {
998 channel_id: c.channel_id,
999 access_hash,
1000 }),
1001 filter,
1002 offset: 0,
1003 limit,
1004 hash: 0,
1005 };
1006 let body = self.rpc_call_raw_pub(&req).await?;
1007 let mut cur = Cursor::from_slice(&body);
1008 let raw = match tl::enums::channels::ChannelParticipants::deserialize(&mut cur)? {
1009 tl::enums::channels::ChannelParticipants::ChannelParticipants(p) => p,
1010 tl::enums::channels::ChannelParticipants::NotModified => return Ok(vec![]),
1011 };
1012 let user_map: std::collections::HashMap<i64, tl::types::User> = raw
1013 .users
1014 .into_iter()
1015 .filter_map(|u| match u {
1016 tl::enums::User::User(u) => Some((u.id, u)),
1017 _ => None,
1018 })
1019 .collect();
1020 {
1021 let mut cache = self.inner.peer_cache.write().await;
1022 for u in user_map.values() {
1023 if let Some(h) = u.access_hash {
1024 cache.users.insert(u.id, h);
1025 }
1026 }
1027 }
1028 Ok(raw
1029 .participants
1030 .into_iter()
1031 .filter_map(|p| {
1032 let (uid, status) = match &p {
1033 tl::enums::ChannelParticipant::ChannelParticipant(x) => {
1034 (x.user_id, ParticipantStatus::Member)
1035 }
1036 tl::enums::ChannelParticipant::ParticipantSelf(x) => {
1037 (x.user_id, ParticipantStatus::Member)
1038 }
1039 tl::enums::ChannelParticipant::Creator(x) => {
1040 (x.user_id, ParticipantStatus::Creator)
1041 }
1042 tl::enums::ChannelParticipant::Admin(x) => {
1043 (x.user_id, ParticipantStatus::Admin)
1044 }
1045 tl::enums::ChannelParticipant::Banned(x) => {
1046 if let tl::enums::Peer::User(u) = &x.peer {
1047 (u.user_id, ParticipantStatus::Banned)
1048 } else {
1049 return None;
1050 }
1051 }
1052 tl::enums::ChannelParticipant::Left(x) => {
1053 if let tl::enums::Peer::User(u) = &x.peer {
1054 (u.user_id, ParticipantStatus::Left)
1055 } else {
1056 return None;
1057 }
1058 }
1059 };
1060 user_map.get(&uid).map(|u| Participant {
1061 user: u.clone(),
1062 status,
1063 })
1064 })
1065 .collect())
1066 }
1067 tl::enums::Peer::Chat(c) => self.get_chat_participants(c.chat_id).await,
1068 _ => Err(InvocationError::Deserialize(
1069 "iter_participants: must be chat or channel".into(),
1070 )),
1071 }
1072 }
1073
1074 pub async fn get_permissions(
1078 &self,
1079 channel: impl Into<PeerRef>,
1080 user_id: i64,
1081 ) -> Result<ParticipantPermissions, InvocationError> {
1082 let channel = channel.into().resolve(self).await?;
1083 let (channel_id, ch_hash) = match &channel {
1084 tl::enums::Peer::Channel(c) => {
1085 let h = self
1086 .inner
1087 .peer_cache
1088 .read()
1089 .await
1090 .channels
1091 .get(&c.channel_id)
1092 .copied()
1093 .unwrap_or(0);
1094 (c.channel_id, h)
1095 }
1096 _ => {
1097 return Err(InvocationError::Deserialize(
1098 "get_permissions: must be a channel".into(),
1099 ));
1100 }
1101 };
1102 let user_hash = self
1103 .inner
1104 .peer_cache
1105 .read()
1106 .await
1107 .users
1108 .get(&user_id)
1109 .copied()
1110 .unwrap_or(0);
1111 let req = tl::functions::channels::GetParticipant {
1112 channel: tl::enums::InputChannel::InputChannel(tl::types::InputChannel {
1113 channel_id,
1114 access_hash: ch_hash,
1115 }),
1116 participant: tl::enums::InputPeer::User(tl::types::InputPeerUser {
1117 user_id,
1118 access_hash: user_hash,
1119 }),
1120 };
1121 let body = self.rpc_call_raw_pub(&req).await?;
1122 let mut cur = Cursor::from_slice(&body);
1123 let tl::enums::channels::ChannelParticipant::ChannelParticipant(raw) =
1124 tl::enums::channels::ChannelParticipant::deserialize(&mut cur)?;
1125
1126 let perms = match raw.participant {
1127 tl::enums::ChannelParticipant::Creator(_) => ParticipantPermissions {
1128 is_creator: true,
1129 is_admin: true,
1130 is_banned: false,
1131 is_left: false,
1132 can_send_messages: true,
1133 can_send_media: true,
1134 can_pin_messages: true,
1135 can_add_admins: true,
1136 admin_rank: None,
1137 },
1138 tl::enums::ChannelParticipant::Admin(a) => {
1139 let tl::enums::ChatAdminRights::ChatAdminRights(rights) = a.admin_rights;
1140 ParticipantPermissions {
1141 is_creator: false,
1142 is_admin: true,
1143 is_banned: false,
1144 is_left: false,
1145 can_send_messages: true,
1146 can_send_media: true,
1147 can_pin_messages: rights.pin_messages,
1148 can_add_admins: rights.add_admins,
1149 admin_rank: a.rank,
1150 }
1151 }
1152 tl::enums::ChannelParticipant::Banned(b) => {
1153 let tl::enums::ChatBannedRights::ChatBannedRights(rights) = b.banned_rights;
1154 ParticipantPermissions {
1155 is_creator: false,
1156 is_admin: false,
1157 is_banned: true,
1158 is_left: false,
1159 can_send_messages: !rights.send_messages,
1160 can_send_media: !rights.send_media,
1161 can_pin_messages: !rights.pin_messages,
1162 can_add_admins: false,
1163 admin_rank: None,
1164 }
1165 }
1166 tl::enums::ChannelParticipant::Left(_) => ParticipantPermissions {
1167 is_creator: false,
1168 is_admin: false,
1169 is_banned: false,
1170 is_left: true,
1171 can_send_messages: false,
1172 can_send_media: false,
1173 can_pin_messages: false,
1174 can_add_admins: false,
1175 admin_rank: None,
1176 },
1177 _ => ParticipantPermissions {
1178 is_creator: false,
1179 is_admin: false,
1180 is_banned: false,
1181 is_left: false,
1182 can_send_messages: true,
1183 can_send_media: true,
1184 can_pin_messages: false,
1185 can_add_admins: false,
1186 admin_rank: None,
1187 },
1188 };
1189
1190 Ok(perms)
1191 }
1192}
1193
1194pub struct ProfilePhotoIter {
1212 client: Client,
1213 input_user: tl::enums::InputUser,
1214 chunk_size: i32,
1215 offset: i32,
1217 buffer: VecDeque<tl::enums::Photo>,
1219 done: bool,
1221}
1222
1223impl ProfilePhotoIter {
1224 pub async fn next(&mut self) -> Result<Option<tl::enums::Photo>, InvocationError> {
1229 if let Some(photo) = self.buffer.pop_front() {
1231 return Ok(Some(photo));
1232 }
1233
1234 if self.done {
1236 return Ok(None);
1237 }
1238
1239 let req = tl::functions::photos::GetUserPhotos {
1241 user_id: self.input_user.clone(),
1242 offset: self.offset,
1243 max_id: 0,
1244 limit: self.chunk_size,
1245 };
1246 let body = self.client.rpc_call_raw_pub(&req).await?;
1247 let mut cur = Cursor::from_slice(&body);
1248
1249 let (photos, total): (Vec<tl::enums::Photo>, Option<i32>) =
1250 match tl::enums::photos::Photos::deserialize(&mut cur)? {
1251 tl::enums::photos::Photos::Photos(p) => {
1252 self.done = true;
1254 (p.photos, None)
1255 }
1256 tl::enums::photos::Photos::Slice(p) => (p.photos, Some(p.count)),
1257 };
1258
1259 let returned = photos.len() as i32;
1260 self.offset += returned;
1261
1262 if returned < self.chunk_size {
1264 self.done = true;
1265 }
1266 if let Some(total) = total
1267 && self.offset >= total
1268 {
1269 self.done = true;
1270 }
1271
1272 self.buffer.extend(photos);
1273 Ok(self.buffer.pop_front())
1274 }
1275
1276 pub async fn collect(mut self) -> Result<Vec<tl::enums::Photo>, InvocationError> {
1280 let mut out = Vec::new();
1281 while let Some(photo) = self.next().await? {
1282 out.push(photo);
1283 }
1284 Ok(out)
1285 }
1286
1287 pub fn total_count(&self) -> Option<i32> {
1292 if self.offset > 0 {
1297 Some(self.offset)
1298 } else {
1299 None
1300 }
1301 }
1302}