From 2d3679e323b54434c992116a8df787410f85d02a Mon Sep 17 00:00:00 2001 From: Arran Ireland Date: Sat, 22 Aug 2026 14:44:38 +0100 Subject: [PATCH] bulk-pairings: add bulk pairing category endpoints Covers all 6 operations: list, create, show, cancel, export games, and manually start clocks. --- lib/src/api/bulk_pairings.rs | 49 +++++++++++++++++++++ lib/src/api/mod.rs | 1 + lib/src/model/bulk_pairings/create.rs | 34 ++++++++++++++ lib/src/model/bulk_pairings/games.rs | 26 +++++++++++ lib/src/model/bulk_pairings/list.rs | 13 ++++++ lib/src/model/bulk_pairings/mod.rs | 30 +++++++++++++ lib/src/model/bulk_pairings/remove.rs | 19 ++++++++ lib/src/model/bulk_pairings/show.rs | 19 ++++++++ lib/src/model/bulk_pairings/start_clocks.rs | 24 ++++++++++ lib/src/model/mod.rs | 1 + lib/src/model/simuls/mod.rs | 4 +- lib/tests/data/response/bulk_pairing.json | 15 +++++++ lib/tests/offline.rs | 5 +++ 13 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 lib/src/api/bulk_pairings.rs create mode 100644 lib/src/model/bulk_pairings/create.rs create mode 100644 lib/src/model/bulk_pairings/games.rs create mode 100644 lib/src/model/bulk_pairings/list.rs create mode 100644 lib/src/model/bulk_pairings/mod.rs create mode 100644 lib/src/model/bulk_pairings/remove.rs create mode 100644 lib/src/model/bulk_pairings/show.rs create mode 100644 lib/src/model/bulk_pairings/start_clocks.rs create mode 100644 lib/tests/data/response/bulk_pairing.json diff --git a/lib/src/api/bulk_pairings.rs b/lib/src/api/bulk_pairings.rs new file mode 100644 index 0000000..cee3d41 --- /dev/null +++ b/lib/src/api/bulk_pairings.rs @@ -0,0 +1,49 @@ +use futures::stream::StreamExt; + +use crate::client::LichessApi; +use crate::error::Result; +use crate::model::bulk_pairings::*; +use crate::model::games::GameJson; + +impl LichessApi { + pub async fn get_bulk_pairings(&self) -> Result> { + self.get_single_model(list::GetRequest::new()).await + } + + pub async fn create_bulk_pairing( + &self, + form: create::CreateBulkPairingForm, + ) -> Result { + self.get_single_model(create::PostRequest::new(form)).await + } + + pub async fn get_bulk_pairing( + &self, + request: impl Into, + ) -> Result { + self.get_single_model(request.into()).await + } + + pub async fn cancel_bulk_pairing( + &self, + request: impl Into, + ) -> Result { + self.get_ok(request.into()).await + } + + pub async fn export_bulk_pairing_games( + &self, + id: &str, + query: games::GetQuery, + ) -> Result>> { + self.get_streamed_models(games::GetRequest::new(id, query)) + .await + } + + pub async fn start_bulk_pairing_clocks( + &self, + request: impl Into, + ) -> Result { + self.get_ok(request.into()).await + } +} diff --git a/lib/src/api/mod.rs b/lib/src/api/mod.rs index 7ed74a9..7b661f9 100644 --- a/lib/src/api/mod.rs +++ b/lib/src/api/mod.rs @@ -3,6 +3,7 @@ pub mod analysis; pub mod arena_tournaments; pub mod board; pub mod bot; +pub mod bulk_pairings; pub mod challenges; pub mod external_engine; pub mod fide; diff --git a/lib/src/model/bulk_pairings/create.rs b/lib/src/model/bulk_pairings/create.rs new file mode 100644 index 0000000..6234e93 --- /dev/null +++ b/lib/src/model/bulk_pairings/create.rs @@ -0,0 +1,34 @@ +use crate::model::{Body, Days, Request, VariantKey}; +use serde::Serialize; +use serde_with::skip_serializing_none; + +#[skip_serializing_none] +#[derive(Default, Clone, Debug, Serialize)] +pub struct CreateBulkPairingForm { + pub players: String, + #[serde(rename = "clock.limit")] + pub clock_limit: Option, + #[serde(rename = "clock.increment")] + pub clock_increment: Option, + pub days: Option, + #[serde(rename = "pairAt")] + pub pair_at: Option, + #[serde(rename = "startClocksAt")] + pub start_clocks_at: Option, + pub rated: Option, + pub variant: Option, + pub fen: Option, + pub message: Option, + pub rules: Option, +} + +#[derive(Default, Clone, Debug, Serialize)] +pub struct PostQuery; + +pub type PostRequest = Request; + +impl PostRequest { + pub fn new(form: CreateBulkPairingForm) -> Self { + Self::post("/api/bulk-pairing", None, Body::Form(form), None) + } +} diff --git a/lib/src/model/bulk_pairings/games.rs b/lib/src/model/bulk_pairings/games.rs new file mode 100644 index 0000000..83b79e7 --- /dev/null +++ b/lib/src/model/bulk_pairings/games.rs @@ -0,0 +1,26 @@ +use crate::model::Request; +use serde::Serialize; +use serde_with::skip_serializing_none; + +#[skip_serializing_none] +#[derive(Default, Clone, Debug, Serialize)] +pub struct GetQuery { + pub moves: Option, + #[serde(rename = "pgnInJson")] + pub pgn_in_json: Option, + pub tags: Option, + pub clocks: Option, + pub evals: Option, + pub accuracy: Option, + pub opening: Option, + pub division: Option, + pub literate: Option, +} + +pub type GetRequest = Request; + +impl GetRequest { + pub fn new(id: &str, query: GetQuery) -> Self { + Self::get(format!("/api/bulk-pairing/{id}/games"), query, None) + } +} diff --git a/lib/src/model/bulk_pairings/list.rs b/lib/src/model/bulk_pairings/list.rs new file mode 100644 index 0000000..c02e66c --- /dev/null +++ b/lib/src/model/bulk_pairings/list.rs @@ -0,0 +1,13 @@ +use crate::model::Request; +use serde::Serialize; + +#[derive(Default, Clone, Debug, Serialize)] +pub struct GetQuery; + +pub type GetRequest = Request; + +impl GetRequest { + pub fn new() -> Self { + Self::get("/api/bulk-pairing", None, None) + } +} diff --git a/lib/src/model/bulk_pairings/mod.rs b/lib/src/model/bulk_pairings/mod.rs new file mode 100644 index 0000000..0a01af2 --- /dev/null +++ b/lib/src/model/bulk_pairings/mod.rs @@ -0,0 +1,30 @@ +pub mod create; +pub mod games; +pub mod list; +pub mod remove; +pub mod show; +pub mod start_clocks; + +use crate::model::{ArenaClock, VariantKey}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct BulkPairing { + pub id: String, + pub games: Vec, + pub variant: VariantKey, + pub clock: ArenaClock, + pub pair_at: i64, + pub paired_at: Option, + pub rated: bool, + pub start_clocks_at: i64, + pub scheduled_at: i64, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct BulkPairingGame { + pub id: String, + pub black: String, + pub white: String, +} diff --git a/lib/src/model/bulk_pairings/remove.rs b/lib/src/model/bulk_pairings/remove.rs new file mode 100644 index 0000000..8d54bad --- /dev/null +++ b/lib/src/model/bulk_pairings/remove.rs @@ -0,0 +1,19 @@ +use crate::model::Request; +use serde::Serialize; + +#[derive(Default, Clone, Debug, Serialize)] +pub struct DeleteQuery; + +pub type DeleteRequest = Request; + +impl DeleteRequest { + pub fn new(id: &str) -> Self { + Self::delete(format!("/api/bulk-pairing/{id}"), None, None, None) + } +} + +impl> From for DeleteRequest { + fn from(id: S) -> Self { + Self::new(id.as_ref()) + } +} diff --git a/lib/src/model/bulk_pairings/show.rs b/lib/src/model/bulk_pairings/show.rs new file mode 100644 index 0000000..4d7ead2 --- /dev/null +++ b/lib/src/model/bulk_pairings/show.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(id: &str) -> Self { + Self::get(format!("/api/bulk-pairing/{id}"), None, None) + } +} + +impl> From for GetRequest { + fn from(id: S) -> Self { + Self::new(id.as_ref()) + } +} diff --git a/lib/src/model/bulk_pairings/start_clocks.rs b/lib/src/model/bulk_pairings/start_clocks.rs new file mode 100644 index 0000000..e38729c --- /dev/null +++ b/lib/src/model/bulk_pairings/start_clocks.rs @@ -0,0 +1,24 @@ +use crate::model::Request; +use serde::Serialize; + +#[derive(Default, Clone, Debug, Serialize)] +pub struct PostQuery; + +pub type PostRequest = Request; + +impl PostRequest { + pub fn new(id: &str) -> Self { + Self::post( + format!("/api/bulk-pairing/{id}/start-clocks"), + None, + None, + None, + ) + } +} + +impl> From for PostRequest { + fn from(id: S) -> Self { + Self::new(id.as_ref()) + } +} diff --git a/lib/src/model/mod.rs b/lib/src/model/mod.rs index a6b59b0..fbcc2a6 100644 --- a/lib/src/model/mod.rs +++ b/lib/src/model/mod.rs @@ -3,6 +3,7 @@ pub mod analysis; pub mod arena_tournaments; pub mod board; pub mod bot; +pub mod bulk_pairings; pub mod challenges; pub mod external_engine; pub mod fide; diff --git a/lib/src/model/simuls/mod.rs b/lib/src/model/simuls/mod.rs index b1360d8..a59a027 100644 --- a/lib/src/model/simuls/mod.rs +++ b/lib/src/model/simuls/mod.rs @@ -17,8 +17,8 @@ pub struct Simul { pub is_created: bool, pub is_finished: bool, pub is_running: bool, - pub estimated_start_at: u64, - pub started_at: u64, + pub estimated_start_at: Option, + pub started_at: Option, pub finished_at: Option, #[serde(rename = "nbApplicants")] pub applicants: u32, diff --git a/lib/tests/data/response/bulk_pairing.json b/lib/tests/data/response/bulk_pairing.json new file mode 100644 index 0000000..249e3d3 --- /dev/null +++ b/lib/tests/data/response/bulk_pairing.json @@ -0,0 +1,15 @@ +{ + "id": "RVAcwgg7", + "games": [ + { "id": "NKop9IyD", "black": "lizen1", "white": "thibault" }, + { "id": "KT8374ut", "black": "lizen3", "white": "lizen2" }, + { "id": "wInQr8Sk", "black": "lizen5", "white": "lizen4" } + ], + "variant": "standard", + "clock": { "increment": 0, "limit": 300 }, + "pairAt": 1612289869919, + "pairedAt": null, + "rated": false, + "startClocksAt": 1612200422971, + "scheduledAt": 1612203514628 +} diff --git a/lib/tests/offline.rs b/lib/tests/offline.rs index 1e3528f..0aa3c15 100644 --- a/lib/tests/offline.rs +++ b/lib/tests/offline.rs @@ -141,6 +141,11 @@ pub fn swiss_tournaments() { test_response_model::("swiss_result"); } +#[test] +pub fn bulk_pairings() { + test_response_model::("bulk_pairing"); +} + #[test] pub fn studies() { test_response_model::("study_create");