diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2096913f..66215880 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,9 +15,9 @@ jobs: - id: setup_env run: ./ci/testenv/setup.sh env: - MISSKEY_IMAGE: 'misskey/misskey:12.75.1' + MISSKEY_IMAGE: 'misskey/misskey:12.89.1' MISSKEY_ID: aid - - run: cargo test --features 12-75-0 + - run: cargo test --features 12-89-1 timeout-minutes: 15 env: TEST_API_URL: http://localhost:3000/api/ diff --git a/.github/workflows/flaky.yml b/.github/workflows/flaky.yml index cc51a576..9cd59902 100644 --- a/.github/workflows/flaky.yml +++ b/.github/workflows/flaky.yml @@ -12,6 +12,26 @@ jobs: strategy: matrix: include: + - image: 'misskey/misskey:12.89.1' + flags: --features 12-89-1 + - image: 'misskey/misskey:12.89.0' + flags: --features 12-89-0 + - image: 'misskey/misskey:12.88.0' + flags: --features 12-88-0 + - image: 'misskey/misskey:12.82.0' + flags: --features 12-82-0 + - image: 'misskey/misskey:12.81.0' + flags: --features 12-81-0 + - image: 'misskey/misskey:12.80.0' + flags: --features 12-80-0 + - image: 'misskey/misskey:12.79.2' + flags: --features 12-79-2 + - image: 'misskey/misskey:12.79.0' + flags: --features 12-79-0 + - image: 'misskey/misskey:12.77.1' + flags: --features 12-77-1 + - image: 'misskey/misskey:12.77.0' + flags: --features 12-77-0 - image: 'misskey/misskey:12.75.0' flags: --features 12-75-0 - image: 'misskey/misskey:12.71.0' diff --git a/.github/workflows/unstable.yml b/.github/workflows/unstable.yml index 7c14bf85..f6dda953 100644 --- a/.github/workflows/unstable.yml +++ b/.github/workflows/unstable.yml @@ -28,9 +28,9 @@ jobs: - id: setup_env run: ./ci/testenv/setup.sh env: - MISSKEY_IMAGE: 'misskey/misskey:12.75.1' + MISSKEY_IMAGE: 'misskey/misskey:12.89.1' MISSKEY_ID: aid - - run: cargo test --features 12-75-0 + - run: cargo test --features 12-89-1 timeout-minutes: 15 env: TEST_API_URL: http://localhost:3000/api/ diff --git a/misskey-api/CHANGELOG.md b/misskey-api/CHANGELOG.md index ec9d11c3..7f086a72 100644 --- a/misskey-api/CHANGELOG.md +++ b/misskey-api/CHANGELOG.md @@ -21,12 +21,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support for Misskey v12.69.0 - Support for Misskey v12.70.0 - Support for Misskey v12.71.0 ~ v12.74.1 -- Support for Misskey v12.75.0 ~ v12.75.1 +- Support for Misskey v12.75.0 ~ v12.76.1 - `muted_notification_types` user setting which is available since v12.48.0 - Page related endpoints - endpoint `pages/*` - endpoint `i/pages` - endpoint `i/page_likes` +- Support for Misskey v12.77.0 +- Support for Misskey v12.77.1 ~ v12.78.0 + - endpoint `notifications/read` +- Support for Misskey v12.79.0 ~ v12.79.1 + - endpoint `gallery/*` + - endpoint `i/gallery/*` + - endpoint `users/gallery/posts` +- Support for Misskey v12.79.2 ~ v12.79.3 + - endpoint `gallery/posts/delete` + - endpoint `gallery/posts/update` +- Partial support for Misskey v12.80.0 ~ v12.80.3 + - endpoint `admin/ad/*` +- Support for Misskey v12.81.0 ~ 12.81.2 + - endpoint `admin/get-index-stats` +- Support for Misskey v12.82.0 ~ v12.87.0 +- Partial support for Misskey v12.88.0 +- Support for Misskey v12.89.0 +- Support for Misskey v12.89.1 ~ v12.90.1 ### Changed ### Deprecated @@ -35,6 +53,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `ClientSettingUpdated` variant from `MainStreamEvent` - For Misskey v12.67.0 ~ v12.68.0 - Latest version flag from being enabled as default +- endpoint `users` + - For Misskey v12.88.0 +- endpoint `users/recommendation` + - For Misskey v12.88.0 ~ ### Fixed diff --git a/misskey-api/Cargo.toml b/misskey-api/Cargo.toml index 8d5a0343..61193af4 100644 --- a/misskey-api/Cargo.toml +++ b/misskey-api/Cargo.toml @@ -15,6 +15,16 @@ categories = ["api-bindings"] [features] default = ["aid"] +12-89-1 = ["12-89-0"] +12-89-0 = ["12-88-0"] +12-88-0 = ["12-82-0"] +12-82-0 = ["12-81-0"] +12-81-0 = ["12-80-0"] +12-80-0 = ["12-79-2"] +12-79-2 = ["12-79-0"] +12-79-0 = ["12-77-1"] +12-77-1 = ["12-77-0"] +12-77-0 = ["12-75-0"] 12-75-0 = ["12-71-0"] 12-71-0 = ["12-70-0"] 12-70-0 = ["12-69-0"] diff --git a/misskey-api/src/endpoint.rs b/misskey-api/src/endpoint.rs index 0478a47d..8cdb928d 100644 --- a/misskey-api/src/endpoint.rs +++ b/misskey-api/src/endpoint.rs @@ -78,3 +78,7 @@ pub mod server_info; #[cfg(feature = "12-67-0")] #[cfg_attr(docsrs, doc(cfg(feature = "12-67-0")))] pub mod ping; + +#[cfg(feature = "12-79-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] +pub mod gallery; diff --git a/misskey-api/src/endpoint/admin.rs b/misskey-api/src/endpoint/admin.rs index 9cf376c5..bf5fd769 100644 --- a/misskey-api/src/endpoint/admin.rs +++ b/misskey-api/src/endpoint/admin.rs @@ -31,3 +31,11 @@ pub mod remove_abuse_user_report; #[cfg(feature = "12-49-0")] #[cfg_attr(docsrs, doc(cfg(feature = "12-49-0")))] pub mod resolve_abuse_user_report; + +#[cfg(feature = "12-80-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] +pub mod ad; + +#[cfg(feature = "12-81-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-81-0")))] +pub mod get_index_stats; diff --git a/misskey-api/src/endpoint/admin/ad.rs b/misskey-api/src/endpoint/admin/ad.rs new file mode 100644 index 00000000..ffd48daf --- /dev/null +++ b/misskey-api/src/endpoint/admin/ad.rs @@ -0,0 +1,4 @@ +pub mod create; +pub mod delete; +pub mod list; +pub mod update; diff --git a/misskey-api/src/endpoint/admin/ad/create.rs b/misskey-api/src/endpoint/admin/ad/create.rs new file mode 100644 index 00000000..3831dcda --- /dev/null +++ b/misskey-api/src/endpoint/admin/ad/create.rs @@ -0,0 +1,64 @@ +use chrono::{serde::ts_milliseconds, DateTime, Utc}; +use serde::Serialize; +use typed_builder::TypedBuilder; + +use crate::model::ad::{Place, Priority}; + +#[derive(Serialize, Debug, Clone, TypedBuilder)] +#[serde(rename_all = "camelCase")] +#[builder(doc)] +pub struct Request { + /// [ 1 .. ] characters + #[builder(setter(into))] + pub url: String, + #[builder(default, setter(into))] + pub memo: String, + #[builder(default)] + pub place: Place, + #[builder(default)] + pub priority: Priority, + #[cfg(feature = "12-81-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-81-0")))] + #[builder(default, setter(into))] + pub ratio: u64, + #[serde(with = "ts_milliseconds")] + #[builder(setter(into))] + pub expires_at: DateTime, + /// [ 1 .. ] characters + #[builder(setter(into))] + pub image_url: String, +} + +impl misskey_core::Request for Request { + type Response = (); + const ENDPOINT: &'static str = "admin/ad/create"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::{ + model::ad::{Place, Priority}, + test::{ClientExt, TestClient}, + }; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + let url = client.avatar_url().await; + + client + .admin + .test(Request { + url: url.to_string(), + memo: "memo".to_string(), + place: Place::Square, + priority: Priority::Middle, + #[cfg(feature = "12-81-0")] + ratio: 1, + image_url: url.to_string(), + expires_at: chrono::Utc::now() + chrono::Duration::hours(1), + }) + .await; + } +} diff --git a/misskey-api/src/endpoint/admin/ad/delete.rs b/misskey-api/src/endpoint/admin/ad/delete.rs new file mode 100644 index 00000000..11fb315b --- /dev/null +++ b/misskey-api/src/endpoint/admin/ad/delete.rs @@ -0,0 +1,44 @@ +use crate::model::{ad::Ad, id::Id}; + +use serde::Serialize; + +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Request { + pub id: Id, +} + +impl misskey_core::Request for Request { + type Response = (); + const ENDPOINT: &'static str = "admin/ad/delete"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + let url = client.avatar_url().await; + + client + .admin + .test( + crate::endpoint::admin::ad::create::Request::builder() + .url(url.clone()) + .image_url(url.clone()) + .expires_at(chrono::Utc::now() + chrono::Duration::hours(1)) + .build(), + ) + .await; + + let ads = client + .admin + .test(crate::endpoint::admin::ad::list::Request::default()) + .await; + + client.admin.test(Request { id: ads[0].id }).await; + } +} diff --git a/misskey-api/src/endpoint/admin/ad/list.rs b/misskey-api/src/endpoint/admin/ad/list.rs new file mode 100644 index 00000000..0b3f79bc --- /dev/null +++ b/misskey-api/src/endpoint/admin/ad/list.rs @@ -0,0 +1,80 @@ +use crate::model::{ad::Ad, id::Id}; + +use serde::Serialize; +use typed_builder::TypedBuilder; + +#[derive(Serialize, Default, Debug, Clone, TypedBuilder)] +#[serde(rename_all = "camelCase")] +#[builder(doc)] +pub struct Request { + /// 1 .. 100 + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub since_id: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub until_id: Option>, +} + +impl misskey_core::Request for Request { + type Response = Vec; + const ENDPOINT: &'static str = "admin/ad/list"; +} + +impl_pagination!(Request, Ad); + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + client.admin.test(Request::default()).await; + } + + #[tokio::test] + async fn request_with_limit() { + let client = TestClient::new(); + + client + .admin + .test(Request { + limit: Some(100), + since_id: None, + until_id: None, + }) + .await; + } + + #[tokio::test] + async fn request_paginate() { + let client = TestClient::new(); + let url = client.avatar_url().await; + client + .admin + .test( + crate::endpoint::admin::ad::create::Request::builder() + .url(url.clone()) + .image_url(url.clone()) + .expires_at(chrono::Utc::now() + chrono::Duration::hours(1)) + .build(), + ) + .await; + + let ads = client.admin.test(Request::default()).await; + + client + .admin + .test(Request { + limit: None, + since_id: Some(ads[0].id.clone()), + until_id: Some(ads[0].id.clone()), + }) + .await; + } +} diff --git a/misskey-api/src/endpoint/admin/ad/update.rs b/misskey-api/src/endpoint/admin/ad/update.rs new file mode 100644 index 00000000..667b2bdb --- /dev/null +++ b/misskey-api/src/endpoint/admin/ad/update.rs @@ -0,0 +1,85 @@ +use chrono::{serde::ts_milliseconds, DateTime, Utc}; +use serde::Serialize; +use typed_builder::TypedBuilder; + +use crate::model::{ + ad::{Ad, Place, Priority}, + id::Id, +}; + +#[derive(Serialize, Debug, Clone, TypedBuilder)] +#[serde(rename_all = "camelCase")] +#[builder(doc)] +pub struct Request { + pub id: Id, + #[builder(default, setter(into))] + pub memo: String, + /// [ 1 .. ] characters + #[builder(setter(into))] + pub url: String, + /// [ 1 .. ] characters + #[builder(setter(into))] + pub image_url: String, + #[builder(default)] + pub place: Place, + #[builder(default)] + pub priority: Priority, + #[cfg(feature = "12-81-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-81-0")))] + #[builder(default, setter(into))] + pub ratio: u64, + #[serde(with = "ts_milliseconds")] + #[builder(setter(into))] + pub expires_at: DateTime, +} + +impl misskey_core::Request for Request { + type Response = (); + const ENDPOINT: &'static str = "admin/ad/update"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::{ + model::ad::{Place, Priority}, + test::{ClientExt, TestClient}, + }; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + let url = client.avatar_url().await; + + client + .admin + .test( + crate::endpoint::admin::ad::create::Request::builder() + .url(url.clone()) + .image_url(url.clone()) + .expires_at(chrono::Utc::now() + chrono::Duration::hours(1)) + .build(), + ) + .await; + + let ads = client + .admin + .test(crate::endpoint::admin::ad::list::Request::default()) + .await; + + client + .admin + .test(Request { + id: ads[0].id, + url: url.to_string(), + memo: "memo".to_string(), + place: Place::Horizontal, + priority: Priority::High, + #[cfg(feature = "12-81-0")] + ratio: 2, + image_url: url.to_string(), + expires_at: chrono::Utc::now() + chrono::Duration::hours(2), + }) + .await; + } +} diff --git a/misskey-api/src/endpoint/admin/get_index_stats.rs b/misskey-api/src/endpoint/admin/get_index_stats.rs new file mode 100644 index 00000000..c638c6fb --- /dev/null +++ b/misskey-api/src/endpoint/admin/get_index_stats.rs @@ -0,0 +1,29 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Default, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Request {} + +#[derive(Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Stat { + pub tablename: String, + pub indexname: String, +} + +impl misskey_core::Request for Request { + type Response = Vec; + const ENDPOINT: &'static str = "admin/get-index-stats"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + client.admin.test(Request::default()).await; + } +} diff --git a/misskey-api/src/endpoint/admin/logs.rs b/misskey-api/src/endpoint/admin/logs.rs index eb16cd5f..6354f44b 100644 --- a/misskey-api/src/endpoint/admin/logs.rs +++ b/misskey-api/src/endpoint/admin/logs.rs @@ -60,7 +60,10 @@ mod tests { .test(Request { limit: None, level: Some(LogLevel::Debug), + #[cfg(not(feature = "12-89-0"))] domain: Some("chart remote -resolve-user".to_string()), + #[cfg(feature = "12-89-0")] + domain: Some("chart".to_string()), }) .await; } diff --git a/misskey-api/src/endpoint/admin/update_meta.rs b/misskey-api/src/endpoint/admin/update_meta.rs index 1c25742d..6b0837fe 100644 --- a/misskey-api/src/endpoint/admin/update_meta.rs +++ b/misskey-api/src/endpoint/admin/update_meta.rs @@ -113,6 +113,16 @@ pub struct Request { #[serde(skip_serializing_if = "Option::is_none")] #[builder(default, setter(strip_option))] pub summaly_proxy: Option>, + #[cfg(feature = "12-88-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-88-0")))] + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub deepl_auth_key: Option>, + #[cfg(feature = "12-89-1")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-89-1")))] + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub deepl_is_pro: Option, #[serde(skip_serializing_if = "Option::is_none")] #[builder(default, setter(strip_option))] pub enable_twitter_integration: Option, @@ -303,6 +313,10 @@ mod tests { maintainer_email: Some(Some("me@coord-e.com".to_string())), langs: Some(vec!["ja_JP".to_string()]), summaly_proxy: Some(None), + #[cfg(feature = "12-88-0")] + deepl_auth_key: Some(None), + #[cfg(feature = "12-89-1")] + deepl_is_pro: Some(false), enable_twitter_integration: Some(false), twitter_consumer_key: Some(None), twitter_consumer_secret: Some(None), diff --git a/misskey-api/src/endpoint/antennas/create.rs b/misskey-api/src/endpoint/antennas/create.rs index b55655bc..b4e8f19e 100644 --- a/misskey-api/src/endpoint/antennas/create.rs +++ b/misskey-api/src/endpoint/antennas/create.rs @@ -17,6 +17,7 @@ pub struct Request { /// [ 1 .. 100 ] characters #[builder(setter(into))] pub name: String, + #[builder(default)] pub src: AntennaSource, #[builder(default, setter(strip_option))] pub user_list_id: Option>, @@ -30,10 +31,15 @@ pub struct Request { #[cfg_attr(docsrs, doc(cfg(feature = "12-19-0")))] #[builder(default, setter(into))] pub exclude_keywords: Query, + #[builder(default)] pub users: Vec, + #[builder(default)] pub case_sensitive: bool, + #[builder(default)] pub with_replies: bool, + #[builder(default)] pub with_file: bool, + #[builder(default)] pub notify: bool, } diff --git a/misskey-api/src/endpoint/antennas/delete.rs b/misskey-api/src/endpoint/antennas/delete.rs index 76c3c0a1..32f6384e 100644 --- a/misskey-api/src/endpoint/antennas/delete.rs +++ b/misskey-api/src/endpoint/antennas/delete.rs @@ -20,25 +20,13 @@ mod tests { #[tokio::test] async fn request() { - use crate::model::{antenna::AntennaSource, query::Query}; - let client = TestClient::new(); let antenna = client - .test(crate::endpoint::antennas::create::Request { - name: "test".to_string(), - src: AntennaSource::All, - user_list_id: None, - #[cfg(feature = "12-10-0")] - user_group_id: None, - keywords: Query::default(), - #[cfg(feature = "12-19-0")] - exclude_keywords: Query::default(), - users: Vec::new(), - case_sensitive: false, - with_replies: false, - with_file: false, - notify: false, - }) + .test( + crate::endpoint::antennas::create::Request::builder() + .name("test") + .build(), + ) .await; client diff --git a/misskey-api/src/endpoint/antennas/list.rs b/misskey-api/src/endpoint/antennas/list.rs index 0ada1f3e..a30a6616 100644 --- a/misskey-api/src/endpoint/antennas/list.rs +++ b/misskey-api/src/endpoint/antennas/list.rs @@ -18,25 +18,13 @@ mod tests { #[tokio::test] async fn request() { - use crate::model::{antenna::AntennaSource, query::Query}; - let client = TestClient::new(); client - .test(crate::endpoint::antennas::create::Request { - name: "test".to_string(), - src: AntennaSource::All, - user_list_id: None, - #[cfg(feature = "12-10-0")] - user_group_id: None, - keywords: Query::default(), - #[cfg(feature = "12-19-0")] - exclude_keywords: Query::default(), - users: Vec::new(), - case_sensitive: false, - with_replies: false, - with_file: false, - notify: false, - }) + .test( + crate::endpoint::antennas::create::Request::builder() + .name("test") + .build(), + ) .await; client.test(Request::default()).await; diff --git a/misskey-api/src/endpoint/antennas/notes.rs b/misskey-api/src/endpoint/antennas/notes.rs index 193e3234..f72f3773 100644 --- a/misskey-api/src/endpoint/antennas/notes.rs +++ b/misskey-api/src/endpoint/antennas/notes.rs @@ -34,26 +34,13 @@ mod tests { #[tokio::test] async fn request() { - use crate::model::{antenna::AntennaSource, query::Query}; - let client = TestClient::new(); let antenna = client - .user - .test(crate::endpoint::antennas::create::Request { - name: "test".to_string(), - src: AntennaSource::All, - user_list_id: None, - #[cfg(feature = "12-10-0")] - user_group_id: None, - keywords: Query::default(), - #[cfg(feature = "12-19-0")] - exclude_keywords: Query::default(), - users: Vec::new(), - case_sensitive: false, - with_replies: false, - with_file: false, - notify: false, - }) + .test( + crate::endpoint::antennas::create::Request::builder() + .name("test") + .build(), + ) .await; client @@ -69,26 +56,14 @@ mod tests { #[tokio::test] async fn request_with_limit() { - use crate::model::{antenna::AntennaSource, query::Query}; - let client = TestClient::new(); let antenna = client - .user - .test(crate::endpoint::antennas::create::Request { - name: "test".to_string(), - src: AntennaSource::All, - user_list_id: None, - #[cfg(feature = "12-10-0")] - user_group_id: None, - keywords: Query::from_vec(vec![vec!["hello".to_string(), "awesome".to_string()]]), - #[cfg(feature = "12-19-0")] - exclude_keywords: Query::default(), - users: Vec::new(), - case_sensitive: false, - with_replies: false, - with_file: false, - notify: false, - }) + .test( + crate::endpoint::antennas::create::Request::builder() + .name("test") + .keywords("hello awesome") + .build(), + ) .await; client @@ -104,26 +79,14 @@ mod tests { #[tokio::test] async fn request_paginate() { - use crate::model::{antenna::AntennaSource, query::Query}; - let client = TestClient::new(); let antenna = client - .user - .test(crate::endpoint::antennas::create::Request { - name: "test".to_string(), - src: AntennaSource::All, - user_list_id: None, - #[cfg(feature = "12-10-0")] - user_group_id: None, - keywords: Query::from_vec(vec![vec!["hello".to_string(), "awesome".to_string()]]), - #[cfg(feature = "12-19-0")] - exclude_keywords: Query::default(), - users: Vec::new(), - case_sensitive: false, - with_replies: false, - with_file: false, - notify: false, - }) + .test( + crate::endpoint::antennas::create::Request::builder() + .name("test") + .keywords("hello awesome") + .build(), + ) .await; let note = client .admin diff --git a/misskey-api/src/endpoint/antennas/show.rs b/misskey-api/src/endpoint/antennas/show.rs index 538b03e3..2827403d 100644 --- a/misskey-api/src/endpoint/antennas/show.rs +++ b/misskey-api/src/endpoint/antennas/show.rs @@ -20,26 +20,14 @@ mod tests { #[tokio::test] async fn request() { - use crate::model::{antenna::AntennaSource, query::Query}; - let client = TestClient::new(); let antenna = client - .user - .test(crate::endpoint::antennas::create::Request { - name: "test".to_string(), - src: AntennaSource::All, - user_list_id: None, - #[cfg(feature = "12-10-0")] - user_group_id: None, - keywords: Query::from_vec(vec![vec!["hello".to_string(), "awesome".to_string()]]), - #[cfg(feature = "12-19-0")] - exclude_keywords: Query(vec![vec!["oh".to_string()]]), - users: Vec::new(), - case_sensitive: false, - with_replies: false, - with_file: false, - notify: false, - }) + .test( + crate::endpoint::antennas::create::Request::builder() + .name("test") + .keywords("hello awesome") + .build(), + ) .await; client diff --git a/misskey-api/src/endpoint/antennas/update.rs b/misskey-api/src/endpoint/antennas/update.rs index 2d555f34..5b4d283a 100644 --- a/misskey-api/src/endpoint/antennas/update.rs +++ b/misskey-api/src/endpoint/antennas/update.rs @@ -55,21 +55,17 @@ mod tests { let client = TestClient::new(); let antenna = client .user - .test(crate::endpoint::antennas::create::Request { - name: "test".to_string(), - src: AntennaSource::All, - user_list_id: None, - #[cfg(feature = "12-10-0")] - user_group_id: None, - keywords: Query::from_vec(vec![vec!["hello".to_string(), "awesome".to_string()]]), - #[cfg(feature = "12-19-0")] - exclude_keywords: Query::default(), - users: Vec::new(), - case_sensitive: true, - with_replies: false, - with_file: true, - notify: false, - }) + .test( + crate::endpoint::antennas::create::Request::builder() + .name("test") + .keywords(Query::from_vec(vec![vec![ + "hello".to_string(), + "awesome".to_string(), + ]])) + .case_sensitive(true) + .with_file(true) + .build(), + ) .await; let list = client diff --git a/misskey-api/src/endpoint/channels/follow.rs b/misskey-api/src/endpoint/channels/follow.rs index e2e9c729..c78f516c 100644 --- a/misskey-api/src/endpoint/channels/follow.rs +++ b/misskey-api/src/endpoint/channels/follow.rs @@ -22,11 +22,11 @@ mod tests { async fn request() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test channel".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test channel") + .build(), + ) .await; client diff --git a/misskey-api/src/endpoint/channels/followed.rs b/misskey-api/src/endpoint/channels/followed.rs index ff77a899..638701bd 100644 --- a/misskey-api/src/endpoint/channels/followed.rs +++ b/misskey-api/src/endpoint/channels/followed.rs @@ -64,11 +64,11 @@ mod tests { async fn request_paginate() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test channel".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test channel") + .build(), + ) .await; client .test(crate::endpoint::channels::follow::Request { diff --git a/misskey-api/src/endpoint/channels/owned.rs b/misskey-api/src/endpoint/channels/owned.rs index d950caec..4de00ca5 100644 --- a/misskey-api/src/endpoint/channels/owned.rs +++ b/misskey-api/src/endpoint/channels/owned.rs @@ -64,11 +64,11 @@ mod tests { async fn request_paginate() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test channel".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test channel") + .build(), + ) .await; client diff --git a/misskey-api/src/endpoint/channels/show.rs b/misskey-api/src/endpoint/channels/show.rs index 027523e0..1bbc51c6 100644 --- a/misskey-api/src/endpoint/channels/show.rs +++ b/misskey-api/src/endpoint/channels/show.rs @@ -22,11 +22,11 @@ mod tests { async fn request() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test channel".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test channel") + .build(), + ) .await; client diff --git a/misskey-api/src/endpoint/channels/timeline.rs b/misskey-api/src/endpoint/channels/timeline.rs index a3881cac..aa2b4b38 100644 --- a/misskey-api/src/endpoint/channels/timeline.rs +++ b/misskey-api/src/endpoint/channels/timeline.rs @@ -49,11 +49,11 @@ mod tests { async fn request() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test") + .build(), + ) .await; client @@ -72,11 +72,11 @@ mod tests { async fn request_with_limit() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test") + .build(), + ) .await; client @@ -95,29 +95,19 @@ mod tests { async fn request_paginate() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test") + .build(), + ) .await; let note = client - .test(crate::endpoint::notes::create::Request { - visibility: None, - visible_user_ids: None, - text: Some("some text".to_string()), - cw: None, - via_mobile: None, - local_only: None, - no_extract_mentions: None, - no_extract_hashtags: None, - no_extract_emojis: None, - file_ids: None, - reply_id: None, - renote_id: None, - poll: None, - channel_id: Some(channel.id.clone()), - }) + .test( + crate::endpoint::notes::create::Request::builder() + .text("some text") + .channel_id(channel.id.clone()) + .build(), + ) .await .created_note; @@ -137,11 +127,11 @@ mod tests { async fn request_with_date() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test") + .build(), + ) .await; let now = chrono::Utc::now(); diff --git a/misskey-api/src/endpoint/channels/unfollow.rs b/misskey-api/src/endpoint/channels/unfollow.rs index b5f91e57..e82fd9d5 100644 --- a/misskey-api/src/endpoint/channels/unfollow.rs +++ b/misskey-api/src/endpoint/channels/unfollow.rs @@ -22,11 +22,11 @@ mod tests { async fn request() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test channel".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test channel") + .build(), + ) .await; client .test(crate::endpoint::channels::follow::Request { diff --git a/misskey-api/src/endpoint/channels/update.rs b/misskey-api/src/endpoint/channels/update.rs index 31439e89..dea2e20a 100644 --- a/misskey-api/src/endpoint/channels/update.rs +++ b/misskey-api/src/endpoint/channels/update.rs @@ -35,11 +35,11 @@ mod tests { async fn request_with_name() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test channel".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test channel") + .build(), + ) .await; client.test(Request { @@ -55,11 +55,11 @@ mod tests { async fn request_with_description() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test channel".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test channel") + .build(), + ) .await; client @@ -84,11 +84,11 @@ mod tests { async fn request_with_banner() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test channel".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test channel") + .build(), + ) .await; let url = client.avatar_url().await; let file = client.upload_from_url(url).await; diff --git a/misskey-api/src/endpoint/drive/files/attached_notes.rs b/misskey-api/src/endpoint/drive/files/attached_notes.rs index 58c9aabc..77e7ec8d 100644 --- a/misskey-api/src/endpoint/drive/files/attached_notes.rs +++ b/misskey-api/src/endpoint/drive/files/attached_notes.rs @@ -23,23 +23,11 @@ mod tests { let client = TestClient::new(); let file = client.create_text_file("test.txt", "test").await; client - .test(crate::endpoint::notes::create::Request { - visibility: None, - visible_user_ids: None, - text: None, - cw: None, - via_mobile: None, - local_only: None, - no_extract_mentions: None, - no_extract_hashtags: None, - no_extract_emojis: None, - file_ids: Some(vec![file.id.clone()]), - reply_id: None, - renote_id: None, - poll: None, - #[cfg(feature = "12-47-0")] - channel_id: None, - }) + .test( + crate::endpoint::notes::create::Request::builder() + .file_ids(vec![file.id.clone()]) + .build(), + ) .await; client.test(Request { file_id: file.id }).await; diff --git a/misskey-api/src/endpoint/drive/files/update.rs b/misskey-api/src/endpoint/drive/files/update.rs index c636ce71..0bfe92f3 100644 --- a/misskey-api/src/endpoint/drive/files/update.rs +++ b/misskey-api/src/endpoint/drive/files/update.rs @@ -20,6 +20,11 @@ pub struct Request { #[serde(skip_serializing_if = "Option::is_none")] #[builder(default, setter(strip_option))] pub is_sensitive: Option, + #[cfg(feature = "12-82-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-82-0")))] + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub comment: Option, } impl misskey_core::Request for Request { @@ -42,6 +47,8 @@ mod tests { folder_id: None, name: None, is_sensitive: None, + #[cfg(feature = "12-82-0")] + comment: None, }) .await; } @@ -63,6 +70,8 @@ mod tests { folder_id: Some(Some(folder.id)), name: Some("test2.txt".to_string()), is_sensitive: Some(true), + #[cfg(feature = "12-82-0")] + comment: Some("comment".to_string()), }) .await; } @@ -77,6 +86,8 @@ mod tests { folder_id: Some(None), name: None, is_sensitive: None, + #[cfg(feature = "12-82-0")] + comment: None, }) .await; } diff --git a/misskey-api/src/endpoint/following/requests/accept.rs b/misskey-api/src/endpoint/following/requests/accept.rs index 85850844..f85840a9 100644 --- a/misskey-api/src/endpoint/following/requests/accept.rs +++ b/misskey-api/src/endpoint/following/requests/accept.rs @@ -24,37 +24,11 @@ mod tests { let (new_user, new_client) = client.admin.create_user().await; new_client - .test(crate::endpoint::i::update::Request { - name: None, - description: None, - lang: None, - location: None, - birthday: None, - avatar_id: None, - banner_id: None, - fields: None, - is_locked: Some(true), - #[cfg(feature = "12-63-0")] - is_explorable: None, - careful_bot: None, - auto_accept_followed: None, - is_bot: None, - is_cat: None, - #[cfg(not(feature = "12-55-0"))] - auto_watch: None, - inject_featured_note: None, - always_mark_nsfw: None, - pinned_page_id: None, - muted_words: None, - #[cfg(feature = "12-60-0")] - no_crawle: None, - #[cfg(feature = "12-69-0")] - receive_announcement_email: None, - #[cfg(feature = "12-48-0")] - muting_notification_types: None, - #[cfg(feature = "12-70-0")] - email_notification_types: None, - }) + .test( + crate::endpoint::i::update::Request::builder() + .is_locked(true) + .build(), + ) .await; client .user diff --git a/misskey-api/src/endpoint/following/requests/cancel.rs b/misskey-api/src/endpoint/following/requests/cancel.rs index f1f2348d..9eecca2e 100644 --- a/misskey-api/src/endpoint/following/requests/cancel.rs +++ b/misskey-api/src/endpoint/following/requests/cancel.rs @@ -24,37 +24,12 @@ mod tests { let (new_user, new_client) = client.admin.create_user().await; new_client - .test(crate::endpoint::i::update::Request { - name: None, - description: None, - lang: None, - location: None, - birthday: None, - avatar_id: None, - banner_id: None, - fields: None, - is_locked: Some(true), - #[cfg(feature = "12-63-0")] - is_explorable: None, - careful_bot: None, - auto_accept_followed: Some(false), - is_bot: None, - is_cat: None, - #[cfg(not(feature = "12-55-0"))] - auto_watch: None, - inject_featured_note: None, - always_mark_nsfw: None, - pinned_page_id: None, - muted_words: None, - #[cfg(feature = "12-60-0")] - no_crawle: None, - #[cfg(feature = "12-69-0")] - receive_announcement_email: None, - #[cfg(feature = "12-48-0")] - muting_notification_types: None, - #[cfg(feature = "12-70-0")] - email_notification_types: None, - }) + .test( + crate::endpoint::i::update::Request::builder() + .is_locked(true) + .auto_accept_followed(false) + .build(), + ) .await; client .user diff --git a/misskey-api/src/endpoint/following/requests/list.rs b/misskey-api/src/endpoint/following/requests/list.rs index 3a1e9221..bcc19886 100644 --- a/misskey-api/src/endpoint/following/requests/list.rs +++ b/misskey-api/src/endpoint/following/requests/list.rs @@ -22,37 +22,11 @@ mod tests { let (new_user, new_client) = client.admin.create_user().await; new_client - .test(crate::endpoint::i::update::Request { - name: None, - description: None, - lang: None, - location: None, - birthday: None, - avatar_id: None, - banner_id: None, - fields: None, - is_locked: Some(true), - #[cfg(feature = "12-63-0")] - is_explorable: None, - careful_bot: None, - auto_accept_followed: None, - is_bot: None, - is_cat: None, - #[cfg(not(feature = "12-55-0"))] - auto_watch: None, - inject_featured_note: None, - always_mark_nsfw: None, - pinned_page_id: None, - muted_words: None, - #[cfg(feature = "12-60-0")] - no_crawle: None, - #[cfg(feature = "12-69-0")] - receive_announcement_email: None, - #[cfg(feature = "12-48-0")] - muting_notification_types: None, - #[cfg(feature = "12-70-0")] - email_notification_types: None, - }) + .test( + crate::endpoint::i::update::Request::builder() + .is_locked(true) + .build(), + ) .await; client .user diff --git a/misskey-api/src/endpoint/following/requests/reject.rs b/misskey-api/src/endpoint/following/requests/reject.rs index 865255a8..d494d9ac 100644 --- a/misskey-api/src/endpoint/following/requests/reject.rs +++ b/misskey-api/src/endpoint/following/requests/reject.rs @@ -24,37 +24,12 @@ mod tests { let (new_user, new_client) = client.admin.create_user().await; new_client - .test(crate::endpoint::i::update::Request { - name: None, - description: None, - lang: None, - location: None, - birthday: None, - avatar_id: None, - banner_id: None, - fields: None, - is_locked: Some(true), - #[cfg(feature = "12-63-0")] - is_explorable: None, - careful_bot: None, - auto_accept_followed: Some(false), - is_bot: None, - is_cat: None, - #[cfg(not(feature = "12-55-0"))] - auto_watch: None, - inject_featured_note: None, - always_mark_nsfw: None, - pinned_page_id: None, - muted_words: None, - #[cfg(feature = "12-60-0")] - no_crawle: None, - #[cfg(feature = "12-69-0")] - receive_announcement_email: None, - #[cfg(feature = "12-48-0")] - muting_notification_types: None, - #[cfg(feature = "12-70-0")] - email_notification_types: None, - }) + .test( + crate::endpoint::i::update::Request::builder() + .is_locked(true) + .auto_accept_followed(false) + .build(), + ) .await; client .user diff --git a/misskey-api/src/endpoint/gallery.rs b/misskey-api/src/endpoint/gallery.rs new file mode 100644 index 00000000..ca095dc0 --- /dev/null +++ b/misskey-api/src/endpoint/gallery.rs @@ -0,0 +1,3 @@ +pub mod featured; +pub mod popular; +pub mod posts; diff --git a/misskey-api/src/endpoint/gallery/featured.rs b/misskey-api/src/endpoint/gallery/featured.rs new file mode 100644 index 00000000..9677ffeb --- /dev/null +++ b/misskey-api/src/endpoint/gallery/featured.rs @@ -0,0 +1,24 @@ +use crate::model::gallery::GalleryPost; + +use serde::Serialize; + +#[derive(Serialize, Default, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Request {} + +impl misskey_core::Request for Request { + type Response = Vec; + const ENDPOINT: &'static str = "gallery/featured"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + client.test(Request::default()).await; + } +} diff --git a/misskey-api/src/endpoint/gallery/popular.rs b/misskey-api/src/endpoint/gallery/popular.rs new file mode 100644 index 00000000..e2466cb8 --- /dev/null +++ b/misskey-api/src/endpoint/gallery/popular.rs @@ -0,0 +1,24 @@ +use crate::model::gallery::GalleryPost; + +use serde::Serialize; + +#[derive(Serialize, Default, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Request {} + +impl misskey_core::Request for Request { + type Response = Vec; + const ENDPOINT: &'static str = "gallery/popular"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + client.test(Request::default()).await; + } +} diff --git a/misskey-api/src/endpoint/gallery/posts.rs b/misskey-api/src/endpoint/gallery/posts.rs new file mode 100644 index 00000000..0fbcfafd --- /dev/null +++ b/misskey-api/src/endpoint/gallery/posts.rs @@ -0,0 +1,89 @@ +use crate::model::{gallery::GalleryPost, id::Id}; + +use serde::Serialize; +use typed_builder::TypedBuilder; + +pub mod create; +pub mod like; +pub mod show; +pub mod unlike; + +#[cfg(feature = "12-79-2")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-79-2")))] +pub mod delete; + +#[cfg(feature = "12-79-2")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-79-2")))] +pub mod update; + +#[derive(Serialize, Default, Debug, Clone, TypedBuilder)] +#[serde(rename_all = "camelCase")] +#[builder(doc)] +pub struct Request { + /// 1 .. 100 + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub since_id: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub until_id: Option>, +} + +impl misskey_core::Request for Request { + type Response = Vec; + const ENDPOINT: &'static str = "gallery/posts"; +} + +impl_pagination!(Request, GalleryPost); + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + client.user.test(Request::default()).await; + } + + #[tokio::test] + async fn request_with_limit() { + let client = TestClient::new(); + + client + .test(Request { + limit: Some(100), + since_id: None, + until_id: None, + }) + .await; + } + + #[tokio::test] + async fn request_paginate() { + let client = TestClient::new(); + let url = client.avatar_url().await; + let file = client.upload_from_url(url).await; + + let post = client + .test(crate::endpoint::gallery::posts::create::Request { + title: "gallery post".to_string(), + description: None, + file_ids: vec![file.id], + is_sensitive: None, + }) + .await; + + client + .test(Request { + limit: None, + since_id: Some(post.id.clone()), + until_id: Some(post.id.clone()), + }) + .await; + } +} diff --git a/misskey-api/src/endpoint/gallery/posts/create.rs b/misskey-api/src/endpoint/gallery/posts/create.rs new file mode 100644 index 00000000..5601770c --- /dev/null +++ b/misskey-api/src/endpoint/gallery/posts/create.rs @@ -0,0 +1,65 @@ +use crate::model::{drive::DriveFile, gallery::GalleryPost, id::Id}; + +use serde::Serialize; +use typed_builder::TypedBuilder; + +#[derive(Serialize, Debug, Clone, TypedBuilder)] +#[serde(rename_all = "camelCase")] +#[builder(doc)] +pub struct Request { + /// [ 1 .. ] characters + #[builder(default, setter(into))] + pub title: String, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option, into))] + pub description: Option, + /// [ 1 .. 32 ] ids + #[builder(default, setter(into))] + pub file_ids: Vec>, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option, into))] + pub is_sensitive: Option, +} + +impl misskey_core::Request for Request { + type Response = GalleryPost; + const ENDPOINT: &'static str = "gallery/posts/create"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + let url = client.avatar_url().await; + let file = client.upload_from_url(url).await; + + client + .test(Request { + title: "gallery post".to_string(), + description: None, + file_ids: vec![file.id], + is_sensitive: None, + }) + .await; + } + + #[tokio::test] + async fn request_with_options() { + let client = TestClient::new(); + let url = client.avatar_url().await; + let file = client.upload_from_url(url).await; + + client + .test(Request { + title: "gallery post".to_string(), + description: Some("description".to_string()), + file_ids: vec![file.id], + is_sensitive: Some(true), + }) + .await; + } +} diff --git a/misskey-api/src/endpoint/gallery/posts/delete.rs b/misskey-api/src/endpoint/gallery/posts/delete.rs new file mode 100644 index 00000000..bf03ed11 --- /dev/null +++ b/misskey-api/src/endpoint/gallery/posts/delete.rs @@ -0,0 +1,38 @@ +use crate::model::{gallery::GalleryPost, id::Id}; + +use serde::Serialize; + +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Request { + pub post_id: Id, +} + +impl misskey_core::Request for Request { + type Response = (); + const ENDPOINT: &'static str = "gallery/posts/delete"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + let url = client.avatar_url().await; + let file = client.upload_from_url(url).await; + + let post = client + .test(crate::endpoint::gallery::posts::create::Request { + title: "gallery post".to_string(), + description: None, + file_ids: vec![file.id], + is_sensitive: None, + }) + .await; + + client.test(Request { post_id: post.id }).await; + } +} diff --git a/misskey-api/src/endpoint/gallery/posts/like.rs b/misskey-api/src/endpoint/gallery/posts/like.rs new file mode 100644 index 00000000..fdc267c0 --- /dev/null +++ b/misskey-api/src/endpoint/gallery/posts/like.rs @@ -0,0 +1,39 @@ +use crate::model::{gallery::GalleryPost, id::Id}; + +use serde::Serialize; + +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Request { + pub post_id: Id, +} + +impl misskey_core::Request for Request { + type Response = (); + const ENDPOINT: &'static str = "gallery/posts/like"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + let url = client.avatar_url().await; + let file = client.upload_from_url(url).await; + + let post = client + .user + .test(crate::endpoint::gallery::posts::create::Request { + title: "gallery post".to_string(), + description: None, + file_ids: vec![file.id], + is_sensitive: None, + }) + .await; + + client.admin.test(Request { post_id: post.id }).await; + } +} diff --git a/misskey-api/src/endpoint/gallery/posts/show.rs b/misskey-api/src/endpoint/gallery/posts/show.rs new file mode 100644 index 00000000..7efaac0e --- /dev/null +++ b/misskey-api/src/endpoint/gallery/posts/show.rs @@ -0,0 +1,38 @@ +use crate::model::{gallery::GalleryPost, id::Id}; + +use serde::Serialize; + +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Request { + pub post_id: Id, +} + +impl misskey_core::Request for Request { + type Response = GalleryPost; + const ENDPOINT: &'static str = "gallery/posts/show"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + let url = client.avatar_url().await; + let file = client.upload_from_url(url).await; + + let post = client + .test(crate::endpoint::gallery::posts::create::Request { + title: "gallery post".to_string(), + description: None, + file_ids: vec![file.id], + is_sensitive: None, + }) + .await; + + client.test(Request { post_id: post.id }).await; + } +} diff --git a/misskey-api/src/endpoint/gallery/posts/unlike.rs b/misskey-api/src/endpoint/gallery/posts/unlike.rs new file mode 100644 index 00000000..b802d6fd --- /dev/null +++ b/misskey-api/src/endpoint/gallery/posts/unlike.rs @@ -0,0 +1,44 @@ +use crate::model::{gallery::GalleryPost, id::Id}; + +use serde::Serialize; + +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Request { + pub post_id: Id, +} + +impl misskey_core::Request for Request { + type Response = (); + const ENDPOINT: &'static str = "gallery/posts/unlike"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + let url = client.avatar_url().await; + let file = client.upload_from_url(url).await; + + let post = client + .user + .test(crate::endpoint::gallery::posts::create::Request { + title: "gallery post".to_string(), + description: None, + file_ids: vec![file.id], + is_sensitive: None, + }) + .await; + + client + .admin + .test(crate::endpoint::gallery::posts::like::Request { post_id: post.id }) + .await; + + client.admin.test(Request { post_id: post.id }).await; + } +} diff --git a/misskey-api/src/endpoint/gallery/posts/update.rs b/misskey-api/src/endpoint/gallery/posts/update.rs new file mode 100644 index 00000000..51b74685 --- /dev/null +++ b/misskey-api/src/endpoint/gallery/posts/update.rs @@ -0,0 +1,86 @@ +use crate::model::{drive::DriveFile, gallery::GalleryPost, id::Id}; + +use serde::Serialize; +use typed_builder::TypedBuilder; + +#[derive(Serialize, Debug, Clone, TypedBuilder)] +#[serde(rename_all = "camelCase")] +#[builder(doc)] +pub struct Request { + pub post_id: Id, + /// [ 1 .. ] characters + #[builder(default, setter(into))] + pub title: String, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option, into))] + pub description: Option, + /// [ 1 .. 32 ] ids + #[builder(default, setter(into))] + pub file_ids: Vec>, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option, into))] + pub is_sensitive: Option, +} + +impl misskey_core::Request for Request { + type Response = GalleryPost; + const ENDPOINT: &'static str = "gallery/posts/update"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + let url = client.avatar_url().await; + let file = client.upload_from_url(url).await; + + let post = client + .test(crate::endpoint::gallery::posts::create::Request { + title: "gallery post".to_string(), + description: None, + file_ids: vec![file.id], + is_sensitive: None, + }) + .await; + + client + .test(Request { + post_id: post.id, + title: "updated".to_string(), + description: None, + file_ids: vec![file.id], + is_sensitive: None, + }) + .await; + } + + #[tokio::test] + async fn request_with_options() { + let client = TestClient::new(); + let url = client.avatar_url().await; + let file = client.upload_from_url(url).await; + + let post = client + .test(crate::endpoint::gallery::posts::create::Request { + title: "gallery post".to_string(), + description: None, + file_ids: vec![file.id], + is_sensitive: None, + }) + .await; + + client + .test(Request { + post_id: post.id, + title: "updated".to_string(), + description: Some("description".to_string()), + file_ids: vec![file.id], + is_sensitive: Some(true), + }) + .await; + } +} diff --git a/misskey-api/src/endpoint/i.rs b/misskey-api/src/endpoint/i.rs index 25b97155..af8b1f68 100644 --- a/misskey-api/src/endpoint/i.rs +++ b/misskey-api/src/endpoint/i.rs @@ -18,6 +18,10 @@ pub mod user_group_invites; #[cfg_attr(docsrs, doc(cfg(feature = "12-67-0")))] pub mod registry; +#[cfg(feature = "12-79-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] +pub mod gallery; + #[derive(Serialize, Default, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct Request {} diff --git a/misskey-api/src/endpoint/i/gallery.rs b/misskey-api/src/endpoint/i/gallery.rs new file mode 100644 index 00000000..09884894 --- /dev/null +++ b/misskey-api/src/endpoint/i/gallery.rs @@ -0,0 +1,2 @@ +pub mod likes; +pub mod posts; diff --git a/misskey-api/src/endpoint/i/gallery/likes.rs b/misskey-api/src/endpoint/i/gallery/likes.rs new file mode 100644 index 00000000..bb90118c --- /dev/null +++ b/misskey-api/src/endpoint/i/gallery/likes.rs @@ -0,0 +1,91 @@ +use crate::model::{gallery::GalleryLike, id::Id}; + +use serde::Serialize; +use typed_builder::TypedBuilder; + +#[derive(Serialize, Default, Debug, Clone, TypedBuilder)] +#[serde(rename_all = "camelCase")] +#[builder(doc)] +pub struct Request { + /// 1 .. 100 + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub since_id: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub until_id: Option>, +} + +impl misskey_core::Request for Request { + type Response = Vec; + const ENDPOINT: &'static str = "i/gallery/likes"; +} + +impl_pagination!(Request, GalleryLike); + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + client.user.test(Request::default()).await; + } + + #[tokio::test] + async fn request_with_limit() { + let client = TestClient::new(); + + client + .test(Request { + limit: Some(100), + since_id: None, + until_id: None, + }) + .await; + } + + #[tokio::test] + async fn request_paginate() { + let client = TestClient::new(); + let url = client.avatar_url().await; + let file = client.upload_from_url(url).await; + + let post = client + .user + .test(crate::endpoint::gallery::posts::create::Request { + title: "gallery post".to_string(), + description: None, + file_ids: vec![file.id], + is_sensitive: None, + }) + .await; + client + .admin + .test(crate::endpoint::gallery::posts::like::Request { post_id: post.id }) + .await; + + let likes = client + .admin + .test(Request { + limit: None, + since_id: None, + until_id: None, + }) + .await; + + client + .admin + .test(Request { + limit: None, + since_id: Some(likes[0].id.clone()), + until_id: Some(likes[0].id.clone()), + }) + .await; + } +} diff --git a/misskey-api/src/endpoint/i/gallery/posts.rs b/misskey-api/src/endpoint/i/gallery/posts.rs new file mode 100644 index 00000000..13efa780 --- /dev/null +++ b/misskey-api/src/endpoint/i/gallery/posts.rs @@ -0,0 +1,76 @@ +use crate::model::{gallery::GalleryPost, id::Id}; + +use serde::Serialize; +use typed_builder::TypedBuilder; + +#[derive(Serialize, Default, Debug, Clone, TypedBuilder)] +#[serde(rename_all = "camelCase")] +#[builder(doc)] +pub struct Request { + /// 1 .. 100 + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub since_id: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub until_id: Option>, +} + +impl misskey_core::Request for Request { + type Response = Vec; + const ENDPOINT: &'static str = "i/gallery/posts"; +} + +impl_pagination!(Request, GalleryPost); + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + client.user.test(Request::default()).await; + } + + #[tokio::test] + async fn request_with_limit() { + let client = TestClient::new(); + + client + .test(Request { + limit: Some(100), + since_id: None, + until_id: None, + }) + .await; + } + + #[tokio::test] + async fn request_paginate() { + let client = TestClient::new(); + let url = client.avatar_url().await; + let file = client.upload_from_url(url).await; + + let post = client + .test(crate::endpoint::gallery::posts::create::Request { + title: "gallery post".to_string(), + description: None, + file_ids: vec![file.id], + is_sensitive: None, + }) + .await; + + client + .test(Request { + limit: None, + since_id: Some(post.id.clone()), + until_id: Some(post.id.clone()), + }) + .await; + } +} diff --git a/misskey-api/src/endpoint/i/notifications.rs b/misskey-api/src/endpoint/i/notifications.rs index a5b7da30..5bf2aa32 100644 --- a/misskey-api/src/endpoint/i/notifications.rs +++ b/misskey-api/src/endpoint/i/notifications.rs @@ -97,11 +97,11 @@ mod tests { async fn request_paginate() { let client = TestClient::new(); client - .test(crate::endpoint::notifications::create::Request { - body: "hi".to_string(), - header: None, - icon: None, - }) + .test( + crate::endpoint::notifications::create::Request::builder() + .body("hi") + .build(), + ) .await; let mut notification = None; diff --git a/misskey-api/src/endpoint/i/update.rs b/misskey-api/src/endpoint/i/update.rs index 83127a1f..bb878603 100644 --- a/misskey-api/src/endpoint/i/update.rs +++ b/misskey-api/src/endpoint/i/update.rs @@ -52,6 +52,11 @@ pub struct Request { #[serde(skip_serializing_if = "Option::is_none")] #[builder(default, setter(strip_option))] pub is_explorable: Option, + #[cfg(feature = "12-77-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-77-0")))] + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub hide_online_status: Option, #[serde(skip_serializing_if = "Option::is_none")] #[builder(default, setter(strip_option))] pub careful_bot: Option, @@ -149,6 +154,8 @@ mod tests { is_locked: Some(true), #[cfg(feature = "12-63-0")] is_explorable: Some(false), + #[cfg(feature = "12-77-0")] + hide_online_status: Some(true), careful_bot: Some(true), auto_accept_followed: Some(true), is_bot: Some(true), @@ -201,6 +208,8 @@ mod tests { is_locked: None, #[cfg(feature = "12-63-0")] is_explorable: None, + #[cfg(feature = "12-77-0")] + hide_online_status: None, careful_bot: None, auto_accept_followed: None, is_bot: None, diff --git a/misskey-api/src/endpoint/notes/create.rs b/misskey-api/src/endpoint/notes/create.rs index af7ecc76..9cedf13f 100644 --- a/misskey-api/src/endpoint/notes/create.rs +++ b/misskey-api/src/endpoint/notes/create.rs @@ -428,11 +428,11 @@ mod tests { async fn request_with_channel_id() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test channel") + .build(), + ) .await; client diff --git a/misskey-api/src/endpoint/notes/polls/vote.rs b/misskey-api/src/endpoint/notes/polls/vote.rs index bad87799..6e42b497 100644 --- a/misskey-api/src/endpoint/notes/polls/vote.rs +++ b/misskey-api/src/endpoint/notes/polls/vote.rs @@ -30,23 +30,12 @@ mod tests { expired_after: None, }; let note = client - .test(crate::endpoint::notes::create::Request { - visibility: None, - visible_user_ids: None, - text: Some("poll".to_string()), - cw: None, - via_mobile: None, - local_only: None, - no_extract_mentions: None, - no_extract_hashtags: None, - no_extract_emojis: None, - file_ids: None, - reply_id: None, - renote_id: None, - poll: Some(poll), - #[cfg(feature = "12-47-0")] - channel_id: None, - }) + .test( + crate::endpoint::notes::create::Request::builder() + .text("poll") + .poll(poll) + .build(), + ) .await .created_note; diff --git a/misskey-api/src/endpoint/notes/search.rs b/misskey-api/src/endpoint/notes/search.rs index 8cb0b314..6a1479a2 100644 --- a/misskey-api/src/endpoint/notes/search.rs +++ b/misskey-api/src/endpoint/notes/search.rs @@ -83,11 +83,11 @@ mod tests { async fn request_with_channel_id() { let client = TestClient::new(); let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test channel".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test channel") + .build(), + ) .await; client diff --git a/misskey-api/src/endpoint/notifications.rs b/misskey-api/src/endpoint/notifications.rs index 86d65686..d2b78a39 100644 --- a/misskey-api/src/endpoint/notifications.rs +++ b/misskey-api/src/endpoint/notifications.rs @@ -3,3 +3,7 @@ pub mod create; pub mod mark_all_as_read; + +#[cfg(feature = "12-77-1")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-77-1")))] +pub mod read; diff --git a/misskey-api/src/endpoint/notifications/read.rs b/misskey-api/src/endpoint/notifications/read.rs new file mode 100644 index 00000000..188bd44c --- /dev/null +++ b/misskey-api/src/endpoint/notifications/read.rs @@ -0,0 +1,49 @@ +use crate::model::{id::Id, notification::Notification}; + +use serde::Serialize; + +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Request { + pub notification_id: Id, +} + +impl misskey_core::Request for Request { + type Response = (); + const ENDPOINT: &'static str = "notifications/read"; +} + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + client + .admin + .test( + crate::endpoint::notifications::create::Request::builder() + .body("hi") + .build(), + ) + .await; + + let mut notification = None; + while notification.is_none() { + notification = client + .admin + .test(crate::endpoint::i::notifications::Request::default()) + .await + .pop(); + } + + client + .admin + .test(Request { + notification_id: notification.unwrap().id, + }) + .await; + } +} diff --git a/misskey-api/src/endpoint/users.rs b/misskey-api/src/endpoint/users.rs index 07f5f5fd..51df0833 100644 --- a/misskey-api/src/endpoint/users.rs +++ b/misskey-api/src/endpoint/users.rs @@ -1,10 +1,14 @@ +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] use crate::model::{ sort::SortOrder, user::{User, UserOrigin, UserSortKey}, }; +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] use serde::Serialize; +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] use thiserror::Error; +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] use typed_builder::TypedBuilder; pub mod followers; @@ -13,7 +17,6 @@ pub mod get_frequently_replied_users; pub mod groups; pub mod lists; pub mod notes; -pub mod recommendation; pub mod relation; pub mod report_abuse; pub mod search; @@ -32,6 +35,16 @@ pub mod clips; #[cfg_attr(docsrs, doc(cfg(feature = "12-61-0")))] pub mod pages; +#[cfg(feature = "12-79-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] +pub mod gallery; + +// misskey-dev/misskey#7656 +#[cfg(not(feature = "12-88-0"))] +#[cfg_attr(docsrs, doc(cfg(not(feature = "12-88-0"))))] +pub mod recommendation; + +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] #[derive(Serialize, PartialEq, Eq, Clone, Debug, Copy)] #[serde(rename_all = "camelCase")] pub enum UserState { @@ -42,12 +55,14 @@ pub enum UserState { AdminOrModerator, } +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] #[derive(Debug, Error, Clone)] #[error("invalid user state")] pub struct ParseUserStateError { _priv: (), } +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] impl std::str::FromStr for UserState { type Err = ParseUserStateError; @@ -63,6 +78,9 @@ impl std::str::FromStr for UserState { } } +// misskey-dev/misskey#7656 +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] +#[cfg_attr(docsrs, doc(cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))))] #[derive(Serialize, Default, Debug, Clone, TypedBuilder)] #[serde(rename_all = "camelCase")] #[builder(doc)] @@ -85,13 +103,16 @@ pub struct Request { pub origin: Option, } +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] impl misskey_core::Request for Request { type Response = Vec; const ENDPOINT: &'static str = "users"; } +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] impl_offset_pagination!(Request, User); +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] #[cfg(test)] mod tests { use super::{Request, UserState}; diff --git a/misskey-api/src/endpoint/users/gallery.rs b/misskey-api/src/endpoint/users/gallery.rs new file mode 100644 index 00000000..83d81e78 --- /dev/null +++ b/misskey-api/src/endpoint/users/gallery.rs @@ -0,0 +1 @@ +pub mod posts; diff --git a/misskey-api/src/endpoint/users/gallery/posts.rs b/misskey-api/src/endpoint/users/gallery/posts.rs new file mode 100644 index 00000000..60f36e5d --- /dev/null +++ b/misskey-api/src/endpoint/users/gallery/posts.rs @@ -0,0 +1,90 @@ +use crate::model::{gallery::GalleryPost, id::Id, user::User}; + +use serde::Serialize; +use typed_builder::TypedBuilder; + +#[derive(Serialize, Debug, Clone, TypedBuilder)] +#[serde(rename_all = "camelCase")] +#[builder(doc)] +pub struct Request { + pub user_id: Id, + /// 1 .. 100 + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub since_id: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub until_id: Option>, +} + +impl misskey_core::Request for Request { + type Response = Vec; + const ENDPOINT: &'static str = "users/gallery/posts"; +} + +impl_pagination!(Request, GalleryPost); + +#[cfg(test)] +mod tests { + use super::Request; + use crate::test::{ClientExt, TestClient}; + + #[tokio::test] + async fn request() { + let client = TestClient::new(); + let user = client.user.me().await; + client + .user + .test(Request { + user_id: user.id, + limit: None, + since_id: None, + until_id: None, + }) + .await; + } + + #[tokio::test] + async fn request_with_limit() { + let client = TestClient::new(); + let user = client.user.me().await; + + client + .test(Request { + user_id: user.id, + limit: Some(100), + since_id: None, + until_id: None, + }) + .await; + } + + #[tokio::test] + async fn request_paginate() { + let client = TestClient::new(); + let user = client.user.me().await; + let url = client.avatar_url().await; + let file = client.upload_from_url(url).await; + + let post = client + .test(crate::endpoint::gallery::posts::create::Request { + title: "gallery post".to_string(), + description: None, + file_ids: vec![file.id], + is_sensitive: None, + }) + .await; + + client + .test(Request { + user_id: user.id, + limit: None, + since_id: Some(post.id.clone()), + until_id: Some(post.id.clone()), + }) + .await; + } +} diff --git a/misskey-api/src/model.rs b/misskey-api/src/model.rs index 0feedac7..90eca0fd 100644 --- a/misskey-api/src/model.rs +++ b/misskey-api/src/model.rs @@ -17,6 +17,7 @@ macro_rules! impl_entity { } pub mod abuse_user_report; +pub mod ad; pub mod announcement; pub mod antenna; pub mod blocking; @@ -26,6 +27,7 @@ pub mod clip; pub mod drive; pub mod emoji; pub mod following; +pub mod gallery; pub mod id; pub mod log; pub mod messaging; diff --git a/misskey-api/src/model/ad.rs b/misskey-api/src/model/ad.rs new file mode 100644 index 00000000..252315be --- /dev/null +++ b/misskey-api/src/model/ad.rs @@ -0,0 +1,105 @@ +use std::fmt::{self, Display}; + +use crate::model::id::Id; + +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Ad { + pub id: Id, + pub created_at: DateTime, + pub expires_at: DateTime, + pub place: Place, + pub priority: Priority, + #[cfg(feature = "12-81-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-81-0")))] + pub ratio: u64, + pub url: String, + pub image_url: String, + pub memo: String, +} + +impl_entity!(Ad); + +#[derive(Serialize, Deserialize, Default, PartialEq, Eq, Clone, Debug, Copy)] +#[serde(rename_all = "kebab-case")] +pub enum Place { + #[default] + Square, + Horizontal, + #[cfg(feature = "12-81-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-81-0")))] + HorizontalBig, +} + +impl Display for Place { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Place::Square => f.write_str("square"), + Place::Horizontal => f.write_str("horizontal"), + #[cfg(feature = "12-81-0")] + Place::HorizontalBig => f.write_str("horizontal-big"), + } + } +} + +#[derive(Debug, Error, Clone)] +#[error("invalid place")] +pub struct ParsePlaceError { + _priv: (), +} + +impl std::str::FromStr for Place { + type Err = ParsePlaceError; + + fn from_str(s: &str) -> Result { + match s { + "square" | "Square" => Ok(Place::Square), + "horizontal" | "Horizontal" => Ok(Place::Horizontal), + #[cfg(feature = "12-81-0")] + "horizontal-big" | "Horizontal-big" => Ok(Place::HorizontalBig), + _ => Err(ParsePlaceError { _priv: () }), + } + } +} + +#[derive(Serialize, Deserialize, Default, PartialEq, Eq, Clone, Debug, Copy)] +#[serde(rename_all = "camelCase")] +pub enum Priority { + High, + #[default] + Middle, + Low, +} + +impl Display for Priority { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Priority::High => f.write_str("high"), + Priority::Middle => f.write_str("middle"), + Priority::Low => f.write_str("low"), + } + } +} + +#[derive(Debug, Error, Clone)] +#[error("invalid priority")] +pub struct ParsePriorityError { + _priv: (), +} + +impl std::str::FromStr for Priority { + type Err = ParsePriorityError; + + fn from_str(s: &str) -> Result { + match s { + "high" | "High" => Ok(Priority::High), + "middle" | "Middle" => Ok(Priority::Middle), + "low" | "Low" => Ok(Priority::Low), + _ => Err(ParsePriorityError { _priv: () }), + } + } +} diff --git a/misskey-api/src/model/antenna.rs b/misskey-api/src/model/antenna.rs index 8ebabf22..bdcb37bf 100644 --- a/misskey-api/src/model/antenna.rs +++ b/misskey-api/src/model/antenna.rs @@ -30,9 +30,10 @@ pub struct Antenna { impl_entity!(Antenna); -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone, Copy)] #[serde(rename_all = "camelCase")] pub enum AntennaSource { + #[default] All, Home, Users, diff --git a/misskey-api/src/model/gallery.rs b/misskey-api/src/model/gallery.rs new file mode 100644 index 00000000..14d218a5 --- /dev/null +++ b/misskey-api/src/model/gallery.rs @@ -0,0 +1,36 @@ +use crate::model::{drive::DriveFile, id::Id, user::User}; + +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct GalleryPost { + pub id: Id, + pub created_at: DateTime, + pub updated_at: DateTime, + pub user_id: Id, + pub user: User, + pub title: String, + #[serde(default)] + pub description: Option, + pub file_ids: Vec>, + pub files: Vec, + #[serde(default)] + pub tags: Option>, + pub is_sensitive: bool, + pub liked_count: u64, + #[serde(default)] + pub is_liked: Option, +} + +impl_entity!(GalleryPost); + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct GalleryLike { + pub id: Id, + pub post: GalleryPost, +} + +impl_entity!(GalleryLike); diff --git a/misskey-api/src/model/meta.rs b/misskey-api/src/model/meta.rs index 058a7eb3..54998a39 100644 --- a/misskey-api/src/model/meta.rs +++ b/misskey-api/src/model/meta.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "12-81-0")] +use crate::model::ad::{Ad, Place}; #[cfg(feature = "12-62-0")] use crate::model::clip::Clip; use crate::model::{emoji::Emoji, id::Id, user::User}; @@ -54,6 +56,9 @@ pub struct Meta { pub icon_url: Option, pub max_note_text_length: u64, pub emojis: Vec, + #[cfg(feature = "12-81-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-81-0")))] + pub ads: Vec, /// This field is [`bool`] (i.e. not [`Option`]) on non-feature="12-58-0". #[cfg(feature = "12-58-0")] pub require_setup: Option, @@ -64,6 +69,8 @@ pub struct Meta { pub enable_github_integration: bool, pub enable_discord_integration: bool, pub enable_service_worker: bool, + #[cfg(feature = "12-88-0")] + pub translator_available: bool, /// This field is [`Option`][`Option`] on non-feature="12-58-0". #[cfg(feature = "12-58-0")] #[cfg_attr(docsrs, doc(cfg(feature = "12-48-0")))] @@ -88,6 +95,18 @@ pub struct Meta { pub pinned_clip_id: Option>, } +#[cfg(feature = "12-81-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-81-0")))] +#[derive(Deserialize, Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct MetaAd { + pub id: Id, + pub url: String, + pub place: Place, + pub ratio: u64, + pub image_url: String, +} + #[derive(Deserialize, Serialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct AdminMeta { @@ -134,6 +153,12 @@ pub struct AdminMeta { #[cfg(feature = "12-69-0")] #[cfg_attr(docsrs, doc(cfg(feature = "12-69-0")))] pub object_storage_s3_force_path_style: bool, + #[cfg(feature = "12-89-1")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-89-1")))] + pub deepl_auth_key: Option, + #[cfg(feature = "12-89-1")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-89-1")))] + pub deepl_is_pro: bool, } #[derive(Deserialize, Serialize, Debug, Clone)] diff --git a/misskey-api/src/model/user.rs b/misskey-api/src/model/user.rs index 6875f613..72038550 100644 --- a/misskey-api/src/model/user.rs +++ b/misskey-api/src/model/user.rs @@ -91,6 +91,26 @@ impl std::str::FromStr for UserEmailNotificationType { } } +#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug, Copy, Hash)] +#[serde(rename_all = "camelCase")] +pub enum OnlineStatus { + Unknown, + Online, + Active, + Offline, +} + +impl Display for OnlineStatus { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + OnlineStatus::Unknown => f.write_str("unknown"), + OnlineStatus::Online => f.write_str("online"), + OnlineStatus::Active => f.write_str("active"), + OnlineStatus::Offline => f.write_str("offline"), + } + } +} + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct User { @@ -194,6 +214,14 @@ pub struct User { #[cfg_attr(docsrs, doc(cfg(feature = "12-70-0")))] #[serde(default)] pub email_notification_types: Option>, + #[cfg(feature = "12-77-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-77-0")))] + #[serde(default)] + pub online_status: Option, + #[cfg(feature = "12-77-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-77-0")))] + #[serde(default)] + pub hide_online_status: Option, } fn default_false() -> bool { diff --git a/misskey-api/src/streaming/channel/channel.rs b/misskey-api/src/streaming/channel/channel.rs index 89077fd1..9052825b 100644 --- a/misskey-api/src/streaming/channel/channel.rs +++ b/misskey-api/src/streaming/channel/channel.rs @@ -38,11 +38,11 @@ mod tests { async fn subscribe_unsubscribe() { let client = TestClient::new().await; let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test") + .build(), + ) .await; let mut stream = client @@ -58,11 +58,11 @@ mod tests { async fn stream() { let client = TestClient::new().await; let channel = client - .test(crate::endpoint::channels::create::Request { - name: "test".to_string(), - description: None, - banner_id: None, - }) + .test( + crate::endpoint::channels::create::Request::builder() + .name("test") + .build(), + ) .await; let mut stream = client @@ -73,22 +73,12 @@ mod tests { .unwrap(); future::join( - client.test(crate::endpoint::notes::create::Request { - visibility: None, - visible_user_ids: None, - text: Some("some text".to_string()), - cw: None, - via_mobile: None, - local_only: None, - no_extract_mentions: None, - no_extract_hashtags: None, - no_extract_emojis: None, - file_ids: None, - reply_id: None, - renote_id: None, - poll: None, - channel_id: Some(channel.id), - }), + client.test( + crate::endpoint::notes::create::Request::builder() + .text("some text") + .channel_id(channel.id) + .build(), + ), async { stream.next().await.unwrap().unwrap() }, ) .await; diff --git a/misskey-api/src/streaming/channel/drive.rs b/misskey-api/src/streaming/channel/drive.rs index 828feab7..2443c6c3 100644 --- a/misskey-api/src/streaming/channel/drive.rs +++ b/misskey-api/src/streaming/channel/drive.rs @@ -135,12 +135,12 @@ mod tests { let mut stream = client.channel(Request::default()).await.unwrap(); future::join( - client.test(crate::endpoint::drive::files::update::Request { - file_id: file.id, - folder_id: None, - is_sensitive: None, - name: Some("test".to_string()), - }), + client.test( + crate::endpoint::drive::files::update::Request::builder() + .file_id(file.id) + .name("test") + .build(), + ), async { loop { match stream.next().await.unwrap().unwrap() { diff --git a/misskey-api/src/streaming/note.rs b/misskey-api/src/streaming/note.rs index 04fc5dbf..d4e1a48c 100644 --- a/misskey-api/src/streaming/note.rs +++ b/misskey-api/src/streaming/note.rs @@ -143,23 +143,12 @@ mod tests { }; let note = client .user - .test(crate::endpoint::notes::create::Request { - visibility: None, - visible_user_ids: None, - text: Some("?".to_string()), - cw: None, - via_mobile: None, - local_only: None, - no_extract_mentions: None, - no_extract_hashtags: None, - no_extract_emojis: None, - file_ids: None, - reply_id: None, - renote_id: None, - poll: Some(poll), - #[cfg(feature = "12-47-0")] - channel_id: None, - }) + .test( + crate::endpoint::notes::create::Request::builder() + .text("?") + .poll(poll) + .build(), + ) .await .created_note; diff --git a/misskey-util/CHANGELOG.md b/misskey-util/CHANGELOG.md index dec2b2a3..4a667846 100644 --- a/misskey-util/CHANGELOG.md +++ b/misskey-util/CHANGELOG.md @@ -11,12 +11,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Registry APIs - Page APIs +- Gallery APIs ### Changed ### Deprecated ### Removed - Latest version flag from being enabled as default +- `ClientExt::users` + - For Misskey v12.88.0 +- `ClientExt::recommended_users` + - For Misskey v12.88.0 ~ ### Fixed ### Security diff --git a/misskey-util/Cargo.toml b/misskey-util/Cargo.toml index 8e574eef..15e31c7a 100644 --- a/misskey-util/Cargo.toml +++ b/misskey-util/Cargo.toml @@ -14,6 +14,16 @@ keywords = ["async", "client", "misskey"] [features] default = ["aid"] +12-89-1 = ["misskey-api/12-89-1", "12-89-0"] +12-89-0 = ["misskey-api/12-89-0", "12-88-0"] +12-88-0 = ["misskey-api/12-88-0", "12-82-0"] +12-82-0 = ["misskey-api/12-82-0", "12-81-0"] +12-81-0 = ["misskey-api/12-81-0", "12-80-0"] +12-80-0 = ["misskey-api/12-80-0", "12-79-2"] +12-79-2 = ["misskey-api/12-79-2", "12-79-0"] +12-79-0 = ["misskey-api/12-79-0", "12-77-1"] +12-77-1 = ["misskey-api/12-77-1", "12-77-0"] +12-77-0 = ["misskey-api/12-77-0", "12-75-0"] 12-75-0 = ["misskey-api/12-75-0", "12-71-0"] 12-71-0 = ["misskey-api/12-71-0", "12-70-0"] 12-70-0 = ["misskey-api/12-70-0", "12-69-0"] diff --git a/misskey-util/src/builder.rs b/misskey-util/src/builder.rs index 2e74becc..80f72a50 100644 --- a/misskey-util/src/builder.rs +++ b/misskey-util/src/builder.rs @@ -17,11 +17,16 @@ mod messaging; mod misc; mod note; mod page; -mod user; #[cfg(feature = "12-47-0")] mod channel; +#[cfg(feature = "12-79-0")] +mod gallery; + +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] +mod user; + pub use admin::{ AnnouncementUpdateBuilder, EmojiUpdateBuilder, MetaUpdateBuilder, ServerLogListBuilder, }; @@ -35,7 +40,6 @@ pub use me::{IntoUserFields, MeUpdateBuilder}; pub use messaging::MessagingMessageBuilder; pub use note::NoteBuilder; pub use page::{PageBuilder, PageUpdateBuilder}; -pub use user::UserListBuilder; #[cfg(feature = "12-47-0")] #[cfg_attr(docsrs, doc(cfg(feature = "12-47-0")))] @@ -44,3 +48,20 @@ pub use channel::{ChannelBuilder, ChannelUpdateBuilder}; #[cfg(feature = "12-27-0")] #[cfg_attr(docsrs, doc(cfg(feature = "12-27-0")))] pub use misc::NotificationBuilder; + +#[cfg(feature = "12-79-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] +pub use gallery::GalleryPostBuilder; + +#[cfg(feature = "12-79-2")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-79-2")))] +pub use gallery::GalleryPostUpdateBuilder; + +#[cfg(feature = "12-80-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] +pub use admin::{AdBuilder, AdUpdateBuilder}; + +// misskey-dev/misskey#7656 +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] +#[cfg_attr(docsrs, doc(cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))))] +pub use user::UserListBuilder; diff --git a/misskey-util/src/builder/admin.rs b/misskey-util/src/builder/admin.rs index 41115bd1..37745e9f 100644 --- a/misskey-util/src/builder/admin.rs +++ b/misskey-util/src/builder/admin.rs @@ -1,5 +1,9 @@ use crate::Error; +#[cfg(feature = "12-80-0")] +use chrono::{DateTime, Utc}; +#[cfg(feature = "12-80-0")] +use misskey_api::model::ad::{Ad, Place, Priority}; #[cfg(feature = "12-62-0")] use misskey_api::model::clip::Clip; #[cfg(feature = "12-9-0")] @@ -267,7 +271,19 @@ impl MetaUpdateBuilder { pub summaly_proxy: Url { summaly_proxy }; } + update_builder_string_option_field! { + #[doc_name = "DeepL auth key"] + #[cfg(feature = "12-88-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-88-0")))] + pub deepl_auth_key; + } + update_builder_bool_field! { + /// Sets whether or not DeepL is pro. + #[cfg(feature = "12-89-1")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-89-1")))] + pub deepl_is_pro; + /// Sets whether or not to enable the Twitter integration. pub enable_twitter_integration; } @@ -554,3 +570,260 @@ impl EmojiUpdateBuilder { Ok(()) } } + +#[cfg(feature = "12-80-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] +/// Builder for the [`build_ad`][`crate::ClientExt::build_ad`] method. +pub struct AdBuilder { + client: C, + request: endpoint::admin::ad::create::Request, +} + +#[cfg(feature = "12-80-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] +impl AdBuilder { + /// Creates a builder with the client. + pub fn new(client: C) -> Self { + let request = endpoint::admin::ad::create::Request { + url: String::default(), + memo: String::default(), + place: Place::default(), + priority: Priority::default(), + #[cfg(feature = "12-81-0")] + ratio: 1, + expires_at: DateTime::default(), + image_url: String::default(), + }; + AdBuilder { client, request } + } + + /// Gets the request object for reuse. + pub fn as_request(&self) -> &endpoint::admin::ad::create::Request { + &self.request + } + + /// Sets the url of the ad. + pub fn url(&mut self, url: impl Into) -> &mut Self { + self.request.url = url.into(); + self + } + + /// Sets the memo of the ad. + pub fn memo(&mut self, memo: impl Into) -> &mut Self { + self.request.memo = memo.into(); + self + } + + /// Sets the place of the ad. + pub fn place(&mut self, place: Place) -> &mut Self { + self.request.place = place; + self + } + + /// Sets the place of the ad to square. + pub fn square(&mut self) -> &mut Self { + self.place(Place::Square) + } + + /// Sets the place of the ad to horizontal. + pub fn horizontal(&mut self) -> &mut Self { + self.place(Place::Horizontal) + } + + #[cfg(feature = "12-81-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-81-0")))] + /// Sets the place of the ad to horizontal-big. + pub fn horizontal_big(&mut self) -> &mut Self { + self.place(Place::HorizontalBig) + } + + /// Sets the priority of the ad. + pub fn priority(&mut self, priority: Priority) -> &mut Self { + self.request.priority = priority; + self + } + + /// Sets the priority of the ad to high. + pub fn high_priority(&mut self) -> &mut Self { + self.priority(Priority::High) + } + + /// Sets the priority of the ad to middle. + pub fn middle_priority(&mut self) -> &mut Self { + self.priority(Priority::Middle) + } + + /// Sets the priority of the ad to low. + pub fn low_priority(&mut self) -> &mut Self { + self.priority(Priority::Low) + } + + #[cfg(feature = "12-81-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-81-0")))] + /// Sets the ratio of the ad. + pub fn ratio(&mut self, ratio: u64) -> &mut Self { + self.request.ratio = ratio; + self + } + + /// Sets the expiration date of the ad. + pub fn expires_at(&mut self, expires_at: impl Into>) -> &mut Self { + self.request.expires_at = expires_at.into(); + self + } + + /// Sets the image url of the ad. + pub fn image_url(&mut self, image_url: impl Into) -> &mut Self { + self.request.image_url = image_url.into(); + self + } +} + +#[cfg(feature = "12-80-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] +impl AdBuilder { + /// Creates the ad. + pub async fn create(&self) -> Result<(), Error> { + self.client + .request(&self.request) + .await + .map_err(Error::Client)? + .into_result()?; + Ok(()) + } +} + +#[cfg(feature = "12-80-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] +/// Builder for the [`update_ad`][`crate::ClientExt::update_ad`] method. +pub struct AdUpdateBuilder { + client: C, + request: endpoint::admin::ad::update::Request, +} + +#[cfg(feature = "12-80-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] +impl AdUpdateBuilder { + /// Creates a builder with the client. + pub fn new(client: C, ad: Ad) -> Self { + let Ad { + id, + expires_at, + place, + priority, + #[cfg(feature = "12-81-0")] + ratio, + url, + image_url, + memo, + .. + } = ad; + let request = endpoint::admin::ad::update::Request { + id, + url, + memo, + place, + priority, + #[cfg(feature = "12-81-0")] + ratio, + expires_at, + image_url, + }; + AdUpdateBuilder { client, request } + } + + /// Gets the request object for reuse. + pub fn as_request(&self) -> &endpoint::admin::ad::update::Request { + &self.request + } + + /// Sets the url of the ad. + pub fn url(&mut self, url: impl Into) -> &mut Self { + self.request.url = url.into(); + self + } + + /// Sets the memo of the ad. + pub fn memo(&mut self, memo: impl Into) -> &mut Self { + self.request.memo = memo.into(); + self + } + + /// Sets the place of the ad. + pub fn place(&mut self, place: Place) -> &mut Self { + self.request.place = place; + self + } + + /// Sets the place of the ad to square. + pub fn square(&mut self) -> &mut Self { + self.place(Place::Square) + } + + /// Sets the place of the ad to horizontal. + pub fn horizontal(&mut self) -> &mut Self { + self.place(Place::Horizontal) + } + + #[cfg(feature = "12-81-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-81-0")))] + /// Sets the place of the ad to horizontal-big. + pub fn horizontal_big(&mut self) -> &mut Self { + self.place(Place::HorizontalBig) + } + + /// Sets the priority of the ad. + pub fn priority(&mut self, priority: Priority) -> &mut Self { + self.request.priority = priority; + self + } + + /// Sets the priority of the ad to high. + pub fn high_priority(&mut self) -> &mut Self { + self.priority(Priority::High) + } + + /// Sets the priority of the ad to middle. + pub fn middle_priority(&mut self) -> &mut Self { + self.priority(Priority::Middle) + } + + /// Sets the priority of the ad to low. + pub fn low_priority(&mut self) -> &mut Self { + self.priority(Priority::Low) + } + + #[cfg(feature = "12-81-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-81-0")))] + /// Sets the ratio of the ad. + pub fn ratio(&mut self, ratio: u64) -> &mut Self { + self.request.ratio = ratio; + self + } + + /// Sets the expiration date of the ad. + pub fn expires_at(&mut self, expires_at: impl Into>) -> &mut Self { + self.request.expires_at = expires_at.into(); + self + } + + /// Sets the image url of the ad. + pub fn image_url(&mut self, image_url: impl Into) -> &mut Self { + self.request.image_url = image_url.into(); + self + } +} + +#[cfg(feature = "12-80-0")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] +impl AdUpdateBuilder { + /// Updates the ad. + pub async fn update(&self) -> Result<(), Error> { + self.client + .request(&self.request) + .await + .map_err(Error::Client)? + .into_result()?; + Ok(()) + } +} diff --git a/misskey-util/src/builder/drive.rs b/misskey-util/src/builder/drive.rs index ea98882d..7a68c6fb 100644 --- a/misskey-util/src/builder/drive.rs +++ b/misskey-util/src/builder/drive.rs @@ -270,6 +270,8 @@ impl DriveFileUpdateBuilder { folder_id: None, name: None, is_sensitive: None, + #[cfg(feature = "12-82-0")] + comment: None, }; DriveFileUpdateBuilder { client, request } } @@ -302,6 +304,14 @@ impl DriveFileUpdateBuilder { self.request.is_sensitive = Some(sensitive); self } + + #[cfg(feature = "12-82-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-82-0")))] + /// Sets the comment of the file. + pub fn comment(&mut self, comment: impl Into) -> &mut Self { + self.request.comment.replace(comment.into()); + self + } } impl DriveFileUpdateBuilder { diff --git a/misskey-util/src/builder/gallery.rs b/misskey-util/src/builder/gallery.rs new file mode 100644 index 00000000..b68e13a7 --- /dev/null +++ b/misskey-util/src/builder/gallery.rs @@ -0,0 +1,160 @@ +use crate::Error; + +use misskey_api::model::{drive::DriveFile, gallery::GalleryPost}; +use misskey_api::{endpoint, EntityRef}; +use misskey_core::Client; + +/// Builder for the [`build_gallery_post`][`crate::ClientExt::build_gallery_post`] method. +pub struct GalleryPostBuilder { + client: C, + request: endpoint::gallery::posts::create::Request, +} + +impl GalleryPostBuilder { + /// Creates a builder with the client. + pub fn new(client: C) -> Self { + let request = endpoint::gallery::posts::create::Request { + title: String::default(), + description: None, + file_ids: Vec::default(), + is_sensitive: None, + }; + GalleryPostBuilder { client, request } + } + + /// Gets the request object for reuse. + pub fn as_request(&self) -> &endpoint::gallery::posts::create::Request { + &self.request + } + + /// Sets the title of the post. + pub fn title(&mut self, title: impl Into) -> &mut Self { + self.request.title = title.into(); + self + } + + /// Sets the description of the post. + pub fn description(&mut self, description: impl Into) -> &mut Self { + self.request.description.replace(description.into()); + self + } + + /// Sets the files of the post. + pub fn files( + &mut self, + files: impl IntoIterator>, + ) -> &mut Self { + let ids = files.into_iter().map(|file| file.entity_ref()); + self.request.file_ids = ids.collect(); + self + } + + /// Adds a file to the post. + pub fn add_file(&mut self, file: impl EntityRef) -> &mut Self { + self.request.file_ids.push(file.entity_ref()); + self + } + + /// Sets whether the post contains NSFW content. + pub fn sensitive(&mut self, sensitive: bool) -> &mut Self { + self.request.is_sensitive = Some(sensitive); + self + } +} + +impl GalleryPostBuilder { + /// Creates the post. + pub async fn create(&self) -> Result> { + let post = self + .client + .request(&self.request) + .await + .map_err(Error::Client)? + .into_result()?; + Ok(post) + } +} + +#[cfg(feature = "12-79-2")] +#[cfg_attr(docsrs, doc(cfg(feature = "12-79-2")))] +/// Builder for the [`update_gallery_post`][`crate::ClientExt::update_gallery_post`] method. +pub struct GalleryPostUpdateBuilder { + client: C, + request: endpoint::gallery::posts::update::Request, +} + +#[cfg(feature = "12-79-2")] +impl GalleryPostUpdateBuilder { + /// Creates a builder with the client and the post you are going to update. + pub fn new(client: C, post: GalleryPost) -> Self { + let GalleryPost { + id, + title, + description, + file_ids, + is_sensitive, + .. + } = post; + let request = endpoint::gallery::posts::update::Request { + post_id: id, + title, + description, + file_ids, + is_sensitive: Some(is_sensitive), + }; + GalleryPostUpdateBuilder { client, request } + } + + /// Gets the request object for reuse. + pub fn as_request(&self) -> &endpoint::gallery::posts::update::Request { + &self.request + } + + /// Sets the title of the post. + pub fn title(&mut self, title: impl Into) -> &mut Self { + self.request.title = title.into(); + self + } + + /// Sets the description of the post. + pub fn description(&mut self, description: impl Into) -> &mut Self { + self.request.description.replace(description.into()); + self + } + + /// Sets the files of the post. + pub fn files( + &mut self, + files: impl IntoIterator>, + ) -> &mut Self { + let ids = files.into_iter().map(|file| file.entity_ref()); + self.request.file_ids = ids.collect(); + self + } + + /// Adds a file to the post. + pub fn add_file(&mut self, file: impl EntityRef) -> &mut Self { + self.request.file_ids.push(file.entity_ref()); + self + } + + /// Sets whether the post contains NSFW content. + pub fn sensitive(&mut self, sensitive: bool) -> &mut Self { + self.request.is_sensitive.replace(sensitive); + self + } +} + +#[cfg(feature = "12-79-2")] +impl GalleryPostUpdateBuilder { + /// Updates the post. + pub async fn update(&self) -> Result> { + let post = self + .client + .request(&self.request) + .await + .map_err(Error::Client)? + .into_result()?; + Ok(post) + } +} diff --git a/misskey-util/src/builder/me.rs b/misskey-util/src/builder/me.rs index 291a7096..b076e214 100644 --- a/misskey-util/src/builder/me.rs +++ b/misskey-util/src/builder/me.rs @@ -152,6 +152,11 @@ impl MeUpdateBuilder { #[cfg_attr(docsrs, doc(cfg(feature = "12-63-0")))] pub explorable { is_explorable }; + /// Sets whether to hide online status from other users. + #[cfg(feature = "12-77-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-77-0")))] + pub hide_online_status; + /// Sets whether this user requires a follow request from bots. pub require_follow_request_for_bot { careful_bot }; diff --git a/misskey-util/src/client.rs b/misskey-util/src/client.rs index b8530172..c47a17b1 100644 --- a/misskey-util/src/client.rs +++ b/misskey-util/src/client.rs @@ -4,13 +4,21 @@ use std::path::Path; #[cfg(feature = "12-9-0")] use crate::builder::EmojiUpdateBuilder; +#[cfg(feature = "12-79-0")] +use crate::builder::GalleryPostBuilder; +#[cfg(feature = "12-79-2")] +use crate::builder::GalleryPostUpdateBuilder; #[cfg(feature = "12-27-0")] use crate::builder::NotificationBuilder; +#[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] +use crate::builder::UserListBuilder; +#[cfg(feature = "12-80-0")] +use crate::builder::{AdBuilder, AdUpdateBuilder}; use crate::builder::{ AnnouncementUpdateBuilder, AntennaBuilder, AntennaUpdateBuilder, DriveFileBuilder, DriveFileListBuilder, DriveFileUpdateBuilder, DriveFileUrlBuilder, DriveFolderUpdateBuilder, MeUpdateBuilder, MessagingMessageBuilder, MetaUpdateBuilder, NoteBuilder, PageBuilder, - PageUpdateBuilder, ServerLogListBuilder, UserListBuilder, + PageUpdateBuilder, ServerLogListBuilder, }; #[cfg(feature = "12-47-0")] use crate::builder::{ChannelBuilder, ChannelUpdateBuilder}; @@ -25,8 +33,12 @@ use chrono::DateTime; use chrono::Utc; use futures::{future::BoxFuture, stream::TryStreamExt}; use mime::Mime; +#[cfg(feature = "12-80-0")] +use misskey_api::model::ad::Ad; #[cfg(feature = "12-47-0")] use misskey_api::model::channel::Channel; +#[cfg(feature = "12-79-0")] +use misskey_api::model::gallery::GalleryPost; #[cfg(feature = "12-67-0")] use misskey_api::model::registry::{RegistryKey, RegistryScope, RegistryValue}; use misskey_api::model::{ @@ -76,7 +88,7 @@ macro_rules! impl_timeline_method { /// # #[tokio::main] /// # async fn main() -> anyhow::Result<()> { /// # let client = misskey_test::test_client().await?; - /// # let user = client.users().list().try_next().await?.unwrap(); + /// # let user = client.me().await?; /// # #[cfg(feature = "12-47-0")] /// # let channel = client.create_channel("test").await?; /// # let list = client.create_user_list("test").await?; @@ -102,7 +114,7 @@ macro_rules! impl_timeline_method { /// # #[tokio::main] /// # async fn main() -> anyhow::Result<()> { /// # let client = misskey_test::test_client().await?; - /// # let user = client.users().list().try_next().await?.unwrap(); + /// # let user = client.me().await?; /// # #[cfg(feature = "12-47-0")] /// # let channel = client.create_channel("test").await?; /// # let list = client.create_user_list("test").await?; @@ -174,7 +186,7 @@ macro_rules! impl_timeline_method { /// # #[tokio::main] /// # async fn main() -> anyhow::Result<()> { /// # let client = misskey_test::test_client().await?; - /// # let user = client.users().list().try_next().await?.unwrap(); + /// # let user = client.me().await?; /// # #[cfg(feature = "12-47-0")] /// # let channel = client.create_channel("test").await?; /// # let list = client.create_user_list("test").await?; @@ -639,7 +651,8 @@ pub trait ClientExt: Client + Sync { /// /// [user_relation]: ClientExt::user_relation /// - /// ``` + #[cfg_attr(any(not(feature = "12-88-0"), feature = "12-89-0"), doc = "```")] + #[cfg_attr(all(feature = "12-88-0", not(feature = "12-89-0")), doc = "```ignore")] /// # use misskey_util::ClientExt; /// # use futures::stream::TryStreamExt; /// # #[tokio::main] @@ -665,7 +678,8 @@ pub trait ClientExt: Client + Sync { /// /// [user_relation]: ClientExt::user_relation /// - /// ``` + #[cfg_attr(any(not(feature = "12-88-0"), feature = "12-89-0"), doc = "```")] + #[cfg_attr(all(feature = "12-88-0", not(feature = "12-89-0")), doc = "```ignore")] /// # use misskey_util::ClientExt; /// # use futures::stream::TryStreamExt; /// # #[tokio::main] @@ -691,7 +705,8 @@ pub trait ClientExt: Client + Sync { /// /// [user_relation]: ClientExt::user_relation /// - /// ``` + #[cfg_attr(any(not(feature = "12-88-0"), feature = "12-89-0"), doc = "```")] + #[cfg_attr(all(feature = "12-88-0", not(feature = "12-89-0")), doc = "```ignore")] /// # use misskey_util::ClientExt; /// # use futures::stream::TryStreamExt; /// # #[tokio::main] @@ -717,7 +732,8 @@ pub trait ClientExt: Client + Sync { /// /// [user_relation]: ClientExt::user_relation /// - /// ``` + #[cfg_attr(any(not(feature = "12-88-0"), feature = "12-89-0"), doc = "```")] + #[cfg_attr(all(feature = "12-88-0", not(feature = "12-89-0")), doc = "```ignore")] /// # use misskey_util::ClientExt; /// # use futures::stream::TryStreamExt; /// # #[tokio::main] @@ -743,7 +759,8 @@ pub trait ClientExt: Client + Sync { /// /// [user_relation]: ClientExt::user_relation /// - /// ``` + #[cfg_attr(any(not(feature = "12-88-0"), feature = "12-89-0"), doc = "```")] + #[cfg_attr(all(feature = "12-88-0", not(feature = "12-89-0")), doc = "```ignore")] /// # use misskey_util::ClientExt; /// # use futures::stream::TryStreamExt; /// # #[tokio::main] @@ -766,7 +783,8 @@ pub trait ClientExt: Client + Sync { /// /// [user_relation]: ClientExt::user_relation /// - /// ``` + #[cfg_attr(any(not(feature = "12-88-0"), feature = "12-89-0"), doc = "```")] + #[cfg_attr(all(feature = "12-88-0", not(feature = "12-89-0")), doc = "```ignore")] /// # use misskey_util::ClientExt; /// # use futures::stream::TryStreamExt; /// # #[tokio::main] @@ -797,7 +815,8 @@ pub trait ClientExt: Client + Sync { /// /// [user_relation]: ClientExt::user_relation /// - /// ``` + #[cfg_attr(any(not(feature = "12-88-0"), feature = "12-89-0"), doc = "```")] + #[cfg_attr(all(feature = "12-88-0", not(feature = "12-89-0")), doc = "```ignore")] /// # use misskey_util::ClientExt; /// # use futures::stream::TryStreamExt; /// # #[tokio::main] @@ -911,11 +930,17 @@ pub trait ClientExt: Client + Sync { /// # Ok(()) /// # } /// ``` + // misskey-dev/misskey#7656 + #[cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))] + #[cfg_attr(docsrs, doc(cfg(any(not(feature = "12-88-0"), feature = "12-89-0"))))] fn users(&self) -> UserListBuilder<&Self> { UserListBuilder::new(self) } /// Lists the recommended users of the instance. + // misskey-dev/misskey#7656 + #[cfg(not(feature = "12-88-0"))] + #[cfg_attr(docsrs, doc(cfg(not(feature = "12-88-0"))))] fn recommended_users(&self) -> PagerStream> { let pager = OffsetPager::new(self, endpoint::users::recommendation::Request::default()); PagerStream::new(Box::pin(pager)) @@ -3250,6 +3275,192 @@ pub trait ClientExt: Client + Sync { } // }}} + // {{{ Gallery + /// Creates a gallery post with the given title and files. + #[cfg(feature = "12-79-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] + fn create_gallery_post( + &self, + title: impl Into, + files: impl IntoIterator>, + ) -> BoxFuture>> { + let title = title.into(); + let files: Vec> = files.into_iter().map(|file| file.entity_ref()).collect(); + Box::pin(async move { + self.build_gallery_post() + .title(title) + .files(files) + .create() + .await + }) + } + + /// Returns a builder for creating a gallery post. + /// + /// The returned builder provides methods to customize details of the post, + /// and you can chain them to create a post incrementally. + /// Finally, calling [`create`][builder_create] method will actually create a post. + /// See [`GalleryPostBuilder`] for the provided methods. + /// + /// [builder_create]: GalleryPostBuilder::create + #[cfg(feature = "12-79-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] + fn build_gallery_post(&self) -> GalleryPostBuilder<&Self> { + GalleryPostBuilder::new(self) + } + + /// Deletes the specified gallery post. + #[cfg(feature = "12-79-2")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-2")))] + fn delete_gallery_post( + &self, + post: impl EntityRef, + ) -> BoxFuture>> { + let post_id = post.entity_ref(); + Box::pin(async move { + self.request(endpoint::gallery::posts::delete::Request { post_id }) + .await + .map_err(Error::Client)? + .into_result()?; + Ok(()) + }) + } + + /// Gets the corresponding gallery post from the ID. + #[cfg(feature = "12-79-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] + fn get_gallery_post( + &self, + id: Id, + ) -> BoxFuture>> { + Box::pin(async move { + let post = self + .request(endpoint::gallery::posts::show::Request { post_id: id }) + .await + .map_err(Error::Client)? + .into_result()?; + Ok(post) + }) + } + + /// Updates the gallery post. + /// + /// This method actually returns a builder, namely [`GalleryPostUpdateBuilder`]. + /// You can chain the method calls to it corresponding to the fields you want to update. + /// Finally, calling [`update`][builder_update] method will actually perform the update. + /// See [`GalleryPostUpdateBuilder`] for the fields that can be updated. + /// + /// [builder_update]: GalleryPostUpdateBuilder::update + #[cfg(feature = "12-79-2")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-2")))] + fn update_gallery_post(&self, post: GalleryPost) -> GalleryPostUpdateBuilder<&Self> { + GalleryPostUpdateBuilder::new(self, post) + } + + /// Gives a like to the specified gallery post. + #[cfg(feature = "12-79-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] + fn like_gallery_post( + &self, + post: impl EntityRef, + ) -> BoxFuture>> { + let post_id = post.entity_ref(); + Box::pin(async move { + self.request(endpoint::gallery::posts::like::Request { post_id }) + .await + .map_err(Error::Client)? + .into_result()?; + Ok(()) + }) + } + + /// Removes a like from the specified gallery post. + #[cfg(feature = "12-79-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] + fn unlike_gallery_post( + &self, + post: impl EntityRef, + ) -> BoxFuture>> { + let post_id = post.entity_ref(); + Box::pin(async move { + self.request(endpoint::gallery::posts::unlike::Request { post_id }) + .await + .map_err(Error::Client)? + .into_result()?; + Ok(()) + }) + } + + /// Lists the gallery posts created by the user logged in with this client. + #[cfg(feature = "12-79-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] + fn gallery_posts(&self) -> PagerStream> { + let pager = BackwardPager::new(self, endpoint::i::gallery::posts::Request::default()); + PagerStream::new(Box::pin(pager)) + } + + /// Lists the gallery posts liked by the user logged in with this client. + #[cfg(feature = "12-79-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] + fn liked_gallery_posts(&self) -> PagerStream> { + let pager = BackwardPager::new(self, endpoint::i::gallery::likes::Request::default()) + .map_ok(|v| v.into_iter().map(|l| l.post).collect()); + PagerStream::new(Box::pin(pager)) + } + + /// Lists the gallery posts created by the specified user. + #[cfg(feature = "12-79-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] + fn user_gallery_posts( + &self, + user: impl EntityRef, + ) -> PagerStream> { + let pager = BackwardPager::new( + self, + endpoint::users::gallery::posts::Request::builder() + .user_id(user.entity_ref()) + .build(), + ); + PagerStream::new(Box::pin(pager)) + } + + /// Lists the gallery posts in the instance. + #[cfg(feature = "12-79-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] + fn all_gallery_posts(&self) -> PagerStream> { + let pager = BackwardPager::new(self, endpoint::gallery::posts::Request::default()); + PagerStream::new(Box::pin(pager)) + } + + /// Lists the featured gallery posts. + #[cfg(feature = "12-79-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] + fn featured_gallery_posts(&self) -> BoxFuture, Error>> { + Box::pin(async move { + let posts = self + .request(endpoint::gallery::featured::Request::default()) + .await + .map_err(Error::Client)? + .into_result()?; + Ok(posts) + }) + } + + /// Lists the popular gallery posts. + #[cfg(feature = "12-79-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-79-0")))] + fn popular_gallery_posts(&self) -> BoxFuture, Error>> { + Box::pin(async move { + let posts = self + .request(endpoint::gallery::popular::Request::default()) + .await + .map_err(Error::Client)? + .into_result()?; + Ok(posts) + }) + } + // }}} + // {{{ Admin /// Sets moderator privileges for the specified user. /// @@ -3666,6 +3877,80 @@ pub trait ClientExt: Client + Sync { ); PagerStream::new(Box::pin(pager)) } + + /// Creates an ad from the given urls. + /// + /// This operation may require moderator privileges. + #[cfg(feature = "12-80-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] + fn create_ad( + &self, + url: impl Into, + image_url: impl Into, + ) -> BoxFuture>> { + let url = url.into(); + let image_url = image_url.into(); + Box::pin(async move { self.build_ad().url(url).image_url(image_url).create().await }) + } + + /// Returns a builder for creating an ad. + /// + /// This method actually returns a builder, namely [`AdBuilder`]. + /// You can chain the method calls to it corresponding to the fields you want to update. + /// Finally, calling [`create`][builder_create] method will actually perform the update. + /// See [`AdBuilder`] for the fields that can be updated. + /// + /// This operation may require moderator privileges. + /// + /// [builder_create]: AdBuilder::create + #[cfg(feature = "12-80-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] + fn build_ad(&self) -> AdBuilder<&Self> { + AdBuilder::new(self) + } + + /// Deletes the specified ad. + /// + /// This operation may require moderator privileges. + #[cfg(feature = "12-80-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] + fn delete_ad(&self, ad: impl EntityRef) -> BoxFuture>> { + let ad_id = ad.entity_ref(); + Box::pin(async move { + self.request(endpoint::admin::ad::delete::Request { id: ad_id }) + .await + .map_err(Error::Client)? + .into_result()?; + Ok(()) + }) + } + + /// Updates the specified ad. + /// + /// This method actually returns a builder, namely [`AdUpdateBuilder`]. + /// You can chain the method calls to it corresponding to the fields you want to update. + /// Finally, calling [`update`][builder_update] method will actually perform the update. + /// See [`AdUpdateBuilder`] for the fields that can be updated. + /// + /// This operation may require moderator privileges. + /// + /// [builder_update]: AdUpdateBuilder::update + #[cfg(feature = "12-80-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] + fn update_ad(&self, ad: Ad) -> AdUpdateBuilder<&Self> { + AdUpdateBuilder::new(self, ad) + } + + /// Lists the ads in the instance. + /// + /// This operation may require moderator privileges. + /// Use [`meta`][`ClientExt::meta`] method if you want to get a list of ads from normal users, + #[cfg(feature = "12-80-0")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-80-0")))] + fn ads(&self) -> PagerStream> { + let pager = BackwardPager::new(self, endpoint::admin::ad::list::Request::default()); + PagerStream::new(Box::pin(pager)) + } // }}} // {{{ Miscellaneous @@ -3699,6 +3984,23 @@ pub trait ClientExt: Client + Sync { }) } + /// Marks the specified notification as read. + #[cfg(feature = "12-77-1")] + #[cfg_attr(docsrs, doc(cfg(feature = "12-77-1")))] + fn mark_notification_as_read( + &self, + notification: impl EntityRef, + ) -> BoxFuture>> { + let notification_id = notification.entity_ref(); + Box::pin(async move { + self.request(endpoint::notifications::read::Request { notification_id }) + .await + .map_err(Error::Client)? + .into_result()?; + Ok(()) + }) + } + /// Creates a notification with the given text. #[cfg(feature = "12-27-0")] #[cfg_attr(docsrs, doc(cfg(feature = "12-27-0")))] diff --git a/misskey/Cargo.toml b/misskey/Cargo.toml index c7317510..e1b4b529 100644 --- a/misskey/Cargo.toml +++ b/misskey/Cargo.toml @@ -15,6 +15,16 @@ categories = ["api-bindings", "web-programming::http-client", "web-programming:: [features] default = ["http-client", "websocket-client", "tokio-runtime", "aid"] +12-89-1 = ["misskey-api/12-89-1", "misskey-util/12-89-1"] +12-89-0 = ["misskey-api/12-89-0", "misskey-util/12-89-0"] +12-88-0 = ["misskey-api/12-88-0", "misskey-util/12-88-0"] +12-82-0 = ["misskey-api/12-82-0", "misskey-util/12-82-0"] +12-81-0 = ["misskey-api/12-81-0", "misskey-util/12-81-0"] +12-80-0 = ["misskey-api/12-80-0", "misskey-util/12-80-0"] +12-79-2 = ["misskey-api/12-79-2", "misskey-util/12-79-2"] +12-79-0 = ["misskey-api/12-79-0", "misskey-util/12-79-0"] +12-77-1 = ["misskey-api/12-77-1", "misskey-util/12-77-1"] +12-77-0 = ["misskey-api/12-77-0", "misskey-util/12-77-0"] 12-75-0 = ["misskey-api/12-75-0", "misskey-util/12-75-0"] 12-71-0 = ["misskey-api/12-71-0", "misskey-util/12-71-0"] 12-70-0 = ["misskey-api/12-70-0", "misskey-util/12-70-0"] diff --git a/misskey/src/lib.rs b/misskey/src/lib.rs index 2b92cd75..b9cd6f8b 100644 --- a/misskey/src/lib.rs +++ b/misskey/src/lib.rs @@ -102,7 +102,17 @@ //! //! | Feature | Supported Misskey versions (inclusive) | Tested Misskey version | //! | -------------------------- | -------------------------------------- | ---------------------- | -//! | `12-75-0` | v12.75.0 ~ v12.75.1 | v12.75.0 | +//! | `12-89-1` | v12.89.1 ~ v12.90.1 | v12.89.1 | +//! | `12-89-0` | v12.89.0 | v12.89.0 | +//! | `12-88-0` | v12.88.0 | v12.88.0 | +//! | `12-82-0` | v12.82.0 ~ v12.87.0 | v12.82.0 | +//! | `12-81-0` | v12.81.0 ~ v12.81.2 | v12.81.0 | +//! | `12-80-0` | v12.80.0 ~ v12.80.3 | v12.80.0 | +//! | `12-79-2` | v12.79.2 ~ v12.79.3 | v12.79.2 | +//! | `12-79-0` | v12.79.0 ~ v12.79.1 | v12.79.0 | +//! | `12-77-1` | v12.77.1 ~ v12.78.0 | v12.77.1 | +//! | `12-77-0` | v12.77.0 | v12.77.0 | +//! | `12-75-0` | v12.75.0 ~ v12.76.1 | v12.75.0 | //! | `12-71-0` | v12.71.0 ~ v12.74.1 | v12.71.0 | //! | `12-70-0` | v12.70.0 | v12.70.0 | //! | `12-69-0` | v12.69.0 | v12.69.0 |