mz_frontegg_client/client/
user.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! This module implements the client's functions for interacting with the
11//! Frontegg users API.
12
13use reqwest::Method;
14use serde::{Deserialize, Serialize};
15
16use crate::client::Client;
17use crate::client::role::Role;
18use crate::error::Error;
19use crate::parse::{Empty, Paginated};
20
21const USERS_PATH: [&str; 5] = ["frontegg", "identity", "resources", "users", "v3"];
22const CREATE_USERS_PATH: [&str; 5] = ["frontegg", "identity", "resources", "users", "v2"];
23const REMOVE_USERS_PATH: [&str; 5] = ["frontegg", "identity", "resources", "users", "v1"];
24
25/// Representation of all the mandatory fields for a user creation request.
26#[derive(Serialize)]
27#[serde(rename_all = "camelCase")]
28pub struct CreateUserRequest {
29    /// Email for the user
30    pub email: String,
31    /// Name for the user
32    pub name: String,
33    /// Provider for the user.
34    /// E.g.: `local`
35    pub provider: String,
36    /// Roles the user will have in the organization.
37    pub role_ids: Vec<uuid::Uuid>,
38}
39
40/// Representation of the only required field to request a user removal.
41#[derive(Serialize)]
42#[serde(rename_all = "camelCase")]
43pub struct RemoveUserRequest {
44    /// The identifier of the user to remove. Equals to the `id` inside the [User] struct.
45    pub user_id: String,
46}
47
48/// A structure that represents a user in Frontegg.
49#[derive(Debug, Deserialize)]
50#[serde(rename_all = "camelCase")]
51pub struct User {
52    /// The ID of the user.
53    pub id: String,
54    /// The name of the user.
55    pub name: String,
56    /// The email for the user.
57    pub email: String,
58    /// Unique identifier for the subject; Currently it is the user ID
59    pub sub: String,
60}
61
62/// Representation of a succesfully response from a user creation.
63#[derive(Debug, Serialize, Deserialize)]
64#[serde(rename_all = "camelCase")]
65pub struct CreatedUser {
66    /// The ID of the user.
67    pub id: String,
68    /// The email for the user.
69    pub email: String,
70    /// The name of the user.
71    pub name: String,
72    /// The profile picture URL of the user.
73    pub profile_picture_url: String,
74    /// Indicates if the user verified their email.
75    pub verified: Option<bool>,
76    /// Metadata about the user; it is usually empty.
77    pub metadata: Option<String>,
78    /// The roles to which this user belongs.
79    pub roles: Vec<Role>,
80}
81
82impl Client {
83    /// Lists all existing users.
84    pub async fn list_users(&self) -> Result<Vec<User>, Error> {
85        let mut users = vec![];
86        let mut page = 0;
87
88        loop {
89            let req = self.build_request(Method::GET, USERS_PATH);
90            let req = req.query(&[("_limit", "50"), ("_offset", &*page.to_string())]);
91            let res: Paginated<User> = self.send_request(req).await?;
92            for user in res.items {
93                users.push(user);
94            }
95            page += 1;
96            if page >= res.metadata.total_pages {
97                break;
98            }
99        }
100        Ok(users)
101    }
102
103    /// Creates a new user in the authenticated organization.
104    pub async fn create_user(&self, new_user: CreateUserRequest) -> Result<CreatedUser, Error> {
105        let req = self.build_request(Method::POST, CREATE_USERS_PATH);
106        let req = req.json(&new_user);
107        let created_user = self.send_request(req).await?;
108        Ok(created_user)
109    }
110
111    /// Removes a user from the authenticated organization.
112    pub async fn remove_user(&self, remove_user: RemoveUserRequest) -> Result<(), Error> {
113        let mut user_path = REMOVE_USERS_PATH.to_vec();
114        user_path.push(remove_user.user_id.as_str());
115
116        let req = self.build_request(Method::DELETE, user_path);
117
118        let req = req.json(&remove_user);
119        self.send_request::<Empty>(req).await?;
120
121        Ok(())
122    }
123}