gr/gitlab/
user.rs

1use crate::{
2    api_traits::{ApiOperation, UserInfo},
3    cmds::{project::Member, user::UserCliArgs},
4    error::GRError,
5    io::{HttpResponse, HttpRunner},
6    remote::{self, query},
7    Result,
8};
9
10use super::Gitlab;
11
12impl<R: HttpRunner<Response = HttpResponse>> UserInfo for Gitlab<R> {
13    fn get_auth_user(&self) -> Result<Member> {
14        let user = query::get::<_, (), _>(
15            &self.runner,
16            &self.base_current_user_url,
17            None,
18            self.headers(),
19            ApiOperation::Project,
20            |value| GitlabUserFields::from(value).into(),
21        )?;
22        Ok(user)
23    }
24
25    fn get(&self, args: &UserCliArgs) -> Result<Member> {
26        // https://docs.gitlab.com/ee/api/users.html#list-users
27        // In Gitlab, getting a user by username is done by using the list users
28        // API.
29        let url = format!("{}?username={}", self.base_users_url, args.username);
30        // Because we are getting a single user, we can limit the number of
31        // pages to just 1.
32        let list_args = remote::ListBodyArgs::builder()
33            .max_pages(1)
34            .get_args(args.get_args.clone())
35            .build()
36            .unwrap();
37        let user = query::paged::<_, Member>(
38            &self.runner,
39            &url,
40            Some(list_args),
41            self.headers(),
42            None,
43            ApiOperation::Project,
44            |value| GitlabUserFields::from(value).into(),
45        )?;
46        if user.is_empty() {
47            return Err(GRError::UserNotFound(args.username.clone()).into());
48        }
49        Ok(user[0].clone())
50    }
51}
52
53pub struct GitlabUserFields {
54    id: i64,
55    username: String,
56    name: String,
57}
58
59impl From<&serde_json::Value> for GitlabUserFields {
60    fn from(data: &serde_json::Value) -> Self {
61        GitlabUserFields {
62            id: data["id"].as_i64().unwrap(),
63            username: data["username"].as_str().unwrap().to_string(),
64            name: data["name"].as_str().unwrap().to_string(),
65        }
66    }
67}
68
69impl From<GitlabUserFields> for Member {
70    fn from(fields: GitlabUserFields) -> Self {
71        Member::builder()
72            .id(fields.id)
73            .name(fields.name)
74            .username(fields.username)
75            .build()
76            .unwrap()
77    }
78}
79
80#[cfg(test)]
81mod test {
82    use crate::{
83        api_traits::ApiOperation,
84        error, setup_client,
85        test::utils::{default_gitlab, ContractType, ResponseContracts},
86    };
87
88    use super::*;
89
90    #[test]
91    fn test_get_user_id() {
92        let contracts = ResponseContracts::new(ContractType::Gitlab).add_contract(
93            200,
94            "get_user_info.json",
95            None,
96        );
97        let (client, gitlab) = setup_client!(contracts, default_gitlab(), dyn UserInfo);
98        let user = gitlab.get_auth_user().unwrap();
99        assert_eq!(123456, user.id);
100        assert_eq!("jordilin", user.username);
101        assert_eq!("https://gitlab.com/api/v4/user", *client.url(),);
102        assert_eq!("1234", client.headers().get("PRIVATE-TOKEN").unwrap());
103        assert_eq!(Some(ApiOperation::Project), *client.api_operation.borrow());
104    }
105
106    #[test]
107    fn test_get_user_by_username_ok() {
108        let contracts = ResponseContracts::new(ContractType::Gitlab).add_contract(
109            200,
110            "get_user_by_username.json",
111            None,
112        );
113        let (client, gitlab) = setup_client!(contracts, default_gitlab(), dyn UserInfo);
114        let username = "tomsawyer";
115        let args = UserCliArgs::builder()
116            .username(username.to_string())
117            .get_args(remote::GetRemoteCliArgs::builder().build().unwrap())
118            .build()
119            .unwrap();
120        let user = gitlab.get(&args).unwrap();
121        assert_eq!(12345, user.id);
122        assert_eq!("tomsawyer", user.username);
123        assert_eq!(
124            "https://gitlab.com/api/v4/users?username=tomsawyer",
125            *client.url(),
126        );
127        assert_eq!("1234", client.headers().get("PRIVATE-TOKEN").unwrap());
128        assert_eq!(Some(ApiOperation::Project), *client.api_operation.borrow());
129    }
130
131    #[test]
132    fn test_username_not_found_is_error() {
133        let contracts = ResponseContracts::new(ContractType::Gitlab).add_body::<String>(
134            200,
135            Some("[]".to_string()),
136            None,
137        );
138        let (_, gitlab) = setup_client!(contracts, default_gitlab(), dyn UserInfo);
139        let username = "notfound";
140        let args = UserCliArgs::builder()
141            .username(username.to_string())
142            .get_args(remote::GetRemoteCliArgs::builder().build().unwrap())
143            .build()
144            .unwrap();
145        let result = gitlab.get(&args);
146        match result {
147            Err(err) => match err.downcast_ref::<error::GRError>() {
148                Some(error::GRError::UserNotFound(_)) => {}
149                _ => panic!("Expected user not found error"),
150            },
151            Ok(_) => panic!("Expected user not found error"),
152        }
153    }
154}