Skip to main content

canvas_lms_api/resources/
poll.rs

1use crate::{error::Result, http::Requester, pagination::PageStream, params::wrap_params};
2use serde::{Deserialize, Serialize};
3use std::sync::Arc;
4
5// ---------------------------------------------------------------------------
6// Param structs
7// ---------------------------------------------------------------------------
8
9#[derive(Debug, Default, Clone, Serialize)]
10pub struct CreatePollParams {
11    pub question: String,
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub description: Option<String>,
14}
15
16#[derive(Debug, Default, Clone, Serialize)]
17pub struct PollChoiceParams {
18    pub text: String,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub is_correct: Option<bool>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub position: Option<u32>,
23}
24
25#[derive(Debug, Default, Clone, Serialize)]
26pub struct PollSessionParams {
27    pub course_id: u64,
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub course_section_id: Option<u64>,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub has_public_results: Option<bool>,
32}
33
34#[derive(Debug, Default, Clone, Serialize)]
35pub struct PollSubmissionParams {
36    pub poll_choice_id: u64,
37}
38
39// ---------------------------------------------------------------------------
40// Poll
41// ---------------------------------------------------------------------------
42
43/// A Canvas poll created by the current user.
44#[derive(Debug, Clone, Deserialize, Serialize, canvas_lms_api_derive::CanvasResource)]
45pub struct Poll {
46    pub id: u64,
47    pub question: Option<String>,
48    pub description: Option<String>,
49    pub total_results: Option<serde_json::Value>,
50
51    #[serde(skip)]
52    pub(crate) requester: Option<Arc<Requester>>,
53}
54
55impl Poll {
56    fn inject(&mut self, req: &Arc<Requester>) {
57        self.requester = Some(Arc::clone(req));
58    }
59
60    // -------------------------------------------------------------------------
61    // Poll-level
62    // -------------------------------------------------------------------------
63
64    /// Update this poll.
65    ///
66    /// # Canvas API
67    /// `PUT /api/v1/polls/:id`
68    pub async fn update(&self, params: CreatePollParams) -> Result<Poll> {
69        let form = wrap_params("polls[]", &params);
70        let val: serde_json::Value = self.req().put(&format!("polls/{}", self.id), &form).await?;
71        let mut poll: Poll = serde_json::from_value(val["polls"][0].clone())?;
72        poll.inject(self.req());
73        Ok(poll)
74    }
75
76    /// Delete this poll.
77    ///
78    /// # Canvas API
79    /// `DELETE /api/v1/polls/:id`
80    pub async fn delete(&self) -> Result<()> {
81        self.req().delete_void(&format!("polls/{}", self.id)).await
82    }
83
84    // -------------------------------------------------------------------------
85    // Poll choices
86    // -------------------------------------------------------------------------
87
88    /// Fetch a single poll choice.
89    ///
90    /// # Canvas API
91    /// `GET /api/v1/polls/:poll_id/poll_choices/:id`
92    pub async fn get_choice(&self, choice_id: u64) -> Result<PollChoice> {
93        let val: serde_json::Value = self
94            .req()
95            .get(
96                &format!("polls/{}/poll_choices/{}", self.id, choice_id),
97                &[],
98            )
99            .await?;
100        let mut choice: PollChoice = serde_json::from_value(val["poll_choices"][0].clone())?;
101        choice.requester = self.requester.clone();
102        Ok(choice)
103    }
104
105    /// Stream all choices for this poll.
106    ///
107    /// # Canvas API
108    /// `GET /api/v1/polls/:poll_id/poll_choices`
109    pub fn get_choices(&self) -> PageStream<PollChoice> {
110        let poll_id = self.id;
111        PageStream::new_with_injector(
112            Arc::clone(self.req()),
113            &format!("polls/{poll_id}/poll_choices"),
114            vec![],
115            |mut c: PollChoice, req| {
116                c.requester = Some(Arc::clone(&req));
117                c
118            },
119        )
120    }
121
122    /// Create a new choice for this poll.
123    ///
124    /// # Canvas API
125    /// `POST /api/v1/polls/:poll_id/poll_choices`
126    pub async fn create_choice(&self, params: PollChoiceParams) -> Result<PollChoice> {
127        let form = wrap_params("poll_choice[]", &params);
128        let val: serde_json::Value = self
129            .req()
130            .post(&format!("polls/{}/poll_choices", self.id), &form)
131            .await?;
132        let mut choice: PollChoice = serde_json::from_value(val["poll_choices"][0].clone())?;
133        choice.requester = self.requester.clone();
134        Ok(choice)
135    }
136
137    // -------------------------------------------------------------------------
138    // Poll sessions
139    // -------------------------------------------------------------------------
140
141    /// Fetch a single poll session.
142    ///
143    /// # Canvas API
144    /// `GET /api/v1/polls/:poll_id/poll_sessions/:id`
145    pub async fn get_session(&self, session_id: u64) -> Result<PollSession> {
146        let val: serde_json::Value = self
147            .req()
148            .get(
149                &format!("polls/{}/poll_sessions/{}", self.id, session_id),
150                &[],
151            )
152            .await?;
153        let mut session: PollSession = serde_json::from_value(val["poll_sessions"][0].clone())?;
154        session.requester = self.requester.clone();
155        Ok(session)
156    }
157
158    /// Stream all sessions for this poll.
159    ///
160    /// # Canvas API
161    /// `GET /api/v1/polls/:poll_id/poll_sessions`
162    pub fn get_sessions(&self) -> PageStream<PollSession> {
163        let poll_id = self.id;
164        PageStream::new_with_injector(
165            Arc::clone(self.req()),
166            &format!("polls/{poll_id}/poll_sessions"),
167            vec![],
168            |mut s: PollSession, req| {
169                s.requester = Some(Arc::clone(&req));
170                s
171            },
172        )
173    }
174
175    /// Create a new session for this poll.
176    ///
177    /// # Canvas API
178    /// `POST /api/v1/polls/:poll_id/poll_sessions`
179    pub async fn create_session(&self, params: PollSessionParams) -> Result<PollSession> {
180        let form = wrap_params("poll_session[]", &params);
181        let val: serde_json::Value = self
182            .req()
183            .post(&format!("polls/{}/poll_sessions", self.id), &form)
184            .await?;
185        let mut session: PollSession = serde_json::from_value(val["poll_sessions"][0].clone())?;
186        session.requester = self.requester.clone();
187        Ok(session)
188    }
189}
190
191// ---------------------------------------------------------------------------
192// PollChoice
193// ---------------------------------------------------------------------------
194
195/// A choice within a Canvas poll.
196#[derive(Debug, Clone, Deserialize, Serialize)]
197pub struct PollChoice {
198    pub id: u64,
199    pub poll_id: Option<u64>,
200    pub text: Option<String>,
201    pub is_correct: Option<bool>,
202    pub position: Option<u32>,
203
204    #[serde(skip)]
205    pub(crate) requester: Option<Arc<Requester>>,
206}
207
208impl PollChoice {
209    /// Update this poll choice.
210    ///
211    /// # Canvas API
212    /// `PUT /api/v1/polls/:poll_id/poll_choices/:id`
213    pub async fn update(&self, params: PollChoiceParams) -> Result<PollChoice> {
214        let poll_id = self.poll_id.unwrap_or_default();
215        let form = wrap_params("poll_choice[]", &params);
216        let val: serde_json::Value = self
217            .req()
218            .put(&format!("polls/{poll_id}/poll_choices/{}", self.id), &form)
219            .await?;
220        let mut choice: PollChoice = serde_json::from_value(val["poll_choices"][0].clone())?;
221        choice.requester = self.requester.clone();
222        Ok(choice)
223    }
224
225    /// Delete this poll choice.
226    ///
227    /// # Canvas API
228    /// `DELETE /api/v1/polls/:poll_id/poll_choices/:id`
229    pub async fn delete(&self) -> Result<()> {
230        let poll_id = self.poll_id.unwrap_or_default();
231        self.req()
232            .delete_void(&format!("polls/{poll_id}/poll_choices/{}", self.id))
233            .await
234    }
235
236    fn req(&self) -> &Arc<Requester> {
237        self.requester.as_ref().expect("requester not initialized")
238    }
239}
240
241// ---------------------------------------------------------------------------
242// PollSession
243// ---------------------------------------------------------------------------
244
245/// A session of a Canvas poll (tied to a specific course/section).
246#[derive(Debug, Clone, Deserialize, Serialize)]
247pub struct PollSession {
248    pub id: u64,
249    pub poll_id: Option<u64>,
250    pub course_id: Option<u64>,
251    pub course_section_id: Option<u64>,
252    pub is_published: Option<bool>,
253    pub has_public_results: Option<bool>,
254    pub results: Option<serde_json::Value>,
255
256    #[serde(skip)]
257    pub(crate) requester: Option<Arc<Requester>>,
258}
259
260impl PollSession {
261    fn req(&self) -> &Arc<Requester> {
262        self.requester.as_ref().expect("requester not initialized")
263    }
264
265    fn poll_id(&self) -> u64 {
266        self.poll_id.unwrap_or_default()
267    }
268
269    fn endpoint(&self) -> String {
270        format!("polls/{}/poll_sessions/{}", self.poll_id(), self.id)
271    }
272
273    /// Update this poll session.
274    ///
275    /// # Canvas API
276    /// `PUT /api/v1/polls/:poll_id/poll_sessions/:id`
277    pub async fn update(&self, params: PollSessionParams) -> Result<PollSession> {
278        let form = wrap_params("poll_session[]", &params);
279        let val: serde_json::Value = self.req().put(&self.endpoint(), &form).await?;
280        let mut session: PollSession = serde_json::from_value(val["poll_sessions"][0].clone())?;
281        session.requester = self.requester.clone();
282        Ok(session)
283    }
284
285    /// Delete this poll session.
286    ///
287    /// # Canvas API
288    /// `DELETE /api/v1/polls/:poll_id/poll_sessions/:id`
289    pub async fn delete(&self) -> Result<()> {
290        self.req().delete_void(&self.endpoint()).await
291    }
292
293    /// Open this poll session for responses.
294    ///
295    /// # Canvas API
296    /// `GET /api/v1/polls/:poll_id/poll_sessions/:id/open`
297    pub async fn open(&self) -> Result<PollSession> {
298        let val: serde_json::Value = self
299            .req()
300            .get(&format!("{}/open", self.endpoint()), &[])
301            .await?;
302        let mut session: PollSession = serde_json::from_value(val["poll_sessions"][0].clone())?;
303        session.requester = self.requester.clone();
304        Ok(session)
305    }
306
307    /// Close this poll session to responses.
308    ///
309    /// # Canvas API
310    /// `GET /api/v1/polls/:poll_id/poll_sessions/:id/close`
311    pub async fn close(&self) -> Result<PollSession> {
312        let val: serde_json::Value = self
313            .req()
314            .get(&format!("{}/close", self.endpoint()), &[])
315            .await?;
316        let mut session: PollSession = serde_json::from_value(val["poll_sessions"][0].clone())?;
317        session.requester = self.requester.clone();
318        Ok(session)
319    }
320
321    /// Fetch a single poll submission.
322    ///
323    /// # Canvas API
324    /// `GET /api/v1/polls/:poll_id/poll_sessions/:poll_session_id/poll_submissions/:id`
325    pub async fn get_submission(&self, submission_id: u64) -> Result<PollSubmission> {
326        let val: serde_json::Value = self
327            .req()
328            .get(
329                &format!("{}/poll_submissions/{submission_id}", self.endpoint()),
330                &[],
331            )
332            .await?;
333        Ok(serde_json::from_value(val["poll_submissions"][0].clone())?)
334    }
335
336    /// Create a poll submission for this session.
337    ///
338    /// # Canvas API
339    /// `POST /api/v1/polls/:poll_id/poll_sessions/:poll_session_id/poll_submissions`
340    pub async fn create_submission(&self, params: PollSubmissionParams) -> Result<PollSubmission> {
341        let form = wrap_params("poll_submissions[]", &params);
342        let val: serde_json::Value = self
343            .req()
344            .post(&format!("{}/poll_submissions", self.endpoint()), &form)
345            .await?;
346        Ok(serde_json::from_value(val["poll_submissions"][0].clone())?)
347    }
348}
349
350// ---------------------------------------------------------------------------
351// PollSubmission
352// ---------------------------------------------------------------------------
353
354/// A student's response to a poll session.
355#[derive(Debug, Clone, Deserialize, Serialize)]
356pub struct PollSubmission {
357    pub id: u64,
358    pub poll_session_id: Option<u64>,
359    pub poll_choice_id: Option<u64>,
360    pub user_id: Option<u64>,
361    pub created_at: Option<chrono::DateTime<chrono::Utc>>,
362}