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