Skip to main content

canvas_lms_api/resources/
user.rs

1use crate::{
2    error::Result,
3    http::Requester,
4    pagination::PageStream,
5    resources::{
6        communication_channel::CommunicationChannel, course::Course, enrollment::Enrollment,
7    },
8};
9use chrono::{DateTime, Utc};
10use serde::{Deserialize, Serialize};
11use std::sync::Arc;
12
13/// A Canvas user.
14#[derive(Debug, Clone, Deserialize, Serialize, canvas_lms_api_derive::CanvasResource)]
15pub struct User {
16    pub id: u64,
17    pub name: Option<String>,
18    pub sortable_name: Option<String>,
19    pub short_name: Option<String>,
20    pub sis_user_id: Option<String>,
21    pub login_id: Option<String>,
22    pub email: Option<String>,
23    pub avatar_url: Option<String>,
24    pub locale: Option<String>,
25    pub last_login: Option<DateTime<Utc>>,
26    pub time_zone: Option<String>,
27    pub bio: Option<String>,
28
29    #[serde(skip)]
30    pub(crate) requester: Option<Arc<Requester>>,
31}
32
33impl User {
34    /// Stream all courses for this user.
35    ///
36    /// # Canvas API
37    /// `GET /api/v1/users/:id/courses`
38    pub fn get_courses(&self) -> PageStream<Course> {
39        PageStream::new(
40            Arc::clone(self.req()),
41            &format!("users/{}/courses", self.id),
42            vec![],
43        )
44    }
45
46    /// Stream all enrollments for this user.
47    ///
48    /// # Canvas API
49    /// `GET /api/v1/users/:id/enrollments`
50    pub fn get_enrollments(&self) -> PageStream<Enrollment> {
51        PageStream::new(
52            Arc::clone(self.req()),
53            &format!("users/{}/enrollments", self.id),
54            vec![],
55        )
56    }
57
58    /// Stream all communication channels for this user.
59    ///
60    /// # Canvas API
61    /// `GET /api/v1/users/:id/communication_channels`
62    pub fn get_communication_channels(&self) -> PageStream<CommunicationChannel> {
63        let user_id = self.id;
64        PageStream::new_with_injector(
65            Arc::clone(self.req()),
66            &format!("users/{user_id}/communication_channels"),
67            vec![],
68            |mut c: CommunicationChannel, req| {
69                c.requester = Some(Arc::clone(&req));
70                c
71            },
72        )
73    }
74
75    /// Create a communication channel for this user.
76    ///
77    /// `address` is the email address, phone number, etc.
78    /// `channel_type` is `"email"`, `"sms"`, `"push"`, etc.
79    ///
80    /// # Canvas API
81    /// `POST /api/v1/users/:id/communication_channels`
82    pub async fn create_communication_channel(
83        &self,
84        address: &str,
85        channel_type: &str,
86    ) -> Result<CommunicationChannel> {
87        let params = vec![
88            (
89                "communication_channel[address]".to_string(),
90                address.to_string(),
91            ),
92            (
93                "communication_channel[type]".to_string(),
94                channel_type.to_string(),
95            ),
96        ];
97        let mut channel: CommunicationChannel = self
98            .req()
99            .post(
100                &format!("users/{}/communication_channels", self.id),
101                &params,
102            )
103            .await?;
104        channel.requester = self.requester.clone();
105        Ok(channel)
106    }
107}
108
109/// The currently authenticated user (extends User with additional fields).
110#[derive(Debug, Clone, Deserialize, Serialize)]
111pub struct CurrentUser {
112    pub id: u64,
113    pub name: Option<String>,
114    pub sortable_name: Option<String>,
115    pub short_name: Option<String>,
116    pub sis_user_id: Option<String>,
117    pub login_id: Option<String>,
118    pub email: Option<String>,
119    pub avatar_url: Option<String>,
120    pub locale: Option<String>,
121    pub last_login: Option<DateTime<Utc>>,
122    pub time_zone: Option<String>,
123    pub bio: Option<String>,
124    pub effective_locale: Option<String>,
125}
126
127/// A user display stub (id + name only) used in nested contexts.
128#[derive(Debug, Clone, Deserialize, Serialize)]
129pub struct UserDisplay {
130    pub id: u64,
131    pub display_name: Option<String>,
132    pub avatar_image_url: Option<String>,
133    pub html_url: Option<String>,
134}
135
136/// Identifies a user by numeric ID or as the currently authenticated user.
137pub enum UserId {
138    Id(u64),
139    Current,
140}
141
142impl UserId {
143    pub(crate) fn to_path_segment(&self) -> String {
144        match self {
145            UserId::Id(id) => id.to_string(),
146            UserId::Current => "self".to_string(),
147        }
148    }
149}