Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 88 additions & 3 deletions cla-backend-go/v2/cla_manager/emails.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,8 @@ func (s *service) SendDesigneeEmailToUserWithNoLFID(ctx context.Context, input D
// Parse the provided user's name
userFirstName, userLastName := utils.GetFirstAndLastName(input.userWithNoLFIDName)

return acsClient.SendUserInvite(ctx, &v2AcsService.SendUserInviteInput{
// Send invitation for the primary CLA role (e.g., cla-manager-designee)
inviteErr := acsClient.SendUserInvite(ctx, &v2AcsService.SendUserInviteInput{
InviteUserFirstName: userFirstName,
InviteUserLastName: userLastName,
InviteUserEmail: input.userWithNoLFIDEmail,
Expand All @@ -326,6 +327,48 @@ func (s *service) SendDesigneeEmailToUserWithNoLFID(ctx context.Context, input D
EmailContent: body,
Automate: false,
})
if inviteErr != nil {
log.WithFields(f).WithError(inviteErr).Warnf("failed to send primary role invitation")
return inviteErr
}

// Also send invitation for the "contact" role which is required to access Corporate Console
// This is sent at organization scope (not project|organization)
contactSubject := fmt.Sprintf("EasyCLA: Invitation to access Corporate Console for %s", input.companyName)
contactBody, contactBodyErr := emails.RenderV2ToCLAManagerDesigneeTemplate(s.emailTemplateService, input.projectSFIDs,
emails.V2ToCLAManagerDesigneeTemplateParams{
CommonEmailParams: emails.CommonEmailParams{
RecipientName: input.userWithNoLFIDName,
CompanyName: input.companyName,
},
Contributor: input.contributorModel,
}, emails.V2DesigneeToUserWithNoLFIDTemplate, emails.V2DesigneeToUserWithNoLFIDTemplateName)

if contactBodyErr != nil {
log.WithFields(f).WithError(contactBodyErr).Warnf("failed to render contact role invitation email template")
// Don't return error, as the primary invitation was successful
} else {
log.WithFields(f).Debug("sending contact role invite request...")
contactInviteErr := acsClient.SendUserInvite(ctx, &v2AcsService.SendUserInviteInput{
InviteUserFirstName: userFirstName,
InviteUserLastName: userLastName,
InviteUserEmail: input.userWithNoLFIDEmail,
RoleName: utils.ContactRole,
Scope: "organization", // Contact role is at organization scope only
ProjectSFID: "", // Not applicable for organization scope
OrganizationSFID: input.organizationID,
InviteType: "userinvite",
Subject: contactSubject,
EmailContent: contactBody,
Automate: false,
})
if contactInviteErr != nil {
log.WithFields(f).WithError(contactInviteErr).Warnf("failed to send contact role invitation, but primary invitation succeeded")
// Don't return error, as the primary invitation was successful
}
}

return nil
}

// sendEmailToUserWithNoLFID helper function to send email to a given user with no LFID
Expand Down Expand Up @@ -364,8 +407,9 @@ func (s *service) SendEmailToUserWithNoLFID(ctx context.Context, input EmailToUs
userFirstName, userLastName := utils.GetFirstAndLastName(input.userWithNoLFIDName)

log.WithFields(f).Debug("sending user invite request...")
//return acsClient.SendUserInvite(ctx, &userWithNoLFIDEmail, role, utils.ProjectOrgScope, projectID, organizationID, "userinvite", &subject, &body, automate)
return acsClient.SendUserInvite(ctx, &v2AcsService.SendUserInviteInput{

// Send invitation for the primary CLA role (e.g., cla-manager-designee)
inviteErr := acsClient.SendUserInvite(ctx, &v2AcsService.SendUserInviteInput{
InviteUserFirstName: userFirstName,
InviteUserLastName: userLastName,
InviteUserEmail: input.userWithNoLFIDEmail,
Expand All @@ -378,4 +422,45 @@ func (s *service) SendEmailToUserWithNoLFID(ctx context.Context, input EmailToUs
EmailContent: body,
Automate: false,
})
if inviteErr != nil {
log.WithFields(f).WithError(inviteErr).Warnf("failed to send primary role invitation")
return inviteErr
}

// Also send invitation for the "contact" role which is required to access Corporate Console
// This is sent at organization scope (not project|organization)
contactSubject := fmt.Sprintf("EasyCLA: Invitation to access Corporate Console for %s", input.companyName)
contactBody, contactBodyErr := emails.RenderV2CLAManagerToUserWithNoLFIDTemplate(s.emailTemplateService, input.projectID, emails.V2CLAManagerToUserWithNoLFIDTemplateParams{
CommonEmailParams: emails.CommonEmailParams{
RecipientName: input.userWithNoLFIDName,
CompanyName: input.companyName,
},
RequesterUserName: input.requesterUsername,
RequesterEmail: input.requesterEmail,
})
if contactBodyErr != nil {
log.WithFields(f).WithError(contactBodyErr).Warnf("failed to render contact role invitation email template")
// Don't return error, as the primary invitation was successful
} else {
log.WithFields(f).Debug("sending contact role invite request...")
contactInviteErr := acsClient.SendUserInvite(ctx, &v2AcsService.SendUserInviteInput{
InviteUserFirstName: userFirstName,
InviteUserLastName: userLastName,
InviteUserEmail: input.userWithNoLFIDEmail,
RoleName: utils.ContactRole,
Scope: "organization", // Contact role is at organization scope only
ProjectSFID: "", // Not applicable for organization scope
OrganizationSFID: input.organizationID,
InviteType: "userinvite",
Subject: contactSubject,
EmailContent: contactBody,
Automate: false,
})
if contactInviteErr != nil {
log.WithFields(f).WithError(contactInviteErr).Warnf("failed to send contact role invitation, but primary invitation succeeded")
// Don't return error, as the primary invitation was successful
}
}

return nil
}
22 changes: 22 additions & 0 deletions cla-backend-go/v2/cla_manager/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,28 @@ func (s *service) CreateCLAManagerDesignee(ctx context.Context, companyID string
log.WithFields(f).Debugf("created user role organization scope for user: %s, with role: %s with role ID: %s using project|org: %s|%s...",
userEmail, utils.CLADesigneeRole, roleID, projectSFID, v1CompanyModel.CompanyExternalID)

// Also assign the "contact" role which is required to access the Corporate Console
log.WithFields(f).Debugf("loading role ID for %s...", utils.ContactRole)
contactRoleID, contactErr := acServiceClient.GetRoleID(utils.ContactRole)
if contactErr != nil {
log.WithFields(f).Warnf("Problem getting role ID for contact role, error: %+v - continuing without contact role", contactErr)
} else {
log.WithFields(f).Debugf("creating contact role organization scope for user: %s, with role: %s with role ID: %s using org: %s...",
userEmail, utils.ContactRole, contactRoleID, v1CompanyModel.CompanyExternalID)
contactScopeErr := orgClient.CreateOrgUserRoleOrgScope(ctx, userEmail, v1CompanyModel.CompanyExternalID, contactRoleID)
if contactScopeErr != nil {
// Ignore conflict - role has already been assigned - otherwise, log error but don't fail
if _, ok := contactScopeErr.(*organizations.CreateOrgUsrRoleScopesConflict); !ok {
log.WithFields(f).Warnf("problem creating contact role org scope for email: %s, companySFID: %s, error: %+v - continuing without contact role", userEmail, v1CompanyModel.CompanyExternalID, contactScopeErr)
} else {
log.WithFields(f).Debugf("contact role already assigned for user: %s, companySFID: %s", userEmail, v1CompanyModel.CompanyExternalID)
}
} else {
log.WithFields(f).Debugf("successfully created contact role organization scope for user: %s, with role: %s with role ID: %s using org: %s",
userEmail, utils.ContactRole, contactRoleID, v1CompanyModel.CompanyExternalID)
}
}

// Log Event
s.eventService.LogEventWithContext(ctx,
&events.LogEventArgs{
Expand Down
Loading