1- use std:: fmt:: { Debug , Display } ;
1+ use std:: {
2+ fmt:: { Debug , Display } ,
3+ str:: FromStr ,
4+ } ;
25
36use async_trait:: async_trait;
47use http:: StatusCode ;
@@ -8,7 +11,7 @@ use permit_client_rs::{
811 create_relationship_tuple, delete_relationship_tuple, list_relationship_tuples,
912 } ,
1013 resource_instances_api:: { create_resource_instance, delete_resource_instance} ,
11- role_assignments_api:: { assign_role, unassign_role} ,
14+ role_assignments_api:: { assign_role, list_role_assignments , unassign_role} ,
1215 users_api:: { create_user, delete_user, get_user} ,
1316 Error as PermitClientError ,
1417 } ,
@@ -91,6 +94,29 @@ pub trait PermissionsDal {
9194 org_id : & str ,
9295 ) -> Result < ( ) > ;
9396
97+ /// Add a user as a normal member to an organization
98+ async fn add_organization_member (
99+ & self ,
100+ admin_user : & str ,
101+ org_id : & str ,
102+ user_id : & str ,
103+ ) -> Result < ( ) > ;
104+
105+ /// Remove a user from an organization
106+ async fn remove_organization_member (
107+ & self ,
108+ admin_user : & str ,
109+ org_id : & str ,
110+ user_id : & str ,
111+ ) -> Result < ( ) > ;
112+
113+ /// Get a list of all the members of an organization
114+ async fn get_organization_members (
115+ & self ,
116+ user_id : & str ,
117+ org_id : & str ,
118+ ) -> Result < Vec < organization:: MemberResponse > > ;
119+
94120 // Permissions queries
95121
96122 /// Get list of all projects user has permissions for
@@ -398,11 +424,10 @@ impl PermissionsDal for Client {
398424 )
399425 . await ?;
400426
401- let mut projects = Vec :: with_capacity ( relationships. len ( ) ) ;
402-
403- for rel in relationships {
404- projects. push ( rel. object_details . expect ( "to have object details" ) . key ) ;
405- }
427+ let projects = relationships
428+ . into_iter ( )
429+ . map ( |rel| rel. object_details . expect ( "to have object details" ) . key )
430+ . collect ( ) ;
406431
407432 Ok ( projects)
408433 }
@@ -514,60 +539,111 @@ impl PermissionsDal for Client {
514539
515540 Ok ( ( ) )
516541 }
542+
543+ async fn add_organization_member (
544+ & self ,
545+ admin_user : & str ,
546+ org_id : & str ,
547+ user_id : & str ,
548+ ) -> Result < ( ) > {
549+ if !self . allowed_org ( admin_user, org_id, "manage" ) . await ? {
550+ return Err ( Error :: ResponseError ( ResponseContent {
551+ status : StatusCode :: FORBIDDEN ,
552+ content : "User does not have permission to modify the organization" . to_owned ( ) ,
553+ entity : "Organization" . to_owned ( ) ,
554+ } ) ) ;
555+ }
556+
557+ let user = self . get_user ( user_id) . await ?;
558+
559+ if !user
560+ . roles
561+ . is_some_and ( |roles| roles. iter ( ) . any ( |r| r. role == AccountTier :: Pro . to_string ( ) ) )
562+ {
563+ return Err ( Error :: ResponseError ( ResponseContent {
564+ status : StatusCode :: BAD_REQUEST ,
565+ content : "Only Pro users can be added to an organization" . to_owned ( ) ,
566+ entity : "Organization" . to_owned ( ) ,
567+ } ) ) ;
568+ }
569+
570+ self . assign_resource_role ( user_id, format ! ( "Organization:{org_id}" ) , "member" )
571+ . await ?;
572+
573+ Ok ( ( ) )
574+ }
575+
576+ async fn remove_organization_member (
577+ & self ,
578+ admin_user : & str ,
579+ org_id : & str ,
580+ user_id : & str ,
581+ ) -> Result < ( ) > {
582+ if admin_user == user_id {
583+ return Err ( Error :: ResponseError ( ResponseContent {
584+ status : StatusCode :: BAD_REQUEST ,
585+ content : "Cannot remove yourself from an organization" . to_owned ( ) ,
586+ entity : "Organization" . to_owned ( ) ,
587+ } ) ) ;
588+ }
589+
590+ if !self . allowed_org ( admin_user, org_id, "manage" ) . await ? {
591+ return Err ( Error :: ResponseError ( ResponseContent {
592+ status : StatusCode :: FORBIDDEN ,
593+ content : "User does not have permission to modify the organization" . to_owned ( ) ,
594+ entity : "Organization" . to_owned ( ) ,
595+ } ) ) ;
596+ }
597+
598+ self . unassign_resource_role ( user_id, format ! ( "Organization:{org_id}" ) , "member" )
599+ . await ?;
600+
601+ Ok ( ( ) )
602+ }
603+
604+ async fn get_organization_members (
605+ & self ,
606+ user_id : & str ,
607+ org_id : & str ,
608+ ) -> Result < Vec < organization:: MemberResponse > > {
609+ if !self . allowed_org ( user_id, org_id, "view" ) . await ? {
610+ return Err ( Error :: ResponseError ( ResponseContent {
611+ status : StatusCode :: FORBIDDEN ,
612+ content : "User does not have permission to view the organization" . to_owned ( ) ,
613+ entity : "Organization" . to_owned ( ) ,
614+ } ) ) ;
615+ }
616+
617+ let assignments = list_role_assignments (
618+ & self . api ,
619+ & self . proj_id ,
620+ & self . env_id ,
621+ None ,
622+ None ,
623+ Some ( "default" ) ,
624+ None ,
625+ Some ( & format ! ( "Organization:{org_id}" ) ) ,
626+ None ,
627+ None ,
628+ None ,
629+ )
630+ . await ?;
631+
632+ let members = assignments
633+ . into_iter ( )
634+ . map ( |assignment| organization:: MemberResponse {
635+ id : assignment. user ,
636+ role : organization:: MemberRole :: from_str ( & assignment. role )
637+ . unwrap_or ( organization:: MemberRole :: Member ) ,
638+ } )
639+ . collect ( ) ;
640+
641+ Ok ( members)
642+ }
517643}
518644
519645// Helpers for trait methods
520646impl Client {
521- // pub async fn get_organization_members(&self, org_name: &str) -> Result<Vec<Value>> {
522- // self.api
523- // .get(
524- // &format!(
525- // "{}/role_assignments?resource_instance=Organization:{org_name}&role=member",
526- // self.facts
527- // ),
528- // None,
529- // )
530- // .await
531- // }
532-
533- // pub async fn create_organization_member(
534- // &self,
535- // org_name: &str,
536- // user_id: &str,
537- // ) -> Result<()> {
538- // self.api
539- // .post(
540- // &format!("{}/role_assignments", self.facts),
541- // json!({
542- // "role": "member",
543- // "resource_instance": format!("Organization:{org_name}"),
544- // "tenant": "default",
545- // "user": user_id,
546- // }),
547- // None,
548- // )
549- // .await
550- // }
551-
552- // pub async fn delete_organization_member(
553- // &self,
554- // org_name: &str,
555- // user_id: &str,
556- // ) -> Result<()> {
557- // self.api
558- // .delete(
559- // &format!("{}/role_assignments", self.facts),
560- // json!({
561- // "role": "member",
562- // "resource_instance": format!("Organization:{org_name}"),
563- // "tenant": "default",
564- // "user": user_id,
565- // }),
566- // None,
567- // )
568- // .await
569- // }
570-
571647 async fn create_user ( & self , user_id : & str ) -> Result < UserRead > {
572648 Ok ( create_user (
573649 & self . api ,
0 commit comments