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