misskey_util/
client.rs

1use std::path::Path;
2
3#[cfg(feature = "12-9-0")]
4use crate::builder::EmojiUpdateBuilder;
5#[cfg(feature = "12-27-0")]
6use crate::builder::NotificationBuilder;
7use crate::builder::{
8    AnnouncementUpdateBuilder, AntennaBuilder, AntennaUpdateBuilder, DriveFileBuilder,
9    DriveFileListBuilder, DriveFileUpdateBuilder, DriveFileUrlBuilder, DriveFolderUpdateBuilder,
10    MeUpdateBuilder, MessagingMessageBuilder, MetaUpdateBuilder, NoteBuilder, ServerLogListBuilder,
11    UserListBuilder,
12};
13#[cfg(feature = "12-47-0")]
14use crate::builder::{ChannelBuilder, ChannelUpdateBuilder};
15#[cfg(feature = "12-57-0")]
16use crate::builder::{ClipBuilder, ClipUpdateBuilder};
17use crate::pager::{BackwardPager, BoxPager, ForwardPager, OffsetPager, PagerStream};
18use crate::Error;
19use crate::{TimelineCursor, TimelineRange};
20
21#[cfg(feature = "12-13-0")]
22use chrono::DateTime;
23use chrono::Utc;
24use futures::{future::BoxFuture, stream::TryStreamExt};
25use mime::Mime;
26#[cfg(feature = "12-47-0")]
27use misskey_api::model::channel::Channel;
28#[cfg(feature = "12-58-0")]
29use misskey_api::model::page::Page;
30use misskey_api::model::{
31    abuse_user_report::AbuseUserReport,
32    announcement::Announcement,
33    antenna::Antenna,
34    clip::Clip,
35    drive::{DriveFile, DriveFolder},
36    emoji::Emoji,
37    following::FollowRequest,
38    id::Id,
39    log::ModerationLog,
40    messaging::MessagingMessage,
41    meta::Meta,
42    note::{Note, Reaction, Tag},
43    notification::Notification,
44    query::Query,
45    user::{User, UserRelation},
46    user_group::{UserGroup, UserGroupInvitation},
47    user_list::UserList,
48};
49use misskey_api::{endpoint, EntityRef};
50use misskey_core::{Client, UploadFileClient};
51use url::Url;
52
53// {{{ Utility
54macro_rules! impl_timeline_method {
55    ($timeline:ident, $endpoint:path $(,$reqname:ident = $argname:ident : $argentity:ident)* ) => {
56        paste::paste! {
57            #[doc = "Lists the notes in the specified range of the " $timeline " timeline."]
58            ///
59            /// The bound `Into<TimelineRange<Note>>` on the argument type is satisfied by the type
60            /// of some range expressions such as `..` or `start..` (which are desugared into [`RangeFull`][range_full] and
61            /// [`RangeFrom`][range_from] respectively). A note or [`DateTime<Utc>`][datetime] can
62            /// be used to specify the start and end bounds of the range.
63            ///
64            /// [range_full]: std::ops::RangeFull
65            /// [range_from]: std::ops::RangeFrom
66            /// [datetime]: chrono::DateTime
67            ///
68            /// # Examples
69            ///
70            /// ```
71            /// # use misskey_util::ClientExt;
72            /// # use futures::stream::TryStreamExt;
73            /// # #[tokio::main]
74            /// # async fn main() -> anyhow::Result<()> {
75            /// # let client = misskey_test::test_client().await?;
76            /// # let user = client.users().list().try_next().await?.unwrap();
77            /// # #[cfg(feature = "12-47-0")]
78            /// # let channel = client.create_channel("test").await?;
79            /// # let list = client.create_user_list("test").await?;
80            /// use futures::stream::{StreamExt, TryStreamExt};
81            ///
82            #[doc = "// `notes` variable here is a `Stream` to enumerate first 100 " $timeline " notes."]
83            #[doc = "let mut notes = client." $timeline "_notes(" $("&" $argname ", ")* "..).take(100);"]
84            ///
85            /// // Retrieve all notes until there are no more.
86            /// while let Some(note) = notes.try_next().await? {
87            ///     // Print the text of the note, if any.
88            ///     if let Some(text) = note.text {
89            ///         println!("@{}: {}", note.user.username, text);
90            ///     }
91            /// }
92            /// # Ok(())
93            /// # }
94            /// ```
95            ///
96            /// ```
97            /// # use misskey_util::ClientExt;
98            /// # use futures::stream::TryStreamExt;
99            /// # #[tokio::main]
100            /// # async fn main() -> anyhow::Result<()> {
101            /// # let client = misskey_test::test_client().await?;
102            /// # let user = client.users().list().try_next().await?.unwrap();
103            /// # #[cfg(feature = "12-47-0")]
104            /// # let channel = client.create_channel("test").await?;
105            /// # let list = client.create_user_list("test").await?;
106            /// use chrono::Utc;
107            ///
108            #[doc = "// Get the " $timeline " notes since `time`."]
109            /// let time = Utc::today().and_hms(0, 0, 0);
110            #[doc = "let mut notes = client." $timeline "_notes(" $("&" $argname ", ")* "time..);"]
111            /// # Ok(())
112            /// # }
113            /// ```
114            fn [<$timeline _notes>] (
115                &self,
116                $($argname : impl EntityRef<$argentity>,)*
117                range: impl Into<TimelineRange<Note>>,
118            ) -> PagerStream<BoxPager<Self, Note>> {
119                $(
120                let $reqname = $argname.entity_ref();
121                )*
122                let base_request =
123                    endpoint::$endpoint::Request::builder()
124                      $(.$reqname($reqname))*
125                      .build();
126                let pager = match range.into() {
127                    TimelineRange::Id {
128                        since_id,
129                        until_id: None,
130                    } => BackwardPager::with_since_id(
131                        self,
132                        since_id,
133                        base_request
134                    ),
135                    TimelineRange::Id {
136                        since_id,
137                        until_id: Some(until_id),
138                    } => BackwardPager::new(
139                        self,
140                        endpoint::$endpoint::Request {
141                            since_id,
142                            until_id: Some(until_id),
143                            ..base_request
144                        },
145                    ),
146                    TimelineRange::DateTime {
147                        since_date,
148                        until_date,
149                    } => BackwardPager::new(
150                        self,
151                        endpoint::$endpoint::Request {
152                            since_date,
153                            until_date: Some(until_date.unwrap_or(Utc::now())),
154                            ..base_request
155                        },
156                    ),
157                    TimelineRange::Unbounded => {
158                        BackwardPager::new(self, base_request)
159                    }
160                };
161                PagerStream::new(Box::pin(pager))
162            }
163
164            #[doc = "Lists all notes since the specified point in the " $timeline " timeline in reverse order (i.e. the old note comes first, the new note comes after)."]
165            ///
166            /// # Examples
167            ///
168            /// ```
169            /// # use misskey_util::ClientExt;
170            /// # use futures::stream::TryStreamExt;
171            /// # #[tokio::main]
172            /// # async fn main() -> anyhow::Result<()> {
173            /// # let client = misskey_test::test_client().await?;
174            /// # let user = client.users().list().try_next().await?.unwrap();
175            /// # #[cfg(feature = "12-47-0")]
176            /// # let channel = client.create_channel("test").await?;
177            /// # let list = client.create_user_list("test").await?;
178            /// use futures::stream::{StreamExt, TryStreamExt};
179            /// use chrono::Utc;
180            ///
181            /// let time = Utc::today().and_hms(0, 0, 0);
182            ///
183            #[doc = "// `notes_since` is a `Stream` to enumerate first 100 " $timeline " notes since `time` in reverse order."]
184            #[doc = "let mut notes_since = client." $timeline "_notes_since(" $("&" $argname ", ")* "time).take(100);"]
185            ///
186            /// // Retrieve all notes until there are no more.
187            /// while let Some(note) = notes_since.try_next().await? {
188            ///     // Print the text of the note, if any.
189            ///     if let Some(text) = note.text {
190            ///         println!("@{}: {}", note.user.username, text);
191            ///     }
192            /// }
193            /// # Ok(())
194            /// # }
195            /// ```
196            fn [<$timeline _notes_since>] (
197                &self,
198                $($argname : impl EntityRef<$argentity>,)*
199                since: impl Into<TimelineCursor<Note>>,
200            ) -> PagerStream<BoxPager<Self, Note>> {
201                $(
202                let $reqname = $argname.entity_ref();
203                )*
204                let base_request =
205                    endpoint::$endpoint::Request::builder()
206                      $(.$reqname($reqname))*
207                      .build();
208                let request = match since.into() {
209                    TimelineCursor::DateTime(since_date) => endpoint::$endpoint::Request {
210                        since_date: Some(since_date),
211                        ..base_request
212                    },
213                    TimelineCursor::Id(since_id) => endpoint::$endpoint::Request {
214                        since_id: Some(since_id),
215                        ..base_request
216                    },
217                };
218                let pager = ForwardPager::new(self, request);
219                PagerStream::new(Box::pin(pager))
220            }
221
222            #[doc = "Returns a set of streams that fetch notes around the specified point in the " $timeline " timeline in both directions."]
223            fn [<$timeline _notes_around>](
224                &self,
225                $($argname : impl EntityRef<$argentity>,)*
226                cursor: impl Into<TimelineCursor<Note>>,
227            ) -> (
228                PagerStream<BoxPager<Self, Note>>,
229                PagerStream<BoxPager<Self, Note>>,
230            ) {
231                let cursor = cursor.into();
232                $(
233                let $reqname = $argname.entity_ref();
234                )*
235                (
236                    self.[<$timeline _notes_since>]($($reqname,)* cursor),
237                    self.[<$timeline _notes>]($($reqname,)* TimelineRange::until(cursor)),
238                )
239            }
240        }
241    };
242}
243// }}}
244
245/// An extension trait for [`Client`][client] that provides convenient high-level APIs.
246///
247/// [client]: misskey_core::Client
248///
249/// # Streams
250///
251/// Some methods (e.g. [`followers`][followers], [`local_notes`][local_notes], etc.) return a [`Stream`][stream]
252/// that uses pagination to fetch all entries.
253/// You can use methods from [`TryStreamExt`][try_stream_ext] or [`StreamExt`][stream_ext]
254/// to work with this.
255///
256/// [followers]: ClientExt::followers
257/// [local_notes]: ClientExt::local_notes
258/// [stream]: futures::stream::Stream
259/// [try_stream_ext]: futures::stream::TryStreamExt
260/// [stream_ext]: futures::stream::StreamExt
261pub trait ClientExt: Client + Sync {
262    // {{{ User
263    /// Gets the information of the user who is logged in with this client.
264    ///
265    /// # Examples
266    ///
267    /// ```
268    /// # use misskey_util::ClientExt;
269    /// # #[tokio::main]
270    /// # async fn main() -> anyhow::Result<()> {
271    /// # let client = misskey_test::test_client().await?;
272    /// let me = client.me().await?;
273    /// println!("Logged in as @{}", me.username);
274    /// # Ok(())
275    /// # }
276    /// ```
277    fn me(&self) -> BoxFuture<Result<User, Error<Self::Error>>> {
278        Box::pin(async move {
279            let user = self
280                .request(endpoint::i::Request::default())
281                .await
282                .map_err(Error::Client)?
283                .into_result()?;
284            Ok(user)
285        })
286    }
287
288    /// Updates the user logged in with this client.
289    ///
290    /// This method actually returns a builder, namely [`MeUpdateBuilder`].
291    /// You can chain the method calls to it corresponding to the fields you want to update.
292    /// Finally, calling [`update`][builder_update] method will actually perform the update.
293    /// See [`MeUpdateBuilder`] for the fields that can be updated.
294    ///
295    /// [builder_update]: MeUpdateBuilder::update
296    ///
297    /// # Examples
298    ///
299    /// ```
300    /// # use misskey_util::ClientExt;
301    /// # #[tokio::main]
302    /// # async fn main() -> anyhow::Result<()> {
303    /// # let client = misskey_test::test_client().await?;
304    /// // Flag it as a bot and set the name to "my awesome bot"
305    /// let updated = client
306    ///     .update_me()
307    ///     .bot(true)
308    ///     .set_name("my awesome bot")
309    ///     .update()
310    ///     .await?;
311    ///
312    /// assert!(updated.is_bot);
313    /// assert_eq!(updated.name.unwrap(), "my awesome bot");
314    /// # Ok(())
315    /// # }
316    /// ```
317    fn update_me(&self) -> MeUpdateBuilder<&Self> {
318        MeUpdateBuilder::new(self)
319    }
320
321    /// Follows the specified user.
322    fn follow(&self, user: impl EntityRef<User>) -> BoxFuture<Result<User, Error<Self::Error>>> {
323        let user_id = user.entity_ref();
324        Box::pin(async move {
325            let user = self
326                .request(endpoint::following::create::Request { user_id })
327                .await
328                .map_err(Error::Client)?
329                .into_result()?;
330            Ok(user)
331        })
332    }
333
334    /// Unfollows the specified user.
335    fn unfollow(&self, user: impl EntityRef<User>) -> BoxFuture<Result<User, Error<Self::Error>>> {
336        let user_id = user.entity_ref();
337        Box::pin(async move {
338            let user = self
339                .request(endpoint::following::delete::Request { user_id })
340                .await
341                .map_err(Error::Client)?
342                .into_result()?;
343            Ok(user)
344        })
345    }
346
347    /// Mutes the specified user.
348    fn mute(&self, user: impl EntityRef<User>) -> BoxFuture<Result<(), Error<Self::Error>>> {
349        let user_id = user.entity_ref();
350        Box::pin(async move {
351            self.request(endpoint::mute::create::Request { user_id })
352                .await
353                .map_err(Error::Client)?
354                .into_result()?;
355            Ok(())
356        })
357    }
358
359    /// Unmutes the specified user.
360    fn unmute(&self, user: impl EntityRef<User>) -> BoxFuture<Result<(), Error<Self::Error>>> {
361        let user_id = user.entity_ref();
362        Box::pin(async move {
363            self.request(endpoint::mute::delete::Request { user_id })
364                .await
365                .map_err(Error::Client)?
366                .into_result()?;
367            Ok(())
368        })
369    }
370
371    /// Blocks the specified user.
372    fn block(&self, user: impl EntityRef<User>) -> BoxFuture<Result<User, Error<Self::Error>>> {
373        let user_id = user.entity_ref();
374        Box::pin(async move {
375            let user = self
376                .request(endpoint::blocking::create::Request { user_id })
377                .await
378                .map_err(Error::Client)?
379                .into_result()?;
380            Ok(user)
381        })
382    }
383
384    /// Unblocks the specified user.
385    fn unblock(&self, user: impl EntityRef<User>) -> BoxFuture<Result<User, Error<Self::Error>>> {
386        let user_id = user.entity_ref();
387        Box::pin(async move {
388            let user = self
389                .request(endpoint::blocking::delete::Request { user_id })
390                .await
391                .map_err(Error::Client)?
392                .into_result()?;
393            Ok(user)
394        })
395    }
396
397    /// Lists the followers of the specified user.
398    ///
399    /// # Examples
400    ///
401    /// This example uses [`TryStreamExt::try_next`][try_next] and [`while let`][while_let]
402    /// to retrieve notifications one after another until there are no more.
403    ///
404    /// [try_next]: futures::stream::TryStreamExt::try_next
405    /// [while_let]: https://doc.rust-lang.org/std/keyword.while.html
406    ///
407    /// ```
408    /// # use misskey_util::ClientExt;
409    /// # #[tokio::main]
410    /// # async fn main() -> anyhow::Result<()> {
411    /// # let client = misskey_test::test_client().await?;
412    /// use futures::stream::{StreamExt, TryStreamExt};
413    ///
414    /// // In this example, we will fetch all the followers and follow them.
415    /// // First, obtain your information to pass to `.follwers` method.
416    /// let me = client.me().await?;
417    ///
418    /// // `follwers` variable here is a `Stream` to enumerate first 50 followers of `me`.
419    /// let mut followers = client.followers(&me).take(50);
420    ///
421    /// // Retrieve all followers until there are no more.
422    /// while let Some(user) = followers.try_next().await? {
423    ///     // Follow the `user` if you haven't already.
424    ///     if !client.is_following(&user).await? {
425    ///         client.follow(&user).await?;
426    ///     }
427    /// }
428    /// # Ok(())
429    /// # }
430    /// ```
431    fn followers(&self, user: impl EntityRef<User>) -> PagerStream<BoxPager<Self, User>> {
432        let pager = BackwardPager::new(
433            self,
434            endpoint::users::followers::RequestWithUserId::builder()
435                .user_id(user.entity_ref())
436                .build(),
437        )
438        .map_ok(|v| v.into_iter().map(|f| f.follower).collect());
439        PagerStream::new(Box::pin(pager))
440    }
441
442    /// Lists the users that the specified user is following.
443    fn following(&self, user: impl EntityRef<User>) -> PagerStream<BoxPager<Self, User>> {
444        let pager = BackwardPager::new(
445            self,
446            endpoint::users::following::RequestWithUserId::builder()
447                .user_id(user.entity_ref())
448                .build(),
449        )
450        .map_ok(|v| v.into_iter().map(|f| f.followee).collect());
451        PagerStream::new(Box::pin(pager))
452    }
453
454    /// Pins the specified note to the profile.
455    fn pin_note(&self, note: impl EntityRef<Note>) -> BoxFuture<Result<User, Error<Self::Error>>> {
456        let note_id = note.entity_ref();
457        Box::pin(async move {
458            let user = self
459                .request(endpoint::i::pin::Request { note_id })
460                .await
461                .map_err(Error::Client)?
462                .into_result()?;
463            Ok(user)
464        })
465    }
466
467    /// Unpins the specified note to the profile.
468    fn unpin_note(
469        &self,
470        note: impl EntityRef<Note>,
471    ) -> BoxFuture<Result<User, Error<Self::Error>>> {
472        let note_id = note.entity_ref();
473        Box::pin(async move {
474            let user = self
475                .request(endpoint::i::unpin::Request { note_id })
476                .await
477                .map_err(Error::Client)?
478                .into_result()?;
479            Ok(user)
480        })
481    }
482
483    /// Lists the follow requests sent to the user logged in with this client.
484    ///
485    /// # Examples
486    ///
487    /// ```
488    /// # use misskey_util::ClientExt;
489    /// # #[tokio::main]
490    /// # async fn main() -> anyhow::Result<()> {
491    /// # let client = misskey_test::test_client().await?;
492    /// // Accept all follow requests
493    /// for request in client.follow_requests().await? {
494    ///     client.accept_follow_request(&request.follower).await?;
495    /// }
496    /// # Ok(())
497    /// # }
498    /// ```
499    fn follow_requests(&self) -> BoxFuture<Result<Vec<FollowRequest>, Error<Self::Error>>> {
500        Box::pin(async move {
501            let requests = self
502                .request(endpoint::following::requests::list::Request::default())
503                .await
504                .map_err(Error::Client)?
505                .into_result()?;
506            Ok(requests)
507        })
508    }
509
510    /// Cancels the follow request being sent to the specified user.
511    fn cancel_follow_request(
512        &self,
513        user: impl EntityRef<User>,
514    ) -> BoxFuture<Result<User, Error<Self::Error>>> {
515        let user_id = user.entity_ref();
516        Box::pin(async move {
517            let user = self
518                .request(endpoint::following::requests::cancel::Request { user_id })
519                .await
520                .map_err(Error::Client)?
521                .into_result()?;
522            Ok(user)
523        })
524    }
525
526    /// Accepts the follow request that have been received from the specified user.
527    fn accept_follow_request(
528        &self,
529        user: impl EntityRef<User>,
530    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
531        let user_id = user.entity_ref();
532        Box::pin(async move {
533            self.request(endpoint::following::requests::accept::Request { user_id })
534                .await
535                .map_err(Error::Client)?
536                .into_result()?;
537            Ok(())
538        })
539    }
540
541    /// Rejects the follow request that have been received from the specified user.
542    fn reject_follow_request(
543        &self,
544        user: impl EntityRef<User>,
545    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
546        let user_id = user.entity_ref();
547        Box::pin(async move {
548            self.request(endpoint::following::requests::reject::Request { user_id })
549                .await
550                .map_err(Error::Client)?
551                .into_result()?;
552            Ok(())
553        })
554    }
555
556    /// Lists the users muted by the user logged in with this client.
557    fn muting_users(&self) -> PagerStream<BoxPager<Self, User>> {
558        let pager = BackwardPager::new(self, endpoint::mute::list::Request::default())
559            .map_ok(|v| v.into_iter().map(|m| m.mutee).collect());
560        PagerStream::new(Box::pin(pager))
561    }
562
563    /// Lists the users blocked by the user logged in with this client.
564    fn blocking_users(&self) -> PagerStream<BoxPager<Self, User>> {
565        let pager = BackwardPager::new(self, endpoint::blocking::list::Request::default())
566            .map_ok(|v| v.into_iter().map(|b| b.blockee).collect());
567        PagerStream::new(Box::pin(pager))
568    }
569
570    /// Lists the notes favorited by the user logged in with this client.
571    fn favorited_notes(&self) -> PagerStream<BoxPager<Self, Note>> {
572        let pager = BackwardPager::new(self, endpoint::i::favorites::Request::default())
573            .map_ok(|v| v.into_iter().map(|f| f.note).collect());
574        PagerStream::new(Box::pin(pager))
575    }
576
577    /// Lists the notifications to the user logged in with this client.
578    ///
579    /// # Examples
580    ///
581    /// This example uses [`TryStreamExt::try_next`][try_next] and [`while let`][while_let]
582    /// to retrieve notifications one after another until there are no more.
583    ///
584    /// [try_next]: futures::stream::TryStreamExt::try_next
585    /// [while_let]: https://doc.rust-lang.org/std/keyword.while.html
586    ///
587    /// ```
588    /// # use misskey_util::ClientExt;
589    /// # #[tokio::main]
590    /// # async fn main() -> anyhow::Result<()> {
591    /// # let client = misskey_test::test_client().await?;
592    /// use futures::stream::{StreamExt, TryStreamExt};
593    ///
594    /// // `notifications` here is a `Stream` to enumerate first 10 notifications.
595    /// let mut notifications = client.notifications().take(10);
596    /// // Retrieve notifications until there are no more.
597    /// while let Some(notification) = notifications.try_next().await? {
598    ///     // Print some information about the notification.
599    ///     println!("notification {}: created at {}", notification.id, notification.created_at);
600    /// }
601    /// # Ok(())
602    /// # }
603    /// ```
604    fn notifications(&self) -> PagerStream<BoxPager<Self, Notification>> {
605        let pager = BackwardPager::new(self, endpoint::i::notifications::Request::default());
606        PagerStream::new(Box::pin(pager))
607    }
608
609    /// Returns the relationship between the specified user and the user logged in with this
610    /// client.
611    ///
612    /// The returned [`UserRelation`] object records the various information.
613    /// There are separate methods to examine each relationship (e.g.
614    /// [`is_following`][is_following]), so if you are only interested in one relationship,
615    /// it can be simpler to use those.
616    ///
617    /// [is_following]: ClientExt::is_following
618    fn user_relation(
619        &self,
620        user: impl EntityRef<User>,
621    ) -> BoxFuture<Result<UserRelation, Error<Self::Error>>> {
622        let user_id = user.entity_ref();
623        Box::pin(async move {
624            let relation = self
625                .request(endpoint::users::relation::Request { user_id })
626                .await
627                .map_err(Error::Client)?
628                .into_result()?;
629            Ok(relation)
630        })
631    }
632
633    /// Checks if the specified user is followed by the user logged in with this client.
634    ///
635    /// If you are also interested in other relationships, use [`user_relation`][user_relation].
636    ///
637    /// [user_relation]: ClientExt::user_relation
638    ///
639    /// ```
640    /// # use misskey_util::ClientExt;
641    /// # use futures::stream::TryStreamExt;
642    /// # #[tokio::main]
643    /// # async fn main() -> anyhow::Result<()> {
644    /// # let client = misskey_test::test_client().await?;
645    /// # let user = client.users().list().try_next().await?.unwrap();
646    /// let relation = client.user_relation(&user).await?;
647    /// assert_eq!(client.is_following(&user).await?, relation.is_following);
648    /// # Ok(())
649    /// # }
650    /// ```
651    fn is_following(
652        &self,
653        user: impl EntityRef<User>,
654    ) -> BoxFuture<Result<bool, Error<Self::Error>>> {
655        let user_id = user.entity_ref();
656        Box::pin(async move { Ok(self.user_relation(user_id).await?.is_following) })
657    }
658
659    /// Checks if the specified user follows the user logged in with this client.
660    ///
661    /// If you are also interested in other relationships, use [`user_relation`][user_relation].
662    ///
663    /// [user_relation]: ClientExt::user_relation
664    ///
665    /// ```
666    /// # use misskey_util::ClientExt;
667    /// # use futures::stream::TryStreamExt;
668    /// # #[tokio::main]
669    /// # async fn main() -> anyhow::Result<()> {
670    /// # let client = misskey_test::test_client().await?;
671    /// # let user = client.users().list().try_next().await?.unwrap();
672    /// let relation = client.user_relation(&user).await?;
673    /// assert_eq!(client.is_followed(&user).await?, relation.is_followed);
674    /// # Ok(())
675    /// # }
676    /// ```
677    fn is_followed(
678        &self,
679        user: impl EntityRef<User>,
680    ) -> BoxFuture<Result<bool, Error<Self::Error>>> {
681        let user_id = user.entity_ref();
682        Box::pin(async move { Ok(self.user_relation(user_id).await?.is_followed) })
683    }
684
685    /// Checks if the specified user is blocked by the user logged in with this client.
686    ///
687    /// If you are also interested in other relationships, use [`user_relation`][user_relation].
688    ///
689    /// [user_relation]: ClientExt::user_relation
690    ///
691    /// ```
692    /// # use misskey_util::ClientExt;
693    /// # use futures::stream::TryStreamExt;
694    /// # #[tokio::main]
695    /// # async fn main() -> anyhow::Result<()> {
696    /// # let client = misskey_test::test_client().await?;
697    /// # let user = client.users().list().try_next().await?.unwrap();
698    /// let relation = client.user_relation(&user).await?;
699    /// assert_eq!(client.is_blocking(&user).await?, relation.is_blocking);
700    /// # Ok(())
701    /// # }
702    /// ```
703    fn is_blocking(
704        &self,
705        user: impl EntityRef<User>,
706    ) -> BoxFuture<Result<bool, Error<Self::Error>>> {
707        let user_id = user.entity_ref();
708        Box::pin(async move { Ok(self.user_relation(user_id).await?.is_blocking) })
709    }
710
711    /// Checks if the specified user blocks the user logged in with this client.
712    ///
713    /// If you are also interested in other relationships, use [`user_relation`][user_relation].
714    ///
715    /// [user_relation]: ClientExt::user_relation
716    ///
717    /// ```
718    /// # use misskey_util::ClientExt;
719    /// # use futures::stream::TryStreamExt;
720    /// # #[tokio::main]
721    /// # async fn main() -> anyhow::Result<()> {
722    /// # let client = misskey_test::test_client().await?;
723    /// # let user = client.users().list().try_next().await?.unwrap();
724    /// let relation = client.user_relation(&user).await?;
725    /// assert_eq!(client.is_blocked(&user).await?, relation.is_blocked);
726    /// # Ok(())
727    /// # }
728    /// ```
729    fn is_blocked(
730        &self,
731        user: impl EntityRef<User>,
732    ) -> BoxFuture<Result<bool, Error<Self::Error>>> {
733        let user_id = user.entity_ref();
734        Box::pin(async move { Ok(self.user_relation(user_id).await?.is_blocked) })
735    }
736
737    /// Checks if the specified user is muted by the user logged in with this client.
738    ///
739    /// If you are also interested in other relationships, use [`user_relation`][user_relation].
740    ///
741    /// [user_relation]: ClientExt::user_relation
742    ///
743    /// ```
744    /// # use misskey_util::ClientExt;
745    /// # use futures::stream::TryStreamExt;
746    /// # #[tokio::main]
747    /// # async fn main() -> anyhow::Result<()> {
748    /// # let client = misskey_test::test_client().await?;
749    /// # let user = client.users().list().try_next().await?.unwrap();
750    /// let relation = client.user_relation(&user).await?;
751    /// assert_eq!(client.is_muted(&user).await?, relation.is_muted);
752    /// # Ok(())
753    /// # }
754    /// ```
755    fn is_muted(&self, user: impl EntityRef<User>) -> BoxFuture<Result<bool, Error<Self::Error>>> {
756        let user_id = user.entity_ref();
757        Box::pin(async move { Ok(self.user_relation(user_id).await?.is_muted) })
758    }
759
760    /// Checks if the specified user has a pending follow request from the user logged in with this client.
761    ///
762    /// If you are also interested in other relationships, use [`user_relation`][user_relation].
763    ///
764    /// [user_relation]: ClientExt::user_relation
765    ///
766    /// ```
767    /// # use misskey_util::ClientExt;
768    /// # use futures::stream::TryStreamExt;
769    /// # #[tokio::main]
770    /// # async fn main() -> anyhow::Result<()> {
771    /// # let client = misskey_test::test_client().await?;
772    /// # let user = client.users().list().try_next().await?.unwrap();
773    /// let relation = client.user_relation(&user).await?;
774    /// assert_eq!(client.has_pending_follow_request_from_me(&user).await?, relation.has_pending_follow_request_from_you);
775    /// # Ok(())
776    /// # }
777    /// ```
778    fn has_pending_follow_request_from_me(
779        &self,
780        user: impl EntityRef<User>,
781    ) -> BoxFuture<Result<bool, Error<Self::Error>>> {
782        let user_id = user.entity_ref();
783        Box::pin(async move {
784            Ok(self
785                .user_relation(user_id)
786                .await?
787                .has_pending_follow_request_from_you)
788        })
789    }
790
791    /// Checks if the specified user has a pending follow request to the user logged in with this client.
792    ///
793    /// If you are also interested in other relationships, use [`user_relation`][user_relation].
794    ///
795    /// [user_relation]: ClientExt::user_relation
796    ///
797    /// ```
798    /// # use misskey_util::ClientExt;
799    /// # use futures::stream::TryStreamExt;
800    /// # #[tokio::main]
801    /// # async fn main() -> anyhow::Result<()> {
802    /// # let client = misskey_test::test_client().await?;
803    /// # let user = client.users().list().try_next().await?.unwrap();
804    /// let relation = client.user_relation(&user).await?;
805    /// assert_eq!(client.has_pending_follow_request_to_me(&user).await?, relation.has_pending_follow_request_to_you);
806    /// # Ok(())
807    /// # }
808    /// ```
809    fn has_pending_follow_request_to_me(
810        &self,
811        user: impl EntityRef<User>,
812    ) -> BoxFuture<Result<bool, Error<Self::Error>>> {
813        let user_id = user.entity_ref();
814        Box::pin(async move {
815            Ok(self
816                .user_relation(user_id)
817                .await?
818                .has_pending_follow_request_to_you)
819        })
820    }
821
822    /// Gets the corresponding user from the ID.
823    fn get_user(&self, id: Id<User>) -> BoxFuture<Result<User, Error<Self::Error>>> {
824        Box::pin(async move {
825            let note = self
826                .request(endpoint::users::show::Request::WithUserId { user_id: id })
827                .await
828                .map_err(Error::Client)?
829                .into_result()?;
830            Ok(note)
831        })
832    }
833
834    /// Gets the list of corresponding user from the list of IDs.
835    fn get_users(
836        &self,
837        ids: impl IntoIterator<Item = Id<User>>,
838    ) -> BoxFuture<Result<Vec<User>, Error<Self::Error>>> {
839        let user_ids = ids.into_iter().collect();
840        Box::pin(async move {
841            let note = self
842                .request(endpoint::users::show::RequestWithUserIds { user_ids })
843                .await
844                .map_err(Error::Client)?
845                .into_result()?;
846            Ok(note)
847        })
848    }
849
850    /// Reports abuse by the specified user.
851    fn report_abuse(
852        &self,
853        user: impl EntityRef<User>,
854        comment: impl Into<String>,
855    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
856        let user_id = user.entity_ref();
857        let comment = comment.into();
858        Box::pin(async move {
859            self.request(endpoint::users::report_abuse::Request { user_id, comment })
860                .await
861                .map_err(Error::Client)?
862                .into_result()?;
863            Ok(())
864        })
865    }
866
867    /// Searches for users with the specified query string.
868    fn search_users(&self, query: impl Into<String>) -> PagerStream<BoxPager<Self, User>> {
869        let pager = OffsetPager::new(
870            self,
871            endpoint::users::search::Request::builder()
872                .query(query)
873                .build(),
874        );
875        PagerStream::new(Box::pin(pager))
876    }
877
878    /// Lists the users in the instance.
879    ///
880    /// This method actually returns a builder, namely [`UserListBuilder`].
881    /// You can specify how you want to list users by chaining methods.
882    /// The [`list`][builder_list] method of the builder returns a [`Stream`][stream]
883    /// that lists users in the specified way.
884    ///
885    /// [builder_list]: UserListBuilder::list
886    /// [stream]: futures::stream::Stream
887    ///
888    /// # Examples
889    ///
890    /// ```
891    /// # use misskey_util::ClientExt;
892    /// # #[tokio::main]
893    /// # async fn main() -> anyhow::Result<()> {
894    /// # let client = misskey_test::test_client().await?;
895    /// # use misskey_api as misskey;
896    /// use futures::stream::TryStreamExt;
897    /// use misskey::model::user::{User, UserSortKey};
898    ///
899    /// // Get a list of local moderator users sorted by number of followers.
900    /// let users: Vec<User> = client
901    ///     .users()
902    ///     .local()
903    ///     .moderator()
904    ///     .sort_by_followers()
905    ///     .list()
906    ///     .try_collect()
907    ///     .await?;
908    /// # Ok(())
909    /// # }
910    /// ```
911    fn users(&self) -> UserListBuilder<&Self> {
912        UserListBuilder::new(self)
913    }
914
915    /// Lists the recommended users of the instance.
916    fn recommended_users(&self) -> PagerStream<BoxPager<Self, User>> {
917        let pager = OffsetPager::new(self, endpoint::users::recommendation::Request::default());
918        PagerStream::new(Box::pin(pager))
919    }
920
921    /// Lists the users who frequently reply to the specified user.
922    fn frequently_replied_users(
923        &self,
924        user: impl EntityRef<User>,
925    ) -> BoxFuture<Result<Vec<User>, Error<Self::Error>>> {
926        let user_id = user.entity_ref();
927        Box::pin(async move {
928            let users = self
929                .request(endpoint::users::get_frequently_replied_users::Request {
930                    user_id,
931                    limit: None,
932                })
933                .await
934                .map_err(Error::Client)?
935                .into_result()?
936                .into_iter()
937                .map(|endpoint::users::get_frequently_replied_users::Reply { user, .. }| user)
938                .collect();
939            Ok(users)
940        })
941    }
942
943    /// Lists the users pinned to the instance.
944    fn pinned_users(&self) -> BoxFuture<Result<Vec<User>, Error<Self::Error>>> {
945        Box::pin(async move {
946            let users = self
947                .request(endpoint::pinned_users::Request::default())
948                .await
949                .map_err(Error::Client)?
950                .into_result()?;
951            Ok(users)
952        })
953    }
954
955    // }}}
956
957    // {{{ Note
958    /// Returns a builder for composing a note.
959    ///
960    /// The returned builder provides methods to customize details of the note,
961    /// and you can chain them to compose a note incrementally.
962    /// Finally, calling [`create`][builder_create] method will actually create a note.
963    /// See [`NoteBuilder`] for the provided methods.
964    ///
965    /// [builder_create]: NoteBuilder::create
966    ///
967    /// # Examples
968    ///
969    /// ```
970    /// # use misskey_util::ClientExt;
971    /// # #[tokio::main]
972    /// # async fn main() -> anyhow::Result<()> {
973    /// # let client = misskey_test::test_client().await?;
974    /// let note = client
975    ///     .build_note()
976    ///     .text("Hello, World")
977    ///     .followers_only()
978    ///     .create()
979    ///     .await?;
980    ///
981    /// assert_eq!(note.text.unwrap(), "Hello, World");
982    /// # Ok(())
983    /// # }
984    /// ```
985    fn build_note(&self) -> NoteBuilder<&Self> {
986        NoteBuilder::new(self)
987    }
988
989    /// Deletes the specified note.
990    ///
991    /// # Examples
992    ///
993    /// ```
994    /// # use misskey_util::ClientExt;
995    /// # #[tokio::main]
996    /// # async fn main() -> anyhow::Result<()> {
997    /// # let client = misskey_test::test_client().await?;
998    /// let note = client.create_note("Oops!").await?;
999    /// client.delete_note(&note).await?;
1000    /// # Ok(())
1001    /// # }
1002    /// ```
1003    fn delete_note(&self, note: impl EntityRef<Note>) -> BoxFuture<Result<(), Error<Self::Error>>> {
1004        let note_id = note.entity_ref();
1005        Box::pin(async move {
1006            self.request(endpoint::notes::delete::Request { note_id })
1007                .await
1008                .map_err(Error::Client)?
1009                .into_result()?;
1010            Ok(())
1011        })
1012    }
1013
1014    /// Gets the corresponding note from the ID.
1015    fn get_note(&self, id: Id<Note>) -> BoxFuture<Result<Note, Error<Self::Error>>> {
1016        Box::pin(async move {
1017            let note = self
1018                .request(endpoint::notes::show::Request { note_id: id })
1019                .await
1020                .map_err(Error::Client)?
1021                .into_result()?;
1022            Ok(note)
1023        })
1024    }
1025
1026    /// Creates a note with the given text.
1027    ///
1028    /// # Examples
1029    ///
1030    /// ```
1031    /// # use misskey_util::ClientExt;
1032    /// # #[tokio::main]
1033    /// # async fn main() -> anyhow::Result<()> {
1034    /// # let client = misskey_test::test_client().await?;
1035    /// let note = client.create_note("Hello, Misskey!").await?;
1036    /// assert_eq!(note.text.unwrap(), "Hello, Misskey!");
1037    /// # Ok(())
1038    /// # }
1039    /// ```
1040    fn create_note(&self, text: impl Into<String>) -> BoxFuture<Result<Note, Error<Self::Error>>> {
1041        let text = text.into();
1042        Box::pin(async move { self.build_note().text(text).create().await })
1043    }
1044
1045    /// Creates a poll with the given text and choices.
1046    ///
1047    /// # Examples
1048    ///
1049    /// ```
1050    /// # use misskey_util::ClientExt;
1051    /// # #[tokio::main]
1052    /// # async fn main() -> anyhow::Result<()> {
1053    /// # let client = misskey_test::test_client().await?;
1054    /// let note = client
1055    ///     .poll("Which fruit is your favorite?", vec!["Apple", "Orange", "Banana"])
1056    ///     .await?;
1057    /// # Ok(())
1058    /// # }
1059    /// ```
1060    fn poll(
1061        &self,
1062        text: impl Into<String>,
1063        choices: impl IntoIterator<Item = impl Into<String>>,
1064    ) -> BoxFuture<Result<Note, Error<Self::Error>>> {
1065        let text = text.into();
1066        let choices: Vec<_> = choices.into_iter().map(Into::into).collect();
1067        Box::pin(async move { self.build_note().text(text).poll(choices).create().await })
1068    }
1069
1070    /// Creates a reply note with the given text.
1071    fn reply(
1072        &self,
1073        note: impl EntityRef<Note>,
1074        text: impl Into<String>,
1075    ) -> BoxFuture<Result<Note, Error<Self::Error>>> {
1076        let note_id = note.entity_ref();
1077        let text = text.into();
1078        Box::pin(async move { self.build_note().reply(note_id).text(text).create().await })
1079    }
1080
1081    /// Creates a renote.
1082    fn renote(&self, note: impl EntityRef<Note>) -> BoxFuture<Result<Note, Error<Self::Error>>> {
1083        let note_id = note.entity_ref();
1084        Box::pin(async move { self.build_note().renote(note_id).create().await })
1085    }
1086
1087    /// Creates a quote note with the given text.
1088    fn quote(
1089        &self,
1090        note: impl EntityRef<Note>,
1091        text: impl Into<String>,
1092    ) -> BoxFuture<Result<Note, Error<Self::Error>>> {
1093        let note_id = note.entity_ref();
1094        let text = text.into();
1095        Box::pin(async move { self.build_note().renote(note_id).text(text).create().await })
1096    }
1097
1098    /// Adds the reaction to the specified note.
1099    fn react(
1100        &self,
1101        note: impl EntityRef<Note>,
1102        reaction: impl Into<Reaction>,
1103    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
1104        let note_id = note.entity_ref();
1105        let reaction = reaction.into();
1106        Box::pin(async move {
1107            self.request(endpoint::notes::reactions::create::Request { note_id, reaction })
1108                .await
1109                .map_err(Error::Client)?
1110                .into_result()?;
1111            Ok(())
1112        })
1113    }
1114
1115    /// Deletes a reaction from the specified note.
1116    fn unreact(&self, note: impl EntityRef<Note>) -> BoxFuture<Result<(), Error<Self::Error>>> {
1117        let note_id = note.entity_ref();
1118        Box::pin(async move {
1119            self.request(endpoint::notes::reactions::delete::Request { note_id })
1120                .await
1121                .map_err(Error::Client)?
1122                .into_result()?;
1123            Ok(())
1124        })
1125    }
1126
1127    /// Favorites the specified note.
1128    fn favorite(&self, note: impl EntityRef<Note>) -> BoxFuture<Result<(), Error<Self::Error>>> {
1129        let note_id = note.entity_ref();
1130        Box::pin(async move {
1131            self.request(endpoint::notes::favorites::create::Request { note_id })
1132                .await
1133                .map_err(Error::Client)?
1134                .into_result()?;
1135            Ok(())
1136        })
1137    }
1138
1139    /// Unfavorites the specified note.
1140    fn unfavorite(&self, note: impl EntityRef<Note>) -> BoxFuture<Result<(), Error<Self::Error>>> {
1141        let note_id = note.entity_ref();
1142        Box::pin(async move {
1143            self.request(endpoint::notes::favorites::delete::Request { note_id })
1144                .await
1145                .map_err(Error::Client)?
1146                .into_result()?;
1147            Ok(())
1148        })
1149    }
1150
1151    /// Watches the specified note.
1152    fn watch(&self, note: impl EntityRef<Note>) -> BoxFuture<Result<(), Error<Self::Error>>> {
1153        let note_id = note.entity_ref();
1154        Box::pin(async move {
1155            self.request(endpoint::notes::watching::create::Request { note_id })
1156                .await
1157                .map_err(Error::Client)?
1158                .into_result()?;
1159            Ok(())
1160        })
1161    }
1162
1163    /// Unwatches the specified note.
1164    fn unwatch(&self, note: impl EntityRef<Note>) -> BoxFuture<Result<(), Error<Self::Error>>> {
1165        let note_id = note.entity_ref();
1166        Box::pin(async move {
1167            self.request(endpoint::notes::watching::delete::Request { note_id })
1168                .await
1169                .map_err(Error::Client)?
1170                .into_result()?;
1171            Ok(())
1172        })
1173    }
1174
1175    /// Checks if the specified note is favorited by the user logged in with this client.
1176    fn is_favorited(
1177        &self,
1178        note: impl EntityRef<Note>,
1179    ) -> BoxFuture<Result<bool, Error<Self::Error>>> {
1180        let note_id = note.entity_ref();
1181        Box::pin(async move {
1182            let state = self
1183                .request(endpoint::notes::state::Request { note_id })
1184                .await
1185                .map_err(Error::Client)?
1186                .into_result()?;
1187            Ok(state.is_favorited)
1188        })
1189    }
1190
1191    /// Checks if the specified note is watched by the user logged in with this client.
1192    fn is_watched(
1193        &self,
1194        note: impl EntityRef<Note>,
1195    ) -> BoxFuture<Result<bool, Error<Self::Error>>> {
1196        let note_id = note.entity_ref();
1197        Box::pin(async move {
1198            let state = self
1199                .request(endpoint::notes::state::Request { note_id })
1200                .await
1201                .map_err(Error::Client)?
1202                .into_result()?;
1203            Ok(state.is_watching)
1204        })
1205    }
1206
1207    /// Vote on the specified note.
1208    fn vote(
1209        &self,
1210        note: impl EntityRef<Note>,
1211        choice: u64,
1212    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
1213        let note_id = note.entity_ref();
1214        Box::pin(async move {
1215            self.request(endpoint::notes::polls::vote::Request { note_id, choice })
1216                .await
1217                .map_err(Error::Client)?
1218                .into_result()?;
1219            Ok(())
1220        })
1221    }
1222
1223    /// Lists the featured notes.
1224    fn featured_notes(&self) -> PagerStream<BoxPager<Self, Note>> {
1225        let pager = OffsetPager::new(self, endpoint::notes::featured::Request::default());
1226        PagerStream::new(Box::pin(pager))
1227    }
1228
1229    /// Lists the notes of the conversation.
1230    fn conversation(&self, note: impl EntityRef<Note>) -> PagerStream<BoxPager<Self, Note>> {
1231        let pager = OffsetPager::new(
1232            self,
1233            endpoint::notes::conversation::Request::builder()
1234                .note_id(note.entity_ref())
1235                .build(),
1236        );
1237        PagerStream::new(Box::pin(pager))
1238    }
1239
1240    /// Lists the reply notes to the specified note.
1241    fn children_notes(&self, note: impl EntityRef<Note>) -> PagerStream<BoxPager<Self, Note>> {
1242        let pager = BackwardPager::new(
1243            self,
1244            endpoint::notes::children::Request::builder()
1245                .note_id(note.entity_ref())
1246                .build(),
1247        );
1248        PagerStream::new(Box::pin(pager))
1249    }
1250
1251    /// Lists the notes that are mentioning the account you are logged into with this client.
1252    fn mentioned_notes(&self) -> PagerStream<BoxPager<Self, Note>> {
1253        let pager = BackwardPager::new(self, endpoint::notes::mentions::Request::default());
1254        PagerStream::new(Box::pin(pager))
1255    }
1256
1257    /// Lists the renotes of the specified note.
1258    fn renotes(&self, note: impl EntityRef<Note>) -> PagerStream<BoxPager<Self, Note>> {
1259        let pager = BackwardPager::new(
1260            self,
1261            endpoint::notes::renotes::Request::builder()
1262                .note_id(note.entity_ref())
1263                .build(),
1264        );
1265        PagerStream::new(Box::pin(pager))
1266    }
1267
1268    /// Lists the replies to the specified note.
1269    fn replies(&self, note: impl EntityRef<Note>) -> PagerStream<BoxPager<Self, Note>> {
1270        let pager = BackwardPager::new(
1271            self,
1272            endpoint::notes::renotes::Request::builder()
1273                .note_id(note.entity_ref())
1274                .build(),
1275        );
1276        PagerStream::new(Box::pin(pager))
1277    }
1278
1279    /// Searches for notes with the specified query string.
1280    fn search_notes(&self, query: impl Into<String>) -> PagerStream<BoxPager<Self, Note>> {
1281        let pager = BackwardPager::new(
1282            self,
1283            endpoint::notes::search::Request::builder()
1284                .query(query)
1285                .build(),
1286        );
1287        PagerStream::new(Box::pin(pager))
1288    }
1289
1290    impl_timeline_method! { local, notes::local_timeline }
1291    impl_timeline_method! { global, notes::global_timeline }
1292    impl_timeline_method! { social, notes::hybrid_timeline }
1293    impl_timeline_method! { home, notes::timeline }
1294    impl_timeline_method! { user, users::notes, user_id = user : User }
1295    impl_timeline_method! { user_list, notes::user_list_timeline, list_id = list : UserList }
1296
1297    #[cfg(feature = "12-47-0")]
1298    impl_timeline_method! { channel, channels::timeline, channel_id = channel : Channel }
1299
1300    /// Lists the notes with tags as specified in the given query.
1301    ///
1302    /// # Examples
1303    ///
1304    /// ```
1305    /// # use misskey_util::ClientExt;
1306    /// # #[tokio::main]
1307    /// # async fn main() -> anyhow::Result<()> {
1308    /// # let client = misskey_test::test_client().await?;
1309    /// // Get all notes with the "linux" tag.
1310    /// let mut notes = client.tagged_notes("linux");
1311    /// # Ok(())
1312    /// # }
1313    /// ```
1314    ///
1315    /// ```
1316    /// # use misskey_util::ClientExt;
1317    /// # #[tokio::main]
1318    /// # async fn main() -> anyhow::Result<()> {
1319    /// # let client = misskey_test::test_client().await?;
1320    /// # use misskey_api as misskey;
1321    /// use misskey::model::query::Query;
1322    ///
1323    /// // Get all notes tagged with "test" or "bot".
1324    /// let mut notes = client.tagged_notes(Query::atom("test").or("bot"));
1325    /// # Ok(())
1326    /// # }
1327    /// ```
1328    fn tagged_notes(&self, query: impl Into<Query<Tag>>) -> PagerStream<BoxPager<Self, Note>> {
1329        let pager = BackwardPager::new(
1330            self,
1331            endpoint::notes::search_by_tag::Request::builder()
1332                .query(query)
1333                .build(),
1334        );
1335        PagerStream::new(Box::pin(pager))
1336    }
1337
1338    /// Lists the local notes with the given file types.
1339    ///
1340    /// # Examples
1341    ///
1342    /// ```
1343    /// # use misskey_util::ClientExt;
1344    /// # #[tokio::main]
1345    /// # async fn main() -> anyhow::Result<()> {
1346    /// # let client = misskey_test::test_client().await?;
1347    /// use mime::IMAGE_STAR;
1348    ///
1349    /// // Get all local notes with image files.
1350    /// let mut notes = client.local_notes_with_file_types(vec![IMAGE_STAR]);
1351    /// # Ok(())
1352    /// # }
1353    /// ```
1354    fn local_notes_with_file_types(
1355        &self,
1356        types: impl IntoIterator<Item = Mime>,
1357    ) -> PagerStream<BoxPager<Self, Note>> {
1358        let pager = BackwardPager::new(
1359            self,
1360            endpoint::notes::local_timeline::Request::builder()
1361                .file_type(types.into_iter().map(Into::into).collect())
1362                .build(),
1363        );
1364        PagerStream::new(Box::pin(pager))
1365    }
1366    // }}}
1367
1368    // {{{ User List
1369    /// Creates a user list with the given name.
1370    ///
1371    /// # Examples
1372    ///
1373    /// ```
1374    /// # use misskey_util::ClientExt;
1375    /// # #[tokio::main]
1376    /// # async fn main() -> anyhow::Result<()> {
1377    /// # let client = misskey_test::test_client().await?;
1378    /// let list = client.create_user_list("list").await?;
1379    /// assert_eq!(list.name, "list");
1380    /// # Ok(())
1381    /// # }
1382    /// ```
1383    fn create_user_list(
1384        &self,
1385        name: impl Into<String>,
1386    ) -> BoxFuture<Result<UserList, Error<Self::Error>>> {
1387        let name = name.into();
1388        Box::pin(async move {
1389            let list = self
1390                .request(endpoint::users::lists::create::Request { name })
1391                .await
1392                .map_err(Error::Client)?
1393                .into_result()?;
1394            Ok(list)
1395        })
1396    }
1397
1398    /// Deletes the specified user list.
1399    ///
1400    /// # Examples
1401    ///
1402    /// ```
1403    /// # use misskey_util::ClientExt;
1404    /// # #[tokio::main]
1405    /// # async fn main() -> anyhow::Result<()> {
1406    /// # let client = misskey_test::test_client().await?;
1407    /// let list = client.create_user_list("list").await?;
1408    /// client.delete_user_list(&list).await?;
1409    /// # Ok(())
1410    /// # }
1411    /// ```
1412    fn delete_user_list(
1413        &self,
1414        list: impl EntityRef<UserList>,
1415    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
1416        let list_id = list.entity_ref();
1417        Box::pin(async move {
1418            self.request(endpoint::users::lists::delete::Request { list_id })
1419                .await
1420                .map_err(Error::Client)?
1421                .into_result()?;
1422            Ok(())
1423        })
1424    }
1425
1426    /// Updates the name of the specified user list to the given one.
1427    ///
1428    /// # Examples
1429    ///
1430    /// ```
1431    /// # use misskey_util::ClientExt;
1432    /// # #[tokio::main]
1433    /// # async fn main() -> anyhow::Result<()> {
1434    /// # let client = misskey_test::test_client().await?;
1435    /// let list = client.create_user_list("list").await?;
1436    /// let renamed_list = client.rename_user_list(&list, "list2").await?;
1437    /// assert_eq!(renamed_list.name, "list2");
1438    /// # Ok(())
1439    /// # }
1440    /// ```
1441    fn rename_user_list(
1442        &self,
1443        list: impl EntityRef<UserList>,
1444        name: impl Into<String>,
1445    ) -> BoxFuture<Result<UserList, Error<Self::Error>>> {
1446        let list_id = list.entity_ref();
1447        let name = name.into();
1448        Box::pin(async move {
1449            let list = self
1450                .request(endpoint::users::lists::update::Request { list_id, name })
1451                .await
1452                .map_err(Error::Client)?
1453                .into_result()?;
1454            Ok(list)
1455        })
1456    }
1457
1458    /// Gets the corresponding user list from the ID.
1459    fn get_user_list(&self, id: Id<UserList>) -> BoxFuture<Result<UserList, Error<Self::Error>>> {
1460        Box::pin(async move {
1461            let list = self
1462                .request(endpoint::users::lists::show::Request { list_id: id })
1463                .await
1464                .map_err(Error::Client)?
1465                .into_result()?;
1466            Ok(list)
1467        })
1468    }
1469
1470    /// Adds the user from the specified user list.
1471    fn push_to_user_list(
1472        &self,
1473        list: impl EntityRef<UserList>,
1474        user: impl EntityRef<User>,
1475    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
1476        let list_id = list.entity_ref();
1477        let user_id = user.entity_ref();
1478        Box::pin(async move {
1479            self.request(endpoint::users::lists::push::Request { list_id, user_id })
1480                .await
1481                .map_err(Error::Client)?
1482                .into_result()?;
1483            Ok(())
1484        })
1485    }
1486
1487    /// Deletes the user from the specified user list.
1488    fn pull_from_user_list(
1489        &self,
1490        list: impl EntityRef<UserList>,
1491        user: impl EntityRef<User>,
1492    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
1493        let list_id = list.entity_ref();
1494        let user_id = user.entity_ref();
1495        Box::pin(async move {
1496            self.request(endpoint::users::lists::pull::Request { list_id, user_id })
1497                .await
1498                .map_err(Error::Client)?
1499                .into_result()?;
1500            Ok(())
1501        })
1502    }
1503    // }}}
1504
1505    // {{{ User Group
1506    /// Creates a user group with the given name.
1507    ///
1508    /// # Examples
1509    ///
1510    /// ```
1511    /// # use misskey_util::ClientExt;
1512    /// # #[tokio::main]
1513    /// # async fn main() -> anyhow::Result<()> {
1514    /// # let client = misskey_test::test_client().await?;
1515    /// let group = client.create_user_group("group").await?;
1516    /// assert_eq!(group.name, "group");
1517    /// # Ok(())
1518    /// # }
1519    /// ```
1520    fn create_user_group(
1521        &self,
1522        name: impl Into<String>,
1523    ) -> BoxFuture<Result<UserGroup, Error<Self::Error>>> {
1524        let name = name.into();
1525        Box::pin(async move {
1526            let group = self
1527                .request(endpoint::users::groups::create::Request { name })
1528                .await
1529                .map_err(Error::Client)?
1530                .into_result()?;
1531            Ok(group)
1532        })
1533    }
1534
1535    /// Deletes the specified user group.
1536    ///
1537    /// # Examples
1538    ///
1539    /// ```
1540    /// # use misskey_util::ClientExt;
1541    /// # #[tokio::main]
1542    /// # async fn main() -> anyhow::Result<()> {
1543    /// # let client = misskey_test::test_client().await?;
1544    /// let group = client.create_user_group("group").await?;
1545    /// client.delete_user_group(&group).await?;
1546    /// # Ok(())
1547    /// # }
1548    /// ```
1549    fn delete_user_group(
1550        &self,
1551        group: impl EntityRef<UserGroup>,
1552    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
1553        let group_id = group.entity_ref();
1554        Box::pin(async move {
1555            self.request(endpoint::users::groups::delete::Request { group_id })
1556                .await
1557                .map_err(Error::Client)?
1558                .into_result()?;
1559            Ok(())
1560        })
1561    }
1562
1563    /// Updates the name of the specified user group to the given one.
1564    ///
1565    /// # Examples
1566    ///
1567    /// ```
1568    /// # use misskey_util::ClientExt;
1569    /// # #[tokio::main]
1570    /// # async fn main() -> anyhow::Result<()> {
1571    /// # let client = misskey_test::test_client().await?;
1572    /// let group = client.create_user_group("group").await?;
1573    /// let renamed_group = client.rename_user_group(&group, "group2").await?;
1574    /// assert_eq!(renamed_group.name, "group2");
1575    /// # Ok(())
1576    /// # }
1577    /// ```
1578    fn rename_user_group(
1579        &self,
1580        group: impl EntityRef<UserGroup>,
1581        name: impl Into<String>,
1582    ) -> BoxFuture<Result<UserGroup, Error<Self::Error>>> {
1583        let group_id = group.entity_ref();
1584        let name = name.into();
1585        Box::pin(async move {
1586            let group = self
1587                .request(endpoint::users::groups::update::Request { group_id, name })
1588                .await
1589                .map_err(Error::Client)?
1590                .into_result()?;
1591            Ok(group)
1592        })
1593    }
1594
1595    /// Gets the corresponding user group from the ID.
1596    fn get_user_group(
1597        &self,
1598        id: Id<UserGroup>,
1599    ) -> BoxFuture<Result<UserGroup, Error<Self::Error>>> {
1600        Box::pin(async move {
1601            let group = self
1602                .request(endpoint::users::groups::show::Request { group_id: id })
1603                .await
1604                .map_err(Error::Client)?
1605                .into_result()?;
1606            Ok(group)
1607        })
1608    }
1609
1610    /// Invites the user to the specified user group.
1611    fn invite_to_user_group(
1612        &self,
1613        group: impl EntityRef<UserGroup>,
1614        user: impl EntityRef<User>,
1615    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
1616        let group_id = group.entity_ref();
1617        let user_id = user.entity_ref();
1618        Box::pin(async move {
1619            self.request(endpoint::users::groups::invite::Request { group_id, user_id })
1620                .await
1621                .map_err(Error::Client)?
1622                .into_result()?;
1623            Ok(())
1624        })
1625    }
1626
1627    /// Deletes the user from the specified user group.
1628    ///
1629    /// Note that the owner of the group cannot be deleted.
1630    /// If you want to do so, you first need to transfer the group with
1631    /// [`transfer_user_group`][transfer].
1632    ///
1633    /// [transfer]: ClientExt::transfer_user_group
1634    fn pull_from_user_group(
1635        &self,
1636        group: impl EntityRef<UserGroup>,
1637        user: impl EntityRef<User>,
1638    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
1639        let group_id = group.entity_ref();
1640        let user_id = user.entity_ref();
1641        Box::pin(async move {
1642            self.request(endpoint::users::groups::pull::Request { group_id, user_id })
1643                .await
1644                .map_err(Error::Client)?
1645                .into_result()?;
1646            Ok(())
1647        })
1648    }
1649
1650    /// Transfers the specified user group.
1651    ///
1652    /// Note that you can only transfer the group to one of its members.
1653    fn transfer_user_group(
1654        &self,
1655        group: impl EntityRef<UserGroup>,
1656        user: impl EntityRef<User>,
1657    ) -> BoxFuture<Result<UserGroup, Error<Self::Error>>> {
1658        let group_id = group.entity_ref();
1659        let user_id = user.entity_ref();
1660        Box::pin(async move {
1661            let group = self
1662                .request(endpoint::users::groups::transfer::Request { group_id, user_id })
1663                .await
1664                .map_err(Error::Client)?
1665                .into_result()?;
1666            Ok(group)
1667        })
1668    }
1669
1670    /// Lists the user group invitations sent to the user who is logged in with this client.
1671    ///
1672    /// # Examples
1673    ///
1674    /// This example uses [`TryStreamExt::try_next`][try_next] and [`while let`][while_let]
1675    /// to retrieve invitations one after another until there are no more.
1676    ///
1677    /// [try_next]: futures::stream::TryStreamExt::try_next
1678    /// [while_let]: https://doc.rust-lang.org/std/keyword.while.html
1679    ///
1680    /// ```
1681    /// # use misskey_util::ClientExt;
1682    /// # #[tokio::main]
1683    /// # async fn main() -> anyhow::Result<()> {
1684    /// # let client = misskey_test::test_client().await?;
1685    /// use futures::stream::TryStreamExt;
1686    ///
1687    /// // `invitations` here is a `Stream` to enumerate all the invitations.
1688    /// let mut invitations = client.user_group_invitations();
1689    /// // Retrieve invitations until there are no more.
1690    /// while let Some(invitation) = invitations.try_next().await? {
1691    ///     // Accept the invitation.
1692    ///     client.accept_user_group_invitation(&invitation).await?;
1693    /// }
1694    /// # Ok(())
1695    /// # }
1696    /// ```
1697    fn user_group_invitations(&self) -> PagerStream<BoxPager<Self, UserGroupInvitation>> {
1698        let pager = BackwardPager::new(self, endpoint::i::user_group_invites::Request::default());
1699        PagerStream::new(Box::pin(pager))
1700    }
1701
1702    /// Accepts the specified user group invitation sent to the user logged in with this client.
1703    fn accept_user_group_invitation(
1704        &self,
1705        invitation: impl EntityRef<UserGroupInvitation>,
1706    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
1707        let invitation_id = invitation.entity_ref();
1708        Box::pin(async move {
1709            self.request(endpoint::users::groups::invitations::accept::Request { invitation_id })
1710                .await
1711                .map_err(Error::Client)?
1712                .into_result()?;
1713            Ok(())
1714        })
1715    }
1716
1717    /// Rejects the specified user group invitation sent to the user logged in with this client.
1718    fn reject_user_group_invitation(
1719        &self,
1720        invitation: impl EntityRef<UserGroupInvitation>,
1721    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
1722        let invitation_id = invitation.entity_ref();
1723        Box::pin(async move {
1724            self.request(endpoint::users::groups::invitations::reject::Request { invitation_id })
1725                .await
1726                .map_err(Error::Client)?
1727                .into_result()?;
1728            Ok(())
1729        })
1730    }
1731
1732    /// Lists the user groups joined by the user logged in with this client.
1733    fn joined_user_groups(&self) -> BoxFuture<Result<Vec<UserGroup>, Error<Self::Error>>> {
1734        Box::pin(async move {
1735            let groups = self
1736                .request(endpoint::users::groups::joined::Request::default())
1737                .await
1738                .map_err(Error::Client)?
1739                .into_result()?;
1740            Ok(groups)
1741        })
1742    }
1743
1744    /// Lists the user groups owned by the user logged in with this client.
1745    fn owned_user_groups(&self) -> BoxFuture<Result<Vec<UserGroup>, Error<Self::Error>>> {
1746        Box::pin(async move {
1747            let groups = self
1748                .request(endpoint::users::groups::owned::Request::default())
1749                .await
1750                .map_err(Error::Client)?
1751                .into_result()?;
1752            Ok(groups)
1753        })
1754    }
1755    // }}}
1756
1757    // {{{ Antenna
1758    /// Creates an antenna with the given name and query.
1759    ///
1760    /// # Examples
1761    ///
1762    /// ```
1763    /// # use misskey_util::ClientExt;
1764    /// # #[tokio::main]
1765    /// # async fn main() -> anyhow::Result<()> {
1766    /// # let client = misskey_test::test_client().await?;
1767    /// # use misskey_api as misskey;
1768    /// use misskey::model::query::Query;
1769    ///
1770    /// // Create an antenna for notes containing "misskey" or "msky"
1771    /// let antenna = client
1772    ///     .create_antenna("misskey antenna", Query::atom("misskey").or("msky"))
1773    ///     .await?;
1774    ///
1775    /// assert_eq!(antenna.name, "misskey antenna");
1776    /// # Ok(())
1777    /// # }
1778    /// ```
1779    fn create_antenna(
1780        &self,
1781        name: impl Into<String>,
1782        query: impl Into<Query<String>>,
1783    ) -> BoxFuture<Result<Antenna, Error<Self::Error>>> {
1784        let name = name.into();
1785        let query = query.into();
1786        Box::pin(async move {
1787            self.build_antenna()
1788                .name(name)
1789                .include(query)
1790                .create()
1791                .await
1792        })
1793    }
1794
1795    /// Returns a builder for creating an antenna.
1796    ///
1797    /// The returned builder provides methods to customize details of the antenna,
1798    /// and you can chain them to create an antenna incrementally.
1799    /// Finally, calling [`create`][builder_create] method will actually create an antenna.
1800    /// See [`AntennaBuilder`] for the provided methods.
1801    ///
1802    /// [builder_create]: AntennaBuilder::create
1803    ///
1804    /// # Examples
1805    ///
1806    /// ```
1807    /// # use misskey_util::ClientExt;
1808    /// # #[tokio::main]
1809    /// # async fn main() -> anyhow::Result<()> {
1810    /// # let client = misskey_test::test_client().await?;
1811    /// // Create an antenna for non-reply notes in home timeline that include "misskey"
1812    /// let antenna = client
1813    ///     .build_antenna()
1814    ///     .name("misskey antenna")
1815    ///     .include("misskey")
1816    ///     .home()
1817    ///     .exclude_replies(true)
1818    ///     .create()
1819    ///     .await?;
1820    ///
1821    /// assert_eq!(antenna.name, "misskey antenna");
1822    /// # Ok(())
1823    /// # }
1824    /// ```
1825    fn build_antenna(&self) -> AntennaBuilder<&Self> {
1826        AntennaBuilder::new(self)
1827    }
1828
1829    /// Deletes the specified antenna.
1830    ///
1831    /// # Examples
1832    ///
1833    /// ```
1834    /// # use misskey_util::ClientExt;
1835    /// # #[tokio::main]
1836    /// # async fn main() -> anyhow::Result<()> {
1837    /// # let client = misskey_test::test_client().await?;
1838    /// let antenna = client
1839    ///     .create_antenna("antenna", "misskey")
1840    ///     .await?;
1841    /// client.delete_antenna(&antenna).await?;
1842    /// # Ok(())
1843    /// # }
1844    /// ```
1845    fn delete_antenna(
1846        &self,
1847        antenna: impl EntityRef<Antenna>,
1848    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
1849        let antenna_id = antenna.entity_ref();
1850        Box::pin(async move {
1851            self.request(endpoint::antennas::delete::Request { antenna_id })
1852                .await
1853                .map_err(Error::Client)?
1854                .into_result()?;
1855            Ok(())
1856        })
1857    }
1858
1859    /// Gets the corresponding antenna from the ID.
1860    fn get_antenna(&self, id: Id<Antenna>) -> BoxFuture<Result<Antenna, Error<Self::Error>>> {
1861        Box::pin(async move {
1862            let antenna = self
1863                .request(endpoint::antennas::show::Request { antenna_id: id })
1864                .await
1865                .map_err(Error::Client)?
1866                .into_result()?;
1867            Ok(antenna)
1868        })
1869    }
1870
1871    /// Updates the antenna.
1872    ///
1873    /// This method actually returns a builder, namely [`AntennaUpdateBuilder`].
1874    /// You can chain the method calls to it corresponding to the fields you want to update.
1875    /// Finally, calling [`update`][builder_update] method will actually perform the update.
1876    /// See [`AntennaUpdateBuilder`] for the fields that can be updated.
1877    ///
1878    /// [builder_update]: AntennaUpdateBuilder::update
1879    ///
1880    /// # Examples
1881    ///
1882    /// ```
1883    /// # use misskey_util::ClientExt;
1884    /// # #[tokio::main]
1885    /// # async fn main() -> anyhow::Result<()> {
1886    /// # let client = misskey_test::test_client().await?;
1887    /// let antenna = client
1888    ///     .create_antenna("antenna", "misskey")
1889    ///     .await?;
1890    ///
1891    /// // Change source and case sensitivity of the antenna
1892    /// client
1893    ///     .update_antenna(antenna)
1894    ///     .case_sensitive(true)
1895    ///     .all()
1896    ///     .update()
1897    ///     .await?;
1898    /// # Ok(())
1899    /// # }
1900    /// ```
1901    fn update_antenna(&self, antenna: Antenna) -> AntennaUpdateBuilder<&Self> {
1902        AntennaUpdateBuilder::new(self, antenna)
1903    }
1904
1905    /// Lists the antennas created by the user logged in with this client.
1906    fn antennas(&self) -> BoxFuture<Result<Vec<Antenna>, Error<Self::Error>>> {
1907        Box::pin(async move {
1908            let antennas = self
1909                .request(endpoint::antennas::list::Request::default())
1910                .await
1911                .map_err(Error::Client)?
1912                .into_result()?;
1913            Ok(antennas)
1914        })
1915    }
1916
1917    /// Lists the notes that hit the specified antenna.
1918    fn antenna_notes(&self, antenna: impl EntityRef<Antenna>) -> PagerStream<BoxPager<Self, Note>> {
1919        let pager = BackwardPager::new(
1920            self,
1921            endpoint::antennas::notes::Request::builder()
1922                .antenna_id(antenna.entity_ref())
1923                .build(),
1924        );
1925        PagerStream::new(Box::pin(pager))
1926    }
1927    // }}}
1928
1929    // {{{ Channel
1930    /// Creates a channel with the given name.
1931    ///
1932    /// # Examples
1933    ///
1934    /// ```
1935    /// # use misskey_util::ClientExt;
1936    /// # #[tokio::main]
1937    /// # async fn main() -> anyhow::Result<()> {
1938    /// # let client = misskey_test::test_client().await?;
1939    /// let channel = client.create_channel("name").await?;
1940    /// assert_eq!(channel.name, "name");
1941    /// # Ok(())
1942    /// # }
1943    /// ```
1944    #[cfg(feature = "12-47-0")]
1945    #[cfg_attr(docsrs, doc(cfg(feature = "12-47-0")))]
1946    fn create_channel(
1947        &self,
1948        name: impl Into<String>,
1949    ) -> BoxFuture<Result<Channel, Error<Self::Error>>> {
1950        let name = name.into();
1951        Box::pin(async move { self.build_channel().name(name).create().await })
1952    }
1953
1954    /// Returns a builder for creating a channel.
1955    ///
1956    /// The returned builder provides methods to customize details of the channel,
1957    /// and you can chain them to create a channel incrementally.
1958    /// Finally, calling [`create`][builder_create] method will actually create a channel.
1959    /// See [`ChannelBuilder`] for the provided methods.
1960    ///
1961    /// [builder_create]: ChannelBuilder::create
1962    ///
1963    /// # Examples
1964    ///
1965    /// ```
1966    /// # use misskey_util::ClientExt;
1967    /// # #[tokio::main]
1968    /// # async fn main() -> anyhow::Result<()> {
1969    /// # let client = misskey_test::test_client().await?;
1970    /// let channel = client
1971    ///     .build_channel()
1972    ///     .name("bot devs")
1973    ///     .description("Let's talk about Misskey's bot development!")
1974    ///     .create()
1975    ///     .await?;
1976    ///
1977    /// assert_eq!(channel.name, "bot devs");
1978    /// # Ok(())
1979    /// # }
1980    /// ```
1981    #[cfg(feature = "12-47-0")]
1982    #[cfg_attr(docsrs, doc(cfg(feature = "12-47-0")))]
1983    fn build_channel(&self) -> ChannelBuilder<&Self> {
1984        ChannelBuilder::new(self)
1985    }
1986
1987    /// Gets the corresponding channel from the ID.
1988    #[cfg(feature = "12-47-0")]
1989    #[cfg_attr(docsrs, doc(cfg(feature = "12-47-0")))]
1990    fn get_channel(&self, id: Id<Channel>) -> BoxFuture<Result<Channel, Error<Self::Error>>> {
1991        Box::pin(async move {
1992            let channel = self
1993                .request(endpoint::channels::show::Request { channel_id: id })
1994                .await
1995                .map_err(Error::Client)?
1996                .into_result()?;
1997            Ok(channel)
1998        })
1999    }
2000
2001    /// Updates the specified channel.
2002    ///
2003    /// This method actually returns a builder, namely [`ChannelUpdateBuilder`].
2004    /// You can chain the method calls to it corresponding to the fields you want to update.
2005    /// Finally, calling [`update`][builder_update] method will actually perform the update.
2006    /// See [`ChannelUpdateBuilder`] for the fields that can be updated.
2007    ///
2008    /// [builder_update]: ChannelUpdateBuilder::update
2009    ///
2010    /// # Examples
2011    ///
2012    /// ```
2013    /// # use misskey_util::ClientExt;
2014    /// # #[tokio::main]
2015    /// # async fn main() -> anyhow::Result<()> {
2016    /// # let client = misskey_test::test_client().await?;
2017    /// let channel = client.create_channel("feedback").await?;
2018    /// client
2019    ///     .update_channel(&channel)
2020    ///     .set_description("Give us feedback on the instance.")
2021    ///     .update()
2022    ///     .await?;
2023    /// # Ok(())
2024    /// # }
2025    /// ```
2026    #[cfg(feature = "12-47-0")]
2027    #[cfg_attr(docsrs, doc(cfg(feature = "12-47-0")))]
2028    fn update_channel(&self, channel: impl EntityRef<Channel>) -> ChannelUpdateBuilder<&Self> {
2029        ChannelUpdateBuilder::new(self, channel)
2030    }
2031
2032    /// Follows the specified channel.
2033    #[cfg(feature = "12-47-0")]
2034    #[cfg_attr(docsrs, doc(cfg(feature = "12-47-0")))]
2035    fn follow_channel(
2036        &self,
2037        channel: impl EntityRef<Channel>,
2038    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
2039        let channel_id = channel.entity_ref();
2040        Box::pin(async move {
2041            self.request(endpoint::channels::follow::Request { channel_id })
2042                .await
2043                .map_err(Error::Client)?
2044                .into_result()?;
2045            Ok(())
2046        })
2047    }
2048
2049    /// Unfollows the specified channel.
2050    #[cfg(feature = "12-47-0")]
2051    #[cfg_attr(docsrs, doc(cfg(feature = "12-47-0")))]
2052    fn unfollow_channel(
2053        &self,
2054        channel: impl EntityRef<Channel>,
2055    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
2056        let channel_id = channel.entity_ref();
2057        Box::pin(async move {
2058            self.request(endpoint::channels::unfollow::Request { channel_id })
2059                .await
2060                .map_err(Error::Client)?
2061                .into_result()?;
2062            Ok(())
2063        })
2064    }
2065
2066    /// Lists the channels followed by the user logged in with this client.
2067    #[cfg(feature = "12-48-0")]
2068    #[cfg_attr(docsrs, doc(cfg(feature = "12-48-0")))]
2069    fn followed_channels(&self) -> PagerStream<BoxPager<Self, Channel>> {
2070        let pager = BackwardPager::new(self, endpoint::channels::followed::Request::default());
2071        PagerStream::new(Box::pin(pager))
2072    }
2073
2074    /// Lists the channels owned by the user logged in with this client.
2075    #[cfg(feature = "12-48-0")]
2076    #[cfg_attr(docsrs, doc(cfg(feature = "12-48-0")))]
2077    fn owned_channels(&self) -> PagerStream<BoxPager<Self, Channel>> {
2078        let pager = BackwardPager::new(self, endpoint::channels::owned::Request::default());
2079        PagerStream::new(Box::pin(pager))
2080    }
2081
2082    /// Lists the featured channels.
2083    #[cfg(feature = "12-47-0")]
2084    #[cfg_attr(docsrs, doc(cfg(feature = "12-47-0")))]
2085    fn featured_channels(&self) -> BoxFuture<Result<Vec<Channel>, Error<Self::Error>>> {
2086        Box::pin(async move {
2087            let channels = self
2088                .request(endpoint::channels::featured::Request::default())
2089                .await
2090                .map_err(Error::Client)?
2091                .into_result()?;
2092            Ok(channels)
2093        })
2094    }
2095    // }}}
2096
2097    // {{{ Clip
2098    /// Creates a clip with the given name.
2099    ///
2100    /// # Examples
2101    ///
2102    /// ```
2103    /// # use misskey_util::ClientExt;
2104    /// # #[tokio::main]
2105    /// # async fn main() -> anyhow::Result<()> {
2106    /// # let client = misskey_test::test_client().await?;
2107    /// let clip = client.create_clip("name").await?;
2108    /// assert_eq!(clip.name, "name");
2109    /// # Ok(())
2110    /// # }
2111    /// ```
2112    fn create_clip(&self, name: impl Into<String>) -> BoxFuture<Result<Clip, Error<Self::Error>>> {
2113        let name = name.into();
2114        #[cfg(not(feature = "12-57-0"))]
2115        let request = endpoint::clips::create::Request { name };
2116        #[cfg(feature = "12-57-0")]
2117        let request = endpoint::clips::create::Request {
2118            name,
2119            is_public: Some(false),
2120            description: None,
2121        };
2122        Box::pin(async move {
2123            let clip = self
2124                .request(request)
2125                .await
2126                .map_err(Error::Client)?
2127                .into_result()?;
2128            Ok(clip)
2129        })
2130    }
2131
2132    /// Returns a builder for creating a clip.
2133    ///
2134    /// The returned builder provides methods to customize details of the clip,
2135    /// and you can chain them to create a clip incrementally.
2136    /// Finally, calling [`create`][builder_create] method will actually create a clip.
2137    /// See [`ClipBuilder`] for the provided methods.
2138    ///
2139    /// [builder_create]: ClipBuilder::create
2140    ///
2141    /// # Examples
2142    ///
2143    /// ```
2144    /// # use misskey_util::ClientExt;
2145    /// # #[tokio::main]
2146    /// # async fn main() -> anyhow::Result<()> {
2147    /// # let client = misskey_test::test_client().await?;
2148    /// let clip = client
2149    ///     .build_clip()
2150    ///     .name("kawaii notes")
2151    ///     .public(true)
2152    ///     .create()
2153    ///     .await?;
2154    ///
2155    /// assert_eq!(clip.name, "kawaii notes");
2156    /// # Ok(())
2157    /// # }
2158    /// ```
2159    #[cfg(feature = "12-57-0")]
2160    #[cfg_attr(docsrs, doc(cfg(feature = "12-57-0")))]
2161    fn build_clip(&self) -> ClipBuilder<&Self> {
2162        ClipBuilder::new(&self)
2163    }
2164
2165    /// Deletes the specified clip.
2166    ///
2167    /// # Examples
2168    ///
2169    /// ```
2170    /// # use misskey_util::ClientExt;
2171    /// # #[tokio::main]
2172    /// # async fn main() -> anyhow::Result<()> {
2173    /// # let client = misskey_test::test_client().await?;
2174    /// let clip = client.create_clip("Oops!").await?;
2175    /// client.delete_clip(&clip).await?;
2176    /// # Ok(())
2177    /// # }
2178    /// ```
2179    fn delete_clip(&self, clip: impl EntityRef<Clip>) -> BoxFuture<Result<(), Error<Self::Error>>> {
2180        let clip_id = clip.entity_ref();
2181        Box::pin(async move {
2182            self.request(endpoint::clips::delete::Request { clip_id })
2183                .await
2184                .map_err(Error::Client)?
2185                .into_result()?;
2186            Ok(())
2187        })
2188    }
2189
2190    /// Lists the clips created by the user logged in with this client.
2191    fn clips(&self) -> BoxFuture<Result<Vec<Clip>, Error<Self::Error>>> {
2192        Box::pin(async move {
2193            let clips = self
2194                .request(endpoint::clips::list::Request::default())
2195                .await
2196                .map_err(Error::Client)?
2197                .into_result()?;
2198            Ok(clips)
2199        })
2200    }
2201
2202    /// Lists the clips that contain the specified note.
2203    #[cfg(feature = "12-58-0")]
2204    #[cfg_attr(docsrs, doc(cfg(feature = "12-58-0")))]
2205    fn note_clips(
2206        &self,
2207        note: impl EntityRef<Note>,
2208    ) -> BoxFuture<Result<Vec<Clip>, Error<Self::Error>>> {
2209        let note_id = note.entity_ref();
2210        Box::pin(async move {
2211            let clips = self
2212                .request(endpoint::notes::clips::Request { note_id })
2213                .await
2214                .map_err(Error::Client)?
2215                .into_result()?;
2216            Ok(clips)
2217        })
2218    }
2219
2220    /// Clips the specified note.
2221    #[cfg(feature = "12-57-0")]
2222    #[cfg_attr(docsrs, doc(cfg(feature = "12-57-0")))]
2223    fn clip_note(
2224        &self,
2225        clip: impl EntityRef<Clip>,
2226        note: impl EntityRef<Note>,
2227    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
2228        let clip_id = clip.entity_ref();
2229        let note_id = note.entity_ref();
2230        Box::pin(async move {
2231            self.request(endpoint::clips::add_note::Request { clip_id, note_id })
2232                .await
2233                .map_err(Error::Client)?
2234                .into_result()?;
2235            Ok(())
2236        })
2237    }
2238
2239    /// Lists the notes that are clipped to the specified clip.
2240    fn clip_notes(&self, clip: impl EntityRef<Clip>) -> PagerStream<BoxPager<Self, Note>> {
2241        let pager = BackwardPager::new(
2242            self,
2243            endpoint::clips::notes::Request::builder()
2244                .clip_id(clip.entity_ref())
2245                .build(),
2246        );
2247        PagerStream::new(Box::pin(pager))
2248    }
2249
2250    /// Gets the corresponding clip from the ID.
2251    fn get_clip(&self, id: Id<Clip>) -> BoxFuture<Result<Clip, Error<Self::Error>>> {
2252        Box::pin(async move {
2253            let clip = self
2254                .request(endpoint::clips::show::Request { clip_id: id })
2255                .await
2256                .map_err(Error::Client)?
2257                .into_result()?;
2258            Ok(clip)
2259        })
2260    }
2261
2262    /// Updates the name of the specified clip to the given one.
2263    #[cfg(not(feature = "12-57-0"))]
2264    #[cfg_attr(docsrs, doc(cfg(not(feature = "12-57-0"))))]
2265    fn rename_clip(
2266        &self,
2267        clip: impl EntityRef<Clip>,
2268        name: impl Into<String>,
2269    ) -> BoxFuture<Result<Clip, Error<Self::Error>>> {
2270        let clip_id = clip.entity_ref();
2271        let name = name.into();
2272        Box::pin(async move {
2273            let clip = self
2274                .request(endpoint::clips::update::Request { clip_id, name })
2275                .await
2276                .map_err(Error::Client)?
2277                .into_result()?;
2278            Ok(clip)
2279        })
2280    }
2281
2282    /// Updates the specified clip.
2283    ///
2284    /// This method actually returns a builder, namely [`ClipUpdateBuilder`].
2285    /// You can chain the method calls to it corresponding to the fields you want to update.
2286    /// Finally, calling [`update`][builder_update] method will actually perform the update.
2287    /// See [`ClipUpdateBuilder`] for the fields that can be updated.
2288    ///
2289    /// [builder_update]: ClipUpdateBuilder::update
2290    ///
2291    /// # Examples
2292    ///
2293    /// ```
2294    /// # use misskey_util::ClientExt;
2295    /// # #[tokio::main]
2296    /// # async fn main() -> anyhow::Result<()> {
2297    /// # let client = misskey_test::test_client().await?;
2298    /// let clip = client.create_clip("kawaii notes").await?;
2299    /// // Update the description and publish it.
2300    /// client
2301    ///     .update_clip(clip)
2302    ///     .public(true)
2303    ///     .description("collection of kawaii notes")
2304    ///     .update()
2305    ///     .await?;
2306    /// # Ok(())
2307    /// # }
2308    /// ```
2309    #[cfg(feature = "12-57-0")]
2310    #[cfg_attr(docsrs, doc(cfg(feature = "12-57-0")))]
2311    fn update_clip(&self, clip: Clip) -> ClipUpdateBuilder<&Self> {
2312        ClipUpdateBuilder::new(self, clip)
2313    }
2314
2315    /// Lists the clips created by the specified user.
2316    #[cfg(feature = "12-61-0")]
2317    #[cfg_attr(docsrs, doc(cfg(feature = "12-61-0")))]
2318    fn user_clips(&self, user: impl EntityRef<User>) -> PagerStream<BoxPager<Self, Clip>> {
2319        let pager = BackwardPager::new(
2320            self,
2321            endpoint::users::clips::Request::builder()
2322                .user_id(user.entity_ref())
2323                .build(),
2324        );
2325        PagerStream::new(Box::pin(pager))
2326    }
2327    // }}}
2328
2329    // {{{ Messaging
2330    /// Sends a message to the user with the given text.
2331    fn create_message(
2332        &self,
2333        recipient: impl EntityRef<User>,
2334        text: impl Into<String>,
2335    ) -> BoxFuture<Result<MessagingMessage, Error<Self::Error>>> {
2336        let recipient = recipient.entity_ref();
2337        let text = text.into();
2338        Box::pin(async move {
2339            self.build_message()
2340                .user(recipient)
2341                .text(text)
2342                .create()
2343                .await
2344        })
2345    }
2346
2347    /// Sends a message to the user group with the given text.
2348    fn create_group_message(
2349        &self,
2350        recipient: impl EntityRef<UserGroup>,
2351        text: impl Into<String>,
2352    ) -> BoxFuture<Result<MessagingMessage, Error<Self::Error>>> {
2353        let recipient = recipient.entity_ref();
2354        let text = text.into();
2355        Box::pin(async move {
2356            self.build_message()
2357                .group(recipient)
2358                .text(text)
2359                .create()
2360                .await
2361        })
2362    }
2363
2364    /// Returns a builder for creating a message.
2365    ///
2366    /// The returned builder provides methods to customize details of the message and its recipients,
2367    /// and you can chain them to create a message incrementally.
2368    /// Finally, calling [`create`][builder_create] method will actually create and send a message.
2369    /// See [`MessagingMessageBuilder`] for the provided methods.
2370    ///
2371    /// [builder_create]: MessagingMessageBuilder::create
2372    fn build_message(&self) -> MessagingMessageBuilder<&Self> {
2373        MessagingMessageBuilder::new(self)
2374    }
2375
2376    /// Deletes the specified message.
2377    fn delete_message(
2378        &self,
2379        message: impl EntityRef<MessagingMessage>,
2380    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
2381        let message_id = message.entity_ref();
2382        Box::pin(async move {
2383            self.request(endpoint::messaging::messages::delete::Request { message_id })
2384                .await
2385                .map_err(Error::Client)?
2386                .into_result()?;
2387            Ok(())
2388        })
2389    }
2390
2391    /// Marks the specified message as read.
2392    fn read_message(
2393        &self,
2394        message: impl EntityRef<MessagingMessage>,
2395    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
2396        let message_id = message.entity_ref();
2397        Box::pin(async move {
2398            self.request(endpoint::messaging::messages::read::Request { message_id })
2399                .await
2400                .map_err(Error::Client)?
2401                .into_result()?;
2402            Ok(())
2403        })
2404    }
2405
2406    /// Lists the messages with the specified user.
2407    fn user_messages(
2408        &self,
2409        user: impl EntityRef<User>,
2410    ) -> PagerStream<BoxPager<Self, MessagingMessage>> {
2411        let pager = BackwardPager::new(
2412            self,
2413            endpoint::messaging::messages::Request::builder()
2414                .mark_as_read(false)
2415                .user_id(user.entity_ref())
2416                .build(),
2417        );
2418        PagerStream::new(Box::pin(pager))
2419    }
2420
2421    /// Lists the messages in the specified user group.
2422    fn group_messages(
2423        &self,
2424        group: impl EntityRef<UserGroup>,
2425    ) -> PagerStream<BoxPager<Self, MessagingMessage>> {
2426        let pager = BackwardPager::new(
2427            self,
2428            endpoint::messaging::messages::Request::builder()
2429                .mark_as_read(false)
2430                .group_id(group.entity_ref())
2431                .build(),
2432        );
2433        PagerStream::new(Box::pin(pager))
2434    }
2435
2436    /// Gets message logs for the user who is logged in with this client.
2437    fn messaging_history(&self) -> BoxFuture<Result<Vec<MessagingMessage>, Error<Self::Error>>> {
2438        Box::pin(async move {
2439            let mut messages = self
2440                .request(endpoint::messaging::history::Request {
2441                    group: Some(false),
2442                    limit: None,
2443                })
2444                .await
2445                .map_err(Error::Client)?
2446                .into_result()?;
2447            let group_messages = self
2448                .request(endpoint::messaging::history::Request {
2449                    group: Some(true),
2450                    limit: None,
2451                })
2452                .await
2453                .map_err(Error::Client)?
2454                .into_result()?;
2455            messages.extend(group_messages);
2456            Ok(messages)
2457        })
2458    }
2459    // }}}
2460
2461    // {{{ Drive
2462    /// Uploads the file from the given url to the drive.
2463    ///
2464    /// The difference between [`upload_file_from_url_`][alt] and this method is that the former
2465    /// can get the [`DriveFile`][drive_file] of the uploaded file, while the latter cannot.
2466    /// If you want to obtain the [`DriveFile`] of an uploaded file in v12.48.0 or later, you can
2467    /// use [`DriveFileUrlBuilder::upload_and_wait`] or download the file once on the client side
2468    /// and the use [`UploadFileClientExt::upload_file`] to upload it.
2469    ///
2470    /// [alt]: ClientExt::upload_file_from_url_
2471    /// [drive_file]: misskey_api::model::drive::DriveFile
2472    #[cfg(feature = "12-48-0")]
2473    #[cfg_attr(docsrs, doc(cfg(feature = "12-48-0")))]
2474    fn upload_file_from_url(&self, url: Url) -> BoxFuture<Result<(), Error<Self::Error>>> {
2475        Box::pin(async move { self.build_file_from_url(url).upload().await })
2476    }
2477
2478    /// Uploads the file from the given url to the drive.
2479    ///
2480    /// See [`upload_file_from_url`][alt] for the difference between them.
2481    ///
2482    /// [alt]: ClientExt::upload_file_from_url
2483    #[cfg(any(docsrs, not(feature = "12-48-0")))]
2484    #[cfg_attr(docsrs, doc(cfg(not(feature = "12-48-0"))))]
2485    fn upload_file_from_url_(&self, url: Url) -> BoxFuture<Result<DriveFile, Error<Self::Error>>> {
2486        Box::pin(async move { self.build_file_from_url(url).upload_().await })
2487    }
2488
2489    /// Returns a builder for creating a file on the drive.
2490    ///
2491    /// The returned builder provides methods to customize details of the file,
2492    /// and you can chain them to create a file incrementally.
2493    /// See [`DriveFileUrlBuilder`] for the provided methods.
2494    fn build_file_from_url(&self, url: Url) -> DriveFileUrlBuilder<&Self> {
2495        DriveFileUrlBuilder::with_url(self, url)
2496    }
2497
2498    /// Deletes the specified file on the drive.
2499    fn delete_file(
2500        &self,
2501        file: impl EntityRef<DriveFile>,
2502    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
2503        let file_id = file.entity_ref();
2504        Box::pin(async move {
2505            self.request(endpoint::drive::files::delete::Request { file_id })
2506                .await
2507                .map_err(Error::Client)?
2508                .into_result()?;
2509            Ok(())
2510        })
2511    }
2512
2513    /// Updates the specified file
2514    ///
2515    /// This method actually returns a builder, namely [`DriveFileUpdateBuilder`].
2516    /// You can chain the method calls to it corresponding to the fields you want to update.
2517    /// Finally, calling [`update`][builder_update] method will actually perform the update.
2518    /// See [`DriveFileUpdateBuilder`] for the fields that can be updated.
2519    ///
2520    /// [builder_update]: DriveFileUpdateBuilder::update
2521    fn update_file(&self, file: impl EntityRef<DriveFile>) -> DriveFileUpdateBuilder<&Self> {
2522        DriveFileUpdateBuilder::new(self, file)
2523    }
2524
2525    /// Gets the corresponding file from the ID.
2526    fn get_file(&self, id: Id<DriveFile>) -> BoxFuture<Result<DriveFile, Error<Self::Error>>> {
2527        Box::pin(async move {
2528            let file = self
2529                .request(endpoint::drive::files::show::Request {
2530                    file_id: Some(id),
2531                    url: None,
2532                })
2533                .await
2534                .map_err(Error::Client)?
2535                .into_result()?;
2536            Ok(file)
2537        })
2538    }
2539
2540    /// Creates a folder on the drive with the given name.
2541    ///
2542    /// # Examples
2543    ///
2544    /// ```
2545    /// # use misskey_util::ClientExt;
2546    /// # #[tokio::main]
2547    /// # async fn main() -> anyhow::Result<()> {
2548    /// # let client = misskey_test::test_client().await?;
2549    /// let folder = client.create_folder("Folder1").await?;
2550    /// assert_eq!(folder.name, "Folder1");
2551    /// # Ok(())
2552    /// # }
2553    /// ```
2554    fn create_folder(
2555        &self,
2556        name: impl Into<String>,
2557    ) -> BoxFuture<Result<DriveFolder, Error<Self::Error>>> {
2558        let name = name.into();
2559        Box::pin(async move {
2560            let folder = self
2561                .request(endpoint::drive::folders::create::Request {
2562                    name: Some(name),
2563                    parent_id: None,
2564                })
2565                .await
2566                .map_err(Error::Client)?
2567                .into_result()?;
2568            Ok(folder)
2569        })
2570    }
2571
2572    /// Creates a folder on the drive with the given name and parent folder.
2573    fn create_folder_with_parent(
2574        &self,
2575        name: impl Into<String>,
2576        parent: impl EntityRef<DriveFolder>,
2577    ) -> BoxFuture<Result<DriveFolder, Error<Self::Error>>> {
2578        let name = name.into();
2579        let parent_id = parent.entity_ref();
2580        Box::pin(async move {
2581            let folder = self
2582                .request(endpoint::drive::folders::create::Request {
2583                    name: Some(name),
2584                    parent_id: Some(parent_id),
2585                })
2586                .await
2587                .map_err(Error::Client)?
2588                .into_result()?;
2589            Ok(folder)
2590        })
2591    }
2592
2593    /// Deletes the specified folder on the drive.
2594    fn delete_folder(
2595        &self,
2596        folder: impl EntityRef<DriveFolder>,
2597    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
2598        let folder_id = folder.entity_ref();
2599        Box::pin(async move {
2600            self.request(endpoint::drive::folders::delete::Request { folder_id })
2601                .await
2602                .map_err(Error::Client)?
2603                .into_result()?;
2604            Ok(())
2605        })
2606    }
2607
2608    /// Updates the specified folder.
2609    ///
2610    /// This method actually returns a builder, namely [`DriveFolderUpdateBuilder`].
2611    /// You can chain the method calls to it corresponding to the fields you want to update.
2612    /// Finally, calling [`update`][builder_update] method will actually perform the update.
2613    /// See [`DriveFolderUpdateBuilder`] for the fields that can be updated.
2614    ///
2615    /// [builder_update]: DriveFolderUpdateBuilder::update
2616    ///
2617    /// # Examples
2618    ///
2619    /// ```
2620    /// # use misskey_util::ClientExt;
2621    /// # #[tokio::main]
2622    /// # async fn main() -> anyhow::Result<()> {
2623    /// # let client = misskey_test::test_client().await?;
2624    /// let folder = client.create_folder("Folder1").await?;
2625    /// client
2626    ///     .update_folder(&folder)
2627    ///     .name("Folder2")
2628    ///     .update()
2629    ///     .await?;
2630    /// # Ok(())
2631    /// # }
2632    /// ```
2633    fn update_folder(
2634        &self,
2635        folder: impl EntityRef<DriveFolder>,
2636    ) -> DriveFolderUpdateBuilder<&Self> {
2637        DriveFolderUpdateBuilder::new(self, folder)
2638    }
2639
2640    /// Gets the corresponding folder from the ID.
2641    fn get_folder(
2642        &self,
2643        id: Id<DriveFolder>,
2644    ) -> BoxFuture<Result<DriveFolder, Error<Self::Error>>> {
2645        Box::pin(async move {
2646            let folder = self
2647                .request(endpoint::drive::folders::show::Request { folder_id: id })
2648                .await
2649                .map_err(Error::Client)?
2650                .into_result()?;
2651            Ok(folder)
2652        })
2653    }
2654
2655    /// Lists the notes that have the specified file attached.
2656    fn attached_notes(
2657        &self,
2658        file: impl EntityRef<DriveFile>,
2659    ) -> BoxFuture<Result<Vec<Note>, Error<Self::Error>>> {
2660        let file_id = file.entity_ref();
2661        Box::pin(async move {
2662            let notes = self
2663                .request(endpoint::drive::files::attached_notes::Request { file_id })
2664                .await
2665                .map_err(Error::Client)?
2666                .into_result()?;
2667            Ok(notes)
2668        })
2669    }
2670
2671    /// Lists the files with the specified name.
2672    fn find_file_by_name(
2673        &self,
2674        name: impl Into<String>,
2675    ) -> BoxFuture<Result<Vec<DriveFile>, Error<Self::Error>>> {
2676        let name = name.into();
2677        Box::pin(async move {
2678            let files = self
2679                .request(endpoint::drive::files::find::Request {
2680                    name,
2681                    folder_id: None,
2682                })
2683                .await
2684                .map_err(Error::Client)?
2685                .into_result()?;
2686            Ok(files)
2687        })
2688    }
2689
2690    /// Lists the files with the specified name in the folder.
2691    fn find_file_by_name_in_folder(
2692        &self,
2693        name: impl Into<String>,
2694        folder: impl EntityRef<DriveFolder>,
2695    ) -> BoxFuture<Result<Vec<DriveFile>, Error<Self::Error>>> {
2696        let name = name.into();
2697        let folder_id = folder.entity_ref();
2698        Box::pin(async move {
2699            let files = self
2700                .request(endpoint::drive::files::find::Request {
2701                    name,
2702                    folder_id: Some(folder_id),
2703                })
2704                .await
2705                .map_err(Error::Client)?
2706                .into_result()?;
2707            Ok(files)
2708        })
2709    }
2710
2711    /// Lists the folders with the specified name.
2712    fn find_folder_by_name(
2713        &self,
2714        name: impl Into<String>,
2715    ) -> BoxFuture<Result<Vec<DriveFolder>, Error<Self::Error>>> {
2716        let name = name.into();
2717        Box::pin(async move {
2718            let files = self
2719                .request(endpoint::drive::folders::find::Request {
2720                    name,
2721                    parent_id: None,
2722                })
2723                .await
2724                .map_err(Error::Client)?
2725                .into_result()?;
2726            Ok(files)
2727        })
2728    }
2729
2730    /// Lists the folders with the specified name in the folder.
2731    fn find_folder_by_name_in_folder(
2732        &self,
2733        name: impl Into<String>,
2734        folder: impl EntityRef<DriveFolder>,
2735    ) -> BoxFuture<Result<Vec<DriveFolder>, Error<Self::Error>>> {
2736        let name = name.into();
2737        let folder_id = folder.entity_ref();
2738        Box::pin(async move {
2739            let files = self
2740                .request(endpoint::drive::folders::find::Request {
2741                    name,
2742                    parent_id: Some(folder_id),
2743                })
2744                .await
2745                .map_err(Error::Client)?
2746                .into_result()?;
2747            Ok(files)
2748        })
2749    }
2750
2751    /// Lists the files on the drive.
2752    ///
2753    /// This method actually returns a builder, namely [`DriveFileListBuilder`].
2754    /// You can specify how you want to list files by chaining methods.
2755    /// The [`list`][builder_list] method of the builder returns a [`Stream`][stream]
2756    /// that lists files in the specified way.
2757    ///
2758    /// [builder_list]: DriveFileListBuilder::list
2759    /// [stream]: futures::stream::Stream
2760    ///
2761    /// # Examples
2762    ///
2763    /// ```
2764    /// # use misskey_util::ClientExt;
2765    /// # #[tokio::main]
2766    /// # async fn main() -> anyhow::Result<()> {
2767    /// # let client = misskey_test::test_client().await?;
2768    /// # use misskey_api as misskey;
2769    /// use futures::stream::TryStreamExt;
2770    /// use mime::IMAGE_STAR;
2771    /// use misskey::model::drive::DriveFile;
2772    ///
2773    /// // Get a list of image files
2774    /// let images: Vec<DriveFile> = client
2775    ///     .files()
2776    ///     .type_(IMAGE_STAR)
2777    ///     .list()
2778    ///     .try_collect()
2779    ///     .await?;
2780    /// # Ok(())
2781    /// # }
2782    /// ```
2783    fn files(&self) -> DriveFileListBuilder<&Self> {
2784        DriveFileListBuilder::new(self)
2785    }
2786
2787    /// Lists the folders.
2788    fn folders(&self) -> PagerStream<BoxPager<Self, DriveFolder>> {
2789        let pager = BackwardPager::new(self, endpoint::drive::folders::Request::default());
2790        PagerStream::new(Box::pin(pager))
2791    }
2792
2793    /// Lists the folders in the folder.
2794    fn folders_in_folder(
2795        &self,
2796        folder: impl EntityRef<DriveFolder>,
2797    ) -> PagerStream<BoxPager<Self, DriveFolder>> {
2798        let pager = BackwardPager::new(
2799            self,
2800            endpoint::drive::folders::Request {
2801                folder_id: Some(folder.entity_ref()),
2802                ..Default::default()
2803            },
2804        );
2805        PagerStream::new(Box::pin(pager))
2806    }
2807    // }}}
2808
2809    // {{{ Admin
2810    /// Sets moderator privileges for the specified user.
2811    ///
2812    /// This operation may require this client to be logged in with an admin account.
2813    fn add_moderator(
2814        &self,
2815        user: impl EntityRef<User>,
2816    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
2817        let user_id = user.entity_ref();
2818        Box::pin(async move {
2819            self.request(endpoint::admin::moderators::add::Request { user_id })
2820                .await
2821                .map_err(Error::Client)?
2822                .into_result()?;
2823            Ok(())
2824        })
2825    }
2826
2827    /// Removes moderator privileges for the specified user.
2828    ///
2829    /// This operation may require this client to be logged in with an admin account.
2830    fn remove_moderator(
2831        &self,
2832        user: impl EntityRef<User>,
2833    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
2834        let user_id = user.entity_ref();
2835        Box::pin(async move {
2836            self.request(endpoint::admin::moderators::remove::Request { user_id })
2837                .await
2838                .map_err(Error::Client)?
2839                .into_result()?;
2840            Ok(())
2841        })
2842    }
2843
2844    /// Promotes the specified note until the time.
2845    ///
2846    /// This operation may require moderator privileges.
2847    #[cfg(feature = "12-13-0")]
2848    #[cfg_attr(docsrs, doc(cfg(feature = "12-13-0")))]
2849    fn promote_note(
2850        &self,
2851        note: impl EntityRef<Note>,
2852        expires_at: DateTime<Utc>,
2853    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
2854        let note_id = note.entity_ref();
2855        Box::pin(async move {
2856            self.request(endpoint::admin::promo::create::Request {
2857                note_id,
2858                expires_at,
2859            })
2860            .await
2861            .map_err(Error::Client)?
2862            .into_result()?;
2863            Ok(())
2864        })
2865    }
2866
2867    /// Lists the abuse user reports.
2868    ///
2869    /// This operation may require moderator privileges.
2870    fn abuse_user_reports(&self) -> PagerStream<BoxPager<Self, AbuseUserReport>> {
2871        let pager = BackwardPager::new(
2872            self,
2873            endpoint::admin::abuse_user_reports::Request::default(),
2874        );
2875        PagerStream::new(Box::pin(pager))
2876    }
2877
2878    /// Removes the specified abuse user report.
2879    ///
2880    /// This operation may require moderator privileges.
2881    #[cfg(any(docsrs, not(feature = "12-49-0")))]
2882    #[cfg_attr(docsrs, doc(cfg(not(feature = "12-49-0"))))]
2883    fn remove_abuse_user_report(
2884        &self,
2885        report: impl EntityRef<AbuseUserReport>,
2886    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
2887        let report_id = report.entity_ref();
2888        Box::pin(async move {
2889            self.request(endpoint::admin::remove_abuse_user_report::Request { report_id })
2890                .await
2891                .map_err(Error::Client)?
2892                .into_result()?;
2893            Ok(())
2894        })
2895    }
2896
2897    /// Marks the specified abuse user report as resolved.
2898    ///
2899    /// This operation may require moderator privileges.
2900    #[cfg(feature = "12-49-0")]
2901    #[cfg_attr(docsrs, doc(cfg(feature = "12-49-0")))]
2902    fn resolve_abuse_user_report(
2903        &self,
2904        report: impl EntityRef<AbuseUserReport>,
2905    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
2906        let report_id = report.entity_ref();
2907        Box::pin(async move {
2908            self.request(endpoint::admin::resolve_abuse_user_report::Request { report_id })
2909                .await
2910                .map_err(Error::Client)?
2911                .into_result()?;
2912            Ok(())
2913        })
2914    }
2915
2916    /// Lists the server logs in the instance.
2917    ///
2918    /// This method actually returns a builder, namely [`ServerLogListBuilder`].
2919    /// You can specify how you want to list users by chaining methods.
2920    /// The [`list`][builder_list] method of the builder fetches the actual logs.
2921    ///
2922    /// This operation may require moderator privileges.
2923    ///
2924    /// [builder_list]: ServerLogListBuilder::list
2925    ///
2926    /// # Examples
2927    ///
2928    /// ```
2929    /// # use misskey_util::ClientExt;
2930    /// # #[tokio::main]
2931    /// # async fn main() -> anyhow::Result<()> {
2932    /// # let client = misskey_test::test_client().await?;
2933    /// # use misskey_api as misskey;
2934    /// // Get a first 10 entries of 'info' logs with 'chart' domain
2935    /// let logs = client
2936    ///     .server_logs()
2937    ///     .take(10)
2938    ///     .info()
2939    ///     .with_domain("chart")
2940    ///     .list()
2941    ///     .await?;
2942    /// # Ok(())
2943    /// # }
2944    /// ```
2945    fn server_logs(&self) -> ServerLogListBuilder<&Self> {
2946        ServerLogListBuilder::new(self)
2947    }
2948
2949    /// Lists the moderation logs in the instance.
2950    ///
2951    /// This operation may require moderator privileges.
2952    fn moderation_logs(&self) -> PagerStream<BoxPager<Self, ModerationLog>> {
2953        let pager = BackwardPager::new(
2954            self,
2955            endpoint::admin::show_moderation_logs::Request::default(),
2956        );
2957        PagerStream::new(Box::pin(pager))
2958    }
2959
2960    /// Silences the specified user.
2961    ///
2962    /// This operation may require moderator privileges.
2963    fn silence(&self, user: impl EntityRef<User>) -> BoxFuture<Result<(), Error<Self::Error>>> {
2964        let user_id = user.entity_ref();
2965        Box::pin(async move {
2966            self.request(endpoint::admin::silence_user::Request { user_id })
2967                .await
2968                .map_err(Error::Client)?
2969                .into_result()?;
2970            Ok(())
2971        })
2972    }
2973
2974    /// Suspends the specified user.
2975    ///
2976    /// This operation may require moderator privileges.
2977    fn suspend(&self, user: impl EntityRef<User>) -> BoxFuture<Result<(), Error<Self::Error>>> {
2978        let user_id = user.entity_ref();
2979        Box::pin(async move {
2980            self.request(endpoint::admin::suspend_user::Request { user_id })
2981                .await
2982                .map_err(Error::Client)?
2983                .into_result()?;
2984            Ok(())
2985        })
2986    }
2987
2988    /// Unsilences the specified user.
2989    ///
2990    /// This operation may require moderator privileges.
2991    fn unsilence(&self, user: impl EntityRef<User>) -> BoxFuture<Result<(), Error<Self::Error>>> {
2992        let user_id = user.entity_ref();
2993        Box::pin(async move {
2994            self.request(endpoint::admin::unsilence_user::Request { user_id })
2995                .await
2996                .map_err(Error::Client)?
2997                .into_result()?;
2998            Ok(())
2999        })
3000    }
3001
3002    /// Unsuspends the specified user.
3003    ///
3004    /// This operation may require moderator privileges.
3005    fn unsuspend(&self, user: impl EntityRef<User>) -> BoxFuture<Result<(), Error<Self::Error>>> {
3006        let user_id = user.entity_ref();
3007        Box::pin(async move {
3008            self.request(endpoint::admin::unsuspend_user::Request { user_id })
3009                .await
3010                .map_err(Error::Client)?
3011                .into_result()?;
3012            Ok(())
3013        })
3014    }
3015
3016    /// Updates the instance information.
3017    ///
3018    /// This method actually returns a builder, namely [`MetaUpdateBuilder`].
3019    /// You can chain the method calls to it corresponding to the fields you want to update.
3020    /// Finally, calling [`update`][builder_update] method will actually perform the update.
3021    /// See [`MetaUpdateBuilder`] for the fields that can be updated.
3022    ///
3023    /// This operation may require this client to be logged in with an admin account.
3024    ///
3025    /// [builder_update]: MetaUpdateBuilder::update
3026    ///
3027    /// # Examples
3028    ///
3029    /// ```
3030    /// # use misskey_util::ClientExt;
3031    /// # #[tokio::main]
3032    /// # async fn main() -> anyhow::Result<()> {
3033    /// # let client = misskey_test::test_admin_client().await?;
3034    /// client
3035    ///     .update_meta()
3036    ///     .set_name("The Instance of Saturn")
3037    ///     .max_note_text_length(5000)
3038    ///     .update()
3039    ///     .await?;
3040    /// # Ok(())
3041    /// # }
3042    /// ```
3043    fn update_meta(&self) -> MetaUpdateBuilder<&Self> {
3044        MetaUpdateBuilder::new(self)
3045    }
3046
3047    /// Creates an announcement with given title and text.
3048    ///
3049    /// This operation may require moderator privileges.
3050    fn create_announcement(
3051        &self,
3052        title: impl Into<String>,
3053        text: impl Into<String>,
3054    ) -> BoxFuture<Result<Announcement, Error<Self::Error>>> {
3055        let title = title.into();
3056        let text = text.into();
3057        Box::pin(async move {
3058            let announcement = self
3059                .request(endpoint::admin::announcements::create::Request {
3060                    title,
3061                    text,
3062                    image_url: None,
3063                })
3064                .await
3065                .map_err(Error::Client)?
3066                .into_result()?;
3067            Ok(announcement)
3068        })
3069    }
3070
3071    /// Creates an announcement with given title, text, and image URL.
3072    ///
3073    /// This operation may require moderator privileges.
3074    fn create_announcement_with_image(
3075        &self,
3076        title: impl Into<String>,
3077        text: impl Into<String>,
3078        image_url: Url,
3079    ) -> BoxFuture<Result<Announcement, Error<Self::Error>>> {
3080        let title = title.into();
3081        let text = text.into();
3082        Box::pin(async move {
3083            let announcement = self
3084                .request(endpoint::admin::announcements::create::Request {
3085                    title,
3086                    text,
3087                    image_url: Some(image_url),
3088                })
3089                .await
3090                .map_err(Error::Client)?
3091                .into_result()?;
3092            Ok(announcement)
3093        })
3094    }
3095
3096    /// Deletes the specified announcement.
3097    ///
3098    /// This operation may require moderator privileges.
3099    fn delete_announcement(
3100        &self,
3101        announcement: impl EntityRef<Announcement>,
3102    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
3103        let announcement_id = announcement.entity_ref();
3104        Box::pin(async move {
3105            self.request(endpoint::admin::announcements::delete::Request {
3106                id: announcement_id,
3107            })
3108            .await
3109            .map_err(Error::Client)?
3110            .into_result()?;
3111            Ok(())
3112        })
3113    }
3114
3115    /// Updates the specified announcement.
3116    ///
3117    /// This method actually returns a builder, namely [`AnnouncementUpdateBuilder`].
3118    /// You can chain the method calls to it corresponding to the fields you want to update.
3119    /// Finally, calling [`update`][builder_update] method will actually perform the update.
3120    /// See [`AnnouncementUpdateBuilder`] for the fields that can be updated.
3121    ///
3122    /// This operation may require moderator privileges.
3123    ///
3124    /// [builder_update]: AnnouncementUpdateBuilder::update
3125    fn update_announcement(&self, announcement: Announcement) -> AnnouncementUpdateBuilder<&Self> {
3126        AnnouncementUpdateBuilder::new(self, announcement)
3127    }
3128
3129    /// Creates a custom emoji from the given file.
3130    ///
3131    /// This operation may require moderator privileges.
3132    #[cfg(feature = "12-9-0")]
3133    #[cfg_attr(docsrs, doc(cfg(feature = "12-9-0")))]
3134    fn create_emoji(
3135        &self,
3136        file: impl EntityRef<DriveFile>,
3137    ) -> BoxFuture<Result<Id<Emoji>, Error<Self::Error>>> {
3138        let file_id = file.entity_ref();
3139        Box::pin(async move {
3140            let id = self
3141                .request(endpoint::admin::emoji::add::Request { file_id })
3142                .await
3143                .map_err(Error::Client)?
3144                .into_result()?
3145                .id;
3146            Ok(id)
3147        })
3148    }
3149
3150    /// Deletes the specified emoji.
3151    ///
3152    /// This operation may require moderator privileges.
3153    fn delete_emoji(
3154        &self,
3155        emoji: impl EntityRef<Emoji>,
3156    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
3157        let emoji_id = emoji.entity_ref();
3158        Box::pin(async move {
3159            self.request(endpoint::admin::emoji::remove::Request { id: emoji_id })
3160                .await
3161                .map_err(Error::Client)?
3162                .into_result()?;
3163            Ok(())
3164        })
3165    }
3166
3167    /// Updates the specified emoji.
3168    ///
3169    /// This method actually returns a builder, namely [`EmojiUpdateBuilder`].
3170    /// You can chain the method calls to it corresponding to the fields you want to update.
3171    /// Finally, calling [`update`][builder_update] method will actually perform the update.
3172    /// See [`EmojiUpdateBuilder`] for the fields that can be updated.
3173    ///
3174    /// This operation may require moderator privileges.
3175    ///
3176    /// [builder_update]: EmojiUpdateBuilder::update
3177    #[cfg(feature = "12-9-0")]
3178    #[cfg_attr(docsrs, doc(cfg(feature = "12-9-0")))]
3179    fn update_emoji(&self, emoji: Emoji) -> EmojiUpdateBuilder<&Self> {
3180        EmojiUpdateBuilder::new(self, emoji)
3181    }
3182
3183    /// Copies the specified emoji.
3184    ///
3185    /// This operation may require moderator privileges.
3186    fn copy_emoji(
3187        &self,
3188        emoji: impl EntityRef<Emoji>,
3189    ) -> BoxFuture<Result<Id<Emoji>, Error<Self::Error>>> {
3190        let emoji_id = emoji.entity_ref();
3191        Box::pin(async move {
3192            let id = self
3193                .request(endpoint::admin::emoji::copy::Request { emoji_id })
3194                .await
3195                .map_err(Error::Client)?
3196                .into_result()?
3197                .id;
3198            Ok(id)
3199        })
3200    }
3201
3202    /// Lists the emojis in the instance.
3203    ///
3204    /// This operation may require moderator privileges.
3205    /// Use [`meta`][`ClientExt::meta`] method if you want to get a list of custom emojis from normal users,
3206    fn emojis(&self) -> PagerStream<BoxPager<Self, Emoji>> {
3207        let pager = BackwardPager::new(self, endpoint::admin::emoji::list::Request::default());
3208        PagerStream::new(Box::pin(pager))
3209    }
3210
3211    /// Searches the emojis using the given query string.
3212    ///
3213    /// This operation may require moderator privileges.
3214    #[cfg(feature = "12-48-0")]
3215    fn search_emojis(&self, query: impl Into<String>) -> PagerStream<BoxPager<Self, Emoji>> {
3216        let pager = BackwardPager::new(
3217            self,
3218            endpoint::admin::emoji::list::Request {
3219                query: Some(query.into()),
3220                ..Default::default()
3221            },
3222        );
3223        PagerStream::new(Box::pin(pager))
3224    }
3225    // }}}
3226
3227    // {{{ Miscellaneous
3228    /// Gets information about the instance.
3229    fn meta(&self) -> BoxFuture<Result<Meta, Error<Self::Error>>> {
3230        Box::pin(async move {
3231            let meta = self
3232                .request(endpoint::meta::Request::default())
3233                .await
3234                .map_err(Error::Client)?
3235                .into_result()?;
3236            Ok(meta)
3237        })
3238    }
3239
3240    /// Lists announcements of the instance.
3241    fn announcements(&self) -> PagerStream<BoxPager<Self, Announcement>> {
3242        let pager = BackwardPager::new(self, endpoint::announcements::Request::default())
3243            .map_ok(|v| v.into_iter().map(|f| f.announcement).collect());
3244        PagerStream::new(Box::pin(pager))
3245    }
3246
3247    /// Lists the featured pages.
3248    #[cfg(feature = "12-58-0")]
3249    #[cfg_attr(docsrs, doc(cfg(feature = "12-58-0")))]
3250    fn featured_pages(&self) -> BoxFuture<Result<Vec<Page>, Error<Self::Error>>> {
3251        Box::pin(async move {
3252            let pages = self
3253                .request(endpoint::pages::featured::Request::default())
3254                .await
3255                .map_err(Error::Client)?
3256                .into_result()?;
3257            Ok(pages)
3258        })
3259    }
3260
3261    /// Lists the pages created by the specified user.
3262    #[cfg(feature = "12-61-0")]
3263    #[cfg_attr(docsrs, doc(cfg(feature = "12-61-0")))]
3264    fn user_pages(&self, user: impl EntityRef<User>) -> PagerStream<BoxPager<Self, Page>> {
3265        let pager = BackwardPager::new(
3266            self,
3267            endpoint::users::pages::Request::builder()
3268                .user_id(user.entity_ref())
3269                .build(),
3270        );
3271        PagerStream::new(Box::pin(pager))
3272    }
3273
3274    /// Marks all notifications as read.
3275    fn mark_all_notifications_as_read(&self) -> BoxFuture<Result<(), Error<Self::Error>>> {
3276        Box::pin(async move {
3277            self.request(endpoint::notifications::mark_all_as_read::Request::default())
3278                .await
3279                .map_err(Error::Client)?
3280                .into_result()?;
3281            Ok(())
3282        })
3283    }
3284
3285    /// Creates a notification with the given text.
3286    #[cfg(feature = "12-27-0")]
3287    #[cfg_attr(docsrs, doc(cfg(feature = "12-27-0")))]
3288    fn create_notification(
3289        &self,
3290        body: impl Into<String>,
3291    ) -> BoxFuture<Result<(), Error<Self::Error>>> {
3292        let body = body.into();
3293        Box::pin(async move { self.build_notification().body(body).create().await })
3294    }
3295
3296    /// Returns a builder for creating a notification.
3297    ///
3298    /// The returned builder provides methods to customize details of the notification,
3299    /// and you can chain them to create a notification incrementally.
3300    /// Finally, calling [`create`][builder_create] method will actually create a notification.
3301    /// See [`NotificationBuilder`] for the provided methods.
3302    ///
3303    /// [builder_create]: NotificationBuilder::create
3304    #[cfg(feature = "12-27-0")]
3305    #[cfg_attr(docsrs, doc(cfg(feature = "12-27-0")))]
3306    fn build_notification(&self) -> NotificationBuilder<&Self> {
3307        NotificationBuilder::new(self)
3308    }
3309    // }}}
3310}
3311
3312impl<C: Client + Sync> ClientExt for C {}
3313
3314/// An extension trait for [`UploadFileClient`][client] that provides convenient high-level APIs.
3315///
3316/// [client]: misskey_core::UploadFileClient
3317pub trait UploadFileClientExt: UploadFileClient + Sync {
3318    /// Uploads the file from the specified local path.
3319    fn upload_file(
3320        &self,
3321        path: impl AsRef<Path>,
3322    ) -> BoxFuture<Result<DriveFile, Error<Self::Error>>> {
3323        let path = path.as_ref().to_owned();
3324        Box::pin(async move { self.build_file(path).upload().await })
3325    }
3326
3327    /// Returns a builder for creating a file on the drive.
3328    ///
3329    /// The returned builder provides methods to customize details of the file,
3330    /// and you can chain them to create a file incrementally.
3331    /// See [`DriveFileBuilder`] for the provided methods.
3332    fn build_file(&self, path: impl AsRef<Path>) -> DriveFileBuilder<&Self> {
3333        DriveFileBuilder::with_path(self, path)
3334    }
3335}
3336
3337impl<C: UploadFileClient + Sync> UploadFileClientExt for C {}