Skip to content

Commit 43be746

Browse files
atrakhConvex, Inc.
authored andcommitted
update SSO creation time types
GitOrigin-RevId: 36a7f13ef200234426533b610cf3dedb7fba0964
1 parent d6c75a4 commit 43be746

File tree

3 files changed

+141
-8
lines changed

3 files changed

+141
-8
lines changed

crates/workos_client/src/lib.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,25 @@ pub struct WorkOSOrganizationDomain {
142142
pub domain: String,
143143
}
144144

145+
#[derive(Debug, Deserialize, Serialize, Clone)]
146+
pub struct WorkOSOrganizationMembershipResponse {
147+
/// always "organization_membership"
148+
pub object: String,
149+
/// like "om_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E"
150+
pub id: String,
151+
pub user_id: String,
152+
pub organization_id: String,
153+
pub role: WorkOSOrganizationRole,
154+
pub status: String,
155+
pub created_at: String,
156+
pub updated_at: String,
157+
}
158+
159+
#[derive(Debug, Deserialize, Serialize, Clone)]
160+
pub struct WorkOSOrganizationRole {
161+
pub slug: String,
162+
}
163+
145164
#[async_trait]
146165
pub trait WorkOSClient: Send + Sync {
147166
async fn fetch_identities(&self, user_id: &str) -> anyhow::Result<Vec<WorkOSIdentity>>;
@@ -167,6 +186,14 @@ pub trait WorkOSClient: Send + Sync {
167186
domain: Option<&str>,
168187
) -> anyhow::Result<WorkOSOrganizationResponse>;
169188
async fn delete_organization(&self, organization_id: &str) -> anyhow::Result<()>;
189+
190+
// Organization membership methods
191+
async fn create_membership(
192+
&self,
193+
user_id: &str,
194+
organization_id: &str,
195+
role_slug: &str,
196+
) -> anyhow::Result<WorkOSOrganizationMembershipResponse>;
170197
}
171198

172199
// Separate trait for WorkOS Platform API operations (requires different API
@@ -274,6 +301,22 @@ where
274301
async fn delete_organization(&self, organization_id: &str) -> anyhow::Result<()> {
275302
delete_workos_organization(&self.api_key, organization_id, &*self.http_client).await
276303
}
304+
305+
async fn create_membership(
306+
&self,
307+
user_id: &str,
308+
organization_id: &str,
309+
role_slug: &str,
310+
) -> anyhow::Result<WorkOSOrganizationMembershipResponse> {
311+
create_workos_membership(
312+
&self.api_key,
313+
user_id,
314+
organization_id,
315+
role_slug,
316+
&*self.http_client,
317+
)
318+
.await
319+
}
277320
}
278321

279322
pub struct MockWorkOSClient;
@@ -396,6 +439,26 @@ impl WorkOSClient for MockWorkOSClient {
396439
async fn delete_organization(&self, _organization_id: &str) -> anyhow::Result<()> {
397440
Ok(())
398441
}
442+
443+
async fn create_membership(
444+
&self,
445+
user_id: &str,
446+
organization_id: &str,
447+
role_slug: &str,
448+
) -> anyhow::Result<WorkOSOrganizationMembershipResponse> {
449+
Ok(WorkOSOrganizationMembershipResponse {
450+
object: "organization_membership".to_string(),
451+
id: "om_mock123".to_string(),
452+
user_id: user_id.to_string(),
453+
organization_id: organization_id.to_string(),
454+
role: WorkOSOrganizationRole {
455+
slug: role_slug.to_string(),
456+
},
457+
status: "active".to_string(),
458+
created_at: "2024-01-01T00:00:00.000Z".to_string(),
459+
updated_at: "2024-01-01T00:00:00.000Z".to_string(),
460+
})
461+
}
399462
}
400463

401464
// Separate implementation for WorkOS Platform API
@@ -1153,6 +1216,72 @@ where
11531216
Ok(())
11541217
}
11551218

1219+
pub async fn create_workos_membership<F, E>(
1220+
api_key: &str,
1221+
user_id: &str,
1222+
organization_id: &str,
1223+
role_slug: &str,
1224+
http_client: &(impl Fn(HttpRequest) -> F + 'static + ?Sized),
1225+
) -> anyhow::Result<WorkOSOrganizationMembershipResponse>
1226+
where
1227+
F: Future<Output = Result<HttpResponse, E>>,
1228+
E: std::error::Error + 'static + Send + Sync,
1229+
{
1230+
#[derive(Serialize)]
1231+
struct CreateMembershipRequest {
1232+
user_id: String,
1233+
organization_id: String,
1234+
role_slug: String,
1235+
}
1236+
1237+
let request_body = CreateMembershipRequest {
1238+
user_id: user_id.to_string(),
1239+
organization_id: organization_id.to_string(),
1240+
role_slug: role_slug.to_string(),
1241+
};
1242+
1243+
let url = "https://api.workos.com/user_management/organization_memberships";
1244+
1245+
let request = http::Request::builder()
1246+
.uri(url)
1247+
.method(http::Method::POST)
1248+
.header(http::header::AUTHORIZATION, format!("Bearer {api_key}"))
1249+
.header(http::header::CONTENT_TYPE, APPLICATION_JSON)
1250+
.header(http::header::ACCEPT, APPLICATION_JSON)
1251+
.body(serde_json::to_vec(&request_body)?)?;
1252+
1253+
let response = timeout(WORKOS_API_TIMEOUT, http_client(request))
1254+
.await
1255+
.map_err(|_| {
1256+
anyhow::anyhow!(
1257+
"WorkOS API call timed out after {}s",
1258+
WORKOS_API_TIMEOUT.as_secs()
1259+
)
1260+
})?
1261+
.map_err(|e| anyhow::anyhow!("Could not create WorkOS membership: {}", e))?;
1262+
1263+
if !response.status().is_success() {
1264+
let status = response.status();
1265+
let response_body = response.into_body();
1266+
anyhow::bail!(format_workos_error(
1267+
"create membership",
1268+
status,
1269+
&response_body
1270+
));
1271+
}
1272+
1273+
let response_body = response.into_body();
1274+
let membership: WorkOSOrganizationMembershipResponse = serde_json::from_slice(&response_body)
1275+
.with_context(|| {
1276+
format!(
1277+
"Invalid WorkOS membership response: {}",
1278+
String::from_utf8_lossy(&response_body)
1279+
)
1280+
})?;
1281+
1282+
Ok(membership)
1283+
}
1284+
11561285
#[cfg(test)]
11571286
mod tests {
11581287
use super::WorkOSIdentity;

npm-packages/dashboard/dashboard-management-openapi.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5120,13 +5120,14 @@
51205120
"required": [
51215121
"id",
51225122
"name",
5123-
"createdAt",
5124-
"updatedAt",
5123+
"createTime",
5124+
"updateTime",
51255125
"domains"
51265126
],
51275127
"properties": {
5128-
"createdAt": {
5129-
"type": "string"
5128+
"createTime": {
5129+
"type": "integer",
5130+
"format": "int64"
51305131
},
51315132
"domains": {
51325133
"type": "array",
@@ -5140,8 +5141,9 @@
51405141
"name": {
51415142
"type": "string"
51425143
},
5143-
"updatedAt": {
5144-
"type": "string"
5144+
"updateTime": {
5145+
"type": "integer",
5146+
"format": "int64"
51455147
}
51465148
}
51475149
},

npm-packages/dashboard/src/generatedApi.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2234,11 +2234,13 @@ export interface components {
22342234
id: string;
22352235
};
22362236
SSOOrganizationResponse: {
2237-
createdAt: string;
2237+
/** Format: int64 */
2238+
createTime: number;
22382239
domains: components["schemas"]["SSOOrganizationDomain"][];
22392240
id: string;
22402241
name: string;
2241-
updatedAt: string;
2242+
/** Format: int64 */
2243+
updateTime: number;
22422244
};
22432245
/** @description ConvexAccessToken is our own internal notion of authorization.
22442246
* It is versioned.

0 commit comments

Comments
 (0)