lichess_api/model/broadcasts/
create_tournament.rs1use crate::model::broadcasts::BroadcastTiebreakExtendedCode;
2use crate::model::{Body, Request};
3use serde::Serialize;
4use serde::ser::SerializeMap;
5use serde_with::skip_serializing_none;
6
7#[skip_serializing_none]
8#[derive(Default, Clone, Debug, Serialize)]
9pub struct CreateBroadcastTournamentForm {
10 pub name: String,
11 #[serde(rename = "info.format")]
12 pub info_format: Option<String>,
13 #[serde(rename = "info.tc")]
14 pub info_tc: Option<String>,
15 #[serde(rename = "info.fideTC")]
16 pub info_fide_tc: Option<String>,
17 #[serde(rename = "info.timeZone")]
18 pub info_time_zone: Option<String>,
19 #[serde(rename = "info.location")]
20 pub info_location: Option<String>,
21 #[serde(rename = "info.players")]
22 pub info_players: Option<String>,
23 #[serde(rename = "info.website")]
24 pub info_website: Option<String>,
25 #[serde(rename = "info.standings")]
26 pub info_standings: Option<String>,
27 #[serde(rename = "info.regulations")]
28 pub info_regulations: Option<String>,
29 pub markdown: Option<String>,
30 #[serde(rename = "showScores")]
31 pub show_scores: Option<bool>,
32 #[serde(rename = "showRatingDiffs")]
33 pub show_rating_diffs: Option<bool>,
34 #[serde(rename = "teamTable")]
35 pub team_table: Option<bool>,
36 pub visibility: Option<String>,
37 pub players: Option<String>,
38 pub teams: Option<String>,
39 pub tier: Option<i32>,
40 pub tiebreaks: Option<Vec<BroadcastTiebreakExtendedCode>>,
41 #[serde(flatten)]
42 pub grouping: Option<BroadcastGrouping>,
43}
44
45#[derive(Default, Clone, Debug)]
52pub struct BroadcastGrouping {
53 pub info_name: Option<String>,
54 pub info_tours: Option<String>,
56 pub score_groups: Option<Vec<String>>,
58}
59
60impl Serialize for BroadcastGrouping {
61 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
62 where
63 S: serde::Serializer,
64 {
65 let score_groups_len = self.score_groups.as_ref().map_or(0, Vec::len);
66 let len = self.info_name.is_some() as usize
67 + self.info_tours.is_some() as usize
68 + score_groups_len;
69 let mut map = serializer.serialize_map(Some(len))?;
70 if let Some(name) = &self.info_name {
71 map.serialize_entry("grouping.info.name", name)?;
72 }
73 if let Some(tours) = &self.info_tours {
74 map.serialize_entry("grouping.info.tours", tours)?;
75 }
76 if let Some(score_groups) = &self.score_groups {
77 for (i, group) in score_groups.iter().enumerate() {
78 map.serialize_entry(&format!("grouping.scoreGroups[{i}]"), group)?;
79 }
80 }
81 map.end()
82 }
83}
84
85#[derive(Default, Clone, Debug, Serialize)]
86pub struct PostQuery;
87
88pub type PostRequest = Request<PostQuery, CreateBroadcastTournamentForm>;
89
90impl PostRequest {
91 pub fn new(form: CreateBroadcastTournamentForm) -> Self {
92 Self::post("/broadcast/new", None, Body::Form(form), None)
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn grouping_serializes_score_groups_as_indexed_keys() {
102 let form = CreateBroadcastTournamentForm {
103 name: "Sinquefield Cup".to_string(),
104 grouping: Some(BroadcastGrouping {
105 info_name: Some("Chess Olympiad | Open".to_string()),
106 info_tours: Some("wYigbpXq\nM5YHvpOX".to_string()),
107 score_groups: Some(vec![
108 "wYigbpXq,M5YHvpOX".to_string(),
109 "q6ezoCXP".to_string(),
110 ]),
111 }),
112 ..Default::default()
113 };
114
115 let encoded = serde_urlencoded::to_string(&form).unwrap();
116
117 assert_eq!(
118 encoded,
119 "name=Sinquefield+Cup\
120 &grouping.info.name=Chess+Olympiad+%7C+Open\
121 &grouping.info.tours=wYigbpXq%0AM5YHvpOX\
122 &grouping.scoreGroups%5B0%5D=wYigbpXq%2CM5YHvpOX\
123 &grouping.scoreGroups%5B1%5D=q6ezoCXP"
124 );
125 }
126
127 #[test]
128 fn grouping_omitted_when_none() {
129 let form = CreateBroadcastTournamentForm {
130 name: "Sinquefield Cup".to_string(),
131 ..Default::default()
132 };
133
134 let encoded = serde_urlencoded::to_string(&form).unwrap();
135
136 assert_eq!(encoded, "name=Sinquefield+Cup");
137 }
138}