Skip to content
This repository was archived by the owner on May 13, 2026. It is now read-only.

Commit 9f1778f

Browse files
feat(user-management): add resend invitation (#231)
1 parent 24f4cf0 commit 9f1778f

5 files changed

Lines changed: 530 additions & 1 deletion

File tree

src/user_management/operations.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ mod list_organization_memberships;
3636
mod list_sessions;
3737
mod list_users;
3838
mod reactivate_organization_membership;
39+
mod resend_invitation;
3940
mod reset_password;
4041
mod revoke_invitation;
4142
mod revoke_session;
@@ -81,6 +82,7 @@ pub use list_organization_memberships::*;
8182
pub use list_sessions::*;
8283
pub use list_users::*;
8384
pub use reactivate_organization_membership::*;
85+
pub use resend_invitation::*;
8486
pub use reset_password::*;
8587
pub use revoke_invitation::*;
8688
pub use revoke_session::*;
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
use async_trait::async_trait;
2+
use serde::Serialize;
3+
use thiserror::Error;
4+
5+
use crate::user_management::{Invitation, InvitationId, Locale, UserManagement};
6+
use crate::{ResponseExt, WorkOsError, WorkOsResult};
7+
8+
/// The parameters for [`ResendInvitation`].
9+
#[derive(Debug, Serialize)]
10+
pub struct ResendInvitationParams<'a> {
11+
/// The ID of the invitation.
12+
#[serde(skip_serializing)]
13+
pub invitation_id: &'a InvitationId,
14+
15+
/// The locale to use when rendering the invitation email.
16+
pub locale: Option<&'a Locale>,
17+
}
18+
19+
/// An error returned from [`ResendInvitation`].
20+
#[derive(Debug, Error)]
21+
pub enum ResendInvitationError {}
22+
23+
impl From<ResendInvitationError> for WorkOsError<ResendInvitationError> {
24+
fn from(err: ResendInvitationError) -> Self {
25+
Self::Operation(err)
26+
}
27+
}
28+
29+
/// [WorkOS Docs: Resend an invitation](https://workos.com/docs/reference/user-management/invitation/resend)
30+
#[async_trait]
31+
pub trait ResendInvitation {
32+
/// Resends an invitation email to the recipient. The invitation must be in a pending state.
33+
///
34+
/// [WorkOS Docs: Resend an invitation](https://workos.com/docs/reference/user-management/invitation/resend)
35+
///
36+
/// # Examples
37+
///
38+
/// ```
39+
/// # use workos::WorkOsResult;
40+
/// # use workos::user_management::*;
41+
/// use workos::{ApiKey, WorkOs};
42+
///
43+
/// # async fn run() -> WorkOsResult<(), ResendInvitationError> {
44+
/// let workos = WorkOs::new(&ApiKey::from("sk_example_123456789"));
45+
///
46+
/// let invitation = workos
47+
/// .user_management()
48+
/// .resend_invitation(&ResendInvitationParams {
49+
/// invitation_id: &InvitationId::from("invitation_01E4ZCR3C56J083X43JQXF3JK5"),
50+
/// locale: None,
51+
/// })
52+
/// .await?;
53+
/// # Ok(())
54+
/// # }
55+
/// ```
56+
async fn resend_invitation(
57+
&self,
58+
params: &ResendInvitationParams<'_>,
59+
) -> WorkOsResult<Invitation, ResendInvitationError>;
60+
}
61+
62+
#[async_trait]
63+
impl ResendInvitation for UserManagement<'_> {
64+
async fn resend_invitation(
65+
&self,
66+
params: &ResendInvitationParams<'_>,
67+
) -> WorkOsResult<Invitation, ResendInvitationError> {
68+
let url = self.workos.base_url().join(&format!(
69+
"/user_management/invitations/{id}/resend",
70+
id = params.invitation_id
71+
))?;
72+
let invitation = self
73+
.workos
74+
.client()
75+
.post(url)
76+
.bearer_auth(self.workos.key())
77+
.json(&params)
78+
.send()
79+
.await?
80+
.handle_unauthorized_or_generic_error()
81+
.await?
82+
.json::<Invitation>()
83+
.await?;
84+
85+
Ok(invitation)
86+
}
87+
}
88+
89+
#[cfg(test)]
90+
mod test {
91+
use serde_json::json;
92+
use tokio;
93+
94+
use crate::user_management::InvitationId;
95+
use crate::{ApiKey, WorkOs};
96+
97+
use super::*;
98+
99+
#[tokio::test]
100+
async fn it_calls_the_resend_invitation_endpoint() {
101+
let mut server = mockito::Server::new_async().await;
102+
103+
let workos = WorkOs::builder(&ApiKey::from("sk_example_123456789"))
104+
.base_url(&server.url())
105+
.unwrap()
106+
.build();
107+
108+
server
109+
.mock("POST", "/user_management/invitations/invitation_01E4ZCR3C56J083X43JQXF3JK5/resend")
110+
.match_header("Authorization", "Bearer sk_example_123456789")
111+
.with_status(200)
112+
.with_body(
113+
json!({
114+
"object": "invitation",
115+
"id": "invitation_01E4ZCR3C56J083X43JQXF3JK5",
116+
"email": "marcelina.davis@example.com",
117+
"state": "pending",
118+
"accepted_at": null,
119+
"revoked_at": null,
120+
"expires_at": "2021-07-01T19:07:33.155Z",
121+
"token": "Z1uX3RbwcIl5fIGJJJCXXisdI",
122+
"accept_invitation_url": "https://your-app.com/invite?invitation_token=Z1uX3RbwcIl5fIGJJJCXXisdI",
123+
"organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5",
124+
"inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3",
125+
"accepted_user_id": null,
126+
"created_at": "2021-06-25T19:07:33.155Z",
127+
"updated_at": "2021-06-25T19:07:33.155Z"
128+
})
129+
.to_string(),
130+
)
131+
.create_async()
132+
.await;
133+
134+
let invitation = workos
135+
.user_management()
136+
.resend_invitation(&ResendInvitationParams {
137+
invitation_id: &InvitationId::from("invitation_01E4ZCR3C56J083X43JQXF3JK5"),
138+
locale: None,
139+
})
140+
.await
141+
.unwrap();
142+
143+
assert_eq!(
144+
invitation.id,
145+
InvitationId::from("invitation_01E4ZCR3C56J083X43JQXF3JK5")
146+
);
147+
}
148+
}

src/user_management/operations/send_invitation.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use thiserror::Error;
44

55
use crate::organizations::OrganizationId;
66
use crate::roles::RoleSlug;
7-
use crate::user_management::{Invitation, UserId, UserManagement};
7+
use crate::user_management::{Invitation, Locale, UserId, UserManagement};
88
use crate::{ResponseExt, WorkOsError, WorkOsResult};
99

1010
/// The parameters for [`SendInvitation`].
@@ -26,6 +26,9 @@ pub struct SendInvitationParams<'a> {
2626

2727
/// The role that the recipient will receive when they join the organization in the invitation.
2828
pub role_slug: Option<&'a RoleSlug>,
29+
30+
/// The locale to use when rendering the invitation email.
31+
pub locale: Option<&'a Locale>,
2932
}
3033

3134
/// An error returned from [`SendInvitation`].
@@ -63,6 +66,7 @@ pub trait SendInvitation {
6366
/// expires_in_days: None,
6467
/// inviter_user_id: None,
6568
/// role_slug: None,
69+
/// locale: None,
6670
/// })
6771
/// .await?;
6872
/// # Ok(())
@@ -153,6 +157,7 @@ mod test {
153157
expires_in_days: None,
154158
inviter_user_id: None,
155159
role_slug: None,
160+
locale: None,
156161
})
157162
.await
158163
.unwrap();

src/user_management/types.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod email_verification;
99
mod identity;
1010
mod impersonator;
1111
mod invitation;
12+
mod locale;
1213
mod magic_auth;
1314
mod organization_membership;
1415
mod password;
@@ -32,6 +33,7 @@ pub use email_verification::*;
3233
pub use identity::*;
3334
pub use impersonator::*;
3435
pub use invitation::*;
36+
pub use locale::*;
3537
pub use magic_auth::*;
3638
pub use organization_membership::*;
3739
pub use password::*;

0 commit comments

Comments
 (0)