1use reqwest::Client;
5
6use crate::types::{FormsError, ResponseList};
7
8const FORMS_BASE: &str = "https://forms.googleapis.com/v1/forms";
9
10#[derive(Debug, Clone, Default)]
16pub struct ListResponsesParams {
17 pub page_size: Option<u32>,
19
20 pub page_token: Option<String>,
22
23 pub filter: Option<String>,
25}
26
27pub async fn list_responses(
35 client: &Client,
36 access_token: &str,
37 form_id: &str,
38 params: &ListResponsesParams,
39) -> Result<ResponseList, FormsError> {
40 let url = format!("{FORMS_BASE}/{form_id}/responses");
41
42 let mut query: Vec<(&str, String)> = Vec::new();
43
44 if let Some(size) = params.page_size {
45 query.push(("pageSize", size.to_string()));
46 }
47 if let Some(token) = ¶ms.page_token {
48 query.push(("pageToken", token.clone()));
49 }
50 if let Some(filter) = ¶ms.filter {
51 query.push(("filter", filter.clone()));
52 }
53
54 let resp = client
55 .get(&url)
56 .bearer_auth(access_token)
57 .query(&query)
58 .send()
59 .await?;
60
61 if !resp.status().is_success() {
62 let status = resp.status().as_u16();
63 let message = resp.text().await.unwrap_or_default();
64 return Err(FormsError::Api { status, message });
65 }
66
67 let list: ResponseList = resp.json().await?;
68 Ok(list)
69}
70
71#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn test_list_responses_url_construction() {
81 let form_id = "form_abc";
82 let url = format!("{FORMS_BASE}/{form_id}/responses");
83 assert_eq!(url, "https://forms.googleapis.com/v1/forms/form_abc/responses");
84 }
85
86 #[test]
87 fn test_list_responses_params_default() {
88 let params = ListResponsesParams::default();
89 assert!(params.page_size.is_none());
90 assert!(params.page_token.is_none());
91 assert!(params.filter.is_none());
92 }
93
94 #[test]
95 fn test_list_responses_params_with_values() {
96 let params = ListResponsesParams {
97 page_size: Some(100),
98 page_token: Some("tok_abc".to_string()),
99 filter: Some("timestamp > 2024-01-01T00:00:00Z".to_string()),
100 };
101 assert_eq!(params.page_size, Some(100));
102 assert_eq!(params.page_token.as_deref(), Some("tok_abc"));
103 assert!(params.filter.is_some());
104 }
105
106 #[test]
107 fn test_query_params_built_correctly() {
108 let params = ListResponsesParams {
110 page_size: Some(50),
111 page_token: Some("next_page".to_string()),
112 filter: None,
113 };
114
115 let mut query: Vec<(&str, String)> = Vec::new();
116 if let Some(size) = params.page_size {
117 query.push(("pageSize", size.to_string()));
118 }
119 if let Some(token) = ¶ms.page_token {
120 query.push(("pageToken", token.clone()));
121 }
122 if let Some(filter) = ¶ms.filter {
123 query.push(("filter", filter.clone()));
124 }
125
126 assert_eq!(query.len(), 2);
127 assert_eq!(query[0], ("pageSize", "50".to_string()));
128 assert_eq!(query[1], ("pageToken", "next_page".to_string()));
129 }
130
131 #[test]
132 fn test_query_params_empty_when_all_none() {
133 let params = ListResponsesParams::default();
134
135 let mut query: Vec<(&str, String)> = Vec::new();
136 if let Some(size) = params.page_size {
137 query.push(("pageSize", size.to_string()));
138 }
139 if let Some(token) = ¶ms.page_token {
140 query.push(("pageToken", token.clone()));
141 }
142 if let Some(filter) = ¶ms.filter {
143 query.push(("filter", filter.clone()));
144 }
145
146 assert!(query.is_empty());
147 }
148}