diff --git a/lib/src/api/studies.rs b/lib/src/api/studies.rs index 9df3c08..117359b 100644 --- a/lib/src/api/studies.rs +++ b/lib/src/api/studies.rs @@ -1,12 +1,91 @@ +use futures::stream::StreamExt; + use crate::client::LichessApi; use crate::error::Result; +use crate::model::studies::create::{CreateStudyForm, CreateStudyResponse}; use crate::model::studies::import_pgn_into_study::{PostRequest, StudyImportPgnChapters}; +use crate::model::studies::*; impl LichessApi { + pub async fn create_study(&self, form: CreateStudyForm) -> Result { + self.get_single_model(create::PostRequest::new(form)).await + } + pub async fn import_pgn_into_study( &self, request: impl Into, ) -> Result { self.get_single_model(request.into()).await } + + pub async fn export_study_chapter_pgn( + &self, + study_id: &str, + chapter_id: &str, + query: export_chapter::GetQuery, + ) -> Result>> { + self.get_pgn(export_chapter::GetRequest::new(study_id, chapter_id, query)) + .await + } + + pub async fn export_study_pgn( + &self, + study_id: &str, + query: export_study::GetQuery, + ) -> Result>> { + self.get_pgn(export_study::GetRequest::new(study_id, query)) + .await + } + + pub async fn get_study_metadata( + &self, + request: impl Into, + ) -> Result<()> { + self.get_empty(request.into()).await + } + + pub async fn update_study_chapter_tags( + &self, + study_id: &str, + chapter_id: &str, + form: update_chapter_tags::UpdateChapterTagsForm, + ) -> Result<()> { + self.get_empty(update_chapter_tags::PostRequest::new( + study_id, chapter_id, form, + )) + .await + } + + pub async fn update_study_chapter_moves( + &self, + study_id: &str, + chapter_id: &str, + form: update_chapter_moves::UpdateChapterMovesForm, + ) -> Result<()> { + self.get_empty(update_chapter_moves::PostRequest::new( + study_id, chapter_id, form, + )) + .await + } + + pub async fn export_user_studies_pgn( + &self, + username: &str, + query: export_user_studies::GetQuery, + ) -> Result>> { + self.get_pgn(export_user_studies::GetRequest::new(username, query)) + .await + } + + pub async fn list_user_studies( + &self, + request: impl Into, + ) -> Result>> { + self.get_streamed_models(request.into()).await + } + + pub async fn delete_study_chapter(&self, study_id: &str, chapter_id: &str) -> Result<()> { + self.get_empty(delete_chapter::DeleteRequest::new(study_id, chapter_id)) + .await + } } diff --git a/lib/src/model/mod.rs b/lib/src/model/mod.rs index b6ca1bc..a6b59b0 100644 --- a/lib/src/model/mod.rs +++ b/lib/src/model/mod.rs @@ -125,6 +125,14 @@ where Self::create(path, query, None, domain, http::Method::GET) } + pub(crate) fn head( + path: impl Into, + query: impl Into>, + domain: impl Into>, + ) -> Self { + Self::create(path, query, None, domain, http::Method::HEAD) + } + pub(crate) fn post( path: impl Into, query: impl Into>, diff --git a/lib/src/model/studies/create.rs b/lib/src/model/studies/create.rs new file mode 100644 index 0000000..c27ce66 --- /dev/null +++ b/lib/src/model/studies/create.rs @@ -0,0 +1,52 @@ +use crate::model::{Body, Request}; +use serde::{Deserialize, Serialize}; +use serde_with::skip_serializing_none; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum Visibility { + Public, + Unlisted, + Private, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum StudyUserSelection { + Nobody, + Owner, + Contributor, + Member, + Everyone, +} + +#[skip_serializing_none] +#[derive(Clone, Debug, Serialize)] +pub struct CreateStudyForm { + pub name: String, + pub visibility: Visibility, + pub flair: Option, + pub computer: StudyUserSelection, + pub explorer: StudyUserSelection, + pub cloneable: StudyUserSelection, + pub shareable: StudyUserSelection, + pub chat: StudyUserSelection, + pub sticky: Option, + pub description: Option, +} + +#[derive(Default, Clone, Debug, Deserialize, Serialize)] +pub struct CreateStudyResponse { + pub id: String, +} + +#[derive(Default, Clone, Debug, Serialize)] +pub struct PostQuery; + +pub type PostRequest = Request; + +impl PostRequest { + pub fn new(form: CreateStudyForm) -> Self { + Self::post("/api/study", None, Body::Form(form), None) + } +} diff --git a/lib/src/model/studies/delete_chapter.rs b/lib/src/model/studies/delete_chapter.rs new file mode 100644 index 0000000..15bd672 --- /dev/null +++ b/lib/src/model/studies/delete_chapter.rs @@ -0,0 +1,18 @@ +use crate::model::Request; +use serde::Serialize; + +#[derive(Default, Clone, Debug, Serialize)] +pub struct DeleteQuery; + +pub type DeleteRequest = Request; + +impl DeleteRequest { + pub fn new(study_id: &str, chapter_id: &str) -> Self { + Self::delete( + format!("/api/study/{study_id}/{chapter_id}"), + None, + None, + None, + ) + } +} diff --git a/lib/src/model/studies/export_chapter.rs b/lib/src/model/studies/export_chapter.rs new file mode 100644 index 0000000..12b60b9 --- /dev/null +++ b/lib/src/model/studies/export_chapter.rs @@ -0,0 +1,21 @@ +use crate::model::Request; +use crate::model::studies::PgnExportQuery; +use serde::Serialize; + +#[derive(Default, Clone, Debug, Serialize)] +pub struct GetQuery { + #[serde(flatten)] + pub options: PgnExportQuery, +} + +pub type GetRequest = Request; + +impl GetRequest { + pub fn new(study_id: &str, chapter_id: &str, query: GetQuery) -> Self { + Self::get( + format!("/api/study/{study_id}/{chapter_id}.pgn"), + query, + None, + ) + } +} diff --git a/lib/src/model/studies/export_study.rs b/lib/src/model/studies/export_study.rs new file mode 100644 index 0000000..eeae75c --- /dev/null +++ b/lib/src/model/studies/export_study.rs @@ -0,0 +1,17 @@ +use crate::model::Request; +use crate::model::studies::PgnExportQuery; +use serde::Serialize; + +#[derive(Default, Clone, Debug, Serialize)] +pub struct GetQuery { + #[serde(flatten)] + pub options: PgnExportQuery, +} + +pub type GetRequest = Request; + +impl GetRequest { + pub fn new(study_id: &str, query: GetQuery) -> Self { + Self::get(format!("/api/study/{study_id}.pgn"), query, None) + } +} diff --git a/lib/src/model/studies/export_user_studies.rs b/lib/src/model/studies/export_user_studies.rs new file mode 100644 index 0000000..385b0a4 --- /dev/null +++ b/lib/src/model/studies/export_user_studies.rs @@ -0,0 +1,17 @@ +use crate::model::Request; +use crate::model::studies::PgnExportQuery; +use serde::Serialize; + +#[derive(Default, Clone, Debug, Serialize)] +pub struct GetQuery { + #[serde(flatten)] + pub options: PgnExportQuery, +} + +pub type GetRequest = Request; + +impl GetRequest { + pub fn new(username: &str, query: GetQuery) -> Self { + Self::get(format!("/api/study/by/{username}/export.pgn"), query, None) + } +} diff --git a/lib/src/model/studies/list_user_studies.rs b/lib/src/model/studies/list_user_studies.rs new file mode 100644 index 0000000..833acae --- /dev/null +++ b/lib/src/model/studies/list_user_studies.rs @@ -0,0 +1,19 @@ +use crate::model::Request; +use serde::Serialize; + +#[derive(Default, Clone, Debug, Serialize)] +pub struct GetQuery; + +pub type GetRequest = Request; + +impl GetRequest { + pub fn new(username: &str) -> Self { + Self::get(format!("/api/study/by/{username}"), None, None) + } +} + +impl> From for GetRequest { + fn from(username: S) -> Self { + Self::new(username.as_ref()) + } +} diff --git a/lib/src/model/studies/mod.rs b/lib/src/model/studies/mod.rs index dc04d7a..22d4339 100644 --- a/lib/src/model/studies/mod.rs +++ b/lib/src/model/studies/mod.rs @@ -1 +1,31 @@ +pub mod create; +pub mod delete_chapter; +pub mod export_chapter; +pub mod export_study; +pub mod export_user_studies; pub mod import_pgn_into_study; +pub mod list_user_studies; +pub mod study_metadata; +pub mod update_chapter_moves; +pub mod update_chapter_tags; + +use serde::{Deserialize, Serialize}; +use serde_with::skip_serializing_none; + +#[skip_serializing_none] +#[derive(Default, Clone, Debug, Serialize)] +pub struct PgnExportQuery { + pub clocks: Option, + pub comments: Option, + pub variations: Option, + pub orientation: Option, +} + +#[derive(Default, Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StudyMetadata { + pub id: String, + pub name: String, + pub created_at: i64, + pub updated_at: i64, +} diff --git a/lib/src/model/studies/study_metadata.rs b/lib/src/model/studies/study_metadata.rs new file mode 100644 index 0000000..b258ccd --- /dev/null +++ b/lib/src/model/studies/study_metadata.rs @@ -0,0 +1,19 @@ +use crate::model::Request; +use serde::Serialize; + +#[derive(Default, Clone, Debug, Serialize)] +pub struct HeadQuery; + +pub type HeadRequest = Request; + +impl HeadRequest { + pub fn new(study_id: &str) -> Self { + Self::head(format!("/api/study/{study_id}.pgn"), None, None) + } +} + +impl> From for HeadRequest { + fn from(study_id: S) -> Self { + Self::new(study_id.as_ref()) + } +} diff --git a/lib/src/model/studies/update_chapter_moves.rs b/lib/src/model/studies/update_chapter_moves.rs new file mode 100644 index 0000000..ffd3b8f --- /dev/null +++ b/lib/src/model/studies/update_chapter_moves.rs @@ -0,0 +1,23 @@ +use crate::model::{Body, Request}; +use serde::Serialize; + +#[derive(Default, Clone, Debug, Serialize)] +pub struct UpdateChapterMovesForm { + pub pgn: String, +} + +#[derive(Default, Clone, Debug, Serialize)] +pub struct PostQuery; + +pub type PostRequest = Request; + +impl PostRequest { + pub fn new(study_id: &str, chapter_id: &str, form: UpdateChapterMovesForm) -> Self { + Self::post( + format!("/api/study/{study_id}/{chapter_id}/moves"), + None, + Body::Form(form), + None, + ) + } +} diff --git a/lib/src/model/studies/update_chapter_tags.rs b/lib/src/model/studies/update_chapter_tags.rs new file mode 100644 index 0000000..9702d4f --- /dev/null +++ b/lib/src/model/studies/update_chapter_tags.rs @@ -0,0 +1,23 @@ +use crate::model::{Body, Request}; +use serde::Serialize; + +#[derive(Default, Clone, Debug, Serialize)] +pub struct UpdateChapterTagsForm { + pub pgn: String, +} + +#[derive(Default, Clone, Debug, Serialize)] +pub struct PostQuery; + +pub type PostRequest = Request; + +impl PostRequest { + pub fn new(study_id: &str, chapter_id: &str, form: UpdateChapterTagsForm) -> Self { + Self::post( + format!("/api/study/{study_id}/{chapter_id}/tags"), + None, + Body::Form(form), + None, + ) + } +} diff --git a/lib/tests/data/response/study_create.json b/lib/tests/data/response/study_create.json new file mode 100644 index 0000000..3ca1d48 --- /dev/null +++ b/lib/tests/data/response/study_create.json @@ -0,0 +1 @@ +{ "id": "9kze56XR" } diff --git a/lib/tests/data/response/study_metadata.json b/lib/tests/data/response/study_metadata.json new file mode 100644 index 0000000..96220ab --- /dev/null +++ b/lib/tests/data/response/study_metadata.json @@ -0,0 +1 @@ +{ "id": "WTvnkWAL", "name": "Guess the move", "createdAt": 1463756350225, "updatedAt": 1469965025205 } diff --git a/lib/tests/offline.rs b/lib/tests/offline.rs index 481521d..1e3528f 100644 --- a/lib/tests/offline.rs +++ b/lib/tests/offline.rs @@ -141,6 +141,12 @@ pub fn swiss_tournaments() { test_response_model::("swiss_result"); } +#[test] +pub fn studies() { + test_response_model::("study_create"); + test_response_model::("study_metadata"); +} + fn test_response_model(file_name: &str) { let path = format!("./tests/data/response/{}.json", file_name); test_model::(path);