1use super::{OrganizationPlugin, handlers, types};
3use crate::endpoint::{definition, error_response, validation};
4use alibi_core::endpoint::{
5 EndpointCall, EndpointDefinition, EndpointInput, EndpointResponse, ServerEndpoint,
6};
7use alibi_core::entity::{AuthOrganization, AuthUser};
8use alibi_core::session::SessionRequest;
9use alibi_core::types::{Team, TeamMember};
10use alibi_core::utils::json::JsValue;
11use alibi_core::wire::InvitationView;
12use alibi_core::{AuthContext, AuthError, AuthResponse, AuthResult, AuthSchema, HttpMethod};
13use std::collections::HashMap;
14
15pub(super) fn definitions() -> Vec<EndpointDefinition> {
16 vec![
17 definition(
18 "listOrganizations",
19 "listOrganizations",
20 Some("/organization/list"),
21 HttpMethod::Get,
22 ),
23 definition(
24 "updateOrganization",
25 "updateOrganization",
26 Some("/organization/update"),
27 HttpMethod::Post,
28 ),
29 definition(
30 "getOrganization",
31 "getOrganization",
32 Some("/organization/get-organization"),
33 HttpMethod::Get,
34 ),
35 definition(
36 "getFullOrganization",
37 "getFullOrganization",
38 Some("/organization/get-full-organization"),
39 HttpMethod::Get,
40 ),
41 definition(
42 "checkOrganizationSlug",
43 "checkOrganizationSlug",
44 Some("/organization/check-slug"),
45 HttpMethod::Post,
46 ),
47 definition(
48 "setActiveOrganization",
49 "setActiveOrganization",
50 Some("/organization/set-active"),
51 HttpMethod::Post,
52 ),
53 definition(
54 "leaveOrganization",
55 "leaveOrganization",
56 Some("/organization/leave"),
57 HttpMethod::Post,
58 ),
59 definition(
60 "inviteMember",
61 "inviteMember",
62 Some("/organization/invite-member"),
63 HttpMethod::Post,
64 ),
65 definition(
66 "getInvitation",
67 "getInvitation",
68 Some("/organization/get-invitation"),
69 HttpMethod::Get,
70 ),
71 definition(
72 "listInvitations",
73 "listInvitations",
74 Some("/organization/list-invitations"),
75 HttpMethod::Get,
76 ),
77 definition(
78 "listUserInvitations",
79 "listUserInvitations",
80 Some("/organization/list-user-invitations"),
81 HttpMethod::Get,
82 ),
83 definition(
84 "acceptInvitation",
85 "acceptInvitation",
86 Some("/organization/accept-invitation"),
87 HttpMethod::Post,
88 ),
89 definition(
90 "rejectInvitation",
91 "rejectInvitation",
92 Some("/organization/reject-invitation"),
93 HttpMethod::Post,
94 ),
95 definition(
96 "cancelInvitation",
97 "cancelInvitation",
98 Some("/organization/cancel-invitation"),
99 HttpMethod::Post,
100 ),
101 definition(
102 "getActiveMember",
103 "getActiveMember",
104 Some("/organization/get-active-member"),
105 HttpMethod::Get,
106 ),
107 definition(
108 "getActiveMemberRole",
109 "getActiveMemberRole",
110 Some("/organization/get-active-member-role"),
111 HttpMethod::Get,
112 ),
113 definition(
114 "listMembers",
115 "listMembers",
116 Some("/organization/list-members"),
117 HttpMethod::Get,
118 ),
119 definition(
120 "updateMemberRole",
121 "updateMemberRole",
122 Some("/organization/update-member-role"),
123 HttpMethod::Post,
124 ),
125 definition(
126 "hasPermission",
127 "hasPermission",
128 Some("/organization/has-permission"),
129 HttpMethod::Post,
130 ),
131 definition(
132 "createTeam",
133 "createTeam",
134 Some("/organization/create-team"),
135 HttpMethod::Post,
136 ),
137 definition(
138 "updateTeam",
139 "updateTeam",
140 Some("/organization/update-team"),
141 HttpMethod::Post,
142 ),
143 definition(
144 "removeTeam",
145 "removeTeam",
146 Some("/organization/remove-team"),
147 HttpMethod::Post,
148 ),
149 definition(
150 "setActiveTeam",
151 "setActiveTeam",
152 Some("/organization/set-active-team"),
153 HttpMethod::Post,
154 ),
155 definition(
156 "addTeamMember",
157 "addTeamMember",
158 Some("/organization/add-team-member"),
159 HttpMethod::Post,
160 ),
161 definition(
162 "removeTeamMember",
163 "removeTeamMember",
164 Some("/organization/remove-team-member"),
165 HttpMethod::Post,
166 ),
167 definition(
168 "listTeams",
169 "listTeams",
170 Some("/organization/list-teams"),
171 HttpMethod::Get,
172 ),
173 definition(
174 "listUserTeams",
175 "listUserTeams",
176 Some("/organization/list-user-teams"),
177 HttpMethod::Get,
178 ),
179 definition(
180 "listTeamMembers",
181 "listTeamMembers",
182 Some("/organization/list-team-members"),
183 HttpMethod::Get,
184 ),
185 definition(
186 "createOrganizationRole",
187 "createOrganizationRole",
188 Some("/organization/create-role"),
189 HttpMethod::Post,
190 ),
191 definition(
192 "updateOrganizationRole",
193 "updateOrganizationRole",
194 Some("/organization/update-role"),
195 HttpMethod::Post,
196 ),
197 definition(
198 "deleteOrganizationRole",
199 "deleteOrganizationRole",
200 Some("/organization/delete-role"),
201 HttpMethod::Post,
202 ),
203 definition(
204 "getOrganizationRole",
205 "getOrganizationRole",
206 Some("/organization/get-role"),
207 HttpMethod::Get,
208 ),
209 definition(
210 "listOrganizationRoles",
211 "listOrganizationRoles",
212 Some("/organization/list-roles"),
213 HttpMethod::Get,
214 ),
215 ]
216}
217
218pub(super) fn validate(call: &EndpointCall) -> AuthResult<EndpointInput> {
219 match call.operation_id() {
221 "updateOrganization" => {
222 _ = handlers::org_input::update_value(call.body()).map_err(error_response)?;
223 }
224 "getOrganization" => {
225 let _: types::GetOrganizationQuery = call
226 .query_as()
227 .map_err(|error| validation(error.to_string()))?;
228 }
229 "getFullOrganization" => {
230 let _: types::GetFullOrganizationQuery = call
231 .query_as()
232 .map_err(|error| validation(error.to_string()))?;
233 }
234 "checkOrganizationSlug" => {
235 let _: types::CheckSlugRequest = call
236 .body_as()
237 .map_err(|error| validation(error.to_string()))?;
238 }
239 "setActiveOrganization" => {
240 _ = handlers::org_input::set_active_value(call.body()).map_err(error_response)?;
241 }
242 "leaveOrganization" => {
243 let _: types::LeaveOrganizationRequest = call
244 .body_as()
245 .map_err(|error| validation(error.to_string()))?;
246 }
247 "inviteMember" => {
248 _ = handlers::org_input::invitation_create_value(call.body())
249 .map_err(error_response)?;
250 }
251 "getInvitation" => {
252 let _: types::GetInvitationQuery = call
253 .query_as()
254 .map_err(|error| validation(error.to_string()))?;
255 }
256 "listInvitations" => {
257 let _: types::ListInvitationsQuery = call
258 .query_as()
259 .map_err(|error| validation(error.to_string()))?;
260 }
261 "listUserInvitations" => {
262 let _: types::ListUserInvitationsQuery = call
263 .query_as()
264 .map_err(|error| validation(error.to_string()))?;
265 }
266 "acceptInvitation" => {
267 let _: types::AcceptInvitationRequest = call
268 .body_as()
269 .map_err(|error| validation(error.to_string()))?;
270 }
271 "rejectInvitation" => {
272 let _: types::RejectInvitationRequest = call
273 .body_as()
274 .map_err(|error| validation(error.to_string()))?;
275 }
276 "cancelInvitation" => {
277 let _: types::CancelInvitationRequest = call
278 .body_as()
279 .map_err(|error| validation(error.to_string()))?;
280 }
281 "getActiveMemberRole" => {
282 let _: types::GetActiveMemberRoleQuery = call
283 .query_as()
284 .map_err(|error| validation(error.to_string()))?;
285 }
286 "listMembers" => {
287 let _: types::ListMembersQuery = call
288 .query_as()
289 .map_err(|error| validation(error.to_string()))?;
290 }
291 "updateMemberRole" => {
292 _ = handlers::org_input::member_role_update_value(call.body())
293 .map_err(error_response)?;
294 }
295 "hasPermission" => {
296 let _: types::HasPermissionRequest = call
297 .body_as()
298 .map_err(|error| validation(error.to_string()))?;
299 }
300 "createTeam" => {
301 let _: types::CreateTeamRequest = call
302 .body_as()
303 .map_err(|error| validation(error.to_string()))?;
304 }
305 "updateTeam" => {
306 let _: types::UpdateTeamRequest = call
307 .body_as()
308 .map_err(|error| validation(error.to_string()))?;
309 }
310 "removeTeam" => {
311 let _: types::RemoveTeamRequest = call
312 .body_as()
313 .map_err(|error| validation(error.to_string()))?;
314 }
315 "setActiveTeam" => {
316 let _: types::SetActiveTeamRequest = call
317 .body_as()
318 .map_err(|error| validation(error.to_string()))?;
319 }
320 "addTeamMember" => {
321 let _: types::TeamMemberRequest = call
322 .body_as()
323 .map_err(|error| validation(error.to_string()))?;
324 }
325 "removeTeamMember" => {
326 let _: types::TeamMemberRequest = call
327 .body_as()
328 .map_err(|error| validation(error.to_string()))?;
329 }
330 "listTeams" => {
331 let _: types::TeamQuery = call
332 .query_as()
333 .map_err(|error| validation(error.to_string()))?;
334 }
335 "listUserTeams" => {
336 let _: types::TeamQuery = call
337 .query_as()
338 .map_err(|error| validation(error.to_string()))?;
339 }
340 "listTeamMembers" => {
341 let _: types::TeamQuery = call
342 .query_as()
343 .map_err(|error| validation(error.to_string()))?;
344 }
345 "createOrganizationRole" => {
346 let _: types::CreateRoleRequest = call
347 .body_as()
348 .map_err(|error| validation(error.to_string()))?;
349 }
350 "updateOrganizationRole" => {
351 let _: types::UpdateRoleRequest = call
352 .body_as()
353 .map_err(|error| validation(error.to_string()))?;
354 }
355 "deleteOrganizationRole" => {
356 let _: types::RoleQuery = call
357 .body_as()
358 .map_err(|error| validation(error.to_string()))?;
359 }
360 "getOrganizationRole" => {
361 let _: types::RoleQuery = call
362 .query_as()
363 .map_err(|error| validation(error.to_string()))?;
364 }
365 "listOrganizationRoles" => {
366 let _: types::RoleQuery = call
367 .query_as()
368 .map_err(|error| validation(error.to_string()))?;
369 }
370 _ => {}
371 }
372 Ok(EndpointInput {
373 body: call.body().cloned(),
374 query: call.query().cloned(),
375 })
376}
377
378impl OrganizationPlugin {
379 #[must_use]
383 pub fn list_organizations_endpoint() -> ServerEndpoint<Vec<types::OrganizationResponse>> {
384 ServerEndpoint::new("organization", "listOrganizations")
385 }
386 pub fn update_endpoint(
390 input: &types::UpdateOrganizationRequest,
391 ) -> AuthResult<ServerEndpoint<Option<types::CreatedOrganizationResponse>>> {
392 ServerEndpoint::new("organization", "updateOrganization").with_body(input)
393 }
394 pub fn get_organization_endpoint(
398 input: &types::GetOrganizationQuery,
399 ) -> AuthResult<ServerEndpoint<Option<types::OrganizationResponse>>> {
400 ServerEndpoint::new("organization", "getOrganization").with_query(input)
401 }
402 pub fn get_full_organization_endpoint(
406 input: &types::GetFullOrganizationQuery,
407 ) -> AuthResult<
408 ServerEndpoint<
409 Option<types::FullOrganizationResponse<types::OrganizationResponse, InvitationView>>,
410 >,
411 > {
412 ServerEndpoint::new("organization", "getFullOrganization").with_query(input)
413 }
414 pub fn check_slug_endpoint(
418 input: &types::CheckSlugRequest,
419 ) -> AuthResult<ServerEndpoint<types::CheckSlugResponse>> {
420 ServerEndpoint::new("organization", "checkOrganizationSlug").with_body(input)
421 }
422 pub fn set_active_endpoint(
426 input: &types::SetActiveOrganizationRequest,
427 ) -> AuthResult<ServerEndpoint<Option<types::OrganizationResponse>>> {
428 ServerEndpoint::new("organization", "setActiveOrganization").with_body(input)
429 }
430 pub fn leave_endpoint(
434 input: &types::LeaveOrganizationRequest,
435 ) -> AuthResult<ServerEndpoint<types::SuccessResponse>> {
436 ServerEndpoint::new("organization", "leaveOrganization").with_body(input)
437 }
438 pub fn invite_member_endpoint(
442 input: &types::InviteMemberRequest,
443 ) -> AuthResult<ServerEndpoint<InvitationView>> {
444 ServerEndpoint::new("organization", "inviteMember").with_body(input)
445 }
446 pub fn get_invitation_endpoint(
450 input: &types::GetInvitationQuery,
451 ) -> AuthResult<ServerEndpoint<types::GetInvitationResponse<InvitationView>>> {
452 ServerEndpoint::new("organization", "getInvitation").with_query(input)
453 }
454 pub fn list_invitations_endpoint(
458 input: &types::ListInvitationsQuery,
459 ) -> AuthResult<ServerEndpoint<Vec<InvitationView>>> {
460 ServerEndpoint::new("organization", "listInvitations").with_query(input)
461 }
462 pub fn list_user_invitations_endpoint(
466 input: &types::ListUserInvitationsQuery,
467 ) -> AuthResult<ServerEndpoint<Vec<types::UserInvitationResponse<InvitationView>>>> {
468 ServerEndpoint::new("organization", "listUserInvitations").with_query(input)
469 }
470 pub fn accept_invitation_endpoint(
474 input: &types::AcceptInvitationRequest,
475 ) -> AuthResult<
476 ServerEndpoint<types::AcceptInvitationResponse<InvitationView, types::BasicMemberResponse>>,
477 > {
478 ServerEndpoint::new("organization", "acceptInvitation").with_body(input)
479 }
480 pub fn reject_invitation_endpoint(
484 input: &types::RejectInvitationRequest,
485 ) -> AuthResult<
486 ServerEndpoint<
487 types::AcceptInvitationResponse<InvitationView, Option<types::BasicMemberResponse>>,
488 >,
489 > {
490 ServerEndpoint::new("organization", "rejectInvitation").with_body(input)
491 }
492 pub fn cancel_invitation_endpoint(
496 input: &types::CancelInvitationRequest,
497 ) -> AuthResult<ServerEndpoint<InvitationView>> {
498 ServerEndpoint::new("organization", "cancelInvitation").with_body(input)
499 }
500 #[must_use]
504 pub fn get_active_member_endpoint() -> ServerEndpoint<types::MemberResponse> {
505 ServerEndpoint::new("organization", "getActiveMember")
506 }
507 pub fn get_active_member_role_endpoint(
511 input: &types::GetActiveMemberRoleQuery,
512 ) -> AuthResult<ServerEndpoint<types::GetActiveMemberRoleResponse>> {
513 ServerEndpoint::new("organization", "getActiveMemberRole").with_query(input)
514 }
515 pub fn list_members_endpoint(
519 input: &types::ListMembersQuery,
520 ) -> AuthResult<ServerEndpoint<types::ListMembersResponse>> {
521 ServerEndpoint::new("organization", "listMembers").with_query(input)
522 }
523 pub fn update_member_role_endpoint(
527 input: &types::UpdateMemberRoleRequest,
528 ) -> AuthResult<ServerEndpoint<types::BasicMemberResponse>> {
529 ServerEndpoint::new("organization", "updateMemberRole").with_body(input)
530 }
531 pub fn has_permission_endpoint(
535 input: &types::HasPermissionRequest,
536 ) -> AuthResult<ServerEndpoint<types::HasPermissionResponse>> {
537 ServerEndpoint::new("organization", "hasPermission").with_body(input)
538 }
539 pub fn create_team_endpoint(
543 input: &types::CreateTeamRequest,
544 ) -> AuthResult<ServerEndpoint<Team>> {
545 ServerEndpoint::new("organization", "createTeam").with_body(input)
546 }
547 pub fn update_team_endpoint(
551 input: &types::UpdateTeamRequest,
552 ) -> AuthResult<ServerEndpoint<Team>> {
553 ServerEndpoint::new("organization", "updateTeam").with_body(input)
554 }
555 pub fn remove_team_endpoint(
559 input: &types::RemoveTeamRequest,
560 ) -> AuthResult<ServerEndpoint<types::MessageResponse>> {
561 ServerEndpoint::new("organization", "removeTeam").with_body(input)
562 }
563 pub fn set_active_team_endpoint(
567 input: &types::SetActiveTeamRequest,
568 ) -> AuthResult<ServerEndpoint<Option<Team>>> {
569 ServerEndpoint::new("organization", "setActiveTeam").with_body(input)
570 }
571 pub fn add_team_member_endpoint(
575 input: &types::TeamMemberRequest,
576 ) -> AuthResult<ServerEndpoint<TeamMember>> {
577 ServerEndpoint::new("organization", "addTeamMember").with_body(input)
578 }
579 pub fn remove_team_member_endpoint(
583 input: &types::TeamMemberRequest,
584 ) -> AuthResult<ServerEndpoint<types::MessageResponse>> {
585 ServerEndpoint::new("organization", "removeTeamMember").with_body(input)
586 }
587 pub fn list_teams_endpoint(input: &types::TeamQuery) -> AuthResult<ServerEndpoint<Vec<Team>>> {
591 ServerEndpoint::new("organization", "listTeams").with_query(input)
592 }
593 pub fn list_user_teams_endpoint(
597 input: &types::TeamQuery,
598 ) -> AuthResult<ServerEndpoint<Vec<Team>>> {
599 ServerEndpoint::new("organization", "listUserTeams").with_query(input)
600 }
601 pub fn list_team_members_endpoint(
605 input: &types::TeamQuery,
606 ) -> AuthResult<ServerEndpoint<Vec<TeamMember>>> {
607 ServerEndpoint::new("organization", "listTeamMembers").with_query(input)
608 }
609 pub fn create_role_endpoint(
613 input: &types::CreateRoleRequest,
614 ) -> AuthResult<ServerEndpoint<types::CreateRoleResponse>> {
615 ServerEndpoint::new("organization", "createOrganizationRole").with_body(input)
616 }
617 pub fn update_role_endpoint(
621 input: &types::UpdateRoleRequest,
622 ) -> AuthResult<ServerEndpoint<types::UpdateRoleResponse>> {
623 ServerEndpoint::new("organization", "updateOrganizationRole").with_body(input)
624 }
625 pub fn delete_role_endpoint(
629 input: &types::RoleQuery,
630 ) -> AuthResult<ServerEndpoint<types::SuccessResponse>> {
631 ServerEndpoint::new("organization", "deleteOrganizationRole").with_body(input)
632 }
633 pub fn get_role_endpoint(
637 input: &types::RoleQuery,
638 ) -> AuthResult<ServerEndpoint<types::RoleResponse>> {
639 ServerEndpoint::new("organization", "getOrganizationRole").with_query(input)
640 }
641 pub fn list_roles_endpoint(
645 input: &types::RoleQuery,
646 ) -> AuthResult<ServerEndpoint<Vec<types::RoleResponse>>> {
647 ServerEndpoint::new("organization", "listOrganizationRoles").with_query(input)
648 }
649}
650
651fn response(output: AuthResponse) -> AuthResult<EndpointResponse> {
652 let value = if output.body.is_empty() {
653 JsValue::Null
654 } else {
655 alibi_core::utils::json::from_slice::<JsValue>(&output.body)?
656 };
657 let mut response = if output.status >= 400 {
658 EndpointResponse::error(error_response(output.clone())).with_error_body(value)
659 } else {
660 EndpointResponse::value(value)
661 };
662 response.set_status(Some(output.status));
663 response.merge_headers(output.headers);
664 Ok(response)
665}
666
667fn query_pairs(call: &EndpointCall) -> AuthResult<HashMap<String, String>> {
668 let Some(fields) = call.query().and_then(JsValue::as_object) else {
669 return Ok(HashMap::new());
670 };
671 fields
672 .iter()
673 .map(|(key, value)| {
674 value
675 .coerce_string()
676 .map(|value| (key.clone(), value))
677 .map_err(validation)
678 })
679 .collect()
680}
681
682pub(super) async fn execute<S: AuthSchema>(
683 plugin: &OrganizationPlugin,
684 call: &EndpointCall,
685 ctx: &AuthContext<S>,
686) -> AuthResult<EndpointResponse> {
687 let config = &plugin.config;
688 if call.operation_id() == "listUserInvitations" {
689 let query: types::ListUserInvitationsQuery = call.query_as()?;
690 if let Some(email) = query.email.as_deref().filter(|email| !email.is_empty()) {
691 if call.request().is_some() {
692 return Err(AuthError::bad_request(
693 "User email cannot be passed for client side API calls.",
694 ));
695 }
696 return EndpointResponse::json(
697 &handlers::invitation::list_user_invitations_for_email_core(email, ctx).await?,
698 );
699 }
700 }
701 let (user, session) = ctx.require_cached_session(call).await.map_err(|error| {
702 if matches!(
703 error,
704 AuthError::Unauthenticated | AuthError::SessionNotFound
705 ) {
706 handlers::extension_common::org_error(401, "UNAUTHORIZED")
707 } else {
708 error
709 }
710 })?;
711 match call.operation_id() {
712 "listOrganizations" => {
713 EndpointResponse::json(&handlers::org::list_organizations_core(&user, ctx).await?)
714 }
715 "updateOrganization" => {
716 let (body, metadata) =
717 handlers::org_input::update_value(call.body()).map_err(error_response)?;
718 EndpointResponse::json(
719 &handlers::org::update_organization_core(
720 &body, metadata, &user, &session, config, ctx,
721 )
722 .await?,
723 )
724 }
725 "getOrganization" => {
726 let query: types::GetOrganizationQuery = call.query_as()?;
727 let organization =
728 if let Some(slug) = query.organization_slug.as_deref().filter(|s| !s.is_empty()) {
729 ctx.database.get_organization_by_slug(slug).await?
730 } else if let Some(id) = query
731 .organization_id
732 .as_deref()
733 .filter(|s| !s.is_empty())
734 .or(session.active_organization_id.as_deref())
735 {
736 ctx.database.get_organization_by_id(id).await?
737 } else {
738 return EndpointResponse::json(&Option::<types::OrganizationResponse>::None);
739 }
740 .ok_or_else(|| AuthError::bad_request("Organization not found"))?;
741 if ctx
742 .database
743 .get_member(&organization.id(), &user.id())
744 .await?
745 .is_none()
746 {
747 _ = ctx
748 .database
749 .update_session_active_organization_record(&session.token, None)
750 .await?;
751 return Err(AuthError::forbidden(
752 "User is not a member of the organization",
753 ));
754 }
755 EndpointResponse::json(&types::OrganizationResponse::from_stored_organization(
756 &organization,
757 )?)
758 }
759 "getFullOrganization" => EndpointResponse::json(
760 &handlers::org::get_full_organization_core(
761 &call.query_as()?,
762 &user,
763 &session,
764 config,
765 ctx,
766 )
767 .await
768 .map_err(AuthError::from)?,
769 ),
770 "checkOrganizationSlug" => {
771 EndpointResponse::json(&handlers::org::check_slug_core(&call.body_as()?, ctx).await?)
772 }
773 "setActiveOrganization" => {
774 let body =
775 handlers::org_input::set_active_value(call.body()).map_err(error_response)?;
776 let organization =
777 handlers::org::set_active_organization_core(&body, &user, &session, ctx).await?;
778 if organization.is_some()
779 || session
780 .active_organization_id
781 .as_deref()
782 .is_some_and(|id| !id.is_empty())
783 {
784 use alibi_core::utils::cookie_utils::{
785 create_session_cookie_with_max_age, create_session_like_cookie,
786 related_cookie_name, sign_cookie_value, verify_cookie_value,
787 };
788 let preference = related_cookie_name(&ctx.config, "dont_remember");
789 let dont_remember = call.session_headers().get("cookie").is_some_and(|header| {
790 cookie::Cookie::split_parse(header)
791 .flatten()
792 .find(|cookie| cookie.name() == preference)
793 .and_then(|cookie| {
794 verify_cookie_value(cookie.value(), ctx.config.current_secret())
795 })
796 .is_some_and(|value| !value.is_empty())
797 });
798 call.queue_response_header(
799 "set-cookie",
800 create_session_cookie_with_max_age(
801 Some(&session.token),
802 (!dont_remember).then(|| ctx.config.session.expires_in.num_seconds()),
803 &ctx.config,
804 )?,
805 );
806 if dont_remember {
807 call.queue_response_header(
808 "set-cookie",
809 create_session_like_cookie(
810 &preference,
811 &sign_cookie_value("true", ctx.config.current_secret()),
812 None,
813 &ctx.config,
814 )?,
815 );
816 }
817 }
818 EndpointResponse::json(&organization)
819 }
820 "leaveOrganization" => EndpointResponse::json(
821 &handlers::org::leave_organization_core(&call.body_as()?, &user, &session, config, ctx)
822 .await?,
823 ),
824 "inviteMember" => {
825 let body = handlers::org_input::invitation_create_value(call.body())
826 .map_err(error_response)?;
827 EndpointResponse::json(
828 &handlers::invitation::invite_member_core(&body, &user, &session, config, ctx)
829 .await?,
830 )
831 }
832 "getInvitation" => EndpointResponse::json(
833 &handlers::invitation::get_invitation_core(&call.query_as()?, &user, config, ctx)
834 .await?,
835 ),
836 "listInvitations" => EndpointResponse::json(
837 &handlers::invitation::list_invitations_core(&call.query_as()?, &user, &session, ctx)
838 .await?,
839 ),
840 "listUserInvitations" => EndpointResponse::json(
841 &handlers::invitation::list_user_invitations_core(&user, ctx).await?,
842 ),
843 "acceptInvitation" => {
844 let transport = handlers::invitation_acceptance::AcceptanceTransport::native(call);
845 let result = handlers::invitation_acceptance::accept(
846 &call.body_as()?,
847 &user,
848 &session,
849 config,
850 ctx,
851 &transport,
852 )
853 .await;
854 if matches!(result, Err(AuthError::Internal(_) | AuthError::Database(_))) {
855 transport.discard_cookies();
856 }
857 EndpointResponse::json(&result?)
858 }
859 "rejectInvitation" => EndpointResponse::json(
860 &handlers::invitation::reject_invitation_core(&call.body_as()?, &user, config, ctx)
861 .await?,
862 ),
863 "cancelInvitation" => EndpointResponse::json(
864 &handlers::invitation::cancel_invitation_core(&call.body_as()?, &user, config, ctx)
865 .await?,
866 ),
867 "getActiveMember" => EndpointResponse::json(
868 &handlers::member::get_active_member_core(&user, &session, ctx).await?,
869 ),
870 "getActiveMemberRole" => EndpointResponse::json(
871 &handlers::member::get_active_member_role_core(&call.query_as()?, &user, &session, ctx)
872 .await?,
873 ),
874 "listMembers" => EndpointResponse::json(
875 &handlers::member::list_members_core(&call.query_as()?, &user, &session, config, ctx)
876 .await
877 .map_err(AuthError::from)?,
878 ),
879 "updateMemberRole" => {
880 let body = handlers::org_input::member_role_update_value(call.body())
881 .map_err(error_response)?;
882 response(
883 handlers::member::update_member_role_response(&body, &user, &session, config, ctx)
884 .await?,
885 )
886 }
887 "hasPermission" => EndpointResponse::json(
888 &handlers::has_permission_core(&call.body_as()?, &user, &session, config, ctx).await?,
889 ),
890 "createTeam" | "updateTeam" | "removeTeam" | "setActiveTeam" | "addTeamMember"
891 | "removeTeamMember" | "listTeams" | "listUserTeams" | "listTeamMembers" => {
892 let path = match call.operation_id() {
893 "createTeam" => "/organization/create-team",
894 "updateTeam" => "/organization/update-team",
895 "removeTeam" => "/organization/remove-team",
896 "setActiveTeam" => "/organization/set-active-team",
897 "addTeamMember" => "/organization/add-team-member",
898 "removeTeamMember" => "/organization/remove-team-member",
899 "listTeams" => "/organization/list-teams",
900 "listUserTeams" => "/organization/list-user-teams",
901 "listTeamMembers" => "/organization/list-team-members",
902 _ => return Err(AuthError::not_found("Unknown operation")),
903 };
904 let method = call.default_method();
905 let query = query_pairs(call)?;
906 let body = call
907 .body()
908 .map(JsValue::to_json_value)
909 .transpose()
910 .map_err(|error| validation(error.to_string()))?;
911 let result = handlers::team::team_core(
912 method,
913 path,
914 body,
915 &query,
916 user,
917 session,
918 call.request(),
919 false,
920 ctx,
921 config,
922 )
923 .await?;
924 response(result.ok_or_else(|| AuthError::not_found("Unknown operation"))?)
925 }
926 "createOrganizationRole"
927 | "updateOrganizationRole"
928 | "deleteOrganizationRole"
929 | "getOrganizationRole"
930 | "listOrganizationRoles" => {
931 let path = match call.operation_id() {
932 "createOrganizationRole" => "/organization/create-role",
933 "updateOrganizationRole" => "/organization/update-role",
934 "deleteOrganizationRole" => "/organization/delete-role",
935 "getOrganizationRole" => "/organization/get-role",
936 "listOrganizationRoles" => "/organization/list-roles",
937 _ => return Err(AuthError::not_found("Unknown operation")),
938 };
939 let method = call.default_method();
940 let query = query_pairs(call)?;
941 let body = call
942 .body()
943 .map(JsValue::to_json_value)
944 .transpose()
945 .map_err(|error| validation(error.to_string()))?
946 .and_then(|value| value.as_object().cloned())
947 .unwrap_or_default();
948 let result =
949 handlers::role::role_core(method, path, body, &query, call, ctx, config).await?;
950 response(result.ok_or_else(|| AuthError::not_found("Unknown operation"))?)
951 }
952 _ => Err(AuthError::not_found("Unregistered organization operation")),
953 }
954}