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