Skip to content

Commit a0cda26

Browse files
authored
feat(projects): Allow to include groups to projects (#2170)
Signed-off-by: Javier Rodriguez <[email protected]>
1 parent e3ac631 commit a0cda26

21 files changed

+884
-202
lines changed

app/controlplane/api/controlplane/v1/project.pb.go

Lines changed: 48 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/api/controlplane/v1/project.proto

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,9 @@ message ProjectMembershipReference {
144144
// The membership reference can be a user email or groups references in the future
145145
oneof membership_reference {
146146
// The user to add to the project
147-
string user_email = 3 [(buf.validate.field).string.email = true];
147+
string user_email = 1 [(buf.validate.field).string.email = true];
148+
// The group to add to the project
149+
IdentityReference group_reference = 2;
148150
}
149151
}
150152

app/controlplane/api/gen/frontend/controlplane/v1/project.ts

Lines changed: 28 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/api/gen/jsonschema/controlplane.v1.ProjectMembershipReference.jsonschema.json

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/api/gen/jsonschema/controlplane.v1.ProjectMembershipReference.schema.json

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/cmd/wire_gen.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/internal/service/project.go

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ func (s *ProjectService) AddMember(ctx context.Context, req *pb.ProjectServiceAd
214214
return nil, errors.BadRequest("invalid", fmt.Sprintf("invalid project reference: %s", err.Error()))
215215
}
216216

217-
// Extract the user email from the oneof MembershipReference field
218-
userEmail, err := s.extractUserEmailFromMembershipReference(req.GetMemberReference())
217+
// Extract the user email and group reference from the membership reference field
218+
userEmail, groupReference, err := s.extractMembershipReference(req.GetMemberReference())
219219
if err != nil {
220220
return nil, handleUseCaseErr(err, s.log)
221221
}
@@ -227,6 +227,7 @@ func (s *ProjectService) AddMember(ctx context.Context, req *pb.ProjectServiceAd
227227
opts := &biz.AddMemberToProjectOpts{
228228
ProjectReference: identityRef,
229229
UserEmail: userEmail,
230+
GroupReference: groupReference,
230231
RequesterID: requesterUUID,
231232
Role: role,
232233
}
@@ -278,8 +279,8 @@ func (s *ProjectService) RemoveMember(ctx context.Context, req *pb.ProjectServic
278279
return nil, errors.BadRequest("invalid", fmt.Sprintf("invalid project reference: %s", err.Error()))
279280
}
280281

281-
// Extract the user email from the oneof MembershipReference field
282-
userEmail, err := s.extractUserEmailFromMembershipReference(req.GetMemberReference())
282+
// Extract the user email and group reference from the membership reference field
283+
userEmail, groupReference, err := s.extractMembershipReference(req.GetMemberReference())
283284
if err != nil {
284285
return nil, handleUseCaseErr(err, s.log)
285286
}
@@ -288,6 +289,7 @@ func (s *ProjectService) RemoveMember(ctx context.Context, req *pb.ProjectServic
288289
opts := &biz.RemoveMemberFromProjectOpts{
289290
ProjectReference: identityRef,
290291
UserEmail: userEmail,
292+
GroupReference: groupReference,
291293
RequesterID: requesterUUID,
292294
}
293295

@@ -300,19 +302,41 @@ func (s *ProjectService) RemoveMember(ctx context.Context, req *pb.ProjectServic
300302
return &pb.ProjectServiceRemoveMemberResponse{}, nil
301303
}
302304

303-
// extractUserEmailFromMembershipReference extracts the user email from a membership reference
304-
// Returns the user email and an error if the email is not provided or the membership reference is nil
305-
func (s *ProjectService) extractUserEmailFromMembershipReference(membershipRef *pb.ProjectMembershipReference) (string, error) {
305+
// extractMembershipReference extracts either a user email or a group reference from a membership reference
306+
// If both or neither are provided, returns an error
307+
func (s *ProjectService) extractMembershipReference(membershipRef *pb.ProjectMembershipReference) (string, *biz.IdentityReference, error) {
306308
if membershipRef == nil {
307-
return "", biz.NewErrValidationStr("membership reference is required")
309+
return "", nil, biz.NewErrValidationStr("membership reference is required")
308310
}
309311

312+
// Check if the membershipRef has a user email
310313
userEmail := membershipRef.GetUserEmail()
311-
if userEmail == "" {
312-
return "", biz.NewErrValidationStr("user email is required")
314+
groupRef := membershipRef.GetGroupReference()
315+
316+
// Validate that exactly one of user email or group reference is provided
317+
if (userEmail == "" && groupRef == nil) || (userEmail != "" && groupRef != nil) {
318+
return "", nil, biz.NewErrValidationStr("exactly one of user email or group reference must be provided")
319+
}
320+
321+
// If we have a user email, return it and nil for group reference
322+
if userEmail != "" {
323+
return userEmail, nil, nil
313324
}
314325

315-
return userEmail, nil
326+
// Otherwise, create a new IdentityReference from the group reference
327+
identityRef := &biz.IdentityReference{}
328+
var err error
329+
330+
identityRef.ID, identityRef.Name, err = groupRef.Parse()
331+
if err != nil {
332+
return "", nil, errors.BadRequest("invalid_group_reference", fmt.Sprintf("invalid group reference: %s", err.Error()))
333+
}
334+
335+
if identityRef.ID == nil && identityRef.Name == nil {
336+
return "", nil, biz.NewErrValidationStr("either group ID or name must be provided")
337+
}
338+
339+
return "", identityRef, nil
316340
}
317341

318342
// MapProjectMemberRoleToAuthzRole maps a ProjectMemberRole from protobuf to an authz.Role
@@ -343,12 +367,21 @@ func bizProjectMembershipToPb(m *biz.ProjectMembership) *pb.ProjectMember {
343367
}
344368

345369
pbMember := &pb.ProjectMember{
346-
Subject: &pb.ProjectMember_User{
347-
User: bizUserToPb(m.User),
348-
},
349370
Role: role,
350371
}
351372

373+
if m.User != nil {
374+
pbMember.Subject = &pb.ProjectMember_User{
375+
User: bizUserToPb(m.User),
376+
}
377+
}
378+
379+
if m.Group != nil {
380+
pbMember.Subject = &pb.ProjectMember_Group{
381+
Group: bizGroupToPb(m.Group),
382+
}
383+
}
384+
352385
if m.CreatedAt != nil {
353386
pbMember.CreatedAt = timestamppb.New(*m.CreatedAt)
354387
}

0 commit comments

Comments
 (0)