algorithm_problem_client/codeforces/
client.rs1use super::*;
2
3use crate::util;
4use crate::Result;
5use serde::Deserialize;
6
7const BASE_URL: &str = "https://codeforces.com/api";
8
9pub struct CodeforcesClient;
10
11impl Default for CodeforcesClient {
12 fn default() -> Self {
13 Self
14 }
15}
16
17impl CodeforcesClient {
18 pub async fn fetch_problems(&self) -> Result<Vec<CodeforcesProblem>> {
19 let url = format!("{}/problemset.problems", BASE_URL);
20 util::get_json::<CodeforcesProblemResponse>(&url)
21 .await
22 .map(|response| response.result.problems)
23 }
24
25 pub async fn fetch_submissions(
26 &self,
27 user_id: &str,
28 from: u32,
29 count: u32,
30 ) -> Result<Vec<CodeforcesSubmission>> {
31 let url = format!(
32 "{base_url}/user.status?handle={user_id}&from={from}&count={count}",
33 base_url = BASE_URL,
34 user_id = user_id,
35 from = from,
36 count = count,
37 );
38 util::get_json::<SubmissionResult>(&url)
39 .await
40 .map(|response| {
41 response
42 .result
43 .into_iter()
44 .flat_map(|submission| submission.convert())
45 .collect()
46 })
47 }
48}
49
50#[derive(Deserialize)]
51struct CodeforcesProblemResponse {
52 result: CodeforcesProblemResponseResult,
53}
54
55#[derive(Deserialize)]
56struct CodeforcesProblemResponseResult {
57 problems: Vec<CodeforcesProblem>,
58}
59
60#[derive(Deserialize)]
61struct SubmissionResult {
62 result: Vec<Submission>,
63}
64#[derive(Deserialize)]
65struct Submission {
66 id: u64,
67 problem: CodeforcesProblem,
68 author: Author,
69
70 #[serde(rename = "programmingLanguage")]
71 language: String,
72
73 verdict: String,
74}
75#[derive(Deserialize)]
76struct Author {
77 members: Vec<Member>,
78}
79#[derive(Deserialize)]
80struct Member {
81 handle: String,
82}
83
84impl Submission {
85 fn convert(self) -> Option<CodeforcesSubmission> {
86 let id = self.id;
87 let contest_id = self.problem.contest_id;
88 let problem_index = self.problem.index;
89 let verdict = self.verdict;
90 let language = self.language;
91 let user_id = self.author.members.into_iter().next()?.handle;
92 Some(CodeforcesSubmission {
93 id,
94 contest_id,
95 problem_index,
96 user_id,
97 verdict,
98 language,
99 })
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use futures::executor::block_on;
107
108 #[test]
109 fn test_fetch_problems() {
110 let client = CodeforcesClient::default();
111 assert!(block_on(client.fetch_problems()).unwrap().len() > 0);
112 }
113
114 #[test]
115 fn test_fetch_submissions() {
116 let client = CodeforcesClient::default();
117 let submissions = block_on(client.fetch_submissions("kenkoooo", 1, 10)).unwrap();
118 assert_eq!(submissions.len(), 10);
119 }
120}