@@ -309,7 +309,7 @@ func (s *projectMembersIntegrationTestSuite) TestAddMemberToProject() {
309309 result , err := s .Project .AddMemberToProject (ctx , uuid .MustParse (s .org .ID ), opts )
310310 s .NoError (err )
311311 s .NotNil (result )
312- s .True (result .InvitationSent , "An invitation should be sent for users not in the organization" )
312+ s .True (result .InvitationSent , "An invitation should be sent for users not in the organization when requester is an org admin " )
313313 s .Nil (result .Membership , "No membership should be created directly" )
314314
315315 // Verify an invitation was created
@@ -334,23 +334,73 @@ func (s *projectMembersIntegrationTestSuite) TestAddMemberToProject() {
334334 s .Equal (authz .RoleProjectViewer , foundInvitation .Context .ProjectRole )
335335 })
336336
337- s .Run ("add member who is already in the project" , func () {
338- // Try to add user2 again (who we added in the first test)
339- opts := & biz.AddMemberToProjectOpts {
337+ s .Run ("project admin (non-org admin) should not be able to invite new users" , func () {
338+ // Create a project admin who is not an org admin
339+ projectAdminUser , err := s .User .UpsertByEmail (ctx , "project-admin@example.com" , nil )
340+ require .NoError (s .T (), err )
341+
342+ // Add user to organization as a regular member (not org admin)
343+ _ , err = s .Membership .Create (ctx , s .org .ID , projectAdminUser .ID , biz .WithMembershipRole (authz .RoleOrgMember ), biz .WithCurrentMembership ())
344+ require .NoError (s .T (), err )
345+
346+ // Add user to project as a project admin
347+ projectAdminOpts := & biz.AddMemberToProjectOpts {
340348 ProjectReference : projectRef ,
341- UserEmail : "add-user2 @example.com" ,
342- RequesterID : uuid .MustParse (s .user .ID ),
349+ UserEmail : "project-admin @example.com" ,
350+ RequesterID : uuid .MustParse (s .user .ID ), // Using the org admin to add them
343351 Role : authz .RoleProjectAdmin ,
344352 }
353+ _ , err = s .Project .AddMemberToProject (ctx , uuid .MustParse (s .org .ID ), projectAdminOpts )
354+ require .NoError (s .T (), err )
345355
346- _ , err := s .Project .AddMemberToProject (ctx , uuid .MustParse (s .org .ID ), opts )
356+ // Create a new user who is not in the organization
357+ nonExistingEmail := "not-in-org-2@example.com"
358+ _ , err = s .User .UpsertByEmail (ctx , nonExistingEmail , nil )
359+ require .NoError (s .T (), err )
360+
361+ // Try to add the non-existing user using the project admin
362+ opts := & biz.AddMemberToProjectOpts {
363+ ProjectReference : projectRef ,
364+ UserEmail : nonExistingEmail ,
365+ RequesterID : uuid .MustParse (projectAdminUser .ID ),
366+ Role : authz .RoleProjectViewer ,
367+ }
368+
369+ // The invitation should be rejected
370+ _ , err = s .Project .AddMemberToProject (ctx , uuid .MustParse (s .org .ID ), opts )
347371 s .Error (err )
348- s .True (biz .IsErrAlreadyExists (err ))
372+ s .True (biz .IsErrValidation (err ))
373+ s .Contains (err .Error (), "only organization admins or owners can invite new users" )
374+ })
349375
350- // Verify the number of members hasn't changed
351- _ , count , err := s .Project .ListMembers (ctx , uuid .MustParse (s .org .ID ), projectRef , nil )
376+ s .Run ("org owner should be able to invite new users" , func () {
377+ // Create an org owner
378+ orgOwnerUser , err := s .User .UpsertByEmail (ctx , "org-owner@example.com" , nil )
379+ require .NoError (s .T (), err )
380+
381+ // Add user to organization as an owner
382+ _ , err = s .Membership .Create (ctx , s .org .ID , orgOwnerUser .ID , biz .WithMembershipRole (authz .RoleOwner ), biz .WithCurrentMembership ())
383+ require .NoError (s .T (), err )
384+
385+ // Create a new user who is not in the organization
386+ nonExistingEmail := "not-in-org-3@example.com"
387+ _ , err = s .User .UpsertByEmail (ctx , nonExistingEmail , nil )
388+ require .NoError (s .T (), err )
389+
390+ // Try to add the non-existing user using the org owner
391+ opts := & biz.AddMemberToProjectOpts {
392+ ProjectReference : projectRef ,
393+ UserEmail : nonExistingEmail ,
394+ RequesterID : uuid .MustParse (orgOwnerUser .ID ),
395+ Role : authz .RoleProjectViewer ,
396+ }
397+
398+ // The invitation should be sent successfully
399+ result , err := s .Project .AddMemberToProject (ctx , uuid .MustParse (s .org .ID ), opts )
352400 s .NoError (err )
353- s .Equal (2 , count ) // still the original 2 members
401+ s .NotNil (result )
402+ s .True (result .InvitationSent , "An invitation should be sent for users not in the organization when requester is an org owner" )
403+ s .Nil (result .Membership , "No membership should be created directly" )
354404 })
355405}
356406
0 commit comments