redmine_api/api/
my_account.rs

1//! My Account Rest API Endpoint definitions
2//!
3//! [Redmine Documentation](https://www.redmine.org/projects/redmine/wiki/Rest_MyAccount)
4//!
5//! - [x] my account endpoint
6
7use derive_builder::Builder;
8use reqwest::Method;
9use std::borrow::Cow;
10
11use crate::api::custom_fields::CustomFieldEssentialsWithValue;
12use crate::api::{Endpoint, NoPagination, ReturnsJsonResponse};
13
14/// a type for my account to use as an API return type
15///
16/// alternatively you can use your own type limited to the fields you need
17#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
18pub struct MyAccount {
19    /// numeric id
20    pub id: u64,
21    /// login name
22    pub login: String,
23    /// is this user an admin
24    pub admin: bool,
25    /// user's firstname
26    pub firstname: String,
27    /// user's lastname
28    pub lastname: String,
29    /// primary email of the user
30    #[serde(default, skip_serializing_if = "Option::is_none")]
31    pub mail: Option<String>,
32    /// The time when this user was created
33    #[serde(
34        serialize_with = "crate::api::serialize_rfc3339",
35        deserialize_with = "crate::api::deserialize_rfc3339"
36    )]
37    pub created_on: time::OffsetDateTime,
38    /// the time when this user last logged in
39    #[serde(
40        serialize_with = "crate::api::serialize_optional_rfc3339",
41        deserialize_with = "crate::api::deserialize_optional_rfc3339"
42    )]
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub last_login_on: Option<time::OffsetDateTime>,
45    /// the user's API key
46    pub api_key: String,
47    /// custom fields with values
48    #[serde(default, skip_serializing_if = "Option::is_none")]
49    pub custom_fields: Option<Vec<CustomFieldEssentialsWithValue>>,
50}
51
52/// The endpoint to retrieve the current user's my account settings/data
53#[derive(Debug, Clone, Builder)]
54#[builder(setter(strip_option))]
55pub struct GetMyAccount {}
56
57impl ReturnsJsonResponse for GetMyAccount {}
58impl NoPagination for GetMyAccount {}
59
60impl GetMyAccount {
61    /// Create a builder for the endpoint.
62    #[must_use]
63    pub fn builder() -> GetMyAccountBuilder {
64        GetMyAccountBuilder::default()
65    }
66}
67
68impl Endpoint for GetMyAccount {
69    fn method(&self) -> Method {
70        Method::GET
71    }
72
73    fn endpoint(&self) -> Cow<'static, str> {
74        "my/account.json".into()
75    }
76}
77
78#[cfg(test)]
79mod test {
80    use super::*;
81    use crate::api::users::UserWrapper;
82    use pretty_assertions::assert_eq;
83    use std::error::Error;
84    use tracing_test::traced_test;
85
86    #[traced_test]
87    #[test]
88    fn test_get_my_account() -> Result<(), Box<dyn Error>> {
89        dotenvy::dotenv()?;
90        let redmine = crate::api::Redmine::from_env(
91            reqwest::blocking::Client::builder()
92                .use_rustls_tls()
93                .build()?,
94        )?;
95        let endpoint = GetMyAccount::builder().build()?;
96        redmine.json_response_body::<_, UserWrapper<MyAccount>>(&endpoint)?;
97        Ok(())
98    }
99
100    /// this tests if any of the results contain a field we are not deserializing
101    ///
102    /// this will only catch fields we missed if they are part of the response but
103    /// it is better than nothing
104    #[traced_test]
105    #[test]
106    fn test_completeness_my_account_type() -> Result<(), Box<dyn Error>> {
107        dotenvy::dotenv()?;
108        let redmine = crate::api::Redmine::from_env(
109            reqwest::blocking::Client::builder()
110                .use_rustls_tls()
111                .build()?,
112        )?;
113        let endpoint = GetMyAccount::builder().build()?;
114        let UserWrapper { user: value } =
115            redmine.json_response_body::<_, UserWrapper<serde_json::Value>>(&endpoint)?;
116        let o: MyAccount = serde_json::from_value(value.clone())?;
117        let reserialized = serde_json::to_value(o)?;
118        assert_eq!(value, reserialized);
119        Ok(())
120    }
121}