1use super::{OrganizationPlugin, handlers, types};
3use crate::authentication_helpers::JsonField;
4use crate::endpoint::{definition, error_response, validate_fields, validation};
5use alibi_core::endpoint::{
6 EndpointCall, EndpointDefinition, EndpointInput, EndpointResponse, ServerEndpoint,
7};
8use alibi_core::entity::{AuthOrganization, AuthUser};
9use alibi_core::session::SessionRequest;
10use alibi_core::types::{Team, TeamMember};
11use alibi_core::utils::json::JsValue;
12use alibi_core::wire::InvitationView;
13use alibi_core::{AuthContext, AuthError, AuthResponse, AuthResult, AuthSchema, HttpMethod};
14use std::collections::HashMap;
15
16pub(super) fn definitions() -> Vec<EndpointDefinition> {
17 vec![
18 definition(
19 "listOrganizations",
20 "listOrganizations",
21 Some("/organization/list"),
22 HttpMethod::Get,
23 ),
24 definition(
25 "updateOrganization",
26 "updateOrganization",
27 Some("/organization/update"),
28 HttpMethod::Post,
29 ),
30 definition(
31 "getOrganization",
32 "getOrganization",
33 Some("/organization/get-organization"),
34 HttpMethod::Get,
35 ),
36 definition(
37 "getFullOrganization",
38 "getFullOrganization",
39 Some("/organization/get-full-organization"),
40 HttpMethod::Get,
41 ),
42 definition(
43 "checkOrganizationSlug",
44 "checkOrganizationSlug",
45 Some("/organization/check-slug"),
46 HttpMethod::Post,
47 ),
48 definition(
49 "setActiveOrganization",
50 "setActiveOrganization",
51 Some("/organization/set-active"),
52 HttpMethod::Post,
53 ),
54 definition(
55 "leaveOrganization",
56 "leaveOrganization",
57 Some("/organization/leave"),
58 HttpMethod::Post,
59 ),
60 definition(
61 "createInvitation",
62 "createOrganizationInvitation",
63 Some("/organization/invite-member"),
64 HttpMethod::Post,
65 ),
66 definition(
67 "inviteMember",
68 "inviteMember",
69 Some("/organization/invite-member"),
70 HttpMethod::Post,
71 ),
72 definition(
73 "getInvitation",
74 "getInvitation",
75 Some("/organization/get-invitation"),
76 HttpMethod::Get,
77 ),
78 definition(
79 "listInvitations",
80 "listInvitations",
81 Some("/organization/list-invitations"),
82 HttpMethod::Get,
83 ),
84 definition(
85 "listUserInvitations",
86 "listUserInvitations",
87 Some("/organization/list-user-invitations"),
88 HttpMethod::Get,
89 ),
90 definition(
91 "acceptInvitation",
92 "acceptInvitation",
93 Some("/organization/accept-invitation"),
94 HttpMethod::Post,
95 ),
96 definition(
97 "rejectInvitation",
98 "rejectInvitation",
99 Some("/organization/reject-invitation"),
100 HttpMethod::Post,
101 ),
102 definition(
103 "cancelInvitation",
104 "cancelInvitation",
105 Some("/organization/cancel-invitation"),
106 HttpMethod::Post,
107 ),
108 definition(
109 "getActiveMember",
110 "getActiveMember",
111 Some("/organization/get-active-member"),
112 HttpMethod::Get,
113 ),
114 definition(
115 "getActiveMemberRole",
116 "getActiveMemberRole",
117 Some("/organization/get-active-member-role"),
118 HttpMethod::Get,
119 ),
120 definition(
121 "listMembers",
122 "listMembers",
123 Some("/organization/list-members"),
124 HttpMethod::Get,
125 ),
126 definition(
127 "updateMemberRole",
128 "updateMemberRole",
129 Some("/organization/update-member-role"),
130 HttpMethod::Post,
131 ),
132 definition(
133 "hasPermission",
134 "hasPermission",
135 Some("/organization/has-permission"),
136 HttpMethod::Post,
137 ),
138 definition(
139 "createTeam",
140 "createTeam",
141 Some("/organization/create-team"),
142 HttpMethod::Post,
143 ),
144 definition(
145 "updateTeam",
146 "updateTeam",
147 Some("/organization/update-team"),
148 HttpMethod::Post,
149 ),
150 definition(
151 "removeTeam",
152 "removeTeam",
153 Some("/organization/remove-team"),
154 HttpMethod::Post,
155 ),
156 definition(
157 "setActiveTeam",
158 "setActiveTeam",
159 Some("/organization/set-active-team"),
160 HttpMethod::Post,
161 ),
162 definition(
163 "addTeamMember",
164 "addTeamMember",
165 Some("/organization/add-team-member"),
166 HttpMethod::Post,
167 ),
168 definition(
169 "removeTeamMember",
170 "removeTeamMember",
171 Some("/organization/remove-team-member"),
172 HttpMethod::Post,
173 ),
174 definition(
175 "listOrganizationTeams",
176 "listOrganizationTeams",
177 Some("/organization/list-teams"),
178 HttpMethod::Get,
179 ),
180 definition(
181 "listTeams",
182 "listTeams",
183 Some("/organization/list-teams"),
184 HttpMethod::Get,
185 ),
186 definition(
187 "listUserTeams",
188 "listUserTeams",
189 Some("/organization/list-user-teams"),
190 HttpMethod::Get,
191 ),
192 definition(
193 "listTeamMembers",
194 "listTeamMembers",
195 Some("/organization/list-team-members"),
196 HttpMethod::Get,
197 ),
198 definition(
199 "createOrgRole",
200 "createOrgRole",
201 Some("/organization/create-role"),
202 HttpMethod::Post,
203 ),
204 definition(
205 "createOrganizationRole",
206 "createOrganizationRole",
207 Some("/organization/create-role"),
208 HttpMethod::Post,
209 ),
210 definition(
211 "updateOrgRole",
212 "updateOrgRole",
213 Some("/organization/update-role"),
214 HttpMethod::Post,
215 ),
216 definition(
217 "updateOrganizationRole",
218 "updateOrganizationRole",
219 Some("/organization/update-role"),
220 HttpMethod::Post,
221 ),
222 definition(
223 "deleteOrgRole",
224 "deleteOrgRole",
225 Some("/organization/delete-role"),
226 HttpMethod::Post,
227 ),
228 definition(
229 "deleteOrganizationRole",
230 "deleteOrganizationRole",
231 Some("/organization/delete-role"),
232 HttpMethod::Post,
233 ),
234 definition(
235 "getOrgRole",
236 "getOrgRole",
237 Some("/organization/get-role"),
238 HttpMethod::Get,
239 ),
240 definition(
241 "getOrganizationRole",
242 "getOrganizationRole",
243 Some("/organization/get-role"),
244 HttpMethod::Get,
245 ),
246 definition(
247 "listOrgRoles",
248 "listOrgRoles",
249 Some("/organization/list-roles"),
250 HttpMethod::Get,
251 ),
252 definition(
253 "listOrganizationRoles",
254 "listOrganizationRoles",
255 Some("/organization/list-roles"),
256 HttpMethod::Get,
257 ),
258 ]
259}
260
261pub(super) fn validate(call: &EndpointCall) -> AuthResult<EndpointInput> {
262 match call.operation_id() {
264 "updateOrganization" => {
265 _ = handlers::org_input::update_value(call.body()).map_err(error_response)?;
266 }
267 "getOrganization" => {
268 let _: types::GetOrganizationQuery = call
269 .query_as()
270 .map_err(|error| validation(error.to_string()))?;
271 }
272 "getFullOrganization" => {
273 let _: types::GetFullOrganizationQuery = call
274 .query_as()
275 .map_err(|error| validation(error.to_string()))?;
276 }
277 "checkOrganizationSlug" => {
278 let _: types::CheckSlugRequest = call
279 .body_as()
280 .map_err(|error| validation(error.to_string()))?;
281 }
282 "setActiveOrganization" => {
283 _ = handlers::org_input::set_active_value(call.body()).map_err(error_response)?;
284 }
285 "leaveOrganization" => {
286 let _: types::LeaveOrganizationRequest = call
287 .body_as()
288 .map_err(|error| validation(error.to_string()))?;
289 }
290 "inviteMember" | "createOrganizationInvitation" => {
291 _ = handlers::org_input::invitation_create_value(call.body())
292 .map_err(error_response)?;
293 if call.operation_id() == "createOrganizationInvitation" && call.headers().is_none() {
294 return Err(validation("Headers is required"));
295 }
296 }
297 "getInvitation" => {
298 let _: types::GetInvitationQuery = call
299 .query_as()
300 .map_err(|error| validation(error.to_string()))?;
301 }
302 "listInvitations" => {
303 let _: types::ListInvitationsQuery = call
304 .query_as()
305 .map_err(|error| validation(error.to_string()))?;
306 }
307 "listUserInvitations" => {
308 let _: types::ListUserInvitationsQuery = call
309 .query_as()
310 .map_err(|error| validation(error.to_string()))?;
311 }
312 "acceptInvitation" => {
313 let _: types::AcceptInvitationRequest = call
314 .body_as()
315 .map_err(|error| validation(error.to_string()))?;
316 }
317 "rejectInvitation" => {
318 let _: types::RejectInvitationRequest = call
319 .body_as()
320 .map_err(|error| validation(error.to_string()))?;
321 }
322 "cancelInvitation" => {
323 let _: types::CancelInvitationRequest = call
324 .body_as()
325 .map_err(|error| validation(error.to_string()))?;
326 }
327 "getActiveMemberRole" => {
328 let _: types::GetActiveMemberRoleQuery = call
329 .query_as()
330 .map_err(|error| validation(error.to_string()))?;
331 }
332 "listMembers" => {
333 let _: types::ListMembersQuery = call
334 .query_as()
335 .map_err(|error| validation(error.to_string()))?;
336 }
337 "updateMemberRole" => {
338 _ = handlers::org_input::member_role_update_value(call.body())
339 .map_err(error_response)?;
340 }
341 "hasPermission" => {
342 let _: types::HasPermissionRequest = call
343 .body_as()
344 .map_err(|error| validation(error.to_string()))?;
345 }
346 "createTeam" => {
347 let _: types::CreateTeamRequest = call
348 .body_as()
349 .map_err(|error| validation(error.to_string()))?;
350 }
351 "updateTeam" => {
352 let _: types::UpdateTeamRequest = call
353 .body_as()
354 .map_err(|error| validation(error.to_string()))?;
355 if call.headers().is_none() {
356 return Err(validation("Headers is required"));
357 }
358 }
359 "removeTeam" => {
360 let _: types::RemoveTeamRequest = call
361 .body_as()
362 .map_err(|error| validation(error.to_string()))?;
363 }
364 "setActiveTeam" => {
365 let _: types::SetActiveTeamRequest = call
366 .body_as()
367 .map_err(|error| validation(error.to_string()))?;
368 if call.headers().is_none() {
369 return Err(validation("Headers is required"));
370 }
371 }
372 "addTeamMember" => {
373 let _: types::TeamMemberRequest = call
374 .body_as()
375 .map_err(|error| validation(error.to_string()))?;
376 if call.headers().is_none() {
377 return Err(validation("Headers is required"));
378 }
379 }
380 "removeTeamMember" => {
381 let _: types::TeamMemberRequest = call
382 .body_as()
383 .map_err(|error| validation(error.to_string()))?;
384 if call.headers().is_none() {
385 return Err(validation("Headers is required"));
386 }
387 }
388 "listOrganizationTeams" => {
389 if call.has_query() {
390 let _: types::TeamQuery = call
391 .query_as()
392 .map_err(|error| validation(error.to_string()))?;
393 }
394 if call.headers().is_none() {
395 return Err(validation("Headers is required"));
396 }
397 }
398 "listTeams" => {
399 let _: types::TeamQuery = call
400 .query_as()
401 .map_err(|error| validation(error.to_string()))?;
402 }
403 "listUserTeams" => {
404 let query = if call.has_query() {
405 Some(validate_fields(
406 call.query(),
407 "query",
408 &[
409 JsonField::string("organizationId", false),
410 JsonField::string("userId", false),
411 ],
412 )?)
413 } else {
414 None
415 };
416 if call.headers().is_none() {
417 return Err(validation("Headers is required"));
418 }
419 return Ok(EndpointInput {
420 body: call.body().cloned(),
421 query,
422 });
423 }
424 "listTeamMembers" => {
425 let query = if call.has_query() {
426 Some(validate_fields(
427 call.query(),
428 "query",
429 &[JsonField::string("teamId", false)],
430 )?)
431 } else {
432 None
433 };
434 if call.headers().is_none() {
435 return Err(validation("Headers is required"));
436 }
437 return Ok(EndpointInput {
438 body: call.body().cloned(),
439 query,
440 });
441 }
442 "createOrganizationRole" | "createOrgRole" => {
443 let _: types::CreateRoleRequest = call
444 .body_as()
445 .map_err(|error| validation(error.to_string()))?;
446 if call.operation_id() == "createOrgRole" && call.headers().is_none() {
447 return Err(validation("Headers is required"));
448 }
449 }
450 "updateOrganizationRole" | "updateOrgRole" => {
451 let _: types::UpdateRoleRequest = call
452 .body_as()
453 .map_err(|error| validation(error.to_string()))?;
454 if call.operation_id() == "updateOrgRole" && call.headers().is_none() {
455 return Err(validation("Headers is required"));
456 }
457 }
458 "deleteOrganizationRole" | "deleteOrgRole" => {
459 let _: types::RoleQuery = call
460 .body_as()
461 .map_err(|error| validation(error.to_string()))?;
462 if call.operation_id() == "deleteOrgRole" && call.headers().is_none() {
463 return Err(validation("Headers is required"));
464 }
465 }
466 "getOrgRole" => {
467 if call.has_query() {
468 let _: types::RoleQuery = call
469 .query_as()
470 .map_err(|error| validation(error.to_string()))?;
471 }
472 if call.headers().is_none() {
473 return Err(validation("Headers is required"));
474 }
475 }
476 "getOrganizationRole" => {
477 let _: types::RoleQuery = call
478 .query_as()
479 .map_err(|error| validation(error.to_string()))?;
480 }
481 "listOrgRoles" => {
482 let query = if call.has_query() {
483 Some(validate_fields(
484 call.query(),
485 "query",
486 &[JsonField::string("organizationId", false)],
487 )?)
488 } else {
489 None
490 };
491 if call.headers().is_none() {
492 return Err(validation("Headers is required"));
493 }
494 return Ok(EndpointInput {
495 body: call.body().cloned(),
496 query,
497 });
498 }
499 "listOrganizationRoles" => {
500 let _: types::RoleQuery = call
501 .query_as()
502 .map_err(|error| validation(error.to_string()))?;
503 }
504 _ => {}
505 }
506 Ok(EndpointInput {
507 body: call.body().cloned(),
508 query: call.query().cloned(),
509 })
510}
511
512impl OrganizationPlugin {
513 #[must_use]
517 pub fn list_organizations_endpoint() -> ServerEndpoint<Vec<types::OrganizationResponse>> {
518 ServerEndpoint::new("organization", "listOrganizations")
519 }
520 pub fn update_endpoint(
524 input: &types::UpdateOrganizationRequest,
525 ) -> AuthResult<ServerEndpoint<Option<types::CreatedOrganizationResponse>>> {
526 ServerEndpoint::new("organization", "updateOrganization").with_body(input)
527 }
528 pub fn get_organization_endpoint(
532 input: &types::GetOrganizationQuery,
533 ) -> AuthResult<ServerEndpoint<Option<types::OrganizationResponse>>> {
534 ServerEndpoint::new("organization", "getOrganization").with_query(input)
535 }
536 pub fn get_full_organization_endpoint(
540 input: &types::GetFullOrganizationQuery,
541 ) -> AuthResult<
542 ServerEndpoint<
543 Option<types::FullOrganizationResponse<types::OrganizationResponse, InvitationView>>,
544 >,
545 > {
546 ServerEndpoint::new("organization", "getFullOrganization").with_query(input)
547 }
548 pub fn check_slug_endpoint(
552 input: &types::CheckSlugRequest,
553 ) -> AuthResult<ServerEndpoint<types::CheckSlugResponse>> {
554 ServerEndpoint::new("organization", "checkOrganizationSlug").with_body(input)
555 }
556 pub fn set_active_endpoint(
560 input: &types::SetActiveOrganizationRequest,
561 ) -> AuthResult<ServerEndpoint<Option<types::OrganizationResponse>>> {
562 ServerEndpoint::new("organization", "setActiveOrganization").with_body(input)
563 }
564 pub fn leave_endpoint(
568 input: &types::LeaveOrganizationRequest,
569 ) -> AuthResult<ServerEndpoint<types::SuccessResponse>> {
570 ServerEndpoint::new("organization", "leaveOrganization").with_body(input)
571 }
572 pub fn create_invitation_endpoint(
576 input: &types::InviteMemberRequest,
577 ) -> AuthResult<ServerEndpoint<InvitationView>> {
578 ServerEndpoint::new("organization", "createInvitation").with_body(input)
579 }
580 pub fn invite_member_endpoint(
584 input: &types::InviteMemberRequest,
585 ) -> AuthResult<ServerEndpoint<InvitationView>> {
586 Self::create_invitation_endpoint(input)
587 }
588 pub fn get_invitation_endpoint(
592 input: &types::GetInvitationQuery,
593 ) -> AuthResult<ServerEndpoint<types::GetInvitationResponse<InvitationView>>> {
594 ServerEndpoint::new("organization", "getInvitation").with_query(input)
595 }
596 pub fn list_invitations_endpoint(
600 input: &types::ListInvitationsQuery,
601 ) -> AuthResult<ServerEndpoint<Vec<InvitationView>>> {
602 ServerEndpoint::new("organization", "listInvitations").with_query(input)
603 }
604 pub fn list_user_invitations_endpoint(
608 input: &types::ListUserInvitationsQuery,
609 ) -> AuthResult<ServerEndpoint<Vec<types::UserInvitationResponse<InvitationView>>>> {
610 ServerEndpoint::new("organization", "listUserInvitations").with_query(input)
611 }
612 pub fn accept_invitation_endpoint(
616 input: &types::AcceptInvitationRequest,
617 ) -> AuthResult<
618 ServerEndpoint<types::AcceptInvitationResponse<InvitationView, types::BasicMemberResponse>>,
619 > {
620 ServerEndpoint::new("organization", "acceptInvitation").with_body(input)
621 }
622 pub fn reject_invitation_endpoint(
626 input: &types::RejectInvitationRequest,
627 ) -> AuthResult<
628 ServerEndpoint<
629 types::AcceptInvitationResponse<InvitationView, Option<types::BasicMemberResponse>>,
630 >,
631 > {
632 ServerEndpoint::new("organization", "rejectInvitation").with_body(input)
633 }
634 pub fn cancel_invitation_endpoint(
638 input: &types::CancelInvitationRequest,
639 ) -> AuthResult<ServerEndpoint<InvitationView>> {
640 ServerEndpoint::new("organization", "cancelInvitation").with_body(input)
641 }
642 #[must_use]
646 pub fn get_active_member_endpoint() -> ServerEndpoint<types::MemberResponse> {
647 ServerEndpoint::new("organization", "getActiveMember")
648 }
649 pub fn get_active_member_role_endpoint(
653 input: &types::GetActiveMemberRoleQuery,
654 ) -> AuthResult<ServerEndpoint<types::GetActiveMemberRoleResponse>> {
655 ServerEndpoint::new("organization", "getActiveMemberRole").with_query(input)
656 }
657 pub fn list_members_endpoint(
661 input: &types::ListMembersQuery,
662 ) -> AuthResult<ServerEndpoint<types::ListMembersResponse>> {
663 ServerEndpoint::new("organization", "listMembers").with_query(input)
664 }
665 pub fn update_member_role_endpoint(
669 input: &types::UpdateMemberRoleRequest,
670 ) -> AuthResult<ServerEndpoint<types::BasicMemberResponse>> {
671 ServerEndpoint::new("organization", "updateMemberRole").with_body(input)
672 }
673 pub fn has_permission_endpoint(
677 input: &types::HasPermissionRequest,
678 ) -> AuthResult<ServerEndpoint<types::HasPermissionResponse>> {
679 ServerEndpoint::new("organization", "hasPermission").with_body(input)
680 }
681 pub fn create_team_endpoint(
685 input: &types::CreateTeamRequest,
686 ) -> AuthResult<ServerEndpoint<Team>> {
687 ServerEndpoint::new("organization", "createTeam").with_body(input)
688 }
689 pub fn update_team_endpoint(
693 input: &types::UpdateTeamRequest,
694 ) -> AuthResult<ServerEndpoint<Team>> {
695 ServerEndpoint::new("organization", "updateTeam").with_body(input)
696 }
697 pub fn remove_team_endpoint(
701 input: &types::RemoveTeamRequest,
702 ) -> AuthResult<ServerEndpoint<types::MessageResponse>> {
703 ServerEndpoint::new("organization", "removeTeam").with_body(input)
704 }
705 pub fn set_active_team_endpoint(
709 input: &types::SetActiveTeamRequest,
710 ) -> AuthResult<ServerEndpoint<Option<Team>>> {
711 ServerEndpoint::new("organization", "setActiveTeam").with_body(input)
712 }
713 pub fn add_team_member_endpoint(
717 input: &types::TeamMemberRequest,
718 ) -> AuthResult<ServerEndpoint<TeamMember>> {
719 ServerEndpoint::new("organization", "addTeamMember").with_body(input)
720 }
721 pub fn remove_team_member_endpoint(
725 input: &types::TeamMemberRequest,
726 ) -> AuthResult<ServerEndpoint<types::MessageResponse>> {
727 ServerEndpoint::new("organization", "removeTeamMember").with_body(input)
728 }
729 pub fn list_organization_teams_endpoint(
733 input: &types::TeamQuery,
734 ) -> AuthResult<ServerEndpoint<Vec<Team>>> {
735 ServerEndpoint::new("organization", "listOrganizationTeams").with_query(input)
736 }
737 pub fn list_teams_endpoint(input: &types::TeamQuery) -> AuthResult<ServerEndpoint<Vec<Team>>> {
741 Self::list_organization_teams_endpoint(input)
742 }
743 pub fn list_user_teams_endpoint(
747 input: &types::TeamQuery,
748 ) -> AuthResult<ServerEndpoint<Vec<Team>>> {
749 ServerEndpoint::new("organization", "listUserTeams").with_query(input)
750 }
751 pub fn list_team_members_endpoint(
755 input: &types::TeamQuery,
756 ) -> AuthResult<ServerEndpoint<Vec<TeamMember>>> {
757 ServerEndpoint::new("organization", "listTeamMembers").with_query(input)
758 }
759 pub fn create_org_role_endpoint(
763 input: &types::CreateRoleRequest,
764 ) -> AuthResult<ServerEndpoint<types::CreateRoleResponse>> {
765 ServerEndpoint::new("organization", "createOrgRole").with_body(input)
766 }
767 pub fn create_role_endpoint(
771 input: &types::CreateRoleRequest,
772 ) -> AuthResult<ServerEndpoint<types::CreateRoleResponse>> {
773 Self::create_org_role_endpoint(input)
774 }
775 pub fn update_org_role_endpoint(
779 input: &types::UpdateRoleRequest,
780 ) -> AuthResult<ServerEndpoint<types::UpdateRoleResponse>> {
781 ServerEndpoint::new("organization", "updateOrgRole").with_body(input)
782 }
783 pub fn update_role_endpoint(
787 input: &types::UpdateRoleRequest,
788 ) -> AuthResult<ServerEndpoint<types::UpdateRoleResponse>> {
789 Self::update_org_role_endpoint(input)
790 }
791 pub fn delete_org_role_endpoint(
795 input: &types::RoleQuery,
796 ) -> AuthResult<ServerEndpoint<types::SuccessResponse>> {
797 ServerEndpoint::new("organization", "deleteOrgRole").with_body(input)
798 }
799 pub fn delete_role_endpoint(
803 input: &types::RoleQuery,
804 ) -> AuthResult<ServerEndpoint<types::SuccessResponse>> {
805 Self::delete_org_role_endpoint(input)
806 }
807 pub fn get_org_role_endpoint(
811 input: &types::RoleQuery,
812 ) -> AuthResult<ServerEndpoint<types::RoleResponse>> {
813 ServerEndpoint::new("organization", "getOrgRole").with_query(input)
814 }
815 pub fn get_role_endpoint(
819 input: &types::RoleQuery,
820 ) -> AuthResult<ServerEndpoint<types::RoleResponse>> {
821 Self::get_org_role_endpoint(input)
822 }
823 pub fn list_org_roles_endpoint(
827 input: &types::RoleQuery,
828 ) -> AuthResult<ServerEndpoint<Vec<types::RoleResponse>>> {
829 ServerEndpoint::new("organization", "listOrgRoles").with_query(input)
830 }
831 pub fn list_roles_endpoint(
835 input: &types::RoleQuery,
836 ) -> AuthResult<ServerEndpoint<Vec<types::RoleResponse>>> {
837 Self::list_org_roles_endpoint(input)
838 }
839}
840
841fn response(output: AuthResponse) -> AuthResult<EndpointResponse> {
842 let value = if output.body.is_empty() {
843 JsValue::Null
844 } else {
845 alibi_core::utils::json::from_slice::<JsValue>(&output.body)?
846 };
847 let mut response = if output.status >= 400 {
848 EndpointResponse::error(error_response(output.clone())).with_error_body(value)
849 } else {
850 EndpointResponse::value(value)
851 };
852 response.set_status(Some(output.status));
853 response.merge_headers(output.headers);
854 Ok(response)
855}
856
857fn query_pairs(call: &EndpointCall) -> AuthResult<HashMap<String, String>> {
858 let Some(fields) = call.query().and_then(JsValue::as_object) else {
859 return Ok(HashMap::new());
860 };
861 fields
862 .iter()
863 .map(|(key, value)| {
864 value
865 .coerce_string()
866 .map(|value| (key.clone(), value))
867 .map_err(validation)
868 })
869 .collect()
870}
871
872pub(super) async fn execute<S: AuthSchema>(
873 plugin: &OrganizationPlugin,
874 call: &EndpointCall,
875 ctx: &AuthContext<S>,
876) -> AuthResult<EndpointResponse> {
877 let config = &plugin.config;
878 if call.operation_id() == "checkOrganizationSlug"
881 && call.request().is_none()
882 && call.headers().is_none()
883 {
884 return EndpointResponse::json(
885 &handlers::org::check_slug_core(&call.body_as()?, ctx).await?,
886 );
887 }
888 if call.operation_id() == "createTeam" && call.request().is_none() && call.headers().is_none() {
889 let body: types::CreateTeamRequest = call.body_as()?;
890 let organization_id = body
891 .organization_id
892 .filter(|id| !id.is_empty())
893 .ok_or_else(|| handlers::extension_common::org_error(400, "NO_ACTIVE_ORGANIZATION"))?;
894 return EndpointResponse::json(
895 &handlers::team::create_team_core(
896 alibi_core::types::CreateTeam {
897 name: body.name,
898 organization_id,
899 updated_at: Some(chrono::Utc::now()),
900 },
901 None,
902 None,
903 ctx,
904 config,
905 )
906 .await?,
907 );
908 }
909 if call.operation_id() == "removeTeam" && call.request().is_none() && call.headers().is_none() {
910 let body: types::RemoveTeamRequest = call.body_as()?;
911 let organization_id = body
912 .organization_id
913 .filter(|id| !id.is_empty())
914 .ok_or_else(|| handlers::extension_common::org_error(400, "NO_ACTIVE_ORGANIZATION"))?;
915 handlers::team::remove_team_core(&organization_id, &body.team_id, None, ctx, config)
916 .await?;
917 return EndpointResponse::json(&types::MessageResponse {
918 message: "Team removed successfully.".into(),
919 });
920 }
921 if call.operation_id() == "listUserInvitations" {
922 let query: types::ListUserInvitationsQuery = call.query_as()?;
923 if let Some(email) = query.email.as_deref().filter(|email| !email.is_empty()) {
924 if call.request().is_some() {
925 return Err(AuthError::bad_request(
926 "User email cannot be passed for client side API calls.",
927 ));
928 }
929 return EndpointResponse::json(
930 &handlers::invitation::list_user_invitations_for_email_core(email, ctx).await?,
931 );
932 }
933 }
934 let (user, session) = ctx.require_cached_session(call).await.map_err(|error| {
935 if matches!(
936 error,
937 AuthError::Unauthenticated | AuthError::SessionNotFound
938 ) {
939 handlers::extension_common::org_error(401, "UNAUTHORIZED")
940 } else {
941 error
942 }
943 })?;
944 match call.operation_id() {
945 "listOrganizations" => {
946 EndpointResponse::json(&handlers::org::list_organizations_core(&user, ctx).await?)
947 }
948 "updateOrganization" => {
949 let (body, metadata) =
950 handlers::org_input::update_value(call.body()).map_err(error_response)?;
951 EndpointResponse::json(
952 &handlers::org::update_organization_core(
953 &body, metadata, &user, &session, config, ctx,
954 )
955 .await?,
956 )
957 }
958 "getOrganization" => {
959 let query: types::GetOrganizationQuery = call.query_as()?;
960 let organization =
961 if let Some(slug) = query.organization_slug.as_deref().filter(|s| !s.is_empty()) {
962 ctx.database.get_organization_by_slug(slug).await?
963 } else if let Some(id) = query
964 .organization_id
965 .as_deref()
966 .filter(|s| !s.is_empty())
967 .or(session.active_organization_id.as_deref())
968 {
969 ctx.database.get_organization_by_id(id).await?
970 } else {
971 return EndpointResponse::json(&Option::<types::OrganizationResponse>::None);
972 }
973 .ok_or_else(|| AuthError::bad_request("Organization not found"))?;
974 if ctx
975 .database
976 .get_member(&organization.id(), &user.id())
977 .await?
978 .is_none()
979 {
980 _ = ctx
981 .database
982 .update_session_active_organization_record(&session.token, None)
983 .await?;
984 return Err(AuthError::forbidden(
985 "User is not a member of the organization",
986 ));
987 }
988 EndpointResponse::json(&types::OrganizationResponse::from_stored_organization(
989 &organization,
990 )?)
991 }
992 "getFullOrganization" => EndpointResponse::json(
993 &handlers::org::get_full_organization_core(
994 &call.query_as()?,
995 &user,
996 &session,
997 config,
998 ctx,
999 )
1000 .await
1001 .map_err(AuthError::from)?,
1002 ),
1003 "checkOrganizationSlug" => {
1004 EndpointResponse::json(&handlers::org::check_slug_core(&call.body_as()?, ctx).await?)
1005 }
1006 "setActiveOrganization" => {
1007 let body =
1008 handlers::org_input::set_active_value(call.body()).map_err(error_response)?;
1009 let organization =
1010 handlers::org::set_active_organization_core(&body, &user, &session, ctx).await?;
1011 if organization.is_some()
1012 || session
1013 .active_organization_id
1014 .as_deref()
1015 .is_some_and(|id| !id.is_empty())
1016 {
1017 use alibi_core::utils::cookie_utils::{
1018 create_session_cookie_with_max_age, create_session_like_cookie,
1019 related_cookie_name, sign_cookie_value, verify_cookie_value,
1020 };
1021 let preference = related_cookie_name(&ctx.config, "dont_remember");
1022 let dont_remember = call.session_headers().get("cookie").is_some_and(|header| {
1023 cookie::Cookie::split_parse(header)
1024 .flatten()
1025 .find(|cookie| cookie.name() == preference)
1026 .and_then(|cookie| {
1027 verify_cookie_value(cookie.value(), ctx.config.current_secret())
1028 })
1029 .is_some_and(|value| !value.is_empty())
1030 });
1031 call.queue_response_header(
1032 "set-cookie",
1033 create_session_cookie_with_max_age(
1034 Some(&session.token),
1035 (!dont_remember).then(|| ctx.config.session.expires_in.num_seconds()),
1036 &ctx.config,
1037 )?,
1038 );
1039 if dont_remember {
1040 call.queue_response_header(
1041 "set-cookie",
1042 create_session_like_cookie(
1043 &preference,
1044 &sign_cookie_value("true", ctx.config.current_secret()),
1045 None,
1046 &ctx.config,
1047 )?,
1048 );
1049 }
1050 }
1051 EndpointResponse::json(&organization)
1052 }
1053 "leaveOrganization" => EndpointResponse::json(
1054 &handlers::org::leave_organization_core(&call.body_as()?, &user, &session, config, ctx)
1055 .await?,
1056 ),
1057 "inviteMember" | "createOrganizationInvitation" => {
1058 let body = handlers::org_input::invitation_create_value(call.body())
1059 .map_err(error_response)?;
1060 EndpointResponse::json(
1061 &handlers::invitation::invite_member_core(&body, &user, &session, config, ctx)
1062 .await?,
1063 )
1064 }
1065 "getInvitation" => EndpointResponse::json(
1066 &handlers::invitation::get_invitation_core(&call.query_as()?, &user, config, ctx)
1067 .await?,
1068 ),
1069 "listInvitations" => EndpointResponse::json(
1070 &handlers::invitation::list_invitations_core(&call.query_as()?, &user, &session, ctx)
1071 .await?,
1072 ),
1073 "listUserInvitations" => EndpointResponse::json(
1074 &handlers::invitation::list_user_invitations_core(&user, ctx).await?,
1075 ),
1076 "acceptInvitation" => {
1077 let transport = handlers::invitation_acceptance::AcceptanceTransport::native(call);
1078 let result = handlers::invitation_acceptance::accept(
1079 &call.body_as()?,
1080 &user,
1081 &session,
1082 config,
1083 ctx,
1084 &transport,
1085 )
1086 .await;
1087 if matches!(result, Err(AuthError::Internal(_) | AuthError::Database(_))) {
1088 transport.discard_cookies();
1089 }
1090 EndpointResponse::json(&result?)
1091 }
1092 "rejectInvitation" => EndpointResponse::json(
1093 &handlers::invitation::reject_invitation_core(&call.body_as()?, &user, config, ctx)
1094 .await?,
1095 ),
1096 "cancelInvitation" => EndpointResponse::json(
1097 &handlers::invitation::cancel_invitation_core(&call.body_as()?, &user, config, ctx)
1098 .await?,
1099 ),
1100 "getActiveMember" => EndpointResponse::json(
1101 &handlers::member::get_active_member_core(&user, &session, ctx).await?,
1102 ),
1103 "getActiveMemberRole" => EndpointResponse::json(
1104 &handlers::member::get_active_member_role_core(&call.query_as()?, &user, &session, ctx)
1105 .await?,
1106 ),
1107 "listMembers" => EndpointResponse::json(
1108 &handlers::member::list_members_core(&call.query_as()?, &user, &session, config, ctx)
1109 .await
1110 .map_err(AuthError::from)?,
1111 ),
1112 "updateMemberRole" => {
1113 let body = handlers::org_input::member_role_update_value(call.body())
1114 .map_err(error_response)?;
1115 response(
1116 handlers::member::update_member_role_response(&body, &user, &session, config, ctx)
1117 .await?,
1118 )
1119 }
1120 "hasPermission" => EndpointResponse::json(
1121 &handlers::has_permission_core(&call.body_as()?, &user, &session, config, ctx).await?,
1122 ),
1123 "createTeam"
1124 | "updateTeam"
1125 | "removeTeam"
1126 | "setActiveTeam"
1127 | "addTeamMember"
1128 | "removeTeamMember"
1129 | "listTeams"
1130 | "listOrganizationTeams"
1131 | "listUserTeams"
1132 | "listTeamMembers" => {
1133 let path = match call.operation_id() {
1134 "createTeam" => "/organization/create-team",
1135 "updateTeam" => "/organization/update-team",
1136 "removeTeam" => "/organization/remove-team",
1137 "setActiveTeam" => "/organization/set-active-team",
1138 "addTeamMember" => "/organization/add-team-member",
1139 "removeTeamMember" => "/organization/remove-team-member",
1140 "listTeams" | "listOrganizationTeams" => "/organization/list-teams",
1141 "listUserTeams" => "/organization/list-user-teams",
1142 "listTeamMembers" => "/organization/list-team-members",
1143 _ => return Err(AuthError::not_found("Unknown operation")),
1144 };
1145 let method = call.default_method();
1146 let query = query_pairs(call)?;
1147 let body = call
1148 .body()
1149 .map(JsValue::to_json_value)
1150 .transpose()
1151 .map_err(|error| validation(error.to_string()))?;
1152 let result = handlers::team::team_core(
1153 method,
1154 path,
1155 body,
1156 &query,
1157 user,
1158 session,
1159 call.request(),
1160 false,
1161 ctx,
1162 config,
1163 )
1164 .await?;
1165 response(result.ok_or_else(|| AuthError::not_found("Unknown operation"))?)
1166 }
1167 "createOrganizationRole"
1168 | "createOrgRole"
1169 | "updateOrganizationRole"
1170 | "updateOrgRole"
1171 | "deleteOrganizationRole"
1172 | "deleteOrgRole"
1173 | "getOrganizationRole"
1174 | "getOrgRole"
1175 | "listOrgRoles"
1176 | "listOrganizationRoles" => {
1177 let path = match call.operation_id() {
1178 "createOrganizationRole" | "createOrgRole" => "/organization/create-role",
1179 "updateOrganizationRole" | "updateOrgRole" => "/organization/update-role",
1180 "deleteOrganizationRole" | "deleteOrgRole" => "/organization/delete-role",
1181 "getOrganizationRole" | "getOrgRole" => "/organization/get-role",
1182 "listOrganizationRoles" | "listOrgRoles" => "/organization/list-roles",
1183 _ => return Err(AuthError::not_found("Unknown operation")),
1184 };
1185 let method = call.default_method();
1186 let query = query_pairs(call)?;
1187 let body = call
1188 .body()
1189 .map(JsValue::to_json_value)
1190 .transpose()
1191 .map_err(|error| validation(error.to_string()))?
1192 .and_then(|value| value.as_object().cloned())
1193 .unwrap_or_default();
1194 let result =
1195 handlers::role::role_core(method, path, body, &query, call, ctx, config).await?;
1196 response(result.ok_or_else(|| AuthError::not_found("Unknown operation"))?)
1197 }
1198 _ => Err(AuthError::not_found("Unregistered organization operation")),
1199 }
1200}