diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml
index 386e4633a..d7dee8ce9 100644
--- a/.github/workflows/build-pr.yml
+++ b/.github/workflows/build-pr.yml
@@ -8,7 +8,6 @@ on:
branches:
- dev
-
permissions:
id-token: write
contents: read
diff --git a/.gitignore b/.gitignore
index 834c8f3bb..65b03c4ce 100755
--- a/.gitignore
+++ b/.gitignore
@@ -241,3 +241,7 @@ dist/*
api-postman/*
cla-backend/run-python-test-example-*.py
+
+# LG
+out
+*.secret
diff --git a/aws_env.md b/aws_env.md
new file mode 100644
index 000000000..4e53960f3
--- /dev/null
+++ b/aws_env.md
@@ -0,0 +1,130 @@
+# Setting up AWS environment
+
+You need to have MFA enabled for your AWS user, your `~/.aws/config` shoudl look like this:
+```
+[profile lfproduct-dev]
+role_arn = arn:aws:iam::395594542180:role/product-contractors-role
+source_profile = lfproduct
+region = us-east-1
+output = json
+
+[profile lfproduct-test]
+role_arn = arn:aws:iam::726224182707:role/product-contractors-role
+source_profile = lfproduct
+region = us-east-1
+output = json
+
+[profile lfproduct-staging]
+role_arn = arn:aws:iam::844390194980:role/product-contractors-role
+source_profile = lfproduct
+region = us-east-1
+output = json
+
+[profile lfproduct-prod]
+role_arn = arn:aws:iam::716487311010:role/product-contractors-role
+source_profile = lfproduct
+region = us-east-1
+output = json
+
+[default]
+region = us-east-1
+output = json
+```
+
+It defines 4 profiles to use: `dev`, `staging`, `test` and `prod`.
+
+You will be using one of them.
+
+
+Your `~/.aws/credentials` file shoudl initially look like this (replace `redacted`):
+```
+[lfproduct-long-term]
+aws_secret_access_key = [access_key_redacted]
+aws_access_key_id = [key_id_redacted]
+aws_mfa_device = arn:aws:iam::[arn_number_redacted]:mfa/[your_aws_user_redacted]
+
+[default]
+aws_access_key_id = [key_id_redacted]
+aws_secret_access_key = [access_key_redacted]
+```
+
+Now every 36 hours or less you need to refresh your MFA key by calling: `aws-mfa --force --duration 129600 --profile lfproduct`.
+
+When called it adds or replaces the following section (`[lfproduct]` which is used as a source profile for `dev`, `test`, `staging` or `prod` in aws config) in `~/.aws/credentials`:
+```
+[lfproduct]
+assumed_role = False
+aws_access_key_id = [key_id_redacted]
+aws_secret_access_key = [secret_access_key_redacted]
+aws_session_token = [session_token_redacted]
+aws_security_token = [session_token_redacted]
+expiration = 2024-11-28 16:54:59 [now + 36 hours]
+
+```
+
+
+Once you have all of this, you must set a correct set of environment variables to run either `python` or `golang` backends.
+
+To do so you need to get credentials for a specific profile `lfproduct-`: `dev`, `test`, `staging`, `prod`. To see full one-time set of credentials you can call:
+- for `dev`: `` aws sts assume-role --role-arn arn:aws:iam::395594542180:role/product-contractors-role --profile lfproduct --role-session-name lfproduct-dev-session ``.
+- for `prod`: `` aws sts assume-role --role-arn arn:aws:iam::716487311010:role/product-contractors-role --profile lfproduct --role-session-name lfproduct-prod-session ``.
+
+Note - just replace the iam::[number] depending on environment type (`[stage]`) and update `lfproduct-[stage]-name`.
+
+You can set up a script like `setenv.sh` which will set all required variables, example for `dev`:
+```
+#!/bin/bash
+
+rm -rf /tmp/aws
+cp -R /root/.aws /tmp/.aws
+
+data="$(aws sts assume-role --role-arn arn:aws:iam::395594542180:role/product-contractors-role --profile lfproduct --role-session-name lfproduct-dev-session)"
+export AWS_ACCESS_KEY_ID="$(echo "${data}" | jq -r '.Credentials.AccessKeyId')"
+export AWS_SECRET_ACCESS_KEY="$(echo "${data}" | jq -r '.Credentials.SecretAccessKey')"
+export AWS_SESSION_TOKEN="$(echo "${data}" | jq -r '.Credentials.SessionToken')"
+export AWS_SECURITY_TOKEN="$(echo "${data}" | jq -r '.Credentials.SessionToken')"
+
+export AWS_SDK_LOAD_CONFIG=true
+export AWS_PROFILE='lfproduct-dev'
+export AWS_REGION='us-east-1'
+export AWS_DEFAULT_REGION='us-east-1'
+export DYNAMODB_AWS_REGION='us-east-1'
+export REGION='us-east-1'
+
+export PRODUCT_DOMAIN='dev.lfcla.com'
+export ROOT_DOMAIN='lfcla.dev.platform.linuxfoundation.org'
+export PORT='5000'
+export STAGE='dev'
+# export STAGE='local'
+export GH_ORG_VALIDATION=false
+export DISABLE_LOCAL_PERMISSION_CHECKS=true
+export COMPANY_USER_VALIDATION=false
+export CLA_SIGNATURE_FILES_BUCKET=cla-signature-files-dev
+```
+
+Call it via `` . ./setenv.sh `` or `` source setenv.sh `` to execute in the current shell.
+
+You can reset environment variables by exiting the shell session or calling the following `unsetenv.sh` in the current shell via: `` . ./unsetenv.sh `` or `` source unsetenv.sh ``:
+```
+#!/bin/bash
+rm -rf /tmp/.aws
+unset AWS_PROFILE
+unset AWS_REGION
+unset AWS_ACCESS_KEY_ID
+unset AWS_SECRET_ACCESS_KEY
+unset PRODUCT_DOMAIN
+unset ROOT_DOMAIN
+unset PORT
+unset STAGE
+unset AWS_SESSION_TOKEN
+unset AWS_SECURITY_TOKEN
+unset GH_ORG_VALIDATION
+unset DISABLE_LOCAL_PERMISSION_CHECKS
+unset COMPANY_USER_VALIDATION
+unset CLA_SIGNATURE_FILES_BUCKET
+unset DYNAMODB_AWS_REGION
+unset REGION
+unset AWS_ROLE_ARN
+unset AWS_TOKEN_SERIAL
+unset AWS_SDK_LOAD_CONFIG
+```
diff --git a/cla-backend-go/api_client/api_client.go b/cla-backend-go/api_client/api_client.go
new file mode 100644
index 000000000..42c0d1999
--- /dev/null
+++ b/cla-backend-go/api_client/api_client.go
@@ -0,0 +1,27 @@
+// Copyright The Linux Foundation and each contributor to CommunityBridge.
+// SPDX-License-Identifier: MIT
+
+package apiclient
+
+import (
+ "context"
+ "net/http"
+)
+
+type APIClient interface {
+ GetData(ctx context.Context, url string) (*http.Response, error)
+}
+
+type RestAPIClient struct {
+ Client *http.Client
+}
+
+// GetData makes a get request to the specified url
+
+func (c *RestAPIClient) GetData(ctx context.Context, url string) (*http.Response, error) {
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
+ if err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
diff --git a/cla-backend-go/api_client/mocks/mock_client.go b/cla-backend-go/api_client/mocks/mock_client.go
new file mode 100644
index 000000000..08dd5ceba
--- /dev/null
+++ b/cla-backend-go/api_client/mocks/mock_client.go
@@ -0,0 +1,54 @@
+// Copyright The Linux Foundation and each contributor to CommunityBridge.
+// SPDX-License-Identifier: MIT
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: api_client/api_client.go
+
+// Package mock_apiclient is a generated GoMock package.
+package mock_apiclient
+
+import (
+ context "context"
+ http "net/http"
+ reflect "reflect"
+
+ gomock "github.com/golang/mock/gomock"
+)
+
+// MockAPIClient is a mock of APIClient interface.
+type MockAPIClient struct {
+ ctrl *gomock.Controller
+ recorder *MockAPIClientMockRecorder
+}
+
+// MockAPIClientMockRecorder is the mock recorder for MockAPIClient.
+type MockAPIClientMockRecorder struct {
+ mock *MockAPIClient
+}
+
+// NewMockAPIClient creates a new mock instance.
+func NewMockAPIClient(ctrl *gomock.Controller) *MockAPIClient {
+ mock := &MockAPIClient{ctrl: ctrl}
+ mock.recorder = &MockAPIClientMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockAPIClient) EXPECT() *MockAPIClientMockRecorder {
+ return m.recorder
+}
+
+// GetData mocks base method.
+func (m *MockAPIClient) GetData(ctx context.Context, url string) (*http.Response, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetData", ctx, url)
+ ret0, _ := ret[0].(*http.Response)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetData indicates an expected call of GetData.
+func (mr *MockAPIClientMockRecorder) GetData(ctx, url interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetData", reflect.TypeOf((*MockAPIClient)(nil).GetData), ctx, url)
+}
diff --git a/cla-backend-go/cla_manager/service.go b/cla-backend-go/cla_manager/service.go
index 00961bae2..e13bbf276 100644
--- a/cla-backend-go/cla_manager/service.go
+++ b/cla-backend-go/cla_manager/service.go
@@ -39,7 +39,7 @@ type IService interface {
PendingRequest(companyID, claGroupID, requestID string) (*models.ClaManagerRequest, error)
DeleteRequest(requestID string) error
- AddClaManager(ctx context.Context, authUser *auth.User, companyID string, claGroupID string, LFID string, projectSFName string) (*models.Signature, error)
+ AddClaManager(ctx context.Context, authUser *auth.User, companyID string, claGroupID string, LFID string, projectSFID string) (*models.Signature, error)
RemoveClaManager(ctx context.Context, authUser *auth.User, companyID string, claGroupID string, LFID string, projectSFName string) (*models.Signature, error)
}
@@ -193,7 +193,7 @@ func (s service) DeleteRequest(requestID string) error {
}
// AddClaManager Adds LFID to Signature Access Control list
-func (s service) AddClaManager(ctx context.Context, authUser *auth.User, companyID string, claGroupID string, LFID string, projectSFName string) (*models.Signature, error) {
+func (s service) AddClaManager(ctx context.Context, authUser *auth.User, companyID string, claGroupID string, LFID string, projectSFID string) (*models.Signature, error) {
f := logrus.Fields{
"functionName": "v1.cla_manager.AddClaManager",
@@ -201,9 +201,9 @@ func (s service) AddClaManager(ctx context.Context, authUser *auth.User, company
"companyID": companyID,
"claGroupID": claGroupID,
"LFID": LFID,
- "projectName": projectSFName,
+ "projectSFID": projectSFID,
}
-
+ var projectSFName string
userModel, userErr := s.usersService.GetUserByLFUserName(LFID)
if userErr != nil || userModel == nil {
return nil, userErr
@@ -218,11 +218,6 @@ func (s service) AddClaManager(ctx context.Context, authUser *auth.User, company
return nil, projectErr
}
- // if projectSFName is empty, we can set clagroup project name.
- if projectSFName == "" {
- projectSFName = claGroupModel.ProjectName
- }
-
// Look up signature ACL to ensure the user can add cla manager
signed := true
@@ -258,8 +253,9 @@ func (s service) AddClaManager(ctx context.Context, authUser *auth.User, company
RecipientAddress: manager.LfEmail.String(),
CompanyName: companyModel.CompanyName,
},
- Name: userModel.Username,
- Email: userModel.LfEmail.String(),
+ Name: userModel.Username,
+ Email: userModel.LfEmail.String(),
+ ProjectSFID: projectSFID,
}, claGroupModel)
}
// Notify the added user
@@ -267,7 +263,7 @@ func (s service) AddClaManager(ctx context.Context, authUser *auth.User, company
RecipientName: userModel.Username,
RecipientAddress: userModel.LfEmail.String(),
CompanyName: companyModel.CompanyName,
- }, claGroupModel)
+ }, claGroupModel, projectSFID)
// Send an event
s.eventsService.LogEventWithContext(ctx, &events.LogEventArgs{
@@ -317,7 +313,7 @@ func (s service) getCompanySignature(ctx context.Context, companyID string, claG
}
// RemoveClaManager removes lfid from signature acl with given company and project
-func (s service) RemoveClaManager(ctx context.Context, authUser *auth.User, companyID string, claGroupID string, LFID string, projectSFName string) (*models.Signature, error) {
+func (s service) RemoveClaManager(ctx context.Context, authUser *auth.User, companyID string, claGroupID string, LFID string, projectSFID string) (*models.Signature, error) {
f := logrus.Fields{
"functionName": "v1.cla_manager.RemoveClaManager",
@@ -327,6 +323,7 @@ func (s service) RemoveClaManager(ctx context.Context, authUser *auth.User, comp
"companyID": companyID,
}
+ var projectSFName string
userModel, userErr := s.usersService.GetUserByLFUserName(LFID)
if userErr != nil || userModel == nil {
return nil, userErr
@@ -341,11 +338,6 @@ func (s service) RemoveClaManager(ctx context.Context, authUser *auth.User, comp
return nil, projectErr
}
- // if projectSFName is empty, we can set clagroup project name.
- if projectSFName == "" {
- projectSFName = claGroupModel.ProjectName
- }
-
signed := true
approved := true
sigModel, sigErr := s.sigService.GetProjectCompanySignature(ctx, companyID, claGroupID, &signed, &approved, nil, aws.Int64(5))
@@ -420,50 +412,56 @@ func (s service) RemoveClaManager(ctx context.Context, authUser *auth.User, comp
type ProjectDetails struct {
ProjectName string
- ProjectSFID string
+ ProjectSFID []string
}
-func (s service) getProjectDetails(ctx context.Context, claGroupModel *models.ClaGroup) ProjectDetails {
- f := logrus.Fields{
- "functionName": "v1.cla_manager.getProjectDetails",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "claGroupID": claGroupModel.ProjectID,
- }
+// func (s service) getProjectDetails(ctx context.Context, claGroupModel *models.ClaGroup) ProjectDetails {
+// f := logrus.Fields{
+// "functionName": "v1.cla_manager.getProjectDetails",
+// utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
+// "claGroupID": claGroupModel.ProjectID,
+// }
+// projectSFIDs := make([]string, 0)
- projectDetails := ProjectDetails{
- ProjectName: claGroupModel.ProjectName,
- ProjectSFID: claGroupModel.ProjectExternalID,
- }
- signedAtFoundation := false
+// projectDetails := ProjectDetails{
+// ProjectName: claGroupModel.ProjectName,
+// }
+// signedAtFoundation := false
+// var err error
- pcg, err := s.projectClaRepository.GetCLAGroup(ctx, claGroupModel.ProjectID)
- if err != nil {
- log.WithFields(f).Warnf("unable to fetch project cla group by project id: %s, error: %+v", claGroupModel.ProjectID, err)
- }
+// pcg, pcgErr := s.projectClaRepository.GetCLAGroup(ctx, claGroupModel.ProjectID)
+// if pcgErr != nil {
+// log.WithFields(f).WithError(err).Debug("unable too get pcg record")
+// }
- // check if cla group is signed at foundation level
- if pcg != nil && pcg.FoundationSFID != "" {
- signedAtFoundation, err = s.projectClaRepository.IsExistingFoundationLevelCLAGroup(ctx, pcg.FoundationSFID)
- if err != nil {
- log.WithFields(f).Warnf("unable to fetch foundation level cla group by foundation id: %s, error: %+v", pcg.FoundationSFID, err)
- }
+// signedAtFoundation, err = s.projectClaRepository.SignedAtFoundation(ctx, claGroupModel.ProjectID)
+// if err != nil {
+// log.WithFields(f).WithError(err).Debug("unable to get status of cla signed at foundation")
+// }
- if signedAtFoundation {
- log.WithFields(f).Debugf("cla group is signed at foundation level...")
- projectDetails.ProjectName = pcg.FoundationName
- projectDetails.ProjectSFID = pcg.FoundationSFID
- }
- }
+// if signedAtFoundation && pcg != nil && err != nil {
+// log.WithFields(f).Debug("cla group is signed at foundation level...")
+// projectDetails.ProjectName = pcg.FoundationName
+// projectSFIDs = append(projectSFIDs, pcg.FoundationSFID)
- return projectDetails
-}
+// } else {
+// log.WithFields(f).Debug("cla group is signed at project level ...")
+
+// }
-func (s service) sendClaManagerAddedEmailToUser(emailSvc emails.EmailTemplateService, emailParams emails.CommonEmailParams, claGroupModel *models.ClaGroup) {
- projectDetails := s.getProjectDetails(context.Background(), claGroupModel)
- projectName := projectDetails.ProjectName
- projectSFID := projectDetails.ProjectSFID
+// projectDetails.ProjectSFID = projectSFIDs
+
+// return projectDetails
+// }
+
+func (s service) sendClaManagerAddedEmailToUser(emailSvc emails.EmailTemplateService, emailParams emails.CommonEmailParams, claGroupModel *models.ClaGroup, projectSFID string) {
+ f := logrus.Fields{
+ "functionName": "sendClaManagerAddedEmailToUser",
+ "projectSFID": projectSFID,
+ }
+ log.WithFields(f).Info("Sending email to user")
// subject string, body string, recipients []string
- subject := fmt.Sprintf("EasyCLA: Added as CLA Manager for Project :%s", projectName)
+ subject := fmt.Sprintf("EasyCLA: Added as CLA Manager for Project :%s", claGroupModel.ProjectName)
recipients := []string{emailParams.RecipientAddress}
body, err := emails.RenderClaManagerAddedEToUserTemplate(emailSvc, claGroupModel.Version, projectSFID, emails.ClaManagerAddedEToUserTemplateParams{
CommonEmailParams: emailParams,
@@ -487,7 +485,7 @@ func sendClaManagerAddedEmailToCLAManagers(emailSvc emails.EmailTemplateService,
// subject string, body string, recipients []string
subject := fmt.Sprintf("EasyCLA: CLA Manager Added Notice for %s", projectName)
recipients := []string{emailParams.RecipientAddress}
- body, err := emails.RenderClaManagerAddedToCLAManagersTemplate(emailSvc, claGroupModel.Version, claGroupModel.ProjectExternalID, emailParams)
+ body, err := emails.RenderClaManagerAddedToCLAManagersTemplate(emailSvc, claGroupModel.Version, projectName, emailParams)
if err != nil {
log.Warnf("email template render : %s failed : %v", emails.ClaManagerAddedToCLAManagersTemplate, err)
return
@@ -553,10 +551,12 @@ func sendRemovedClaManagerEmailToRecipient(emailSvc emails.EmailTemplateService,
body, err := emails.RenderRemovedCLAManagerTemplate(
emailSvc,
claGroupModel.Version,
- claGroupModel.ProjectExternalID,
emails.RemovedCLAManagerTemplateParams{
CommonEmailParams: emailParams,
CLAManagers: emailCLAManagerParams,
+ CLAGroupTemplateParams: emails.CLAGroupTemplateParams{
+ CLAGroupName: projectName,
+ },
})
if err != nil {
@@ -573,14 +573,11 @@ func sendRemovedClaManagerEmailToRecipient(emailSvc emails.EmailTemplateService,
}
func (s service) sendClaManagerDeleteEmailToCLAManagers(emailSvc emails.EmailTemplateService, emailParams emails.ClaManagerDeletedToCLAManagersTemplateParams, claGroupModel *models.ClaGroup) {
- projectDetails := s.getProjectDetails(context.Background(), claGroupModel)
- projectName := projectDetails.ProjectName
- projectSFID := projectDetails.ProjectSFID
// subject string, body string, recipients []string
- subject := fmt.Sprintf("EasyCLA: CLA Manager Removed Notice for %s", projectName)
+ subject := fmt.Sprintf("EasyCLA: CLA Manager Removed Notice for %s", claGroupModel.ProjectName)
recipients := []string{emailParams.RecipientAddress}
- body, err := emails.RenderClaManagerDeletedToCLAManagersTemplate(emailSvc, claGroupModel.Version, projectSFID, emailParams)
+ body, err := emails.RenderClaManagerDeletedToCLAManagersTemplate(emailSvc, claGroupModel.Version, claGroupModel.ProjectName)
if err != nil {
log.Warnf("email template render : %s failed : %v", emails.ClaManagerDeletedToCLAManagersTemplateName, err)
diff --git a/cla-backend-go/cmd/dynamo_events_lambda/main.go b/cla-backend-go/cmd/dynamo_events_lambda/main.go
index ee910d335..652f7e4e3 100644
--- a/cla-backend-go/cmd/dynamo_events_lambda/main.go
+++ b/cla-backend-go/cmd/dynamo_events_lambda/main.go
@@ -115,12 +115,7 @@ func init() {
githubOrganizationsService := github_organizations.NewService(githubOrganizationsRepo, repositoriesRepo, projectClaGroupRepo)
repositoriesService := repositories.NewService(repositoriesRepo, githubOrganizationsRepo, projectClaGroupRepo)
- gerritService := gerrits.NewService(gerritRepo, &gerrits.LFGroup{
- LfBaseURL: configFile.LFGroup.ClientURL,
- ClientID: configFile.LFGroup.ClientID,
- ClientSecret: configFile.LFGroup.ClientSecret,
- RefreshToken: configFile.LFGroup.RefreshToken,
- })
+ gerritService := gerrits.NewService(gerritRepo)
// Services
projectService := service.NewService(projectRepo, repositoriesRepo, gerritRepo, projectClaGroupRepo, usersRepo)
diff --git a/cla-backend-go/cmd/gitlab_repository_check/handler/handler.go b/cla-backend-go/cmd/gitlab_repository_check/handler/handler.go
index f4b261403..1097ffa52 100644
--- a/cla-backend-go/cmd/gitlab_repository_check/handler/handler.go
+++ b/cla-backend-go/cmd/gitlab_repository_check/handler/handler.go
@@ -137,12 +137,7 @@ func Handler(ctx context.Context) error {
v1ProjectClaGroupRepo,
})
- gerritService := gerrits.NewService(gerritRepo, &gerrits.LFGroup{
- LfBaseURL: configFile.LFGroup.ClientURL,
- ClientID: configFile.LFGroup.ClientID,
- ClientSecret: configFile.LFGroup.ClientSecret,
- RefreshToken: configFile.LFGroup.RefreshToken,
- })
+ gerritService := gerrits.NewService(gerritRepo)
approvalsTableName := "cla-" + stage + "-approvals"
diff --git a/cla-backend-go/cmd/ldap_gerrit_check/main.go b/cla-backend-go/cmd/ldap_gerrit_check/main.go
new file mode 100644
index 000000000..76fdca97c
--- /dev/null
+++ b/cla-backend-go/cmd/ldap_gerrit_check/main.go
@@ -0,0 +1,173 @@
+// Copyright The Linux Foundation and each contributor to CommunityBridge.
+// SPDX-License-Identifier: MIT
+
+package main
+
+import (
+ // "context"
+ "encoding/csv"
+ "flag"
+ "fmt"
+ "os"
+ "path/filepath"
+ "sync"
+ "time"
+
+ "github.com/aws/aws-sdk-go/aws"
+ "github.com/aws/aws-sdk-go/aws/session"
+ "github.com/communitybridge/easycla/cla-backend-go/events"
+ "github.com/communitybridge/easycla/cla-backend-go/gen/v1/models"
+ eventOps "github.com/communitybridge/easycla/cla-backend-go/gen/v1/restapi/operations/events"
+ log "github.com/communitybridge/easycla/cla-backend-go/logging"
+ // "github.com/communitybridge/easycla/cla-backend-go/users"
+)
+
+var awsSession = session.Must(session.NewSession(&aws.Config{}))
+var stage string
+
+func main() {
+ stage = os.Getenv("STAGE")
+ if stage == "" {
+ log.Fatal("stage not set")
+ }
+ log.Infof("STAGE set to %s\n", stage)
+
+ var wg sync.WaitGroup
+ var mu sync.Mutex
+
+ // Initialize the events repository
+ eventsRepo := events.NewRepository(awsSession, stage)
+ eventService := events.NewService(eventsRepo, nil)
+
+ // Initialize the users repository
+ // usersRepo := users.NewRepository(awsSession, stage)
+
+ inputFilename := flag.String("input-file", "", "Input with a given list of lf usernames")
+ claGroup := flag.String("cla-group-id", "", "The ID of the CLA group")
+ claGroupName := flag.String("cla-group-name", "", "The name of the CLA group")
+ flag.Parse()
+
+ if *inputFilename == "" || *claGroup == "" {
+ log.Fatalf("Both input-file and cla-group are required")
+ }
+
+ log.Debugf("Input file: %s", *inputFilename)
+
+ file, err := os.Open(*inputFilename)
+ if err != nil {
+ log.Fatalf("Unable to read input file: %s", *inputFilename)
+ }
+
+ defer func() {
+ if err = file.Close(); err != nil {
+ log.Fatalf("Error closing file: %v", err)
+ }
+ }()
+
+ reader := csv.NewReader(file)
+
+ records, err := reader.ReadAll()
+ if err != nil {
+ log.Fatalf("Unable to read file")
+ }
+
+ log.Debugf("CLA Group Name: %s", *claGroup)
+
+ type Report struct {
+ Username string
+ Events []*models.Event
+ }
+
+ projectReport := make([]Report, 0)
+
+ for i, record := range records {
+ if i == 0 {
+ continue
+ }
+ lfUsername := record[0]
+ log.Debugf("Processing record: %s", lfUsername)
+ report := Report{
+ Username: lfUsername,
+ }
+
+ // Increment the wait group
+ wg.Add(1)
+
+ go func(lfusername string) {
+ defer wg.Done()
+ log.Debugf("Processing record: %s", lfusername)
+ searchParams := eventOps.SearchEventsParams{
+ SearchTerm: &lfusername,
+ ProjectID: claGroup,
+ }
+ events, eventErr := eventService.SearchEvents(&searchParams)
+ if eventErr != nil {
+ log.Debugf("Error getting events: %v", eventErr)
+ report.Events = nil
+ }
+
+ if len(events.Events) == 0 {
+ log.Warnf("No events found for user: %s", lfusername)
+ report.Events = nil
+ } else {
+ log.Debugf("Events found for user: %s", lfusername)
+ report.Events = events.Events
+ }
+
+ mu.Lock()
+ projectReport = append(projectReport, report)
+ defer mu.Unlock()
+
+ }(lfUsername)
+ }
+
+ // Wait for all the go routines to finish
+ wg.Wait()
+
+ // Create a csv file with the results
+ outputFilename := fmt.Sprintf("ldap-%s-%s.csv", *claGroupName, time.Now().Format("2006-01-02-15-04-05"))
+ outputFile, err := os.Create(filepath.Clean(outputFilename))
+
+ if err != nil {
+ log.Fatalf("Unable to create output file: %s", outputFilename)
+ }
+
+ defer func() {
+ if err = outputFile.Close(); err != nil {
+ log.Fatalf("Error closing file: %v", err)
+ }
+ }()
+
+ writer := csv.NewWriter(outputFile)
+
+ err = writer.Write([]string{"Username", "Event ID", "Event Data", "Event Type", "Event Date"})
+ if err != nil {
+ log.Fatalf("Error writing csv: %v", err)
+ }
+
+ for _, report := range projectReport {
+ if report.Events == nil {
+ err = writer.Write([]string{report.Username, "No events found", "", "", ""})
+ if err != nil {
+ log.Fatalf("Error writing csv: %v", err)
+ }
+ continue
+ }
+ for _, event := range report.Events {
+ err = writer.Write([]string{report.Username, event.EventID, event.EventData, event.EventType, event.EventTime})
+ if err != nil {
+ log.Fatalf("Error writing csv: %v", err)
+ }
+
+ }
+ }
+
+ writer.Flush()
+
+ if err := writer.Error(); err != nil {
+ log.Fatalf("Error writing csv: %v", err)
+ }
+
+ log.Infof("Output written to: %s", outputFilename)
+
+}
diff --git a/cla-backend-go/cmd/migrate_approval_list/main.go b/cla-backend-go/cmd/migrate_approval_list/main.go
index 574b58356..63f6c387f 100644
--- a/cla-backend-go/cmd/migrate_approval_list/main.go
+++ b/cla-backend-go/cmd/migrate_approval_list/main.go
@@ -81,7 +81,7 @@ func init() {
v1ProjectClaGroupRepo,
})
ghOrgRepo = github_organizations.NewRepository(awsSession, stage)
- gerritService = gerrits.NewService(gerritsRepo, nil)
+ gerritService = gerrits.NewService(gerritsRepo)
signatureRepo = signatures.NewRepository(awsSession, stage, companyRepo, usersRepo, eventsService, &ghRepo, ghOrgRepo, gerritService, approvalRepo)
log.Info("initialized repositories\n")
diff --git a/cla-backend-go/cmd/server.go b/cla-backend-go/cmd/server.go
index 1e67f9680..e2291e37d 100644
--- a/cla-backend-go/cmd/server.go
+++ b/cla-backend-go/cmd/server.go
@@ -273,13 +273,7 @@ func server(localMode bool) http.Handler {
v1ProjectClaGroupRepo,
})
- gerritService := gerrits.NewService(gerritRepo, &gerrits.LFGroup{
- LfBaseURL: configFile.LFGroup.ClientURL,
- ClientID: configFile.LFGroup.ClientID,
- ClientSecret: configFile.LFGroup.ClientSecret,
- RefreshToken: configFile.LFGroup.RefreshToken,
- EventsService: eventsService,
- })
+ gerritService := gerrits.NewService(gerritRepo)
// Signature repository handler
signaturesRepo := signatures.NewRepository(awsSession, stage, v1CompanyRepo, usersRepo, eventsService, gitV1Repository, githubOrganizationsRepo, gerritService, approvalsRepo)
diff --git a/cla-backend-go/emails/cla_manager_templates.go b/cla-backend-go/emails/cla_manager_templates.go
index 4c7b85e45..d8f5d2dbc 100644
--- a/cla-backend-go/emails/cla_manager_templates.go
+++ b/cla-backend-go/emails/cla_manager_templates.go
@@ -16,8 +16,8 @@ const (
// RemovedCLAManagerTemplate includes the email template for email when user is removed as CLA Manager
RemovedCLAManagerTemplate = `
Hello {{.RecipientName}},
-This is a notification email from EasyCLA regarding the project {{.GetProjectNameOrFoundation}} and CLA Group {{.CLAGroupName}}.
-You have been removed as a CLA Manager from {{.CompanyName}} for the project {{.Project.ExternalProjectName}}.
+This is a notification email from EasyCLA regarding the CLA Group {{.CLAGroupName}}.
+You have been removed as a CLA Manager from {{.CompanyName}} for the CLA Group {{.CLAGroupName}}.
If you have further questions about this, please contact one of the existing managers from
{{.CompanyName}}:
@@ -29,13 +29,7 @@ const (
)
// RenderRemovedCLAManagerTemplate renders the RemovedCLAManagerTemplate
-func RenderRemovedCLAManagerTemplate(svc EmailTemplateService, claGroupModelVersion, projectSFID string, params RemovedCLAManagerTemplateParams) (string, error) {
- claGroupParams, err := svc.GetCLAGroupTemplateParamsFromProjectSFID(claGroupModelVersion, projectSFID)
- if err != nil {
- return "", err
- }
- params.CLAGroupTemplateParams = claGroupParams
-
+func RenderRemovedCLAManagerTemplate(svc EmailTemplateService, claGroupModelVersion string, params RemovedCLAManagerTemplateParams) (string, error) {
return RenderTemplate(claGroupModelVersion, RemovedCLAManagerTemplateName, RemovedCLAManagerTemplate, params)
}
@@ -218,12 +212,12 @@ const (
//ClaManagerAddedEToUserTemplate email template for cla manager v2
ClaManagerAddedEToUserTemplate = `
Hello {{.RecipientName}},
-This is a notification email from EasyCLA regarding the project {{.Project.ExternalProjectName}} and CLA Group {{.CLAGroupName}}.
-You have been added as a CLA Manager for the organization {{.CompanyName}} and the project {{.Project.ExternalProjectName}}. This means that you can now maintain the
-list of employees allowed to contribute to the project {{.Project.ExternalProjectName}} on behalf of your company, as well as view and manage the list of your
+
This is a notification email from EasyCLA regarding the CLA Group {{.CLAGroupName}}.
+You have been added as a CLA Manager for the organization {{.CompanyName}} and the CLAGroup {{.CLAGroupName}}. This means that you can now maintain the
+list of employees allowed to contribute to the CLA Group {{.CLAGroupName}} on behalf of your company, as well as view and manage the list of your
company’s CLA Managers for the CLA Group {{.CLAGroupName}}.
To get started, please log into the EasyCLA Corporate Console, and select your
-company and then the project {{.Project.ExternalProjectName}}. From here you will be able to edit the list of approved employees and CLA Managers.
+company and then the project {{.CLAGroupName}}. From here you will be able to edit the list of approved employees and CLA Managers.
`
)
@@ -242,8 +236,9 @@ func RenderClaManagerAddedEToUserTemplate(svc EmailTemplateService, claGroupMode
type ClaManagerAddedToCLAManagersTemplateParams struct {
CommonEmailParams
CLAGroupTemplateParams
- Name string
- Email string
+ Name string
+ Email string
+ ProjectSFID string
}
const (
@@ -252,10 +247,10 @@ const (
// ClaManagerAddedToCLAManagersTemplate is email template for
ClaManagerAddedToCLAManagersTemplate = `
Hello {{.RecipientName}},
-This is a notification email from EasyCLA regarding the project {{.Project.ExternalProjectName}} associated with the CLA Group {{.CLAGroupName}}.
-The following user has been added as a CLA Manager from {{.CompanyName}} for the project {{.Project.ExternalProjectName}}. This means that they can now
-maintain the list of employees allowed to contribute to {{.Project.ExternalProjectName}} on behalf of your company, as well as view and manage the
-list of company’s CLA Managers for {{.Project.ExternalProjectName}}.
+This is a notification email from EasyCLA regarding the CLA Group {{.CLAGroupName}}.
+The following user has been added as a CLA Manager from {{.CompanyName}} for the CLA Group {{.CLAGroupName}}. This means that they can now
+maintain the list of employees allowed to contribute to {{.CLAGroupName}} on behalf of your company, as well as view and manage the
+list of company’s CLA Managers for CLA Group {{.CLAGroupName}}.
@@ -263,12 +258,15 @@ list of company’s CLA Managers for {{.Project.ExternalProjectName}}.
)
// RenderClaManagerAddedToCLAManagersTemplate renders the ClaManagerAddedToCLAManagersTemplate
-func RenderClaManagerAddedToCLAManagersTemplate(svc EmailTemplateService, claGroupModelVersion, projectSFID string, params ClaManagerAddedToCLAManagersTemplateParams) (string, error) {
- claGroupParams, err := svc.GetCLAGroupTemplateParamsFromProjectSFID(claGroupModelVersion, projectSFID)
- if err != nil {
- return "", err
+func RenderClaManagerAddedToCLAManagersTemplate(svc EmailTemplateService, claGroupModelVersion, claGroupName string, params ClaManagerAddedToCLAManagersTemplateParams) (string, error) {
+ // claGroupParams, err := svc.GetCLAGroupTemplateParamsFromProjectSFID(claGroupModelVersion, projectSFID)
+ // if err != nil {
+ // return "", err
+ // }
+ // params.CLAGroupTemplateParams = claGroupParams
+ params.CLAGroupTemplateParams = CLAGroupTemplateParams{
+ CLAGroupName: claGroupName,
}
- params.CLAGroupTemplateParams = claGroupParams
return RenderTemplate(claGroupModelVersion, ClaManagerAddedToCLAManagersTemplateName, ClaManagerAddedToCLAManagersTemplate, params)
}
@@ -287,18 +285,17 @@ const (
// ClaManagerDeletedToCLAManagersTemplate is template for
ClaManagerDeletedToCLAManagersTemplate = `
Hello {{.RecipientName}},
-This is a notification email from EasyCLA regarding the project {{.Project.ExternalProjectName}}.
-{{.Name}} ({{.Email}}) has been removed as a CLA Manager from {{.CompanyName}} for the project {{.Project.ExternalProjectName}}.
+This is a notification email from EasyCLA regarding the CLA Group {{.CLAGroupName}}.
+{{.Name}} ({{.Email}}) has been removed as a CLA Manager from {{.CompanyName}} for CLA Group {{.CLAGroupName}}.
`
)
// RenderClaManagerDeletedToCLAManagersTemplate renders the RemovedCLAManagerTemplate
-func RenderClaManagerDeletedToCLAManagersTemplate(svc EmailTemplateService, claGroupModelVersion, projectSFID string, params ClaManagerDeletedToCLAManagersTemplateParams) (string, error) {
- claGroupParams, err := svc.GetCLAGroupTemplateParamsFromProjectSFID(claGroupModelVersion, projectSFID)
- if err != nil {
- return "", err
+func RenderClaManagerDeletedToCLAManagersTemplate(svc EmailTemplateService, claGroupModelVersion, claGroupName string) (string, error) {
+
+ params := CLAGroupTemplateParams{
+ CLAGroupName: claGroupName,
}
- params.CLAGroupTemplateParams = claGroupParams
return RenderTemplate(claGroupModelVersion, ClaManagerDeletedToCLAManagersTemplateName, ClaManagerDeletedToCLAManagersTemplate, params)
}
diff --git a/cla-backend-go/emails/cla_manager_templates_test.go b/cla-backend-go/emails/cla_manager_templates_test.go
index f401af7dc..2d2aa7cf4 100644
--- a/cla-backend-go/emails/cla_manager_templates_test.go
+++ b/cla-backend-go/emails/cla_manager_templates_test.go
@@ -30,8 +30,8 @@ func TestRemovedCLAManagerTemplate(t *testing.T) {
params)
assert.NoError(t, err)
assert.Contains(t, result, "Hello JohnsClaManager")
- assert.Contains(t, result, "regarding the project JohnsProject")
- assert.Contains(t, result, "CLA Manager from JohnsCompany for the project JohnsProject")
+ assert.Contains(t, result, "regarding the CLA Group JohnsProject")
+ assert.Contains(t, result, "CLA Manager from JohnsCompany for the CLA Group JohnsProject")
assert.Contains(t, result, "- LFUserName LFEmail
")
// even if the foundation is set we should show the project name
@@ -41,15 +41,8 @@ func TestRemovedCLAManagerTemplate(t *testing.T) {
params)
assert.NoError(t, err)
assert.Contains(t, result, "Hello JohnsClaManager")
- assert.Contains(t, result, "for the project JohnsProject")
+ assert.Contains(t, result, "for the CLA Group JohnsProject")
- // then we increase the child project count so we should get the FoundationName instead of project name
- params.ChildProjectCount = 2
- result, err = RenderTemplate(utils.V1, RemovedCLAManagerTemplateName, RemovedCLAManagerTemplate,
- params)
- assert.NoError(t, err)
- assert.Contains(t, result, "Hello JohnsClaManager")
- assert.Contains(t, result, "regarding the project CNCF")
}
func TestRequestAccessToCLAManagersTemplate(t *testing.T) {
@@ -198,9 +191,9 @@ func TestClaManagerAddedEToUserTemplate(t *testing.T) {
params)
assert.NoError(t, err)
assert.Contains(t, result, "Hello JohnsClaManager")
- assert.Contains(t, result, "regarding the project JohnsProjectExternal")
- assert.Contains(t, result, "CLA Manager for the organization JohnsCompany and the project JohnsProjectExternal")
- assert.Contains(t, result, "allowed to contribute to the project JohnsProjectExternal")
+ assert.Contains(t, result, "the CLA Group JohnsProject.")
+ assert.Contains(t, result, "organization JohnsCompany and the CLAGroup JohnsProject")
+ assert.Contains(t, result, "allowed to contribute to the CLA Group JohnsProject")
assert.Contains(t, result, "CLA Managers for the CLA Group JohnsProject")
assert.Contains(t, result, "")
assert.Contains(t, result, "and then the project JohnsProject")
@@ -224,10 +217,9 @@ func TestClaManagerAddedToCLAManagersTemplate(t *testing.T) {
params)
assert.NoError(t, err)
assert.Contains(t, result, "Hello JohnsClaManager")
- assert.Contains(t, result, "regarding the project JohnsProjectExternal associated with the CLA Group JohnsProject")
- assert.Contains(t, result, "CLA Manager from JohnsCompany for the project JohnsProjectExternal")
- assert.Contains(t, result, "contribute to JohnsProjectExternal")
- assert.Contains(t, result, "CLA Managers for JohnsProjectExternal")
+ assert.Contains(t, result, "regarding the CLA Group JohnsProject")
+ assert.Contains(t, result, "contribute to JohnsProject")
+ assert.Contains(t, result, "CLA Managers for CLA Group JohnsProject")
assert.Contains(t, result, "- John (john@example.com)
")
}
@@ -250,7 +242,6 @@ func TestClaManagerDeletedToCLAManagersTemplate(t *testing.T) {
params)
assert.NoError(t, err)
assert.Contains(t, result, "Hello JohnsClaManager")
- assert.Contains(t, result, "regarding the project JohnsProject")
assert.Contains(t, result, "John (john@example.com) has been removed")
}
diff --git a/cla-backend-go/emails/prefill.go b/cla-backend-go/emails/prefill.go
index 501df2e0d..d304d5730 100644
--- a/cla-backend-go/emails/prefill.go
+++ b/cla-backend-go/emails/prefill.go
@@ -89,6 +89,8 @@ func (s *emailTemplateServiceProvider) PrefillV2CLAProjectParams(projectSFIDs []
claProjectParams = append(claProjectParams, params)
}
+ log.Debugf("claProjectParams: %+v", claProjectParams)
+
return claProjectParams, nil
}
diff --git a/cla-backend-go/gerrits/mocks/mock_repository.go b/cla-backend-go/gerrits/mocks/mock_repository.go
new file mode 100644
index 000000000..6d45afc36
--- /dev/null
+++ b/cla-backend-go/gerrits/mocks/mock_repository.go
@@ -0,0 +1,143 @@
+// Copyright The Linux Foundation and each contributor to CommunityBridge.
+// SPDX-License-Identifier: MIT
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: gerrits/repository.go
+
+// Package mock_gerrits is a generated GoMock package.
+package mock_gerrits
+
+import (
+ context "context"
+ reflect "reflect"
+
+ models "github.com/communitybridge/easycla/cla-backend-go/gen/v1/models"
+ gomock "github.com/golang/mock/gomock"
+)
+
+// MockRepository is a mock of Repository interface.
+type MockRepository struct {
+ ctrl *gomock.Controller
+ recorder *MockRepositoryMockRecorder
+}
+
+// MockRepositoryMockRecorder is the mock recorder for MockRepository.
+type MockRepositoryMockRecorder struct {
+ mock *MockRepository
+}
+
+// NewMockRepository creates a new mock instance.
+func NewMockRepository(ctrl *gomock.Controller) *MockRepository {
+ mock := &MockRepository{ctrl: ctrl}
+ mock.recorder = &MockRepositoryMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
+ return m.recorder
+}
+
+// AddGerrit mocks base method.
+func (m *MockRepository) AddGerrit(ctx context.Context, input *models.Gerrit) (*models.Gerrit, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "AddGerrit", ctx, input)
+ ret0, _ := ret[0].(*models.Gerrit)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// AddGerrit indicates an expected call of AddGerrit.
+func (mr *MockRepositoryMockRecorder) AddGerrit(ctx, input interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddGerrit", reflect.TypeOf((*MockRepository)(nil).AddGerrit), ctx, input)
+}
+
+// DeleteGerrit mocks base method.
+func (m *MockRepository) DeleteGerrit(ctx context.Context, gerritID string) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "DeleteGerrit", ctx, gerritID)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// DeleteGerrit indicates an expected call of DeleteGerrit.
+func (mr *MockRepositoryMockRecorder) DeleteGerrit(ctx, gerritID interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteGerrit", reflect.TypeOf((*MockRepository)(nil).DeleteGerrit), ctx, gerritID)
+}
+
+// ExistsByName mocks base method.
+func (m *MockRepository) ExistsByName(ctx context.Context, gerritName string) ([]*models.Gerrit, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "ExistsByName", ctx, gerritName)
+ ret0, _ := ret[0].([]*models.Gerrit)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// ExistsByName indicates an expected call of ExistsByName.
+func (mr *MockRepositoryMockRecorder) ExistsByName(ctx, gerritName interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExistsByName", reflect.TypeOf((*MockRepository)(nil).ExistsByName), ctx, gerritName)
+}
+
+// GetClaGroupGerrits mocks base method.
+func (m *MockRepository) GetClaGroupGerrits(ctx context.Context, claGroupID string) (*models.GerritList, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetClaGroupGerrits", ctx, claGroupID)
+ ret0, _ := ret[0].(*models.GerritList)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetClaGroupGerrits indicates an expected call of GetClaGroupGerrits.
+func (mr *MockRepositoryMockRecorder) GetClaGroupGerrits(ctx, claGroupID interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClaGroupGerrits", reflect.TypeOf((*MockRepository)(nil).GetClaGroupGerrits), ctx, claGroupID)
+}
+
+// GetGerrit mocks base method.
+func (m *MockRepository) GetGerrit(ctx context.Context, gerritID string) (*models.Gerrit, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetGerrit", ctx, gerritID)
+ ret0, _ := ret[0].(*models.Gerrit)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetGerrit indicates an expected call of GetGerrit.
+func (mr *MockRepositoryMockRecorder) GetGerrit(ctx, gerritID interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGerrit", reflect.TypeOf((*MockRepository)(nil).GetGerrit), ctx, gerritID)
+}
+
+// GetGerritsByID mocks base method.
+func (m *MockRepository) GetGerritsByID(ctx context.Context, ID, IDType string) (*models.GerritList, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetGerritsByID", ctx, ID, IDType)
+ ret0, _ := ret[0].(*models.GerritList)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetGerritsByID indicates an expected call of GetGerritsByID.
+func (mr *MockRepositoryMockRecorder) GetGerritsByID(ctx, ID, IDType interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGerritsByID", reflect.TypeOf((*MockRepository)(nil).GetGerritsByID), ctx, ID, IDType)
+}
+
+// GetGerritsByProjectSFID mocks base method.
+func (m *MockRepository) GetGerritsByProjectSFID(ctx context.Context, projectSFID string) (*models.GerritList, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetGerritsByProjectSFID", ctx, projectSFID)
+ ret0, _ := ret[0].(*models.GerritList)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetGerritsByProjectSFID indicates an expected call of GetGerritsByProjectSFID.
+func (mr *MockRepositoryMockRecorder) GetGerritsByProjectSFID(ctx, projectSFID interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGerritsByProjectSFID", reflect.TypeOf((*MockRepository)(nil).GetGerritsByProjectSFID), ctx, projectSFID)
+}
diff --git a/cla-backend-go/gerrits/mocks/mock_service.go b/cla-backend-go/gerrits/mocks/mock_service.go
new file mode 100644
index 000000000..64ba64d65
--- /dev/null
+++ b/cla-backend-go/gerrits/mocks/mock_service.go
@@ -0,0 +1,143 @@
+// Copyright The Linux Foundation and each contributor to CommunityBridge.
+// SPDX-License-Identifier: MIT
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: gerrits/service.go
+
+// Package mock_gerrits is a generated GoMock package.
+package mock_gerrits
+
+import (
+ context "context"
+ reflect "reflect"
+
+ models "github.com/communitybridge/easycla/cla-backend-go/gen/v1/models"
+ gomock "github.com/golang/mock/gomock"
+)
+
+// MockService is a mock of Service interface.
+type MockService struct {
+ ctrl *gomock.Controller
+ recorder *MockServiceMockRecorder
+}
+
+// MockServiceMockRecorder is the mock recorder for MockService.
+type MockServiceMockRecorder struct {
+ mock *MockService
+}
+
+// NewMockService creates a new mock instance.
+func NewMockService(ctrl *gomock.Controller) *MockService {
+ mock := &MockService{ctrl: ctrl}
+ mock.recorder = &MockServiceMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockService) EXPECT() *MockServiceMockRecorder {
+ return m.recorder
+}
+
+// AddGerrit mocks base method.
+func (m *MockService) AddGerrit(ctx context.Context, claGroupID, projectSFID string, input *models.AddGerritInput, claGroupModel *models.ClaGroup) (*models.Gerrit, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "AddGerrit", ctx, claGroupID, projectSFID, input, claGroupModel)
+ ret0, _ := ret[0].(*models.Gerrit)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// AddGerrit indicates an expected call of AddGerrit.
+func (mr *MockServiceMockRecorder) AddGerrit(ctx, claGroupID, projectSFID, input, claGroupModel interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddGerrit", reflect.TypeOf((*MockService)(nil).AddGerrit), ctx, claGroupID, projectSFID, input, claGroupModel)
+}
+
+// DeleteClaGroupGerrits mocks base method.
+func (m *MockService) DeleteClaGroupGerrits(ctx context.Context, claGroupID string) (int, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "DeleteClaGroupGerrits", ctx, claGroupID)
+ ret0, _ := ret[0].(int)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// DeleteClaGroupGerrits indicates an expected call of DeleteClaGroupGerrits.
+func (mr *MockServiceMockRecorder) DeleteClaGroupGerrits(ctx, claGroupID interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteClaGroupGerrits", reflect.TypeOf((*MockService)(nil).DeleteClaGroupGerrits), ctx, claGroupID)
+}
+
+// DeleteGerrit mocks base method.
+func (m *MockService) DeleteGerrit(ctx context.Context, gerritID string) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "DeleteGerrit", ctx, gerritID)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// DeleteGerrit indicates an expected call of DeleteGerrit.
+func (mr *MockServiceMockRecorder) DeleteGerrit(ctx, gerritID interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteGerrit", reflect.TypeOf((*MockService)(nil).DeleteGerrit), ctx, gerritID)
+}
+
+// GetClaGroupGerrits mocks base method.
+func (m *MockService) GetClaGroupGerrits(ctx context.Context, claGroupID string) (*models.GerritList, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetClaGroupGerrits", ctx, claGroupID)
+ ret0, _ := ret[0].(*models.GerritList)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetClaGroupGerrits indicates an expected call of GetClaGroupGerrits.
+func (mr *MockServiceMockRecorder) GetClaGroupGerrits(ctx, claGroupID interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClaGroupGerrits", reflect.TypeOf((*MockService)(nil).GetClaGroupGerrits), ctx, claGroupID)
+}
+
+// GetGerrit mocks base method.
+func (m *MockService) GetGerrit(ctx context.Context, gerritID string) (*models.Gerrit, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetGerrit", ctx, gerritID)
+ ret0, _ := ret[0].(*models.Gerrit)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetGerrit indicates an expected call of GetGerrit.
+func (mr *MockServiceMockRecorder) GetGerrit(ctx, gerritID interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGerrit", reflect.TypeOf((*MockService)(nil).GetGerrit), ctx, gerritID)
+}
+
+// GetGerritRepos mocks base method.
+func (m *MockService) GetGerritRepos(ctx context.Context, gerritName string) (*models.GerritRepoList, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetGerritRepos", ctx, gerritName)
+ ret0, _ := ret[0].(*models.GerritRepoList)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetGerritRepos indicates an expected call of GetGerritRepos.
+func (mr *MockServiceMockRecorder) GetGerritRepos(ctx, gerritName interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGerritRepos", reflect.TypeOf((*MockService)(nil).GetGerritRepos), ctx, gerritName)
+}
+
+// GetGerritsByProjectSFID mocks base method.
+func (m *MockService) GetGerritsByProjectSFID(ctx context.Context, projectSFID string) (*models.GerritList, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetGerritsByProjectSFID", ctx, projectSFID)
+ ret0, _ := ret[0].(*models.GerritList)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetGerritsByProjectSFID indicates an expected call of GetGerritsByProjectSFID.
+func (mr *MockServiceMockRecorder) GetGerritsByProjectSFID(ctx, projectSFID interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGerritsByProjectSFID", reflect.TypeOf((*MockService)(nil).GetGerritsByProjectSFID), ctx, projectSFID)
+}
diff --git a/cla-backend-go/gerrits/models.go b/cla-backend-go/gerrits/models.go
index b31689693..f15a074d0 100644
--- a/cla-backend-go/gerrits/models.go
+++ b/cla-backend-go/gerrits/models.go
@@ -27,18 +27,15 @@ type Gerrit struct {
// toModel converts the gerrit structure into a response model
func (g *Gerrit) toModel() *models.Gerrit {
return &models.Gerrit{
- DateCreated: g.DateCreated,
- DateModified: g.DateModified,
- GerritID: strfmt.UUID4(g.GerritID),
- GerritName: g.GerritName,
- GerritURL: strfmt.URI(g.GerritURL),
- GroupIDCcla: g.GroupIDCcla,
- GroupIDIcla: g.GroupIDIcla,
- GroupNameCcla: g.GroupNameCcla,
- GroupNameIcla: g.GroupNameIcla,
- ProjectID: g.ProjectID,
- Version: g.Version,
- ProjectSFID: g.ProjectSFID,
+ DateCreated: g.DateCreated,
+ DateModified: g.DateModified,
+ GerritID: strfmt.UUID4(g.GerritID),
+ GerritName: g.GerritName,
+ GerritURL: strfmt.URI(g.GerritURL),
+ GroupIDCcla: g.GroupIDCcla,
+ ProjectID: g.ProjectID,
+ Version: g.Version,
+ ProjectSFID: g.ProjectSFID,
}
}
diff --git a/cla-backend-go/gerrits/repository.go b/cla-backend-go/gerrits/repository.go
index d9f4ae410..80207f3e3 100644
--- a/cla-backend-go/gerrits/repository.go
+++ b/cla-backend-go/gerrits/repository.go
@@ -71,18 +71,15 @@ func (repo *repo) AddGerrit(ctx context.Context, input *models.Gerrit) (*models.
}
_, currentTime := utils.CurrentTime()
gerrit := &Gerrit{
- DateCreated: currentTime,
- DateModified: currentTime,
- GerritID: gerritID.String(),
- GerritName: input.GerritName,
- GerritURL: input.GerritURL.String(),
- GroupIDCcla: input.GroupIDCcla,
- GroupIDIcla: input.GroupIDIcla,
- GroupNameCcla: input.GroupNameCcla,
- GroupNameIcla: input.GroupNameIcla,
- ProjectID: input.ProjectID,
- ProjectSFID: input.ProjectSFID,
- Version: input.Version,
+ DateCreated: currentTime,
+ DateModified: currentTime,
+ GerritID: gerritID.String(),
+ GerritName: input.GerritName,
+ GerritURL: input.GerritURL.String(),
+ GroupIDCcla: input.GroupIDCcla,
+ ProjectID: input.ProjectID,
+ ProjectSFID: input.ProjectSFID,
+ Version: input.Version,
}
av, err := dynamodbattribute.MarshalMap(gerrit)
if err != nil {
diff --git a/cla-backend-go/gerrits/service.go b/cla-backend-go/gerrits/service.go
index cc818c32c..0fb218cce 100644
--- a/cla-backend-go/gerrits/service.go
+++ b/cla-backend-go/gerrits/service.go
@@ -8,20 +8,25 @@ import (
"encoding/json"
"errors"
"fmt"
+ "io"
+ "net/http"
"net/url"
"strings"
+ "time"
- "github.com/LF-Engineering/lfx-kit/auth"
+ // "github.com/LF-Engineering/lfx-kit/auth"
"github.com/go-openapi/strfmt"
-
"github.com/go-resty/resty/v2"
+
+ // "github.com/go-resty/resty/v2"
+ apiclient "github.com/communitybridge/easycla/cla-backend-go/api_client"
"github.com/sirupsen/logrus"
"github.com/communitybridge/easycla/cla-backend-go/utils"
"github.com/communitybridge/easycla/cla-backend-go/gen/v1/models"
- v2Models "github.com/communitybridge/easycla/cla-backend-go/gen/v2/models"
+ // v2Models "github.com/communitybridge/easycla/cla-backend-go/gen/v2/models"
log "github.com/communitybridge/easycla/cla-backend-go/logging"
)
@@ -35,23 +40,16 @@ type Service interface {
GetGerritRepos(ctx context.Context, gerritName string) (*models.GerritRepoList, error)
DeleteClaGroupGerrits(ctx context.Context, claGroupID string) (int, error)
DeleteGerrit(ctx context.Context, gerritID string) error
- GetUsersOfGroup(ctx context.Context, authUser *auth.User, claGroupID, claType string) (*v2Models.GerritGroupResponse, error)
- AddUserToGroup(ctx context.Context, authUser *auth.User, claGroupID, userName, claType string) error
- AddUsersToGroup(ctx context.Context, authUser *auth.User, claGroupID string, userNameList []string, claType string) error
- RemoveUserFromGroup(ctx context.Context, authUser *auth.User, claGroupID, userName, claType string) error
- RemoveUsersFromGroup(ctx context.Context, authUser *auth.User, claGroupID string, userNameList []string, claType string) error
}
type service struct {
- repo Repository
- lfGroup *LFGroup
+ repo Repository
}
// NewService creates a new gerrit service
-func NewService(repo Repository, lfg *LFGroup) Service {
+func NewService(repo Repository) Service {
return service{
- repo: repo,
- lfGroup: lfg,
+ repo: repo,
}
}
@@ -62,38 +60,12 @@ func (s service) AddGerrit(ctx context.Context, claGroupID string, projectSFID s
"claGroupID": claGroupID,
"projectSFID": projectSFID,
}
- if params.GroupIDIcla == "" && params.GroupIDCcla == "" {
- return nil, errors.New("should specify at least a LDAP group for ICLA or CCLA")
- }
-
- log.WithFields(f).Debugf("cla groupID %s", claGroupID)
- log.WithFields(f).Debugf("project Model %+v", claGroupModel)
-
- if claGroupModel.ProjectCCLAEnabled && claGroupModel.ProjectICLAEnabled {
- if params.GroupIDCcla == "" {
- return nil, errors.New("please provide GroupIDCcla")
- }
- if params.GroupIDIcla == "" {
- return nil, errors.New("please provide GroupIDIcla")
- }
- } else if claGroupModel.ProjectCCLAEnabled {
- if params.GroupIDCcla == "" {
- return nil, errors.New("please provide GroupIDCcla")
- }
- } else if claGroupModel.ProjectICLAEnabled {
- if params.GroupIDIcla == "" {
- return nil, errors.New("please provide GroupIDIcla")
- }
- }
-
- if params.GroupIDIcla == params.GroupIDCcla {
- return nil, errors.New("LDAP group for ICLA and CCLA are same")
- }
if params.GerritName == nil {
return nil, errors.New("gerrit_name required")
}
+ log.WithFields(f).Debugf("checking if gerrit name already exists in the system : %s", *params.GerritName)
gerritObject, err := s.repo.ExistsByName(ctx, *params.GerritName)
if err != nil {
message := fmt.Sprintf("unable to get gerrit by name : %s", *params.GerritName)
@@ -104,61 +76,46 @@ func (s service) AddGerrit(ctx context.Context, claGroupID string, projectSFID s
return nil, errors.New("gerrit_name already present in the system")
}
- gerritCcla, err := s.repo.GetGerritsByID(ctx, params.GroupIDCcla, "CCLA")
- if err != nil {
- message := fmt.Sprintf("unable to get gerrit by ccla id : %s", params.GroupIDCcla)
- log.WithFields(f).WithError(err).Warnf(message)
+ if params.GerritURL == nil {
+ return nil, errors.New("gerrit_url required")
}
- if len(gerritCcla.List) > 0 {
- return nil, errors.New("gerrit_ccla id already present in the system")
+ input := &models.Gerrit{
+ GerritName: utils.StringValue(params.GerritName),
+ GerritURL: strfmt.URI(*params.GerritURL),
+ ProjectID: claGroupID,
+ ProjectSFID: projectSFID,
+ Version: params.Version,
}
- gerritIcla, err := s.repo.GetGerritsByID(ctx, params.GroupIDIcla, "ICLA")
+ // Get the gerrit repos
+ log.WithFields(f).Debugf("fetching gerrit repos for gerrit instance: %s", *params.GerritURL)
+ gerritHost, err := extractGerritHost(*params.GerritURL, f)
if err != nil {
- message := fmt.Sprintf("unable to get gerrit by icla : %s", params.GroupIDIcla)
- log.WithFields(f).WithError(err).Warnf(message)
- }
-
- if len(gerritIcla.List) > 0 {
- return nil, errors.New("gerrit_icla id already present in the system")
+ return nil, err
}
-
- if params.GerritURL == nil {
- return nil, errors.New("gerrit_url required")
+ gerritRepoList, getRepoErr := s.GetGerritRepos(ctx, gerritHost)
+ if getRepoErr != nil {
+ log.WithFields(f).WithError(getRepoErr).Warnf("problem fetching gerrit repos, error: %+v", getRepoErr)
+ return nil, getRepoErr
}
- var groupNameCcla, groupNameIcla string
- if params.GroupIDIcla != "" {
- group, err := s.lfGroup.GetGroup(ctx, params.GroupIDIcla)
- if err != nil {
- message := fmt.Sprintf("unable to get LDAP ICLA Group: %s", params.GroupIDIcla)
- log.WithFields(f).WithError(err).Warnf(message)
- return nil, errors.New(message)
- }
- groupNameIcla = group.Title
+ log.WithFields(f).Debugf("discovered %d gerrit repos", len(gerritRepoList.Repos))
+ log.WithFields(f).Debugf("gerrit repo list %+v", gerritRepoList)
+ // Set the connected flag - for now, we just set this value to true
+ for _, repo := range gerritRepoList.Repos {
+ repo.Connected = true
}
- if params.GroupIDCcla != "" {
- group, err := s.lfGroup.GetGroup(ctx, params.GroupIDCcla)
- if err != nil {
- message := fmt.Sprintf("unable to get LDAP CCLA Group: %s", params.GroupIDCcla)
- log.WithFields(f).WithError(err).Warnf(message)
- return nil, errors.New(message)
- }
- groupNameCcla = group.Title
+ gerritInstance, err := s.repo.AddGerrit(ctx, input)
+ if err != nil {
+ return nil, err
}
- input := &models.Gerrit{
- GerritName: utils.StringValue(params.GerritName),
- GerritURL: strfmt.URI(*params.GerritURL),
- GroupIDCcla: params.GroupIDCcla,
- GroupIDIcla: params.GroupIDIcla,
- GroupNameCcla: groupNameCcla,
- GroupNameIcla: groupNameIcla,
- ProjectID: claGroupID,
- ProjectSFID: projectSFID,
- Version: params.Version,
- }
- return s.repo.AddGerrit(ctx, input)
+ input.GerritID = gerritInstance.GerritID
+ input.DateCreated = gerritInstance.DateCreated
+ input.DateModified = gerritInstance.DateModified
+ input.GerritRepoList = gerritRepoList
+ log.WithFields(f).Debugf("gerrit input %+v", input)
+ return input, nil
}
func (s service) GetGerrit(ctx context.Context, gerritID string) (*models.Gerrit, error) {
@@ -278,192 +235,6 @@ func (s service) DeleteGerrit(ctx context.Context, gerritID string) error {
return s.repo.DeleteGerrit(ctx, gerritID)
}
-// GetUsersOfGroup
-func (s service) GetUsersOfGroup(ctx context.Context, authUser *auth.User, claGroupID, claType string) (*v2Models.GerritGroupResponse, error) {
- f := logrus.Fields{
- "functionName": "v1.gerrits.service.GetUsersOfGroup",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "claGroupID": claGroupID,
- "authUserName": authUser.UserName,
- "authUserEmail": authUser.Email,
- }
-
- log.WithFields(f).Debug("querying for CLA Group gerrits...")
- g, gerritErr := s.GetClaGroupGerrits(ctx, claGroupID)
- if gerritErr != nil {
- log.WithFields(f).WithError(gerritErr).Warnf("unable to locate gerrits associated with CLA Group ID: %s", claGroupID)
- return nil, gerritErr
- }
-
- // Just load the first one...
- if len(g.List) > 0 {
- gerritModel := g.List[0]
- var ldapGroupName string
- switch claType {
- case utils.ClaTypeICLA:
- ldapGroupName = gerritModel.GroupNameIcla
- case utils.ClaTypeECLA:
- ldapGroupName = gerritModel.GroupNameCcla
- default:
- return nil, &utils.InvalidCLAType{
- CLAType: claType,
- }
- }
-
- log.WithFields(f).Debugf("querying for members of gerrit group: %s...", ldapGroupName)
- g, gerritErr := s.lfGroup.GetUsersOfGroup(ctx, authUser, claGroupID, ldapGroupName)
- if gerritErr != nil {
- log.WithFields(f).WithError(gerritErr).Warnf("unable to locate gerrits associated with CLA Group ID: %s", claGroupID)
- return nil, gerritErr
- }
- return g, nil
- }
-
- return nil, nil
-}
-
-// AddUserToGroup adds the specified user to the group
-func (s service) AddUserToGroup(ctx context.Context, authUser *auth.User, claGroupID, userName, claType string) error {
- f := logrus.Fields{
- "functionName": "v1.gerrits.service.AddUserToGroup",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "claGroupID": claGroupID,
- "userName": userName,
- }
-
- log.WithFields(f).Debug("querying for CLA Group gerrits...")
- g, gerritErr := s.GetClaGroupGerrits(ctx, claGroupID)
- if gerritErr != nil {
- log.WithFields(f).WithError(gerritErr).Warnf("unable to locate gerrits associated with CLA Group ID: %s", claGroupID)
- return gerritErr
- }
-
- for _, gerritModel := range g.List {
- var ldapGroupName string
- switch claType {
- case utils.ClaTypeICLA:
- ldapGroupName = gerritModel.GroupNameIcla
- case utils.ClaTypeECLA:
- ldapGroupName = gerritModel.GroupNameCcla
- default:
- return &utils.InvalidCLAType{
- CLAType: claType,
- }
- }
- log.WithFields(f).Debugf("LDAP group name: %s", ldapGroupName)
- addErr := s.lfGroup.AddUserToGroup(ctx, authUser, claGroupID, ldapGroupName, userName)
- if addErr != nil {
- log.WithFields(f).WithError(addErr).Warnf("unable to add user %s to group: %s for CLA Group: %s", userName, ldapGroupName, claGroupID)
- return gerritErr
- }
- log.WithFields(f).Debugf("added user %s to group: %s for CLA Group: %s", userName, ldapGroupName, claGroupID)
-
- // Log Event
- }
-
- return nil
-}
-
-// AddUsersToGroup adds the specified users to the group
-func (s service) AddUsersToGroup(ctx context.Context, authUser *auth.User, claGroupID string, userNameList []string, claType string) error {
- f := logrus.Fields{
- "functionName": "v1.gerrits.service.AddUsersToGroup",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "claGroupID": claGroupID,
- "userNameList": strings.Join(userNameList, ","),
- "authUserName": authUser.UserName,
- "authUserEmail": authUser.Email,
- }
-
- var errorList []error
- for _, userName := range userNameList {
- err := s.AddUserToGroup(ctx, authUser, claGroupID, userName, claType)
- if err != nil {
- log.WithFields(f).WithError(err).Warnf("encountered an error when adding username: %s to the CLA Group: %s", userName, claGroupID)
- errorList = append(errorList, err)
- }
- }
-
- if len(errorList) > 0 {
- log.WithFields(f).Warnf("encountered %d errors when adding %d users to the CLA Group: %s", len(errorList), len(userNameList), claGroupID)
- return errorList[0]
- }
-
- return nil
-}
-
-// RemoveUserFromGroup removes the specified user from the group
-func (s service) RemoveUserFromGroup(ctx context.Context, authUser *auth.User, claGroupID, userName, claType string) error {
- f := logrus.Fields{
- "functionName": "v1.gerrits.service.RemoveUserFromGroup",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "claGroupID": claGroupID,
- "userName": userName,
- "authUserName": authUser.UserName,
- "authUserEmail": authUser.Email,
- }
-
- log.WithFields(f).Debug("querying for CLA Group gerrits...")
- g, gerritErr := s.GetClaGroupGerrits(ctx, claGroupID)
- if gerritErr != nil {
- log.WithFields(f).WithError(gerritErr).Warnf("unable to locate gerrits associated with CLA Group ID: %s", claGroupID)
- return gerritErr
- }
-
- for _, gerritModel := range g.List {
- var ldapGroupName string
- switch claType {
- case utils.ClaTypeICLA:
- ldapGroupName = gerritModel.GroupNameIcla
- case utils.ClaTypeECLA:
- ldapGroupName = gerritModel.GroupNameCcla
- default:
- return &utils.InvalidCLAType{
- CLAType: claType,
- }
- }
- log.WithFields(f).Debugf("LDAP group name: %s", ldapGroupName)
- addErr := s.lfGroup.RemoveUserFromGroup(ctx, authUser, claGroupID, ldapGroupName, userName)
- if addErr != nil {
- log.WithFields(f).WithError(addErr).Warnf("unable to remove user %s from group: %s for CLA Group: %s", userName, ldapGroupName, claGroupID)
- return gerritErr
- }
- log.WithFields(f).Debugf("removed user %s from group: %s for CLA Group: %s", userName, ldapGroupName, claGroupID)
-
- // Log Event
- }
-
- return nil
-}
-
-// RemoveUsersFromGroup removes the specified users from the group
-func (s service) RemoveUsersFromGroup(ctx context.Context, authUser *auth.User, claGroupID string, userNameList []string, claType string) error {
- f := logrus.Fields{
- "functionName": "v1.gerrits.service.RemoveUsersFromGroup",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "claGroupID": claGroupID,
- "userNameList": strings.Join(userNameList, ","),
- "authUserName": authUser.UserName,
- "authUserEmail": authUser.Email,
- }
-
- var errorList []error
- for _, userName := range userNameList {
- err := s.RemoveUserFromGroup(ctx, authUser, claGroupID, userName, claType)
- if err != nil {
- log.WithFields(f).WithError(err).Warnf("encountered an error when removing username: %s from the CLA Group: %s", userName, claGroupID)
- errorList = append(errorList, err)
- }
- }
-
- if len(errorList) > 0 {
- log.WithFields(f).Warnf("encountered %d errors when removing %d users from the CLA Group: %s", len(errorList), len(userNameList), claGroupID)
- return errorList[0]
- }
-
- return nil
-}
-
// convertModel is a helper function to create a GerritRepoList response model
func convertModel(responseModel map[string]GerritRepoInfo, serverInfo *ServerInfo) *models.GerritRepoList {
var gerritRepos []*models.GerritRepo
@@ -476,6 +247,7 @@ func convertModel(responseModel map[string]GerritRepoInfo, serverInfo *ServerInf
URL: strfmt.URI(weblink.URL),
})
}
+ log.Debugf("Processing repo: %s, weblinks: %+v", name, weblinks)
claEnabled := false
if serverInfo != nil && serverInfo.Auth.UseContributorAgreements {
@@ -520,7 +292,11 @@ func listGerritRepos(ctx context.Context, gerritHost string) (map[string]GerritR
utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
"gerritHost": gerritHost,
}
- client := resty.New()
+ client := &apiclient.RestAPIClient{
+ Client: &http.Client{
+ Timeout: 10 * time.Second,
+ },
+ }
base := "https://" + gerritHost
@@ -529,28 +305,40 @@ func listGerritRepos(ctx context.Context, gerritHost string) (map[string]GerritR
return nil, gerritAPIPathErr
}
+ log.WithFields(f).Debugf("gerrit API path using client: %s", gerritAPIPath)
+
if gerritAPIPath != "" {
base = fmt.Sprintf("https://%s/%s", gerritHost, gerritAPIPath)
}
- resp, err := client.R().
- EnableTrace().
- Get(fmt.Sprintf("%s/projects/?d&pp=0", base))
+ url := fmt.Sprintf("%s/projects/?d&pp=0", base)
+ resp, err := client.GetData(ctx, url)
+
if err != nil {
- log.WithFields(f).Warnf("problem querying gerrit host: %s, error: %+v", gerritHost, err)
return nil, err
}
- if resp.IsError() {
- msg := fmt.Sprintf("non-success response from list gerrit host repos for gerrit %s, error code: %s", gerritHost, resp.Status())
- log.WithFields(f).Warn(msg)
- return nil, errors.New(msg)
+ defer func() {
+ if err = resp.Body.Close(); err != nil {
+ log.WithFields(f).Debugf("Failed to close response body; %v", err)
+ }
+ }()
+
+ log.WithFields(f).Debugf("response: %+v", resp.Body)
+
+ // Get the response body
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
}
- var result map[string]GerritRepoInfo
// Need to strip off the leading "magic prefix line" from the response payload, which is: )]}'
// See: https://gerrit.linuxfoundation.org/infra/Documentation/rest-api.html#output
- err = json.Unmarshal(resp.Body()[4:], &result)
+ strippedBody := stripMagicPrefix(body)
+
+ var result map[string]GerritRepoInfo
+
+ err = json.Unmarshal(strippedBody, &result)
if err != nil {
log.WithFields(f).Warnf("problem unmarshalling response for gerrit host: %s, error: %+v", gerritHost, err)
return nil, err
@@ -559,6 +347,13 @@ func listGerritRepos(ctx context.Context, gerritHost string) (map[string]GerritR
return result, nil
}
+func stripMagicPrefix(data []byte) []byte {
+ if len(data) > 4 {
+ return data[4:]
+ }
+ return data
+}
+
// getGerritConfig returns the gerrit configuration for the specified host
func getGerritConfig(ctx context.Context, gerritHost string) (*ServerInfo, error) {
f := logrus.Fields{
diff --git a/cla-backend-go/gerrits/service_test.go b/cla-backend-go/gerrits/service_test.go
new file mode 100644
index 000000000..3374211bf
--- /dev/null
+++ b/cla-backend-go/gerrits/service_test.go
@@ -0,0 +1,123 @@
+// Copyright The Linux Foundation and each contributor to CommunityBridge.
+// SPDX-License-Identifier: MIT
+
+package gerrits
+
+import (
+ // "bytes"
+ "context"
+ // "io"
+ // "net/http"
+ "testing"
+
+ // mock_apiclient "github.com/communitybridge/easycla/cla-backend-go/api_client/mocks"
+ "github.com/communitybridge/easycla/cla-backend-go/gen/v1/models"
+ gerritsMock "github.com/communitybridge/easycla/cla-backend-go/gerrits/mocks"
+ "github.com/go-openapi/strfmt"
+ "github.com/golang/mock/gomock"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestService_AddGerrit(t *testing.T) {
+
+ gerritName := "gerritName"
+ gerritURL := "https://mockapi.gerrit.dev.itx.linuxfoundation.org/"
+ // gerritHost := "mockapi.gerrit.dev.itx.linuxfoundation.org"
+ repos := []*models.GerritRepo{
+ {
+ ClaEnabled: true,
+ Connected: true,
+ ContributorAgreements: []*models.GerritRepoContributorAgreementsItems0{
+ {
+ Description: "CCLA (Corporate Contributor License Agreement) for SUN",
+ Name: "CCLA",
+ URL: "https://api.dev.lfcla.com/v2/gerrit/01af041c-fa69-4052-a23c-fb8c1d3bef24/corporate/agreementUrl.html",
+ },
+ {
+ Description: "ICLA (Individual Contributor License Agreement) for SUN",
+ Name: "ICLA",
+ URL: "https://api.dev.lfcla.com/v2/gerrit/01af041c-fa69-4052-a23c-fb8c1d3bef24/individual/agreementUrl.html",
+ },
+ },
+ Description: "Access inherited by all other projects.",
+ ID: "All-Projects",
+ Name: "All-Projects",
+ State: "ACTIVE",
+ WebLinks: []*models.GerritRepoWebLinksItems0{
+ {
+ Name: "browse",
+ URL: "/plugins/gitiles/All-Projects",
+ },
+ },
+ },
+ }
+
+ testCases := []struct {
+ name string
+ claGroupID string
+ projectSFID string
+ params *models.AddGerritInput
+ gerritRepoList *models.GerritRepoList
+ ReposExist []*models.Gerrit
+ repoListErr error
+ claGroupModel *models.ClaGroup
+ expectedResult *models.Gerrit
+ expectedError error
+ }{
+ {
+ name: "Valid input",
+ claGroupID: "claGroupID",
+ projectSFID: "projectSFID",
+ params: &models.AddGerritInput{
+ GerritName: &gerritName,
+ GerritURL: &gerritURL,
+ Version: "version",
+ },
+ ReposExist: []*models.Gerrit{},
+ gerritRepoList: &models.GerritRepoList{
+ Repos: repos,
+ },
+ repoListErr: nil,
+ claGroupModel: &models.ClaGroup{},
+ expectedResult: &models.Gerrit{
+ GerritName: gerritName,
+ GerritURL: strfmt.URI(gerritURL),
+ ProjectID: "claGroupID",
+ ProjectSFID: "projectSFID",
+ Version: "version",
+ GerritRepoList: &models.GerritRepoList{
+ Repos: repos,
+ },
+ },
+ expectedError: nil,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+ mockRepo := gerritsMock.NewMockRepository(ctrl)
+ mockRepo.EXPECT().ExistsByName(context.Background(), gerritName).Return(tc.ReposExist, nil)
+ gerrit := &models.Gerrit{
+ GerritName: gerritName,
+ GerritURL: strfmt.URI(gerritURL),
+ ProjectID: "claGroupID",
+ ProjectSFID: "projectSFID",
+ Version: "version",
+ GerritRepoList: tc.gerritRepoList,
+ }
+
+ mockRepo.EXPECT().AddGerrit(gomock.Any(), gomock.Any()).Return(gerrit, nil)
+
+ service := NewService(mockRepo)
+
+ result, err := service.AddGerrit(context.Background(), tc.claGroupID, tc.projectSFID, tc.params, tc.claGroupModel)
+
+ if err != nil {
+ t.Fatalf("Add Gerrit returned an error: %v", err)
+ }
+ assert.NotNil(t, result)
+ })
+ }
+}
diff --git a/cla-backend-go/projects_cla_groups/mocks/mock_repository.go b/cla-backend-go/projects_cla_groups/mocks/mock_repository.go
index 9035fdf63..f3950ce47 100644
--- a/cla-backend-go/projects_cla_groups/mocks/mock_repository.go
+++ b/cla-backend-go/projects_cla_groups/mocks/mock_repository.go
@@ -186,6 +186,21 @@ func (mr *MockRepositoryMockRecorder) RemoveProjectAssociatedWithClaGroup(ctx, c
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveProjectAssociatedWithClaGroup", reflect.TypeOf((*MockRepository)(nil).RemoveProjectAssociatedWithClaGroup), ctx, claGroupID, projectSFIDList, all)
}
+// SignedAtFoundation mocks base method.
+func (m *MockRepository) SignedAtFoundation(ctx context.Context, claGroupID string) (bool, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "SignedAtFoundation", ctx, claGroupID)
+ ret0, _ := ret[0].(bool)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// SignedAtFoundation indicates an expected call of SignedAtFoundation.
+func (mr *MockRepositoryMockRecorder) SignedAtFoundation(ctx, claGroupID interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SignedAtFoundation", reflect.TypeOf((*MockRepository)(nil).SignedAtFoundation), ctx, claGroupID)
+}
+
// UpdateClaGroupName mocks base method.
func (m *MockRepository) UpdateClaGroupName(ctx context.Context, projectSFID, claGroupName string) error {
m.ctrl.T.Helper()
diff --git a/cla-backend-go/projects_cla_groups/repository.go b/cla-backend-go/projects_cla_groups/repository.go
index 55efa5b9d..98e686a29 100644
--- a/cla-backend-go/projects_cla_groups/repository.go
+++ b/cla-backend-go/projects_cla_groups/repository.go
@@ -56,6 +56,7 @@ type Repository interface {
IsAssociated(ctx context.Context, projectSFID string, claGroupID string) (bool, error)
UpdateRepositoriesCount(ctx context.Context, projectSFID string, diff int64, reset bool) error
UpdateClaGroupName(ctx context.Context, projectSFID string, claGroupName string) error
+ SignedAtFoundation(ctx context.Context, claGroupID string) (bool, error)
}
type repo struct {
@@ -124,6 +125,26 @@ func (repo *repo) queryClaGroupsProjects(ctx context.Context, keyCondition expre
return projectClaGroups, nil
}
+func (repo *repo) SignedAtFoundation(ctx context.Context, claGroupID string) (bool, error) {
+ f := logrus.Fields{
+ "functionName": "SignedAtFoundation",
+ "claGroupID": claGroupID,
+ }
+ pcgs, err := repo.GetProjectsIdsForClaGroup(ctx, claGroupID)
+ if err != nil {
+ return false, err
+ }
+
+ log.WithFields(f).Info("checking if claGroup is signed at foundation level..")
+ for _, pcg := range pcgs {
+ if pcg.FoundationSFID == pcg.ProjectSFID {
+ return true, nil
+ }
+ }
+
+ return false, nil
+}
+
// GetClaGroupIDForProject retrieves the CLA Group ID for the project
func (repo *repo) GetClaGroupIDForProject(ctx context.Context, projectSFID string) (*ProjectClaGroup, error) {
f := logrus.Fields{
diff --git a/cla-backend-go/signatures/converters.go b/cla-backend-go/signatures/converters.go
index 5b731bb36..6b58735a2 100644
--- a/cla-backend-go/signatures/converters.go
+++ b/cla-backend-go/signatures/converters.go
@@ -75,6 +75,7 @@ func (repo repository) buildProjectSignatureModels(ctx context.Context, results
SignatureReferenceNameLower: dbSignature.SignatureReferenceNameLower,
SignatureSigned: dbSignature.SignatureSigned,
SignatureApproved: dbSignature.SignatureApproved,
+ SignatureEmbargoAcked: dbSignature.SignatureEmbargoAcked,
SignatureDocumentMajorVersion: strconv.Itoa(dbSignature.SignatureDocumentMajorVersion),
SignatureDocumentMinorVersion: strconv.Itoa(dbSignature.SignatureDocumentMinorVersion),
Version: strconv.Itoa(dbSignature.SignatureDocumentMajorVersion) + "." + strconv.Itoa(dbSignature.SignatureDocumentMinorVersion),
@@ -237,6 +238,7 @@ func (repo repository) buildProjectSignatureSummaryModels(ctx context.Context, r
SignatureReferenceNameLower: dbSignature.SignatureReferenceNameLower,
SignatureSigned: dbSignature.SignatureSigned,
SignatureApproved: dbSignature.SignatureApproved,
+ SignatureEmbargoAcked: dbSignature.SignatureEmbargoAcked,
SignatureReferenceType: dbSignature.SignatureReferenceType,
ProjectID: dbSignature.SignatureProjectID,
SignedOn: dbSignature.SignedOn,
diff --git a/cla-backend-go/signatures/dbmodels.go b/cla-backend-go/signatures/dbmodels.go
index 262acfff2..86c043b58 100644
--- a/cla-backend-go/signatures/dbmodels.go
+++ b/cla-backend-go/signatures/dbmodels.go
@@ -10,6 +10,7 @@ type ItemSignature struct {
DateModified string `json:"date_modified,omitempty"`
SignatureApproved bool `json:"signature_approved,omitempty"`
SignatureSigned bool `json:"signature_signed"`
+ SignatureEmbargoAcked bool `json:"signature_embargo_acked,omitempty"`
SignatureDocumentMajorVersion int `json:"signature_document_major_version,omitempty"`
SignatureDocumentMinorVersion int `json:"signature_document_minor_version,omitempty"`
SignatureSignURL string `json:"signature_sign_url,omitempty"`
diff --git a/cla-backend-go/signatures/models.go b/cla-backend-go/signatures/models.go
index 006aedade..a66012131 100644
--- a/cla-backend-go/signatures/models.go
+++ b/cla-backend-go/signatures/models.go
@@ -97,6 +97,7 @@ type SignatureDynamoDB struct {
SignatureACL []string `json:"signature_acl"` // [github:1234567]
SignatureApproved bool `json:"signature_approved"` // true if the signature is approved, false if revoked/invalidated
SignatureSigned bool `json:"signature_signed"` // true if the signature has been signed
+ SignatureEmbargoAcked bool `json:"signature_embargo_acked"` // true if the signature's embargo was acknowledged
SignatureReferenceType string `json:"signature_reference_type"` // one of: user, company
SignatureReferenceName string `json:"signature_reference_name"` // John Doe
SignatureReferenceNameLower string `json:"signature_reference_name_lower"` // john doe
diff --git a/cla-backend-go/signatures/repository.go b/cla-backend-go/signatures/repository.go
index c62001022..842be6a9b 100644
--- a/cla-backend-go/signatures/repository.go
+++ b/cla-backend-go/signatures/repository.go
@@ -19,7 +19,6 @@ import (
"github.com/communitybridge/easycla/cla-backend-go/config"
- "github.com/LF-Engineering/lfx-kit/auth"
"github.com/sirupsen/logrus"
"github.com/communitybridge/easycla/cla-backend-go/users"
@@ -2127,6 +2126,11 @@ func (repo repository) ValidateProjectRecord(ctx context.Context, signatureID, n
expressionAttributeValues[":a"] = &dynamodb.AttributeValue{BOOL: aws.Bool(true)}
updateExpression = updateExpression + " #A = :a,"
+ // Set embago acknowledged flag
+ // expressionAttributeNames["#E"] = aws.String("signature_embargo_acked")
+ // expressionAttributeValues[":e"] = &dynamodb.AttributeValue{BOOL: aws.Bool(true)}
+ // updateExpression = updateExpression + " #E = :e,"
+
expressionAttributeNames["#S"] = aws.String("note")
expressionAttributeValues[":s"] = &dynamodb.AttributeValue{S: aws.String(note)}
updateExpression = updateExpression + " #S = :s"
@@ -2528,6 +2532,7 @@ func (repo repository) CreateProjectCompanyEmployeeSignature(ctx context.Context
SignatureReferenceID: employeeUserModel.UserID,
SignatureApproved: true,
SignatureSigned: true,
+ SignatureEmbargoAcked: true,
SignatureDocumentMajorVersion: 2,
SignatureDocumentMinorVersion: 0,
SigTypeSignedApprovedID: fmt.Sprintf("ecla#true#true#%s", companyModel.CompanyID),
@@ -3200,10 +3205,10 @@ func (repo repository) UpdateApprovalList(ctx context.Context, claManager *model
PageSize: utils.Int64(10),
}
- authUser := auth.User{
- Email: claManager.LfEmail.String(),
- UserName: claManager.LfUsername,
- }
+ // authUser := auth.User{
+ // Email: claManager.LfEmail.String(),
+ // UserName: claManager.LfUsername,
+ // }
// Keep track of gerrit users under a give CLA Group
var gerritICLAECLAs []string
@@ -3214,8 +3219,8 @@ func (repo repository) UpdateApprovalList(ctx context.Context, claManager *model
goRoutines := 2
gerritResultChannel := make(chan *GerritUserResponse, goRoutines)
gerritQueryStartTime, _ := utils.CurrentTime()
- go repo.getGerritUsers(ctx, &authUser, projectID, utils.ClaTypeICLA, gerritResultChannel)
- go repo.getGerritUsers(ctx, &authUser, projectID, utils.ClaTypeECLA, gerritResultChannel)
+ // go repo.getGerritUsers(ctx, &authUser, projectID, utils.ClaTypeICLA, gerritResultChannel)
+ // go repo.getGerritUsers(ctx, &authUser, projectID, utils.ClaTypeECLA, gerritResultChannel)
log.WithFields(f).Debug("waiting on gerrit user query results from 2 go routines...")
for i := 0; i < goRoutines; i++ {
@@ -3313,19 +3318,19 @@ func (repo repository) UpdateApprovalList(ctx context.Context, claManager *model
}
} else {
- // Update gerrit user
- if utils.StringInSlice(user.LfUsername, gerritICLAECLAs) {
- gerritIclaErr := repo.gerritService.RemoveUserFromGroup(ctx, &authUser, approvalList.ClaGroupID, user.LfUsername, utils.ClaTypeICLA)
- if gerritIclaErr != nil {
- msg := fmt.Sprintf("unable to remove gerrit user: %s from group: %s", user.LfUsername, approvalList.ClaGroupID)
- log.WithFields(f).WithError(gerritIclaErr).Warn(msg)
- }
- eclaErr := repo.gerritService.RemoveUserFromGroup(ctx, &authUser, approvalList.ClaGroupID, user.LfUsername, utils.ClaTypeECLA)
- if eclaErr != nil {
- msg := fmt.Sprintf("unable to remove gerrit user: %s from group: %s", user.LfUsername, approvalList.ClaGroupID)
- log.WithFields(f).WithError(eclaErr).Warn(msg)
- }
- }
+ // // Update gerrit user
+ // if utils.StringInSlice(user.LfUsername, gerritICLAECLAs) {
+ // // gerritIclaErr := repo.gerritService.RemoveUserFromGroup(ctx, &authUser, approvalList.ClaGroupID, user.LfUsername, utils.ClaTypeICLA)
+ // if gerritIclaErr != nil {
+ // msg := fmt.Sprintf("unable to remove gerrit user: %s from group: %s", user.LfUsername, approvalList.ClaGroupID)
+ // log.WithFields(f).WithError(gerritIclaErr).Warn(msg)
+ // }
+ // eclaErr := repo.gerritService.RemoveUserFromGroup(ctx, &authUser, approvalList.ClaGroupID, user.LfUsername, utils.ClaTypeECLA)
+ // if eclaErr != nil {
+ // msg := fmt.Sprintf("unable to remove gerrit user: %s from group: %s", user.LfUsername, approvalList.ClaGroupID)
+ // log.WithFields(f).WithError(eclaErr).Warn(msg)
+ // }
+ // }
results <- &ICLAUserResponse{
ICLASignature: &models.IclaSignature{
GithubUsername: icla.UserGHUsername,
@@ -4053,10 +4058,10 @@ func (repo repository) verifyUserApprovals(ctx context.Context, userID, signatur
}
email := getBestEmail(user)
- authUser := auth.User{
- Email: claManager.LfEmail.String(),
- UserName: claManager.LfUsername,
- }
+ // authUser := auth.User{
+ // Email: claManager.LfEmail.String(),
+ // UserName: claManager.LfUsername,
+ // }
if approvalList.Criteria == utils.EmailDomainCriteria {
// Handle Domains
@@ -4072,20 +4077,20 @@ func (repo repository) verifyUserApprovals(ctx context.Context, userID, signatur
return user, err
}
- // Update Gerrit group users
- if utils.StringInSlice(user.LfUsername, approvalList.GerritICLAECLAs) {
- log.WithFields(f).Debugf("removing gerrit user:%s from claGroup: %s ...", user.LfUsername, approvalList.ClaGroupID)
- iclaErr := repo.gerritService.RemoveUserFromGroup(ctx, &authUser, approvalList.ClaGroupID, user.LfUsername, utils.ClaTypeICLA)
- if iclaErr != nil {
- msg := fmt.Sprintf("unable to remove gerrit user:%s from group:%s", user.LfUsername, approvalList.ClaGroupID)
- log.WithFields(f).Warn(msg)
- }
- eclaErr := repo.gerritService.RemoveUserFromGroup(ctx, &authUser, approvalList.ClaGroupID, user.LfUsername, utils.ClaTypeECLA)
- if eclaErr != nil {
- msg := fmt.Sprintf("unable to remove gerrit user:%s from group:%s", user.LfUsername, approvalList.ClaGroupID)
- log.WithFields(f).Warn(msg)
- }
- }
+ // // Update Gerrit group users
+ // if utils.StringInSlice(user.LfUsername, approvalList.GerritICLAECLAs) {
+ // log.WithFields(f).Debugf("removing gerrit user:%s from claGroup: %s ...", user.LfUsername, approvalList.ClaGroupID)
+ // iclaErr := repo.gerritService.RemoveUserFromGroup(ctx, &authUser, approvalList.ClaGroupID, user.LfUsername, utils.ClaTypeICLA)
+ // if iclaErr != nil {
+ // msg := fmt.Sprintf("unable to remove gerrit user:%s from group:%s", user.LfUsername, approvalList.ClaGroupID)
+ // log.WithFields(f).Warn(msg)
+ // }
+ // eclaErr := repo.gerritService.RemoveUserFromGroup(ctx, &authUser, approvalList.ClaGroupID, user.LfUsername, utils.ClaTypeECLA)
+ // if eclaErr != nil {
+ // msg := fmt.Sprintf("unable to remove gerrit user:%s from group:%s", user.LfUsername, approvalList.ClaGroupID)
+ // log.WithFields(f).Warn(msg)
+ // }
+ // }
}
}
} else if approvalList.Criteria == utils.GitHubOrgCriteria {
@@ -4546,6 +4551,7 @@ func (repo repository) getIntermediateICLAResponse(f logrus.Fields, dbSignatures
LfUsername: sig.UserLFUsername,
SignatureApproved: sig.SignatureApproved,
SignatureSigned: sig.SignatureSigned,
+ SignatureEmbargoAcked: true,
SignatureModified: sig.DateModified,
SignatureID: sig.SignatureID,
SignedOn: sigSignedTime,
@@ -4929,7 +4935,10 @@ func (repo repository) ActivateSignature(ctx context.Context, signatureID string
}
// Build the expression
- expressionUpdate := expression.Set(expression.Name("signature_approved"), expression.Value(true)).Set(expression.Name("signature_signed"), expression.Value(false))
+ expressionUpdate := expression.
+ Set(expression.Name("signature_approved"), expression.Value(true)).
+ Set(expression.Name("signature_signed"), expression.Value(false)).
+ Set(expression.Name("signature_embargo_acked"), expression.Value(true))
expr, err := expression.NewBuilder().WithUpdate(expressionUpdate).Build()
if err != nil {
@@ -4959,32 +4968,32 @@ func (repo repository) ActivateSignature(ctx context.Context, signatureID string
}
// getGerritUsers is a helper function to fetch the list of gerrit users for the specified type - results are returned through the specified results channel
-func (repo repository) getGerritUsers(ctx context.Context, authUser *auth.User, projectSFID string, claType string, gerritResultChannel chan *GerritUserResponse) {
- f := logrus.Fields{
- "functionName": "v1.signatures.repository.getGerritUsers",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "projectSFID": projectSFID,
- }
- log.WithFields(f).Debugf("querying gerrit for %s gerrit users...", claType)
- gerritIclaUsers, getGerritQueryErr := repo.gerritService.GetUsersOfGroup(ctx, authUser, projectSFID, claType)
- if getGerritQueryErr != nil || gerritIclaUsers == nil {
- msg := fmt.Sprintf("unable to fetch gerrit users for claGroup: %s , claType: %s ", projectSFID, claType)
- log.WithFields(f).WithError(getGerritQueryErr).Warn(msg)
- gerritResultChannel <- &GerritUserResponse{
- gerritGroupResponse: nil,
- queryType: claType,
- Error: errors.New(msg),
- }
- return
- }
-
- log.WithFields(f).Debugf("retrieved %d gerrit users for CLA type: %s...", len(gerritIclaUsers.Members), claType)
- gerritResultChannel <- &GerritUserResponse{
- gerritGroupResponse: gerritIclaUsers,
- queryType: claType,
- Error: nil,
- }
-}
+// func (repo repository) getGerritUsers(ctx context.Context, authUser *auth.User, projectSFID string, claType string, gerritResultChannel chan *GerritUserResponse) {
+// // f := logrus.Fields{
+// // "functionName": "v1.signatures.repository.getGerritUsers",
+// // utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
+// // "projectSFID": projectSFID,
+// // }
+// // log.WithFields(f).Debugf("querying gerrit for %s gerrit users...", claType)
+// // gerritIclaUsers, getGerritQueryErr := repo.gerritService.GetUsersOfGroup(ctx, authUser, projectSFID, claType)
+// // if getGerritQueryErr != nil || gerritIclaUsers == nil {
+// // msg := fmt.Sprintf("unable to fetch gerrit users for claGroup: %s , claType: %s ", projectSFID, claType)
+// // log.WithFields(f).WithError(getGerritQueryErr).Warn(msg)
+// // gerritResultChannel <- &GerritUserResponse{
+// // gerritGroupResponse: nil,
+// // queryType: claType,
+// // Error: errors.New(msg),
+// // }
+// // return
+// // }
+
+// // log.WithFields(f).Debugf("retrieved %d gerrit users for CLA type: %s...", len(gerritIclaUsers.Members), claType)
+// gerritResultChannel <- &GerritUserResponse{
+// gerritGroupResponse: nil,
+// queryType: claType,
+// Error: nil,
+// }
+// }
func buildNextKey(indexName string, signature *models.Signature) (string, error) {
nextKey := make(map[string]*dynamodb.AttributeValue)
diff --git a/cla-backend-go/signatures/service.go b/cla-backend-go/signatures/service.go
index f4295df4c..bf01ed100 100644
--- a/cla-backend-go/signatures/service.go
+++ b/cla-backend-go/signatures/service.go
@@ -1316,9 +1316,11 @@ func (s service) UserIsApproved(ctx context.Context, user *models.User, cclaSign
if len(emailApprovalList) > 0 {
for _, email := range emails {
log.WithFields(f).Debugf("checking email: %s", email)
- if utils.StringInSlice(email, emailApprovalList) {
- log.WithFields(f).Debugf("found matching email: %s in the email approval list", email)
- return true, nil
+ // case insensitive search
+ for _, emailApproval := range emailApprovalList {
+ if strings.EqualFold(email, emailApproval) {
+ return true, nil
+ }
}
}
} else {
diff --git a/cla-backend-go/signatures/service_test.go b/cla-backend-go/signatures/service_test.go
index 9d35f9da2..61e0f2e73 100644
--- a/cla-backend-go/signatures/service_test.go
+++ b/cla-backend-go/signatures/service_test.go
@@ -70,6 +70,16 @@ func TestUserIsApproved(t *testing.T) {
},
expectedIsApproved: true,
},
+ {
+ name: "Test user email case - email approval",
+ user: &v1Models.User{
+ Emails: []string{"Foo@gmail.com"},
+ },
+ cclaSignature: &v1Models.Signature{
+ EmailApprovalList: []string{"foo@gmail.com"},
+ },
+ expectedIsApproved: true,
+ },
}
for _, tc := range testCases {
diff --git a/cla-backend-go/swagger/cla.v2.yaml b/cla-backend-go/swagger/cla.v2.yaml
index 098fceb2f..f84d6ee3a 100644
--- a/cla-backend-go/swagger/cla.v2.yaml
+++ b/cla-backend-go/swagger/cla.v2.yaml
@@ -3222,201 +3222,201 @@ paths:
tags:
- gerrits
- /cla-group/{claGroupID}/project/{projectSFID}/gerrits/icla/user:
- get:
- summary: Get Gerrit ICLA Users
- description: Gets the authorized individual CLA users from a gerrit instance for the CLA Group/Projecct
- operationId: getGerritICLAUser
- parameters:
- - $ref: "#/parameters/x-request-id"
- - $ref: "#/parameters/x-acl"
- - $ref: "#/parameters/x-username"
- - $ref: "#/parameters/x-email"
- - $ref: "#/parameters/path-claGroupID"
- - $ref: "#/parameters/path-projectSFID"
- responses:
- '200':
- description: 'Success'
- headers:
- x-request-id:
- type: string
- description: The unique request ID value - assigned/set by the API Gateway based on the session
- schema:
- $ref: '#/definitions/gerrit-group-response'
- '400':
- $ref: '#/responses/invalid-request'
- '403':
- $ref: '#/responses/forbidden'
- '409':
- $ref: '#/responses/conflict'
- '500':
- $ref: '#/responses/internal-server-error'
- tags:
- - gerrits
- put:
- summary: Add Gerrit ICLA Users
- description: Adds one or more individual CLA users to the gerrit CLA Group/project
- operationId: addGerritICLAUser
- parameters:
- - $ref: "#/parameters/x-request-id"
- - $ref: "#/parameters/x-acl"
- - $ref: "#/parameters/x-username"
- - $ref: "#/parameters/x-email"
- - $ref: "#/parameters/path-claGroupID"
- - $ref: "#/parameters/path-projectSFID"
- - in: body
- name: add-gerrit-user-input
- schema:
- $ref: '#/definitions/add-gerrit-user-input'
- required: true
- responses:
- '200':
- description: 'Success'
- headers:
- x-request-id:
- type: string
- description: The unique request ID value - assigned/set by the API Gateway based on the session
- '400':
- $ref: '#/responses/invalid-request'
- '403':
- $ref: '#/responses/forbidden'
- '409':
- $ref: '#/responses/conflict'
- '500':
- $ref: '#/responses/internal-server-error'
- tags:
- - gerrits
- delete:
- summary: Remove Gerrit ICLA Users
- description: Removes one or more individual CLA users from a gerrit instance for the CLA Group/Project
- operationId: removeGerritICLAUser
- parameters:
- - $ref: "#/parameters/x-request-id"
- - $ref: "#/parameters/x-acl"
- - $ref: "#/parameters/x-username"
- - $ref: "#/parameters/x-email"
- - $ref: "#/parameters/path-claGroupID"
- - $ref: "#/parameters/path-projectSFID"
- - in: body
- name: remove-gerrit-user-input
- schema:
- $ref: '#/definitions/remove-gerrit-user-input'
- required: true
- responses:
- '200':
- description: 'Success'
- headers:
- x-request-id:
- type: string
- description: The unique request ID value - assigned/set by the API Gateway based on the session
- '400':
- $ref: '#/responses/invalid-request'
- '403':
- $ref: '#/responses/forbidden'
- '409':
- $ref: '#/responses/conflict'
- '500':
- $ref: '#/responses/internal-server-error'
- tags:
- - gerrits
-
- /cla-group/{claGroupID}/project/{projectSFID}/gerrits/ecla/user:
- get:
- summary: Get Gerrit ECLA Users
- description: Gets the authorized employee CLA users from a gerrit instance for the CLA Group/Projecct
- operationId: getGerritECLAUser
- parameters:
- - $ref: "#/parameters/x-request-id"
- - $ref: "#/parameters/x-acl"
- - $ref: "#/parameters/x-username"
- - $ref: "#/parameters/x-email"
- - $ref: "#/parameters/path-claGroupID"
- - $ref: "#/parameters/path-projectSFID"
- responses:
- '200':
- description: 'Success'
- headers:
- x-request-id:
- type: string
- description: The unique request ID value - assigned/set by the API Gateway based on the session
- schema:
- $ref: '#/definitions/gerrit-group-response'
- '400':
- $ref: '#/responses/invalid-request'
- '403':
- $ref: '#/responses/forbidden'
- '409':
- $ref: '#/responses/conflict'
- '500':
- $ref: '#/responses/internal-server-error'
- tags:
- - gerrits
- put:
- summary: Add Gerrit ECLA Users
- description: Adds one or more employee CLA users to a gerrit instance for the CLA Group/Project
- operationId: addGerritECLAUser
- parameters:
- - $ref: "#/parameters/x-request-id"
- - $ref: "#/parameters/x-acl"
- - $ref: "#/parameters/x-username"
- - $ref: "#/parameters/x-email"
- - $ref: "#/parameters/path-claGroupID"
- - $ref: "#/parameters/path-projectSFID"
- - in: body
- name: add-gerrit-user-input
- schema:
- $ref: '#/definitions/add-gerrit-user-input'
- required: true
- responses:
- '200':
- description: 'Success'
- headers:
- x-request-id:
- type: string
- description: The unique request ID value - assigned/set by the API Gateway based on the session
- '400':
- $ref: '#/responses/invalid-request'
- '403':
- $ref: '#/responses/forbidden'
- '409':
- $ref: '#/responses/conflict'
- '500':
- $ref: '#/responses/internal-server-error'
- tags:
- - gerrits
- delete:
- summary: Remove Gerrit ECLA Users
- description: Removes one or more employee CLA users from a gerrit instance for the project
- operationId: removeGerritECLAUser
- parameters:
- - $ref: "#/parameters/x-request-id"
- - $ref: "#/parameters/x-acl"
- - $ref: "#/parameters/x-username"
- - $ref: "#/parameters/x-email"
- - $ref: "#/parameters/path-claGroupID"
- - $ref: "#/parameters/path-projectSFID"
- - in: body
- name: remove-gerrit-user-input
- schema:
- $ref: '#/definitions/remove-gerrit-user-input'
- required: true
- responses:
- '200':
- description: 'Success'
- headers:
- x-request-id:
- type: string
- description: The unique request ID value - assigned/set by the API Gateway based on the session
- '400':
- $ref: '#/responses/invalid-request'
- '403':
- $ref: '#/responses/forbidden'
- '409':
- $ref: '#/responses/conflict'
- '500':
- $ref: '#/responses/internal-server-error'
- tags:
- - gerrits
+ # /cla-group/{claGroupID}/project/{projectSFID}/gerrits/icla/user:
+ # get:
+ # summary: Get Gerrit ICLA Users
+ # description: Gets the authorized individual CLA users from a gerrit instance for the CLA Group/Projecct
+ # operationId: getGerritICLAUser
+ # parameters:
+ # - $ref: "#/parameters/x-request-id"
+ # - $ref: "#/parameters/x-acl"
+ # - $ref: "#/parameters/x-username"
+ # - $ref: "#/parameters/x-email"
+ # - $ref: "#/parameters/path-claGroupID"
+ # - $ref: "#/parameters/path-projectSFID"
+ # responses:
+ # '200':
+ # description: 'Success'
+ # headers:
+ # x-request-id:
+ # type: string
+ # description: The unique request ID value - assigned/set by the API Gateway based on the session
+ # schema:
+ # $ref: '#/definitions/gerrit-group-response'
+ # '400':
+ # $ref: '#/responses/invalid-request'
+ # '403':
+ # $ref: '#/responses/forbidden'
+ # '409':
+ # $ref: '#/responses/conflict'
+ # '500':
+ # $ref: '#/responses/internal-server-error'
+ # tags:
+ # - gerrits
+ # put:
+ # summary: Add Gerrit ICLA Users
+ # description: Adds one or more individual CLA users to the gerrit CLA Group/project
+ # operationId: addGerritICLAUser
+ # parameters:
+ # - $ref: "#/parameters/x-request-id"
+ # - $ref: "#/parameters/x-acl"
+ # - $ref: "#/parameters/x-username"
+ # - $ref: "#/parameters/x-email"
+ # - $ref: "#/parameters/path-claGroupID"
+ # - $ref: "#/parameters/path-projectSFID"
+ # - in: body
+ # name: add-gerrit-user-input
+ # schema:
+ # $ref: '#/definitions/add-gerrit-user-input'
+ # required: true
+ # responses:
+ # '200':
+ # description: 'Success'
+ # headers:
+ # x-request-id:
+ # type: string
+ # description: The unique request ID value - assigned/set by the API Gateway based on the session
+ # '400':
+ # $ref: '#/responses/invalid-request'
+ # '403':
+ # $ref: '#/responses/forbidden'
+ # '409':
+ # $ref: '#/responses/conflict'
+ # '500':
+ # $ref: '#/responses/internal-server-error'
+ # tags:
+ # - gerrits
+ # delete:
+ # summary: Remove Gerrit ICLA Users
+ # description: Removes one or more individual CLA users from a gerrit instance for the CLA Group/Project
+ # operationId: removeGerritICLAUser
+ # parameters:
+ # - $ref: "#/parameters/x-request-id"
+ # - $ref: "#/parameters/x-acl"
+ # - $ref: "#/parameters/x-username"
+ # - $ref: "#/parameters/x-email"
+ # - $ref: "#/parameters/path-claGroupID"
+ # - $ref: "#/parameters/path-projectSFID"
+ # - in: body
+ # name: remove-gerrit-user-input
+ # schema:
+ # $ref: '#/definitions/remove-gerrit-user-input'
+ # required: true
+ # responses:
+ # '200':
+ # description: 'Success'
+ # headers:
+ # x-request-id:
+ # type: string
+ # description: The unique request ID value - assigned/set by the API Gateway based on the session
+ # '400':
+ # $ref: '#/responses/invalid-request'
+ # '403':
+ # $ref: '#/responses/forbidden'
+ # '409':
+ # $ref: '#/responses/conflict'
+ # '500':
+ # $ref: '#/responses/internal-server-error'
+ # tags:
+ # - gerrits
+
+ # /cla-group/{claGroupID}/project/{projectSFID}/gerrits/ecla/user:
+ # get:
+ # summary: Get Gerrit ECLA Users
+ # description: Gets the authorized employee CLA users from a gerrit instance for the CLA Group/Projecct
+ # operationId: getGerritECLAUser
+ # parameters:
+ # - $ref: "#/parameters/x-request-id"
+ # - $ref: "#/parameters/x-acl"
+ # - $ref: "#/parameters/x-username"
+ # - $ref: "#/parameters/x-email"
+ # - $ref: "#/parameters/path-claGroupID"
+ # - $ref: "#/parameters/path-projectSFID"
+ # responses:
+ # '200':
+ # description: 'Success'
+ # headers:
+ # x-request-id:
+ # type: string
+ # description: The unique request ID value - assigned/set by the API Gateway based on the session
+ # schema:
+ # $ref: '#/definitions/gerrit-group-response'
+ # '400':
+ # $ref: '#/responses/invalid-request'
+ # '403':
+ # $ref: '#/responses/forbidden'
+ # '409':
+ # $ref: '#/responses/conflict'
+ # '500':
+ # $ref: '#/responses/internal-server-error'
+ # tags:
+ # - gerrits
+ # put:
+ # summary: Add Gerrit ECLA Users
+ # description: Adds one or more employee CLA users to a gerrit instance for the CLA Group/Project
+ # operationId: addGerritECLAUser
+ # parameters:
+ # - $ref: "#/parameters/x-request-id"
+ # - $ref: "#/parameters/x-acl"
+ # - $ref: "#/parameters/x-username"
+ # - $ref: "#/parameters/x-email"
+ # - $ref: "#/parameters/path-claGroupID"
+ # - $ref: "#/parameters/path-projectSFID"
+ # - in: body
+ # name: add-gerrit-user-input
+ # schema:
+ # $ref: '#/definitions/add-gerrit-user-input'
+ # required: true
+ # responses:
+ # '200':
+ # description: 'Success'
+ # headers:
+ # x-request-id:
+ # type: string
+ # description: The unique request ID value - assigned/set by the API Gateway based on the session
+ # '400':
+ # $ref: '#/responses/invalid-request'
+ # '403':
+ # $ref: '#/responses/forbidden'
+ # '409':
+ # $ref: '#/responses/conflict'
+ # '500':
+ # $ref: '#/responses/internal-server-error'
+ # tags:
+ # - gerrits
+ # delete:
+ # summary: Remove Gerrit ECLA Users
+ # description: Removes one or more employee CLA users from a gerrit instance for the project
+ # operationId: removeGerritECLAUser
+ # parameters:
+ # - $ref: "#/parameters/x-request-id"
+ # - $ref: "#/parameters/x-acl"
+ # - $ref: "#/parameters/x-username"
+ # - $ref: "#/parameters/x-email"
+ # - $ref: "#/parameters/path-claGroupID"
+ # - $ref: "#/parameters/path-projectSFID"
+ # - in: body
+ # name: remove-gerrit-user-input
+ # schema:
+ # $ref: '#/definitions/remove-gerrit-user-input'
+ # required: true
+ # responses:
+ # '200':
+ # description: 'Success'
+ # headers:
+ # x-request-id:
+ # type: string
+ # description: The unique request ID value - assigned/set by the API Gateway based on the session
+ # '400':
+ # $ref: '#/responses/invalid-request'
+ # '403':
+ # $ref: '#/responses/forbidden'
+ # '409':
+ # $ref: '#/responses/conflict'
+ # '500':
+ # $ref: '#/responses/internal-server-error'
+ # tags:
+ # - gerrits
/cla-group/{claGroupID}/user/{userID}/icla:
put:
summary: Invalidate ICLA record
diff --git a/cla-backend-go/swagger/common/add-gerrit-input.yaml b/cla-backend-go/swagger/common/add-gerrit-input.yaml
index 9ad977a16..858bafa89 100644
--- a/cla-backend-go/swagger/common/add-gerrit-input.yaml
+++ b/cla-backend-go/swagger/common/add-gerrit-input.yaml
@@ -26,20 +26,6 @@ properties:
minLength: 10
maxLength: 255
pattern: ^(?:http(s)?:\/\/).+$
- groupIdCcla:
- type: string
- description: the LDAP group ID for CCLA encoded as a string value
- example: '1902'
- minLength: 1
- maxLength: 12
- pattern: ^[1-9]\d{0,11}$
- groupIdIcla:
- type: string
- description: the LDAP group ID for ICLA encoded as a string value
- example: '1903'
- minLength: 1
- maxLength: 12
- pattern: ^[1-9]\d{0,11}$
version:
type: string
description: the version associated with the gerrit record
diff --git a/cla-backend-go/swagger/common/corporate-signature.yaml b/cla-backend-go/swagger/common/corporate-signature.yaml
index 0e9db3594..0ed18c6b5 100644
--- a/cla-backend-go/swagger/common/corporate-signature.yaml
+++ b/cla-backend-go/swagger/common/corporate-signature.yaml
@@ -38,6 +38,11 @@ properties:
description: the signature approved flag - true or false value
example: true
x-omitempty: false
+ signatureEmbargoAcked:
+ type: boolean
+ description: the signature embargo acknowledged flag - true or false value
+ example: true
+ # x-omitempty: false
signatureReferenceType:
type: string
description: the signature reference type - either user or company
diff --git a/cla-backend-go/swagger/common/gerrit.yaml b/cla-backend-go/swagger/common/gerrit.yaml
index 589cc40c2..e3d738c44 100644
--- a/cla-backend-go/swagger/common/gerrit.yaml
+++ b/cla-backend-go/swagger/common/gerrit.yaml
@@ -40,25 +40,6 @@ properties:
minLength: 1
maxLength: 12
pattern: ^[1-9]\d{0,11}$
- groupIdIcla:
- type: string
- description: the LDAP group ID for ICLA encoded as a string value
- example: '1903'
- minLength: 1
- maxLength: 12
- pattern: ^[1-9]\d{0,11}$
- groupNameCcla:
- type: string
- description: the LDAP group name for CCLA
- example: 'onap-cla-ccla'
- minLength: 3
- maxLength: 20
- groupNameIcla:
- type: string
- description: the LDAP group name for ICLA
- example: 'onap-cla-icla'
- minLength: 3
- maxLength: 20
projectSFID:
type: string
description: the Project SalesForce ID (external ID) associated with this gerrit record
diff --git a/cla-backend-go/swagger/common/icla-signature.yaml b/cla-backend-go/swagger/common/icla-signature.yaml
index 39662700c..cf1649284 100644
--- a/cla-backend-go/swagger/common/icla-signature.yaml
+++ b/cla-backend-go/swagger/common/icla-signature.yaml
@@ -52,6 +52,11 @@ properties:
description: the signature signed flag - true or false value
example: true
x-omitempty: false
+ signatureEmbargoAcked:
+ type: boolean
+ description: the signature embargo acknowledged flag - true or false value
+ example: true
+ # x-omitempty: false
signatureModified:
type: string
description: the signature modified created time
diff --git a/cla-backend-go/swagger/common/signature-summary.yaml b/cla-backend-go/swagger/common/signature-summary.yaml
index 69290d7bb..06fdb0983 100644
--- a/cla-backend-go/swagger/common/signature-summary.yaml
+++ b/cla-backend-go/swagger/common/signature-summary.yaml
@@ -29,6 +29,11 @@ properties:
description: the signature approved flag - true or false value
example: true
x-omitempty: false
+ signatureEmbargoAcked:
+ type: boolean
+ description: the signature embargo acknowledged flag - true or false value
+ example: true
+ # x-omitempty: false
signatureReferenceType:
type: string
description: the signature reference type - either user or company
diff --git a/cla-backend-go/swagger/common/signature.yaml b/cla-backend-go/swagger/common/signature.yaml
index 707d36f97..d3a8b13ce 100644
--- a/cla-backend-go/swagger/common/signature.yaml
+++ b/cla-backend-go/swagger/common/signature.yaml
@@ -38,6 +38,11 @@ properties:
description: the signature approved flag - true or false value
example: true
x-omitempty: false
+ signatureEmbargoAcked:
+ type: boolean
+ description: the signature embargo acknowledged flag - true or false value
+ example: true
+ # x-omitempty: false
signatureReferenceType:
type: string
description: the signature reference type - either user or company
diff --git a/cla-backend-go/v2/cla_manager/service.go b/cla-backend-go/v2/cla_manager/service.go
index 6664c853f..1e1cbac34 100644
--- a/cla-backend-go/v2/cla_manager/service.go
+++ b/cla-backend-go/v2/cla_manager/service.go
@@ -239,7 +239,7 @@ func (s *service) CreateCLAManager(ctx context.Context, authUser *auth.User, cla
}
// Add CLA Manager to Database
- signature, addErr := s.managerService.AddClaManager(ctx, authUser, v1CompanyModel.CompanyID, claGroupID, user.Username, projectSF.Name)
+ signature, addErr := s.managerService.AddClaManager(ctx, authUser, v1CompanyModel.CompanyID, claGroupID, user.Username, params.ProjectSFID)
if addErr != nil {
msg := buildErrorMessageCreate(params, addErr)
log.WithFields(f).Warn(msg)
diff --git a/cla-backend-go/v2/company/service_test.go b/cla-backend-go/v2/company/service_test.go
index de5cea1d4..0a3a11405 100644
--- a/cla-backend-go/v2/company/service_test.go
+++ b/cla-backend-go/v2/company/service_test.go
@@ -39,6 +39,7 @@ func TestGetCompanyProjectContributors(t *testing.T) {
SignatureCreated: "2021-09-13T11:59:00.981612+0000",
SignatureApproved: true,
SignatureSigned: true,
+ SignatureEmbargoAcked: true,
SignatureMajorVersion: "1",
SignatureMinorVersion: "0",
SignatureReferenceID: "signature_reference_id",
@@ -48,6 +49,7 @@ func TestGetCompanyProjectContributors(t *testing.T) {
SignatureCreated: "2021-09-15T11:59:00.981612+0000",
SignatureApproved: true,
SignatureSigned: true,
+ SignatureEmbargoAcked: true,
SignatureMajorVersion: "1",
SignatureMinorVersion: "0",
SignatureReferenceID: "signature_reference_id",
@@ -57,6 +59,7 @@ func TestGetCompanyProjectContributors(t *testing.T) {
SignatureCreated: "2021-09-14T11:59:00.981612+0000",
SignatureApproved: true,
SignatureSigned: true,
+ SignatureEmbargoAcked: true,
SignatureMajorVersion: "1",
SignatureMinorVersion: "0",
SignatureReferenceID: "signature_reference_id",
@@ -76,6 +79,7 @@ func TestGetCompanyProjectContributors(t *testing.T) {
SignatureCreated: "2021-09-13T11:59:00.981612+0000",
SignatureApproved: true,
SignatureSigned: true,
+ SignatureEmbargoAcked: true,
SignatureMajorVersion: "1",
SignatureMinorVersion: "0",
SignatureReferenceID: "signature_reference_id",
@@ -85,6 +89,7 @@ func TestGetCompanyProjectContributors(t *testing.T) {
SignatureCreated: "2021-09-15T11:59:00.981612+0000",
SignatureApproved: true,
SignatureSigned: true,
+ SignatureEmbargoAcked: true,
SignatureMajorVersion: "1",
SignatureMinorVersion: "0",
SignatureReferenceID: "signature_reference_id",
@@ -94,6 +99,7 @@ func TestGetCompanyProjectContributors(t *testing.T) {
SignatureCreated: "2021-09-14T11:59:00.981612+0000",
SignatureApproved: true,
SignatureSigned: true,
+ SignatureEmbargoAcked: true,
SignatureMajorVersion: "1",
SignatureMinorVersion: "0",
SignatureReferenceID: "signature_reference_id",
@@ -103,6 +109,7 @@ func TestGetCompanyProjectContributors(t *testing.T) {
SignatureCreated: "",
SignatureApproved: true,
SignatureSigned: true,
+ SignatureEmbargoAcked: true,
SignatureMajorVersion: "1",
SignatureMinorVersion: "0",
SignatureReferenceID: "signature_reference_id_empty",
diff --git a/cla-backend-go/v2/dynamo_events/cla_manager.go b/cla-backend-go/v2/dynamo_events/cla_manager.go
index 3e489ee1c..914326d80 100644
--- a/cla-backend-go/v2/dynamo_events/cla_manager.go
+++ b/cla-backend-go/v2/dynamo_events/cla_manager.go
@@ -40,6 +40,7 @@ func (s *service) SetInitialCLAManagerACSPermissions(ctx context.Context, signat
f["projectID"] = sig.ProjectID
f["signed"] = sig.SignatureSigned
f["approved"] = sig.SignatureApproved
+ f["embargo_acked"] = sig.SignatureEmbargoAcked
f["companyName"] = sig.CompanyName
f["claType"] = sig.ClaType
diff --git a/cla-backend-go/v2/dynamo_events/signatures.go b/cla-backend-go/v2/dynamo_events/signatures.go
index c40a8e263..fe39379fc 100644
--- a/cla-backend-go/v2/dynamo_events/signatures.go
+++ b/cla-backend-go/v2/dynamo_events/signatures.go
@@ -41,6 +41,7 @@ type Signature struct {
DateModified string `json:"date_modified"`
SignatureApproved bool `json:"signature_approved"`
SignatureSigned bool `json:"signature_signed"`
+ SignatureEmbargoAcked bool `json:"signature_embargo_acked"`
SignatureDocumentMajorVersion string `json:"signature_document_major_version"`
SignatureDocumentMinorVersion string `json:"signature_document_minor_version"`
SignatureReferenceID string `json:"signature_reference_id"`
@@ -95,6 +96,7 @@ func (s *service) SignatureAssignContributorEvent(event events.DynamoDBEventReco
f["projectID"] = newSignature.SignatureProjectID
f["approved"] = newSignature.SignatureApproved
f["signed"] = newSignature.SignatureSigned
+ f["embargo_acked"] = newSignature.SignatureEmbargoAcked
if !oldSignature.SignatureSigned && newSignature.SignatureSigned {
log.WithFields(f).Debug("signature is now signed - assigning contributor...")
@@ -138,6 +140,7 @@ func (s *service) SignatureSignedEvent(event events.DynamoDBEventRecord) error {
f["projectID"] = newSignature.SignatureProjectID
f["approved"] = newSignature.SignatureApproved
f["signed"] = newSignature.SignatureSigned
+ f["embargo_acked"] = newSignature.SignatureEmbargoAcked
// check if signature signed event is received
if !oldSignature.SignatureSigned && newSignature.SignatureSigned {
diff --git a/cla-backend-go/v2/gerrits/handlers.go b/cla-backend-go/v2/gerrits/handlers.go
index c0da4a705..1fb02686a 100644
--- a/cla-backend-go/v2/gerrits/handlers.go
+++ b/cla-backend-go/v2/gerrits/handlers.go
@@ -129,11 +129,9 @@ func Configure(api *operations.EasyclaAPI, v1Service v1Gerrits.Service, projectS
// add the gerrit
addGerritInput := &v1Models.AddGerritInput{
- GerritName: params.AddGerritInput.GerritName,
- GerritURL: params.AddGerritInput.GerritURL,
- GroupIDCcla: params.AddGerritInput.GroupIDCcla,
- GroupIDIcla: params.AddGerritInput.GroupIDIcla,
- Version: "v2",
+ GerritName: params.AddGerritInput.GerritName,
+ GerritURL: params.AddGerritInput.GerritURL,
+ Version: "v2",
}
result, err := v1Service.AddGerrit(ctx, params.ClaGroupID, params.ProjectSFID, addGerritInput, projectModel)
if err != nil {
@@ -261,195 +259,195 @@ func Configure(api *operations.EasyclaAPI, v1Service v1Gerrits.Service, projectS
return gerrits.NewGetGerritReposOK().WithXRequestID(reqID).WithPayload(&response)
})
- api.GerritsGetGerritICLAUserHandler = gerrits.GetGerritICLAUserHandlerFunc(func(params gerrits.GetGerritICLAUserParams, authUser *auth.User) middleware.Responder {
- reqID := utils.GetRequestID(params.XREQUESTID)
- ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
- utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
- f := logrus.Fields{
- "functionName": "v2.gerrits.handlers.GerritsGetGerritICLAUserHandler",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "authUserName": authUser.UserName,
- "authUserEmail": authUser.Email,
- "claGroupID": params.ClaGroupID,
- "projectSFID": params.ProjectSFID,
- }
-
- // verify user have access to the project
- if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
- msg := fmt.Sprintf("user %s does not have access to get gerrit users with Project scope of %s", authUser.UserName, params.ProjectSFID)
- log.WithFields(f).Warn(msg)
- return gerrits.NewGetGerritICLAUserForbidden().WithXRequestID(reqID).WithPayload(utils.ErrorResponseForbidden(reqID, msg))
- }
-
- log.WithFields(f).Debugf("getting user list to gerrit...")
- responseModel, err := v1Service.GetUsersOfGroup(ctx, authUser, params.ClaGroupID, utils.ClaTypeICLA)
- if err != nil {
- msg := fmt.Sprintf("problem getting user list of CLA Group %s", params.ClaGroupID)
- log.WithFields(f).WithError(err).Warn(msg)
- return gerrits.NewGetGerritICLAUserInternalServerError().WithXRequestID(reqID).WithPayload(utils.ErrorResponseInternalServerErrorWithError(reqID, msg, err))
- }
-
- return gerrits.NewGetGerritICLAUserOK().WithXRequestID(reqID).WithPayload(responseModel)
- })
-
- api.GerritsGetGerritECLAUserHandler = gerrits.GetGerritECLAUserHandlerFunc(func(params gerrits.GetGerritECLAUserParams, authUser *auth.User) middleware.Responder {
- reqID := utils.GetRequestID(params.XREQUESTID)
- ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
- utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
- f := logrus.Fields{
- "functionName": "v2.gerrits.handlers.GerritsGetGerritECLAUserHandler",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "authUserName": authUser.UserName,
- "authUserEmail": authUser.Email,
- "claGroupID": params.ClaGroupID,
- "projectSFID": params.ProjectSFID,
- }
-
- // verify user have access to the project
- if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
- msg := fmt.Sprintf("user %s does not have access to get gerrit users with Project scope of %s", authUser.UserName, params.ProjectSFID)
- log.WithFields(f).Warn(msg)
- return gerrits.NewGetGerritECLAUserForbidden().WithXRequestID(reqID).WithPayload(utils.ErrorResponseForbidden(reqID, msg))
- }
-
- log.WithFields(f).Debugf("getting user list to gerrit...")
- responseModel, err := v1Service.GetUsersOfGroup(ctx, authUser, params.ClaGroupID, utils.ClaTypeECLA)
- if err != nil {
- msg := fmt.Sprintf("problem getting user list of CLA Group %s", params.ClaGroupID)
- log.WithFields(f).WithError(err).Warn(msg)
- return gerrits.NewGetGerritECLAUserInternalServerError().WithXRequestID(reqID).WithPayload(utils.ErrorResponseInternalServerErrorWithError(reqID, msg, err))
- }
-
- return gerrits.NewGetGerritECLAUserOK().WithXRequestID(reqID).WithPayload(responseModel)
- })
-
- api.GerritsAddGerritICLAUserHandler = gerrits.AddGerritICLAUserHandlerFunc(func(params gerrits.AddGerritICLAUserParams, authUser *auth.User) middleware.Responder {
- reqID := utils.GetRequestID(params.XREQUESTID)
- ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
- utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
- f := logrus.Fields{
- "functionName": "v2.gerrits.handlers.GerritsAddGerritICLAUserHandler",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "authUserName": authUser.UserName,
- "authUserEmail": authUser.Email,
- "claGroupID": params.ClaGroupID,
- "projectSFID": params.ProjectSFID,
- "gerritUsers": strings.Join(params.AddGerritUserInput, ","),
- }
-
- // verify user have access to the project
- if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
- msg := fmt.Sprintf("user %s does not have access to add gerrit users with Project scope of %s", authUser.UserName, params.ProjectSFID)
- log.WithFields(f).Warn(msg)
- return gerrits.NewAddGerritICLAUserForbidden().WithXRequestID(reqID).WithPayload(utils.ErrorResponseForbidden(reqID, msg))
- }
-
- log.WithFields(f).Debugf("adding user list to gerrit...")
- err := v1Service.AddUsersToGroup(ctx, authUser, params.ClaGroupID, params.AddGerritUserInput, utils.ClaTypeICLA)
- if err != nil {
- msg := fmt.Sprintf("problem adding user list %s to CLA Group %s", strings.Join(params.AddGerritUserInput, ","), params.ClaGroupID)
- log.WithFields(f).WithError(err).Warn(msg)
- return gerrits.NewAddGerritICLAUserInternalServerError().WithXRequestID(reqID).WithPayload(utils.ErrorResponseInternalServerErrorWithError(reqID, msg, err))
- }
-
- return gerrits.NewAddGerritICLAUserOK().WithXRequestID(reqID)
- })
-
- api.GerritsRemoveGerritICLAUserHandler = gerrits.RemoveGerritICLAUserHandlerFunc(func(params gerrits.RemoveGerritICLAUserParams, authUser *auth.User) middleware.Responder {
- reqID := utils.GetRequestID(params.XREQUESTID)
- ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
- utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
- f := logrus.Fields{
- "functionName": "v2.gerrits.handlers.GerritsRemoveGerritICLAUserHandler",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "authUserName": authUser.UserName,
- "authUserEmail": authUser.Email,
- "claGroupID": params.ClaGroupID,
- "projectSFID": params.ProjectSFID,
- "gerritUsers": strings.Join(params.RemoveGerritUserInput, ","),
- }
-
- // verify user have access to the project
- if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
- msg := fmt.Sprintf("user %s does not have access to remove gerrit users with Project scope of %s", authUser.UserName, params.ProjectSFID)
- log.WithFields(f).Warn(msg)
- return gerrits.NewRemoveGerritICLAUserForbidden().WithXRequestID(reqID).WithPayload(utils.ErrorResponseForbidden(reqID, msg))
- }
-
- log.WithFields(f).Debugf("removing user list from gerrit...")
- err := v1Service.RemoveUsersFromGroup(ctx, authUser, params.ClaGroupID, params.RemoveGerritUserInput, utils.ClaTypeICLA)
- if err != nil {
- msg := fmt.Sprintf("problem removing user list %s to CLA Group %s", strings.Join(params.RemoveGerritUserInput, ","), params.ClaGroupID)
- log.WithFields(f).WithError(err).Warn(msg)
- return gerrits.NewRemoveGerritICLAUserInternalServerError().WithXRequestID(reqID).WithPayload(utils.ErrorResponseInternalServerErrorWithError(reqID, msg, err))
- }
-
- return gerrits.NewRemoveGerritICLAUserOK().WithXRequestID(reqID)
- })
-
- api.GerritsAddGerritECLAUserHandler = gerrits.AddGerritECLAUserHandlerFunc(func(params gerrits.AddGerritECLAUserParams, authUser *auth.User) middleware.Responder {
- reqID := utils.GetRequestID(params.XREQUESTID)
- ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
- utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
- f := logrus.Fields{
- "functionName": "v2.gerrits.handlers.GerritsAddGerritECLAUserHandler",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "authUserName": authUser.UserName,
- "authUserEmail": authUser.Email,
- "claGroupID": params.ClaGroupID,
- "projectSFID": params.ProjectSFID,
- "gerritUsers": strings.Join(params.AddGerritUserInput, ","),
- }
-
- // verify user have access to the project
- if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
- msg := fmt.Sprintf("user %s does not have access to add gerrit users with Project scope of %s", authUser.UserName, params.ProjectSFID)
- log.WithFields(f).Warn(msg)
- return gerrits.NewAddGerritECLAUserForbidden().WithXRequestID(reqID).WithPayload(utils.ErrorResponseForbidden(reqID, msg))
- }
-
- log.WithFields(f).Debugf("adding user list to gerrit...")
- err := v1Service.AddUsersToGroup(ctx, authUser, params.ClaGroupID, params.AddGerritUserInput, utils.ClaTypeECLA)
- if err != nil {
- msg := fmt.Sprintf("problem adding user list %s to CLA Group %s", strings.Join(params.AddGerritUserInput, ","), params.ClaGroupID)
- log.WithFields(f).WithError(err).Warn(msg)
- return gerrits.NewAddGerritECLAUserInternalServerError().WithXRequestID(reqID).WithPayload(utils.ErrorResponseInternalServerErrorWithError(reqID, msg, err))
- }
-
- return gerrits.NewAddGerritECLAUserOK().WithXRequestID(reqID)
- })
-
- api.GerritsRemoveGerritECLAUserHandler = gerrits.RemoveGerritECLAUserHandlerFunc(func(params gerrits.RemoveGerritECLAUserParams, authUser *auth.User) middleware.Responder {
- reqID := utils.GetRequestID(params.XREQUESTID)
- ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
- utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
- f := logrus.Fields{
- "functionName": "v2.gerrits.handlers.GerritsRemoveGerritECLAUserHandler",
- utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
- "authUserName": authUser.UserName,
- "authUserEmail": authUser.Email,
- "claGroupID": params.ClaGroupID,
- "projectSFID": params.ProjectSFID,
- "gerritUsers": strings.Join(params.RemoveGerritUserInput, ","),
- }
-
- // verify user have access to the project
- if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
- msg := fmt.Sprintf("user %s does not have access to remove gerrit users with Project scope of %s", authUser.UserName, params.ProjectSFID)
- log.WithFields(f).Warn(msg)
- return gerrits.NewRemoveGerritECLAUserForbidden().WithXRequestID(reqID).WithPayload(utils.ErrorResponseForbidden(reqID, msg))
- }
-
- log.WithFields(f).Debugf("removing user list from gerrit...")
- err := v1Service.RemoveUsersFromGroup(ctx, authUser, params.ClaGroupID, params.RemoveGerritUserInput, utils.ClaTypeECLA)
- if err != nil {
- msg := fmt.Sprintf("problem removing user list %s to CLA Group %s", strings.Join(params.RemoveGerritUserInput, ","), params.ClaGroupID)
- log.WithFields(f).WithError(err).Warn(msg)
- return gerrits.NewRemoveGerritECLAUserInternalServerError().WithXRequestID(reqID).WithPayload(utils.ErrorResponseInternalServerErrorWithError(reqID, msg, err))
- }
-
- return gerrits.NewRemoveGerritECLAUserOK().WithXRequestID(reqID)
- })
+ // api.GerritsGetGerritICLAUserHandler = gerrits.GetGerritICLAUserHandlerFunc(func(params gerrits.GetGerritICLAUserParams, authUser *auth.User) middleware.Responder {
+ // reqID := utils.GetRequestID(params.XREQUESTID)
+ // ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
+ // utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
+ // f := logrus.Fields{
+ // "functionName": "v2.gerrits.handlers.GerritsGetGerritICLAUserHandler",
+ // utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
+ // "authUserName": authUser.UserName,
+ // "authUserEmail": authUser.Email,
+ // "claGroupID": params.ClaGroupID,
+ // "projectSFID": params.ProjectSFID,
+ // }
+
+ // // verify user have access to the project
+ // if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
+ // msg := fmt.Sprintf("user %s does not have access to get gerrit users with Project scope of %s", authUser.UserName, params.ProjectSFID)
+ // log.WithFields(f).Warn(msg)
+ // return gerrits.NewGetGerritICLAUserForbidden().WithXRequestID(reqID).WithPayload(utils.ErrorResponseForbidden(reqID, msg))
+ // }
+
+ // log.WithFields(f).Debugf("getting user list to gerrit...")
+ // responseModel, err := v1Service.GetUsersOfGroup(ctx, authUser, params.ClaGroupID, utils.ClaTypeICLA)
+ // if err != nil {
+ // msg := fmt.Sprintf("problem getting user list of CLA Group %s", params.ClaGroupID)
+ // log.WithFields(f).WithError(err).Warn(msg)
+ // return gerrits.NewGetGerritICLAUserInternalServerError().WithXRequestID(reqID).WithPayload(utils.ErrorResponseInternalServerErrorWithError(reqID, msg, err))
+ // }
+
+ // return gerrits.NewGetGerritICLAUserOK().WithXRequestID(reqID).WithPayload(responseModel)
+ // })
+
+ // api.GerritsGetGerritECLAUserHandler = gerrits.GetGerritECLAUserHandlerFunc(func(params gerrits.GetGerritECLAUserParams, authUser *auth.User) middleware.Responder {
+ // reqID := utils.GetRequestID(params.XREQUESTID)
+ // ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
+ // utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
+ // f := logrus.Fields{
+ // "functionName": "v2.gerrits.handlers.GerritsGetGerritECLAUserHandler",
+ // utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
+ // "authUserName": authUser.UserName,
+ // "authUserEmail": authUser.Email,
+ // "claGroupID": params.ClaGroupID,
+ // "projectSFID": params.ProjectSFID,
+ // }
+
+ // // verify user have access to the project
+ // if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
+ // msg := fmt.Sprintf("user %s does not have access to get gerrit users with Project scope of %s", authUser.UserName, params.ProjectSFID)
+ // log.WithFields(f).Warn(msg)
+ // return gerrits.NewGetGerritECLAUserForbidden().WithXRequestID(reqID).WithPayload(utils.ErrorResponseForbidden(reqID, msg))
+ // }
+
+ // log.WithFields(f).Debugf("getting user list to gerrit...")
+ // responseModel, err := v1Service.GetUsersOfGroup(ctx, authUser, params.ClaGroupID, utils.ClaTypeECLA)
+ // if err != nil {
+ // msg := fmt.Sprintf("problem getting user list of CLA Group %s", params.ClaGroupID)
+ // log.WithFields(f).WithError(err).Warn(msg)
+ // return gerrits.NewGetGerritECLAUserInternalServerError().WithXRequestID(reqID).WithPayload(utils.ErrorResponseInternalServerErrorWithError(reqID, msg, err))
+ // }
+
+ // return gerrits.NewGetGerritECLAUserOK().WithXRequestID(reqID).WithPayload(responseModel)
+ // })
+
+ // api.GerritsAddGerritICLAUserHandler = gerrits.AddGerritICLAUserHandlerFunc(func(params gerrits.AddGerritICLAUserParams, authUser *auth.User) middleware.Responder {
+ // reqID := utils.GetRequestID(params.XREQUESTID)
+ // ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
+ // utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
+ // f := logrus.Fields{
+ // "functionName": "v2.gerrits.handlers.GerritsAddGerritICLAUserHandler",
+ // utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
+ // "authUserName": authUser.UserName,
+ // "authUserEmail": authUser.Email,
+ // "claGroupID": params.ClaGroupID,
+ // "projectSFID": params.ProjectSFID,
+ // "gerritUsers": strings.Join(params.AddGerritUserInput, ","),
+ // }
+
+ // // verify user have access to the project
+ // if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
+ // msg := fmt.Sprintf("user %s does not have access to add gerrit users with Project scope of %s", authUser.UserName, params.ProjectSFID)
+ // log.WithFields(f).Warn(msg)
+ // return gerrits.NewAddGerritICLAUserForbidden().WithXRequestID(reqID).WithPayload(utils.ErrorResponseForbidden(reqID, msg))
+ // }
+
+ // log.WithFields(f).Debugf("adding user list to gerrit...")
+ // err := v1Service.AddUsersToGroup(ctx, authUser, params.ClaGroupID, params.AddGerritUserInput, utils.ClaTypeICLA)
+ // if err != nil {
+ // msg := fmt.Sprintf("problem adding user list %s to CLA Group %s", strings.Join(params.AddGerritUserInput, ","), params.ClaGroupID)
+ // log.WithFields(f).WithError(err).Warn(msg)
+ // return gerrits.NewAddGerritICLAUserInternalServerError().WithXRequestID(reqID).WithPayload(utils.ErrorResponseInternalServerErrorWithError(reqID, msg, err))
+ // }
+
+ // return gerrits.NewAddGerritICLAUserOK().WithXRequestID(reqID)
+ // })
+
+ // api.GerritsRemoveGerritICLAUserHandler = gerrits.RemoveGerritICLAUserHandlerFunc(func(params gerrits.RemoveGerritICLAUserParams, authUser *auth.User) middleware.Responder {
+ // reqID := utils.GetRequestID(params.XREQUESTID)
+ // ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
+ // utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
+ // f := logrus.Fields{
+ // "functionName": "v2.gerrits.handlers.GerritsRemoveGerritICLAUserHandler",
+ // utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
+ // "authUserName": authUser.UserName,
+ // "authUserEmail": authUser.Email,
+ // "claGroupID": params.ClaGroupID,
+ // "projectSFID": params.ProjectSFID,
+ // "gerritUsers": strings.Join(params.RemoveGerritUserInput, ","),
+ // }
+
+ // // verify user have access to the project
+ // if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
+ // msg := fmt.Sprintf("user %s does not have access to remove gerrit users with Project scope of %s", authUser.UserName, params.ProjectSFID)
+ // log.WithFields(f).Warn(msg)
+ // return gerrits.NewRemoveGerritICLAUserForbidden().WithXRequestID(reqID).WithPayload(utils.ErrorResponseForbidden(reqID, msg))
+ // }
+
+ // log.WithFields(f).Debugf("removing user list from gerrit...")
+ // err := v1Service.RemoveUsersFromGroup(ctx, authUser, params.ClaGroupID, params.RemoveGerritUserInput, utils.ClaTypeICLA)
+ // if err != nil {
+ // msg := fmt.Sprintf("problem removing user list %s to CLA Group %s", strings.Join(params.RemoveGerritUserInput, ","), params.ClaGroupID)
+ // log.WithFields(f).WithError(err).Warn(msg)
+ // return gerrits.NewRemoveGerritICLAUserInternalServerError().WithXRequestID(reqID).WithPayload(utils.ErrorResponseInternalServerErrorWithError(reqID, msg, err))
+ // }
+
+ // return gerrits.NewRemoveGerritICLAUserOK().WithXRequestID(reqID)
+ // })
+
+ // api.GerritsAddGerritECLAUserHandler = gerrits.AddGerritECLAUserHandlerFunc(func(params gerrits.AddGerritECLAUserParams, authUser *auth.User) middleware.Responder {
+ // reqID := utils.GetRequestID(params.XREQUESTID)
+ // ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
+ // utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
+ // f := logrus.Fields{
+ // "functionName": "v2.gerrits.handlers.GerritsAddGerritECLAUserHandler",
+ // utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
+ // "authUserName": authUser.UserName,
+ // "authUserEmail": authUser.Email,
+ // "claGroupID": params.ClaGroupID,
+ // "projectSFID": params.ProjectSFID,
+ // "gerritUsers": strings.Join(params.AddGerritUserInput, ","),
+ // }
+
+ // // verify user have access to the project
+ // if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
+ // msg := fmt.Sprintf("user %s does not have access to add gerrit users with Project scope of %s", authUser.UserName, params.ProjectSFID)
+ // log.WithFields(f).Warn(msg)
+ // return gerrits.NewAddGerritECLAUserForbidden().WithXRequestID(reqID).WithPayload(utils.ErrorResponseForbidden(reqID, msg))
+ // }
+
+ // log.WithFields(f).Debugf("adding user list to gerrit...")
+ // err := v1Service.AddUsersToGroup(ctx, authUser, params.ClaGroupID, params.AddGerritUserInput, utils.ClaTypeECLA)
+ // if err != nil {
+ // msg := fmt.Sprintf("problem adding user list %s to CLA Group %s", strings.Join(params.AddGerritUserInput, ","), params.ClaGroupID)
+ // log.WithFields(f).WithError(err).Warn(msg)
+ // return gerrits.NewAddGerritECLAUserInternalServerError().WithXRequestID(reqID).WithPayload(utils.ErrorResponseInternalServerErrorWithError(reqID, msg, err))
+ // }
+
+ // return gerrits.NewAddGerritECLAUserOK().WithXRequestID(reqID)
+ // })
+
+ // api.GerritsRemoveGerritECLAUserHandler = gerrits.RemoveGerritECLAUserHandlerFunc(func(params gerrits.RemoveGerritECLAUserParams, authUser *auth.User) middleware.Responder {
+ // reqID := utils.GetRequestID(params.XREQUESTID)
+ // ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
+ // utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
+ // f := logrus.Fields{
+ // "functionName": "v2.gerrits.handlers.GerritsRemoveGerritECLAUserHandler",
+ // utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
+ // "authUserName": authUser.UserName,
+ // "authUserEmail": authUser.Email,
+ // "claGroupID": params.ClaGroupID,
+ // "projectSFID": params.ProjectSFID,
+ // "gerritUsers": strings.Join(params.RemoveGerritUserInput, ","),
+ // }
+
+ // // verify user have access to the project
+ // if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
+ // msg := fmt.Sprintf("user %s does not have access to remove gerrit users with Project scope of %s", authUser.UserName, params.ProjectSFID)
+ // log.WithFields(f).Warn(msg)
+ // return gerrits.NewRemoveGerritECLAUserForbidden().WithXRequestID(reqID).WithPayload(utils.ErrorResponseForbidden(reqID, msg))
+ // }
+
+ // log.WithFields(f).Debugf("removing user list from gerrit...")
+ // err := v1Service.RemoveUsersFromGroup(ctx, authUser, params.ClaGroupID, params.RemoveGerritUserInput, utils.ClaTypeECLA)
+ // if err != nil {
+ // msg := fmt.Sprintf("problem removing user list %s to CLA Group %s", strings.Join(params.RemoveGerritUserInput, ","), params.ClaGroupID)
+ // log.WithFields(f).WithError(err).Warn(msg)
+ // return gerrits.NewRemoveGerritECLAUserInternalServerError().WithXRequestID(reqID).WithPayload(utils.ErrorResponseInternalServerErrorWithError(reqID, msg, err))
+ // }
+
+ // return gerrits.NewRemoveGerritECLAUserOK().WithXRequestID(reqID)
+ // })
}
diff --git a/cla-backend-go/v2/sign/service.go b/cla-backend-go/v2/sign/service.go
index 286e3b3a5..cab9ba3a3 100644
--- a/cla-backend-go/v2/sign/service.go
+++ b/cla-backend-go/v2/sign/service.go
@@ -422,6 +422,7 @@ func (s *service) SignedIndividualCallbackGithub(ctx context.Context, payload []
log.WithFields(f).Debugf("envelope signed - status: %s", status)
updates := map[string]interface{}{
"signature_signed": true,
+ "signature_embargo_acked": true,
"date_modified": currentTime,
"signed_on": currentTime,
"user_docusign_raw_xml": string(payload),
@@ -657,6 +658,7 @@ func (s *service) SignedIndividualCallbackGitlab(ctx context.Context, payload []
log.WithFields(f).Debugf("envelope signed - status: %s", status)
updates := map[string]interface{}{
"signature_signed": true,
+ "signature_embargo_acked": true,
"date_modified": currentTime,
"signed_on": currentTime,
"user_docusign_raw_xml": string(payload),
@@ -890,6 +892,7 @@ func (s *service) SignedIndividualCallbackGerrit(ctx context.Context, payload []
log.WithFields(f).Debugf("envelope signed - status: %s", status)
updates := map[string]interface{}{
"signature_signed": true,
+ "signature_embargo_acked": true,
"date_modified": currentTime,
"signed_on": currentTime,
"user_docusign_raw_xml": string(payload),
@@ -1007,17 +1010,17 @@ func (s *service) SignedIndividualCallbackGerrit(ctx context.Context, payload []
CLAGroupID: signature.ProjectID,
})
- // Add User to Gerrit Group
- if claUser.LfUsername != "" {
- log.WithFields(f).Debugf("adding user to gerrit group: %s", claUser.LfUsername)
- err = s.gerritService.AddUserToGroup(ctx, nil, signature.ProjectID, claUser.LfUsername, utils.ClaTypeICLA)
- if err != nil {
- log.WithFields(f).WithError(err).Warnf("unable to add user to gerrit group")
- return err
- }
- } else {
- log.WithFields(f).Warnf("user LF username is empty")
- }
+ // // Add User to Gerrit Group
+ // if claUser.LfUsername != "" {
+ // log.WithFields(f).Debugf("adding user to gerrit group: %s", claUser.LfUsername)
+ // err = s.gerritService.AddUserToGroup(ctx, nil, signature.ProjectID, claUser.LfUsername, utils.ClaTypeICLA)
+ // if err != nil {
+ // log.WithFields(f).WithError(err).Warnf("unable to add user to gerrit group")
+ // return err
+ // }
+ // } else {
+ // log.WithFields(f).Warnf("user LF username is empty")
+ // }
} else {
log.WithFields(f).Debugf("envelope not signed - status: %s", status)
@@ -1138,9 +1141,10 @@ func (s *service) SignedCorporateCallback(ctx context.Context, payload []byte, c
if status == DocusignCompleted && !signature.SignatureSigned {
_, currentTime := utils.CurrentTime()
updates := map[string]interface{}{
- "signature_signed": true,
- "date_modified": currentTime,
- "signed_on": currentTime,
+ "signature_signed": true,
+ "signature_embargo_acked": true,
+ "date_modified": currentTime,
+ "signed_on": currentTime,
}
userSignedDate := info.EnvelopeStatus.RecipientStatuses[0].Signed
@@ -1194,30 +1198,30 @@ func (s *service) SignedCorporateCallback(ctx context.Context, payload []byte, c
CompanySFID: companyModel.CompanyExternalID,
})
- // Check if project is a gerrit instance
- var gerrits []*v1Models.Gerrit
- gerritList, err := s.gerritService.GetClaGroupGerrits(ctx, projectID)
- if err != nil {
- log.WithFields(f).WithError(err).Warnf("unable to get gerrit instances for project: %s", projectID)
- gerrits = []*v1Models.Gerrit{}
- } else {
- log.WithFields(f).Debugf("gerrit instances found for project: %s", projectID)
- gerrits = gerritList.List
- }
-
- // Add User to Gerrit Group
- if len(gerrits) > 0 {
- if user.LfUsername != "" {
- log.WithFields(f).Debugf("adding user to gerrit group: %s", user.LfUsername)
- err = s.gerritService.AddUserToGroup(ctx, nil, projectID, user.LfUsername, utils.ClaTypeCCLA)
- if err != nil {
- log.WithFields(f).WithError(err).Warnf("unable to add user to gerrit group")
- return err
- }
- } else {
- log.WithFields(f).Warnf("user LF username is empty")
- }
- }
+ // // Check if project is a gerrit instance
+ // var gerrits []*v1Models.Gerrit
+ // gerritList, err := s.gerritService.GetClaGroupGerrits(ctx, projectID)
+ // if err != nil {
+ // log.WithFields(f).WithError(err).Warnf("unable to get gerrit instances for project: %s", projectID)
+ // gerrits = []*v1Models.Gerrit{}
+ // } else {
+ // log.WithFields(f).Debugf("gerrit instances found for project: %s", projectID)
+ // gerrits = gerritList.List
+ // }
+
+ // // Add User to Gerrit Group
+ // if len(gerrits) > 0 {
+ // if user.LfUsername != "" {
+ // log.WithFields(f).Debugf("adding user to gerrit group: %s", user.LfUsername)
+ // err = s.gerritService.AddUserToGroup(ctx, nil, projectID, user.LfUsername, utils.ClaTypeCCLA)
+ // if err != nil {
+ // log.WithFields(f).WithError(err).Warnf("unable to add user to gerrit group")
+ // return err
+ // }
+ // } else {
+ // log.WithFields(f).Warnf("user LF username is empty")
+ // }
+ // }
return nil
@@ -1371,6 +1375,7 @@ func (s *service) RequestIndividualSignature(ctx context.Context, input *models.
SignatureProjectID: latestSignature.ProjectID,
SignatureApproved: latestSignature.SignatureApproved,
SignatureSigned: latestSignature.SignatureSigned,
+ SignatureEmbargoAcked: true,
SignatureReferenceName: latestSignature.SignatureReferenceName,
SignatureReferenceNameLower: latestSignature.SignatureReferenceNameLower,
SignedOn: latestSignature.SignedOn,
@@ -1443,6 +1448,7 @@ func (s *service) RequestIndividualSignature(ctx context.Context, input *models.
DateModified: currentTime,
SignatureSigned: false,
SignatureApproved: true,
+ SignatureEmbargoAcked: true,
SignatureDocumentMajorVersion: majorVersion,
SignatureDocumentMinorVersion: minorVersion,
SignatureReferenceID: *input.UserID,
@@ -2359,6 +2365,7 @@ func (s *service) RequestIndividualSignatureGerrit(ctx context.Context, input *m
SignatureProjectID: latestSignature.ProjectID,
SignatureApproved: latestSignature.SignatureApproved,
SignatureSigned: latestSignature.SignatureSigned,
+ SignatureEmbargoAcked: true,
SignatureReferenceName: latestSignature.SignatureReferenceName,
SignatureReferenceNameLower: latestSignature.SignatureReferenceNameLower,
SignedOn: latestSignature.SignedOn,
@@ -2397,6 +2404,7 @@ func (s *service) RequestIndividualSignatureGerrit(ctx context.Context, input *m
SignatureReferenceType: utils.SignatureReferenceTypeUser,
SignatureSigned: false,
SignatureApproved: true,
+ SignatureEmbargoAcked: true,
SignatureType: utils.SignatureTypeCLA,
SignatureReferenceID: *input.UserID,
SignatureReturnURLType: input.ReturnURLType,
@@ -2571,6 +2579,7 @@ func (s *service) requestCorporateSignature(ctx context.Context, apiURL string,
SignatoryName: signatoryName,
SignatureSigned: companySignature.SignatureSigned,
SignatureApproved: companySignature.SignatureApproved,
+ SignatureEmbargoAcked: true,
DateCreated: companySignature.Created,
SignatureDocumentMajorVersion: majorVersion,
SignatureDocumentMinorVersion: minorVersion,
@@ -2611,6 +2620,7 @@ func (s *service) requestCorporateSignature(ctx context.Context, apiURL string,
SignatoryName: signatoryName,
SignatureSigned: false,
SignatureApproved: true,
+ SignatureEmbargoAcked: true,
SignatureCallbackURL: callbackURL,
SignatureReturnURL: input.ReturnURL,
SigtypeSignedApprovedID: fmt.Sprintf("%s#%v#%v#%s", utils.SignatureTypeCCLA, signed, approved, signatureID),
diff --git a/cla-backend/cla/controllers/signature.py b/cla-backend/cla/controllers/signature.py
index bd6e61e9f..b1178d5c2 100644
--- a/cla-backend/cla/controllers/signature.py
+++ b/cla-backend/cla/controllers/signature.py
@@ -55,6 +55,7 @@ def create_signature(signature_project_id, # pylint: disable=too-many-arguments
signature_type='cla',
signature_approved=False,
signature_signed=False,
+ signature_embargo_acked=True,
signature_return_url=None,
signature_sign_url=None,
signature_user_ccla_company_id=None,
@@ -74,6 +75,8 @@ def create_signature(signature_project_id, # pylint: disable=too-many-arguments
:type signature_signed: boolean
:param signature_approved: Whether or not the signature has been approved.
:type signature_approved: boolean
+ :param signature_embargo_acked: Whether or not the embargo was acknowledged
+ :type signature_embargo_acked: boolean
:param signature_return_url: The URL the user will be redirected to after signing.
:type signature_return_url: string
:param signature_sign_url: The URL the user must visit to sign the signature.
@@ -125,6 +128,7 @@ def create_signature(signature_project_id, # pylint: disable=too-many-arguments
signature.set_signature_type(signature_type)
signature.set_signature_signed(signature_signed)
signature.set_signature_approved(signature_approved)
+ signature.set_signature_embargo_acked(signature_embargo_acked)
signature.set_signature_return_url(signature_return_url)
signature.set_signature_sign_url(signature_sign_url)
if signature_user_ccla_company_id is not None:
@@ -151,6 +155,7 @@ def update_signature(signature_id, # pylint: disable=too-many-arguments,too-man
signature_type=None,
signature_approved=None,
signature_signed=None,
+ signature_embargo_acked=True,
signature_return_url=None,
signature_sign_url=None,
domain_whitelist=None,
@@ -177,6 +182,8 @@ def update_signature(signature_id, # pylint: disable=too-many-arguments,too-man
:type signature_signed: boolean | None
:param signature_approved: Whether this signature is approved or not.
:type signature_approved: boolean | None
+ :param signature_embargo_acked: Whether this signature's embargo is acknowledged
+ :type signature_embargo_acked: boolean | None
:param signature_return_url: The URL the user will be sent to after signing.
:type signature_return_url: string | None
:param signature_sign_url: The URL the user must visit to sign the signature.
@@ -238,6 +245,13 @@ def update_signature(signature_id, # pylint: disable=too-many-arguments,too-man
update_str += f'signature_approved updated to {val} \n'
except KeyError:
return {'errors': {'signature_approved': 'Invalid value passed in for true/false field'}}
+ if signature_embargo_acked is not None:
+ try:
+ val = hug.types.smart_boolean(signature_embargo_acked)
+ signature.set_signature_embargo_acked(val)
+ update_str += f'signature_embargo_acked updated to {val} \n'
+ except KeyError:
+ return {'errors': {'signature_embargo_acked': 'Invalid value passed in for true/false field'}}
if signature_return_url is not None:
try:
val = cla.hug_types.url(signature_return_url)
@@ -554,6 +568,8 @@ def create_bot_signature(bot_user: User, signature: Signature) -> Optional[Signa
bot_sig.set_signature_document_minor_version(signature.get_signature_document_minor_version())
bot_sig.set_signature_approved(True)
bot_sig.set_signature_signed(True)
+ # should bot signature by automaticaly set to "embargo acknowledged"?
+ bot_sig.set_signature_embargo_acked(True)
bot_sig.set_signature_type('cla')
bot_sig.set_signature_reference_type('user')
bot_sig.set_signature_user_ccla_company_id(bot_user.get_user_company_id())
diff --git a/cla-backend/cla/models/docusign_models.py b/cla-backend/cla/models/docusign_models.py
index de52401c4..37982bbd1 100644
--- a/cla-backend/cla/models/docusign_models.py
+++ b/cla-backend/cla/models/docusign_models.py
@@ -8,7 +8,6 @@
https://developers.docusign.com/esign-rest-api/guides/post-go-live
"""
-
import io
import json
import boto3
@@ -198,6 +197,9 @@ def request_individual_signature(self, project_id, user_id, return_url=None, ret
cla.log.debug('Individual Signature - user already has a signatures with this project: {}'.
format(latest_signature.get_signature_id()))
+ # Set embargo acknowledged flag also for the existing signature
+ latest_signature.set_signature_embargo_acked(True)
+
# Re-generate and set the signing url - this will update the signature record
self.populate_sign_url(latest_signature, callback_url, default_values=default_cla_values,
preferred_email=preferred_email)
@@ -254,9 +256,9 @@ def request_individual_signature(self, project_id, user_id, return_url=None, ret
signature_return_url_type=return_url_type,
signature_signed=False,
signature_approved=True,
+ signature_embargo_acked=True,
signature_return_url=return_url,
signature_callback_url=callback_url)
-
# Set signature ACL
if return_url_type.lower() == "github":
acl = user.get_user_github_id()
@@ -314,6 +316,9 @@ def request_individual_signature_gerrit(self, project_id, user_id, return_url=No
last_document.get_document_major_version() == latest_signature.get_signature_document_major_version():
cla.log.info('User already has a signatures with this project: %s', latest_signature.get_signature_id())
+ # Set embargo acknowledged flag also for the existing signature
+ latest_signature.set_signature_embargo_acked(True)
+
# Re-generate and set the signing url - this will update the signature record
self.populate_sign_url(latest_signature, callback_url, default_values=default_cla_values)
@@ -358,6 +363,7 @@ def request_individual_signature_gerrit(self, project_id, user_id, return_url=No
signature_return_url_type='Gerrit',
signature_signed=False,
signature_approved=True,
+ signature_embargo_acked=True,
signature_return_url=return_url,
signature_callback_url=callback_url)
@@ -706,6 +712,7 @@ def request_employee_signature(self, project_id, company_id, user_id, return_url
signature_type='cla',
signature_signed=True,
signature_approved=True,
+ signature_embargo_acked=True,
signature_return_url=return_url,
signature_user_ccla_company_id=company_id)
cla.log.info(f'{fn} - created new signature document for: {request_info} - signature: {new_signature}')
@@ -783,6 +790,7 @@ def _save_employee_signature(self,signature):
'signature_type': {'S': signature.get_signature_type()},
'signature_signed': {'BOOL': signature.get_signature_signed()},
'signature_approved': {'BOOL': signature.get_signature_approved()},
+ 'signature_embargo_acked': {'BOOL': True},
'signature_acl': {'SS': list(signature.get_signature_acl())},
'signature_user_ccla_company_id': {'S': signature.get_signature_user_ccla_company_id()},
'date_modified': {'S': datetime.now().isoformat()},
@@ -865,6 +873,7 @@ def request_employee_signature_gerrit(self, project_id, company_id, user_id, ret
signature_type='cla',
signature_signed=True,
signature_approved=True,
+ signature_embargo_acked=True,
signature_return_url=return_url,
signature_user_ccla_company_id=company_id)
@@ -973,6 +982,7 @@ def handle_signing_new_corporate_signature(self, signature, project, company, us
signatory_name=signatory_name,
signing_entity_name=company.get_signing_entity_name(),
signature_signed=False,
+ signature_embargo_acked=True,
signature_approved=True)
callback_url = self._get_corporate_signature_callback_url(project.get_project_id(), company.get_company_id())
@@ -986,6 +996,9 @@ def handle_signing_new_corporate_signature(self, signature, project, company, us
# Set signature ACL
signature.set_signature_acl(user.get_lf_username())
+ # Set embargo acknowledged flag also for the existing signature
+ signature.set_signature_embargo_acked(True)
+
self.populate_sign_url(signature, callback_url,
signatory_name, signatory_email,
send_as_email,
@@ -1506,6 +1519,7 @@ def signed_individual_callback(self, content, installation_id, github_repository
cla.log.info(f'{fn} - ICLA signature signed ({signature_id}) - '
'Notifying repository service provider')
signature.set_signature_signed(True)
+ signature.set_signature_embargo_acked(True)
populate_signature_from_icla_callback(content, tree, signature)
# Save signature
signature.save()
@@ -1600,6 +1614,7 @@ def signed_individual_callback_gerrit(self, content, user_id):
cla.log.debug(f'{fn} - updating signature in database - setting signed=true...')
# Save signature before adding user to LDAP Groups.
signature.set_signature_signed(True)
+ signature.set_signature_embargo_acked(True)
signature.save()
# Load the Project by ID and send audit event
@@ -1711,6 +1726,7 @@ def signed_individual_callback_gitlab(self, content, user_id, organization_id, g
cla.log.debug(f'{fn} - updating signature in database - setting signed=true...')
signature.set_signature_signed(True)
+ signature.set_signature_embargo_acked(True)
populate_signature_from_icla_callback(content, tree, signature)
signature.save()
@@ -1855,6 +1871,7 @@ def signed_corporate_callback(self, content, project_id, company_id):
# Note: cla-manager role assignment and cla-manager-designee cleanup is handled in the DB trigger handler
# upon save with the signature signed flag transition to true...
signature.set_signature_signed(True)
+ signature.set_signature_embargo_acked(True)
populate_signature_from_ccla_callback(content, tree, signature)
signature.save()
@@ -2464,4 +2481,4 @@ def cla_signatory_email_content(params: ClaSignatoryEmailParams) -> (str, str):
email_body += f'After you sign, {params.cla_manager_name} (as the initial CLA Manager for your company) will be able to maintain the list of specific employees authorized to contribute to the project(s) under this signed CLA.
'
email_body += f'If you are authorized to sign on your company’s behalf, and if you approve {params.cla_manager_name} as your initial CLA Manager, please review the document and sign the CLA. If you have questions, or if you are not an authorized signatory of this company, please contact the requester at {params.cla_manager_email}.
'
email_body = append_email_help_sign_off_content(email_body, params.project_version)
- return email_subject, email_body
\ No newline at end of file
+ return email_subject, email_body
diff --git a/cla-backend/cla/models/dynamo_models.py b/cla-backend/cla/models/dynamo_models.py
index 2ceaed90f..5e6311470 100644
--- a/cla-backend/cla/models/dynamo_models.py
+++ b/cla-backend/cla/models/dynamo_models.py
@@ -2484,6 +2484,7 @@ class Meta:
signature_project_index = ProjectSignatureIndex()
signature_reference_index = ReferenceSignatureIndex()
signature_envelope_id = UnicodeAttribute(null=True)
+ signature_embargo_acked = BooleanAttribute(default=True, null=True)
# Callback type refers to either Gerrit or GitHub
signature_return_url_type = UnicodeAttribute(null=True)
note = UnicodeAttribute(null=True)
@@ -2538,6 +2539,7 @@ def __init__(
signature_type=None,
signature_signed=False,
signature_approved=False,
+ signature_embargo_acked=True,
signed_on=None,
signatory_name=None,
signing_entity_name=None,
@@ -2593,6 +2595,7 @@ def __init__(
self.model.signing_entity_name = signing_entity_name
self.model.sigtype_signed_approved_id = sigtype_signed_approved_id
self.model.signature_approved = signature_approved
+ self.model.signature_embargo_acked = signature_embargo_acked
self.model.signature_sign_url = signature_sign_url
self.model.signature_return_url = signature_return_url
self.model.signature_callback_url = signature_callback_url
@@ -2626,7 +2629,7 @@ def __str__(self):
"reference type: {}, "
"user cla company id: {}, signed: {}, signed_on: {}, signatory_name: {}, signing entity name: {},"
"sigtype_signed_approved_id: {}, "
- "approved: {}, domain whitelist: {}, "
+ "approved: {}, embargo_acked: {}, domain whitelist: {}, "
"email whitelist: {}, github user whitelist: {}, github domain whitelist: {}, "
"note: {},signature project external id: {}, signature company signatory id: {}, "
"signature company signatory name: {}, signature company signatory email: {},"
@@ -2650,6 +2653,7 @@ def __str__(self):
self.model.signing_entity_name,
self.model.sigtype_signed_approved_id,
self.model.signature_approved,
+ self.model.signature_embargo_acked,
self.model.domain_whitelist,
self.model.email_whitelist,
self.model.github_whitelist,
@@ -2739,6 +2743,9 @@ def get_sigtype_signed_approved_id(self):
def get_signature_approved(self):
return self.model.signature_approved
+ def get_signature_embargo_acked(self):
+ return self.model.signature_embargo_acked
+
def get_signature_sign_url(self):
return self.model.signature_sign_url
@@ -2878,6 +2885,9 @@ def set_sigtype_signed_approved_id(self, sigtype_signed_approved_id) -> None:
def set_signature_approved(self, approved) -> None:
self.model.signature_approved = bool(approved)
+ def set_signature_embargo_acked(self, embargo_acked) -> None:
+ self.model.signature_embargo_acked = bool(embargo_acked)
+
def set_signature_sign_url(self, sign_url) -> None:
self.model.signature_sign_url = sign_url
@@ -5065,6 +5075,7 @@ def set_cla_group_details(event, cla_group_id: str):
try:
project = Project()
project.load(str(cla_group_id))
+ event.set_event_cla_group_id(cla_group_id)
event.set_event_cla_group_name(project.get_project_name())
event.set_event_project_sfid(project.get_project_external_id())
Event.set_project_details(event, project.get_project_external_id())
diff --git a/cla-backend/cla/models/model_interfaces.py b/cla-backend/cla/models/model_interfaces.py
index 9c7d0db86..e4348c3bc 100644
--- a/cla-backend/cla/models/model_interfaces.py
+++ b/cla-backend/cla/models/model_interfaces.py
@@ -884,6 +884,15 @@ def get_signature_approved(self):
"""
raise NotImplementedError()
+ def get_signature_embargo_acked(self):
+ """
+ Getter for an signature's embargo acknowledgement status. True is acknowledged, False otherwise.
+
+ :return: The signature's embargo acknowledgement status. True is acknowledged, False otherwise.
+ :rtype: boolean
+ """
+ raise NotImplementedError()
+
def get_signature_sign_url(self):
"""
Getter for an signature's signing URL. The URL the user has to visit in
@@ -1039,6 +1048,15 @@ def set_signature_approved(self, approved):
"""
raise NotImplementedError()
+ def set_signature_embargo_acked(self, embargo_acked):
+ """
+ Setter for an signature's embargo acknowledgement status.
+
+ :param embargo_acked: Embargo acknowledgement status. True for acknowledged, False otherwise.
+ :type embargo_acked: bool
+ """
+ raise NotImplementedError()
+
def set_signature_sign_url(self, sign_url):
"""
Setter for an signature's signing URL. Optional on signature creation.
diff --git a/cla-backend/cla/routes.py b/cla-backend/cla/routes.py
index cdb80a37a..28af40341 100755
--- a/cla-backend/cla/routes.py
+++ b/cla-backend/cla/routes.py
@@ -283,6 +283,7 @@ def get_signature(auth_user: check_auth, signature_id: hug.types.uuid):
"/signature",
versions=1,
examples=" - {'signature_type': 'cla', 'signature_signed': true, \
+ 'signature_embargo_acked': true, \
'signature_approved': true, 'signature_sign_url': 'http://sign.com/here', \
'signature_return_url': 'http://cla-system.com/signed', \
'signature_project_id': '', \
@@ -297,6 +298,7 @@ def post_signature(
signature_type: hug.types.one_of(["cla", "dco"]),
signature_signed: hug.types.smart_boolean,
signature_approved: hug.types.smart_boolean,
+ signature_embargo_acked: hug.types.smart_boolean,
signature_return_url: cla.hug_types.url,
signature_sign_url: cla.hug_types.url,
signature_user_ccla_company_id=None,
@@ -307,6 +309,7 @@ def post_signature(
DATA: {'signature_type': 'cla',
'signature_signed': true,
'signature_approved': true,
+ 'signature_embargo_acked': true,
'signature_sign_url': 'http://sign.com/here',
'signature_return_url': 'http://cla-system.com/signed',
'signature_project_id': '',
@@ -327,6 +330,7 @@ def post_signature(
signature_user_ccla_company_id=signature_user_ccla_company_id,
signature_signed=signature_signed,
signature_approved=signature_approved,
+ signature_embargo_acked=signature_embargo_acked,
signature_return_url=signature_return_url,
signature_sign_url=signature_sign_url,
)
@@ -336,7 +340,7 @@ def post_signature(
"/signature",
versions=1,
examples=" - {'signature_id': '01620259-d202-4350-8264-ef42a861922d', \
- 'signature_type': 'cla', 'signature_signed': true}",
+ 'signature_type': 'cla', 'signature_signed': true, 'signature_embargo_acked': true}",
)
def put_signature(
auth_user: check_auth, # pylint: disable=too-many-arguments
@@ -347,6 +351,7 @@ def put_signature(
signature_type=None,
signature_signed=None,
signature_approved=None,
+ signature_embargo_acked=None,
signature_return_url=None,
signature_sign_url=None,
domain_whitelist=None,
@@ -358,7 +363,7 @@ def put_signature(
PUT: /signature
DATA: {'signature_id': '',
- 'signature_type': 'cla', 'signature_signed': true}
+ 'signature_type': 'cla', 'signature_signed': true, 'signature_embargo_acked': true}
Supports all the fields as the POST equivalent.
@@ -373,6 +378,7 @@ def put_signature(
signature_type=signature_type,
signature_signed=signature_signed,
signature_approved=signature_approved,
+ signature_embargo_acked=signature_embargo_acked,
signature_return_url=signature_return_url,
signature_sign_url=signature_sign_url,
domain_whitelist=domain_whitelist,
diff --git a/cla-backend/cla/tests/unit/test_ecla.py b/cla-backend/cla/tests/unit/test_ecla.py
index 42be1c905..5b6f9a3c4 100644
--- a/cla-backend/cla/tests/unit/test_ecla.py
+++ b/cla-backend/cla/tests/unit/test_ecla.py
@@ -1,3 +1,6 @@
+# Copyright The Linux Foundation and each contributor to CommunityBridge.
+# SPDX-License-Identifier: MIT
+
import unittest
from unittest.mock import Mock, patch
import datetime
@@ -25,6 +28,7 @@ def test_save_employee_signature(project, company, user_instance):
signature.get_signature_type.return_value = "cla"
signature.get_signature_signed.return_value = True
signature.get_signature_approved.return_value = True
+ signature.get_signature_embargo_acked.return_value = True
signature.get_signature_acl.return_value = ['acl1', 'acl2']
signature.get_signature_user_ccla_company_id.return_value = "company_id"
signature.get_signature_return_url.return_value = None
diff --git a/cla-backend/cla/tests/unit/test_event.py b/cla-backend/cla/tests/unit/test_event.py
index 34cfda0f6..05e572852 100644
--- a/cla-backend/cla/tests/unit/test_event.py
+++ b/cla-backend/cla/tests/unit/test_event.py
@@ -57,7 +57,7 @@ def test_event_project_id(project):
event_type=event_types.EventType.DeleteProject,
event_cla_group_id=project.get_project_id()
)
- assert 'data' in response
+ assert project.get_project_id() == response['data']['event_cla_group_id']
def test_event_user_id_attribute(user_instance, mock_event):
diff --git a/cla-backend/helpers/complete_signature.py b/cla-backend/helpers/complete_signature.py
index 9e38df6b8..960ca7f21 100644
--- a/cla-backend/helpers/complete_signature.py
+++ b/cla-backend/helpers/complete_signature.py
@@ -31,6 +31,7 @@
signature = get_signature_instance()
signature.load(SIGNATURE_ID)
signature.set_signature_signed(True)
+signature.set_signature_embargo_acked(True)
signature.save()
if signature.get_signature_reference_type() != 'user':
cla.log.error('Trying to handle CCLA as a ICLA - not implemented yet')
diff --git a/cla-backend/helpers/create_data.py b/cla-backend/helpers/create_data.py
index 709e5b4fa..274465f54 100644
--- a/cla-backend/helpers/create_data.py
+++ b/cla-backend/helpers/create_data.py
@@ -95,6 +95,7 @@
corporate_signature.set_signature_project_id(project.get_project_id())
corporate_signature.set_signature_signed(True)
corporate_signature.set_signature_approved(True)
+corporate_signature.set_signature_embargo_acked(True)
corporate_signature.set_signature_type('cla')
corporate_signature.set_signature_reference_id(company.get_company_id())
corporate_signature.set_signature_reference_type('company')
@@ -140,6 +141,7 @@
individual_signature.set_signature_project_id(project.get_project_id())
individual_signature.set_signature_signed(True)
individual_signature.set_signature_approved(True)
+individual_signature.set_signature_embargo_acked(True)
individual_signature.set_signature_type('cla')
individual_signature.set_signature_reference_id(individual.get_user_id())
individual_signature.set_signature_reference_type('user')
@@ -155,6 +157,7 @@
individual_signature.set_signature_project_id(project.get_project_id())
individual_signature.set_signature_signed(True)
individual_signature.set_signature_approved(True)
+individual_signature.set_signature_embargo_acked(True)
individual_signature.set_signature_type('cla')
individual_signature.set_signature_reference_id(individual.get_user_id())
individual_signature.set_signature_reference_type('user')
@@ -170,6 +173,7 @@
individual_signature.set_signature_project_id(project.get_project_id())
individual_signature.set_signature_signed(True)
individual_signature.set_signature_approved(True)
+individual_signature.set_signature_embargo_acked(True)
individual_signature.set_signature_type('cla')
individual_signature.set_signature_reference_id(individual.get_user_id())
individual_signature.set_signature_reference_type('user')
@@ -194,6 +198,7 @@
individual_b_signature.set_signature_project_id(project.get_project_id())
individual_b_signature.set_signature_signed(True)
individual_b_signature.set_signature_approved(True)
+individual_b_signature.set_signature_embargo_acked(True)
individual_b_signature.set_signature_type('cla')
individual_b_signature.set_signature_reference_id(individual_b.get_user_id())
individual_b_signature.set_signature_reference_type('user')
@@ -210,6 +215,7 @@
employee_signature.set_signature_project_id(project.get_project_id())
employee_signature.set_signature_signed(True)
employee_signature.set_signature_approved(True)
+employee_signature.set_signature_embargo_acked(True)
employee_signature.set_signature_type('cla')
employee_signature.set_signature_reference_id(individual.get_user_id())
employee_signature.set_signature_reference_type('user')
diff --git a/cla-backend/helpers/create_signatures.py b/cla-backend/helpers/create_signatures.py
index 347b4222b..e0da5ab9d 100644
--- a/cla-backend/helpers/create_signatures.py
+++ b/cla-backend/helpers/create_signatures.py
@@ -34,6 +34,7 @@
signature.set_signature_project_id(project1.get_project_id())
signature.set_signature_signed(True)
signature.set_signature_approved(True)
+signature.set_signature_embargo_acked(True)
signature.set_signature_type('cla')
signature.set_signature_reference_id(user.get_user_id())
signature.set_signature_reference_type('user')
@@ -50,6 +51,7 @@
signature.set_signature_project_id(project1.get_project_id())
signature.set_signature_signed(True)
signature.set_signature_approved(True)
+signature.set_signature_embargo_acked(True)
signature.set_signature_type('cla')
signature.set_signature_reference_id(company.get_company_id())
signature.set_signature_reference_type('company')
@@ -66,6 +68,7 @@
signature.set_signature_project_id(project2.get_project_id())
signature.set_signature_signed(True)
signature.set_signature_approved(True)
+signature.set_signature_embargo_acked(True)
signature.set_signature_type('cla')
signature.set_signature_reference_id(company.get_company_id())
signature.set_signature_reference_type('company')
diff --git a/dev.md b/dev.md
index 7f818c9a5..4fcfec0f5 100644
--- a/dev.md
+++ b/dev.md
@@ -133,6 +133,46 @@ locally and simply point to the DEV environment. The `STAGE` environment
variable controls where we point. Make sure you export/provide/setup the AWS
properties in order to connect.
+
+When running on Linux it looks like `.venv` sets $HOME to /tmp, and then python backend is looking for the AWS config file in `~/.aws/config`
+This means it ends up in `/tmp/.aws/config`. You can use the following scritp to activate your environment (`setenv.secret`) via: `source setenv.secret`:
+```
+#!/bin/bash
+rm -rf /tmp/aws
+cp -R ~/.aws /tmp/.aws
+export AWS_SDK_LOAD_CONFIG=1
+export AWS_PROFILE='lfproduct-dev'
+export AWS_REGION='us-east-1'
+data="$(aws sts assume-role --role-arn arn:aws:iam::395594542180:role/product-contractors-role --profile lfproduct --role-session-name lfproduct-dev-session)"
+export AWS_ACCESS_KEY_ID="$(echo "${data}" | jq -r '.Credentials.AccessKeyId')"
+export AWS_SECRET_ACCESS_KEY="$(echo "${data}" | jq -r '.Credentials.SecretAccessKey')"
+export AWS_SESSION_TOKEN="$(echo "${data}" | jq -r '.Credentials.SessionToken')"
+export AWS_SECURITY_TOKEN="$(echo "${data}" | jq -r '.Credentials.SessionToken')"
+export PRODUCT_DOMAIN='dev.lfcla.com'
+export ROOT_DOMAIN='lfcla.dev.platform.linuxfoundation.org'
+export PORT='5000'
+export STAGE='dev'
+```
+
+And the following one to unset the environment:
+```
+#!/bin/bash
+rm -rf /tmp/.aws
+unset AWS_SDK_LOAD_CONFIG=1
+unset AWS_PROFILE
+unset AWS_REGION
+unset AWS_ACCESS_KEY_ID
+unset AWS_SECRET_ACCESS_KEY
+unset AWS_SESSION_TOKEN
+unset AWS_SECURITY_TOKEN
+unset PRODUCT_DOMAIN
+unset ROOT_DOMAIN
+unset PORT
+unset STAGE
+```
+
+Please refer to [aws_env.md](aws_env.md) for more details.
+
## Run the Python Backend
```bash
@@ -162,6 +202,9 @@ open http://localhost:5000/v2/health
open http://localhost:5000/v2/user/
```
+To expose service running on the localhost to the outside world use: `` ./utils/ngrok.sh ``.
+And then tets via: `` API_URL='https://[redacted].ngrok-free.app' ./scripts/health.sh `` from another host (anywhere in the world).
+
## Building and Running the Go Backend
Current Endpoints:
@@ -331,9 +374,9 @@ First build and setup the environment. Then simply run it:
```bash
# Mac
-./cla-mac
+./bin/cla-mac
# or linux
-./cla
+./bin/cla
```
You should see the typical diagnostic details on startup indicating that it
diff --git a/docs/contributor-api.md b/docs/contributor-api.md
new file mode 100644
index 000000000..5b120ecf4
--- /dev/null
+++ b/docs/contributor-api.md
@@ -0,0 +1,116 @@
+# EasyCLA Sign Flow: Sequence Overview
+
+## 1. User Creates a Pull Request (PR)
+- A contributor initiates a PR in the repository hosted on GitHub, Gerrit, or GitLab.
+
+## 2. Repository Triggers Activity Endpoint
+- The repository platform sends a request to EasyCLA's Python endpoint:
+ ```
+ v2/repository-provider/{provider}/activity
+ ```
+
+## 3. EasyCLA Checks User Authorization
+- EasyCLA internally verifies if the users involved in the PR are authorized to contribute to the repository.
+
+## 4. Update Repository with User Status
+- EasyCLA communicates back to the repository provider, updating the status of each user as either **signed** or **not signed**.
+
+## 5. User Initiates Sign Process
+- If a user is marked as **not signed**, they are prompted to begin the signing process and are redirected to the **EasyCLA Contributor Console**.
+
+## 6. Contributor Chooses Sign Type
+- Upon reaching the Contributor Console, the user selects one of two options:
+ - **Individual Contributor**
+ - **Corporate Contributor**
+
+---
+
+## 7. Individual Contributor Flow
+
+### a. Initiate Individual Signature Request
+- The system invokes the Go-based endpoint:
+ ```
+ v4/request-individual-signature
+ ```
+- This action creates a new signature record with `signed = false` and initiates the signing process.
+
+### a1. Redirect to DocuSign
+- The API handles the integration with DocuSign, preparing a callback and redirect URL, and redirects the user to DocuSign for signing.
+
+### a2. Completion of Signing
+- Once the user completes the signing on DocuSign, a callback is triggered to:
+ ```
+ v4/signed/individual/{installation_id}/{github_repository_id}/{change_request_id}
+ ```
+- This endpoint updates the signature record's `signed` flag to **true**, completing the process.
+
+---
+
+## 8. Corporate Contributor Flow
+
+### b. Initiate Corporate Signature Process
+
+#### 1. Redirect to Company Search
+- The user is redirected to a company search interface within the Contributor Console.
+
+#### 2. Search for Company
+- Upon selecting a company, the system calls the Go-based search endpoint:
+ ```
+ v3/organization/search?companyName=&include-signing-entity-name=false
+ ```
+- This retrieves the relevant company information.
+
+#### 3. Check and Prepare Employee Signature
+- The system invokes the Python endpoint:
+ ```
+ v2/check-prepare-employee-signature
+ ```
+- This checks whether the company follows a **Corporate CLA (CCLA)** or an **Entity CLA (ECLA)** flow.
+
+---
+
+### i. If Company Has a CCLA:
+- The system verifies if the user is authorized:
+ - **If not authorized:**
+ - Prompts the user to contact the existing CLA manager for authorization.
+ - Sends a notification to CLA managers via the Go-based endpoint:
+ ```
+ v4/notify-cla-managers
+ ```
+ - An email is sent to the CLA managers, and the process ends.
+ - **If authorized:**
+ - Calls:
+ ```
+ v4/request-employee-signature
+ ```
+
+---
+
+### ii. If Company Does Not Have a CCLA:
+- The system checks if the user is a CLA manager:
+ - **A. User is a CLA Manager:**
+ - Assigns CLA manager designee permissions via:
+ ```
+ v4/company/{companySFID}/user/{userLFID}/claGroupID/{claGroupID}/cla-manager-designee
+ ```
+ - Verifies the assigned role:
+ ```
+ v4/company/{companySFID}/user/{userLFID}/claGroupID/{claGroupID}/is-cla-manager-designee
+ ```
+ - Redirects to the corporate console where the user can see the **Sign** button.
+ - Calls the endpoint to request a corporate signature:
+ ```
+ v4/request-corporate-signature
+ ```
+ - This creates the signature record, completing the process.
+
+ - **B. User is Not a CLA Manager:**
+ - Fetches company administrators using:
+ ```
+ v4/company/{companySFID}/admin
+ ```
+ - Sends an invitation to become a company admin via:
+ ```
+ /user/{userID}/invite-company-admin
+ ```
+ - An email is sent to the user to invite them as a company admin, concluding the process.
diff --git a/setenv.sh b/setenv.sh
new file mode 100644
index 000000000..00bf366e8
--- /dev/null
+++ b/setenv.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+rm -rf /tmp/aws
+cp -R /root/.aws /tmp/.aws
+
+dev_arn="$(cat ./product-contractors-role.dev.secret)"
+data="$(aws sts assume-role --role-arn ${dev_arn} --profile lfproduct --role-session-name lfproduct-dev-session)"
+export AWS_ACCESS_KEY_ID="$(echo "${data}" | jq -r '.Credentials.AccessKeyId')"
+export AWS_SECRET_ACCESS_KEY="$(echo "${data}" | jq -r '.Credentials.SecretAccessKey')"
+export AWS_SESSION_TOKEN="$(echo "${data}" | jq -r '.Credentials.SessionToken')"
+export AWS_SECURITY_TOKEN="$(echo "${data}" | jq -r '.Credentials.SessionToken')"
+export GITHUB_OAUTH_TOKEN="$(cat /etc/github/oauth)"
+export DOCUSIGN_INTEGRATOR_KEY="$(cat ./DOCUSIGN_INTEGRATOR_KEY.secret)"
+export DOCUSIGN_USER_ID="$(cat ./DOCUSIGN_USER_ID.secret)"
+export DOCUSIGN_AUTH_SERVER="$(cat ./DOCUSIGN_AUTH_SERVER.secret)"
+export DOCUSIGN_ROOT_URL="$(cat ./DOCUSIGN_ROOT_URL.secret)"
+export DOCUSIGN_ACCOUNT_ID="$(cat ./DOCUSIGN_ACCOUNT_ID.secret)"
+
+export AWS_SDK_LOAD_CONFIG=true
+export AWS_PROFILE='lfproduct-dev'
+export AWS_REGION='us-east-1'
+export AWS_DEFAULT_REGION='us-east-1'
+export DYNAMODB_AWS_REGION='us-east-1'
+export REGION='us-east-1'
+
+export PRODUCT_DOMAIN='dev.lfcla.com'
+export ROOT_DOMAIN='lfcla.dev.platform.linuxfoundation.org'
+export PORT='5000'
+export STAGE='dev'
+# export STAGE='local'
+export GH_ORG_VALIDATION=false
+export DISABLE_LOCAL_PERMISSION_CHECKS=true
+export COMPANY_USER_VALIDATION=false
+export CLA_SIGNATURE_FILES_BUCKET=cla-signature-files-dev
diff --git a/unsetenv.sh b/unsetenv.sh
new file mode 100644
index 000000000..6786d186c
--- /dev/null
+++ b/unsetenv.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+rm -rf /tmp/.aws
+unset AWS_PROFILE
+unset AWS_REGION
+unset AWS_ACCESS_KEY_ID
+unset AWS_SECRET_ACCESS_KEY
+unset PRODUCT_DOMAIN
+unset ROOT_DOMAIN
+unset PORT
+unset STAGE
+unset AWS_SESSION_TOKEN
+unset AWS_SECURITY_TOKEN
+unset GH_ORG_VALIDATION
+unset DISABLE_LOCAL_PERMISSION_CHECKS
+unset COMPANY_USER_VALIDATION
+unset CLA_SIGNATURE_FILES_BUCKET
+unset DYNAMODB_AWS_REGION
+unset REGION
+unset AWS_ROLE_ARN
+unset AWS_TOKEN_SERIAL
+unset AWS_SDK_LOAD_CONFIG
+unset GITHUB_OAUTH_TOKEN
+unset DOCUSIGN_INTEGRATOR_KEY
+unset DOCUSIGN_USER_ID
+unset DOCUSIGN_AUTH_SERVER
+unset DOCUSIGN_ROOT_URL
+unset DOCUSIGN_ACCOUNT_ID
diff --git a/utils/describe_table.sh b/utils/describe_table.sh
new file mode 100755
index 000000000..61251770c
--- /dev/null
+++ b/utils/describe_table.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+aws --profile lfproduct-dev dynamodb describe-table --table-name cla-dev-signatures
diff --git a/utils/example_pytest.sh b/utils/example_pytest.sh
new file mode 100755
index 000000000..f50d37b0c
--- /dev/null
+++ b/utils/example_pytest.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+pytest -vvv -s cla/tests/unit/test_docusign_models.py -p no:warnings -k test_request_individual_signature
diff --git a/utils/health_python_v2.sh b/utils/health_python_v2.sh
new file mode 100755
index 000000000..03c73f08f
--- /dev/null
+++ b/utils/health_python_v2.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+# API_URL=https://[xyz].ngrok-free.app (defaults to localhost:5000)
+if [ -z "$API_URL" ]
+then
+ export API_URL="http://localhost:5000"
+fi
+curl -s "${API_URL}/v2/health" | jq -r '.'
diff --git a/utils/lookup_company.sh b/utils/lookup_company.sh
new file mode 100755
index 000000000..ff7ce8c8f
--- /dev/null
+++ b/utils/lookup_company.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+aws --profile lfproduct-dev dynamodb query --table-name cla-dev-companies --index-name company-name-index --key-condition-expression "company_name = :name" --expression-attribute-values '{":name":{"S":"Google LLC"}}'
diff --git a/utils/lookup_project.sh b/utils/lookup_project.sh
new file mode 100755
index 000000000..68e84f2ae
--- /dev/null
+++ b/utils/lookup_project.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+aws --profile lfproduct-dev dynamodb query --table-name cla-dev-projects --index-name project-name-lower-search-index --key-condition-expression "project_name_lower = :name" --expression-attribute-values '{":name":{"S":"child group earths"}}'
diff --git a/utils/lookup_user.sh b/utils/lookup_user.sh
new file mode 100755
index 000000000..230809fb6
--- /dev/null
+++ b/utils/lookup_user.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+aws --profile lfproduct-dev dynamodb query --table-name cla-dev-users --index-name github-username-index --key-condition-expression "user_github_username = :name" --expression-attribute-values '{":name":{"S":"lukaszgryglicki"}}'
diff --git a/utils/ngrok.sh b/utils/ngrok.sh
new file mode 100755
index 000000000..829abad2f
--- /dev/null
+++ b/utils/ngrok.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+ngrok http http://localhost:5000
diff --git a/utils/request_corporate_signature_go_post.sh b/utils/request_corporate_signature_go_post.sh
new file mode 100755
index 000000000..04a0e9484
--- /dev/null
+++ b/utils/request_corporate_signature_go_post.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+# API_URL=https://[xyz].ngrok-free.app (defaults to localhost:5000)
+# company_sfid='0016s000006Uq9VAAS'
+# project_sfid='a092h000004wx1DAAQ'
+# return_url_type='github'
+# return_url='http://localhost'
+# TOKEN='...' - Auth0 JWT bearer token
+# XACL='...' - X-ACL
+# DEBUG=1 XACL="$(cat ./x-acl.secret)" TOKEN="$(cat ./auth0.token.secret)" ./utils/request_corporate_signature_go_post.sh 0016s000006Uq9VAAS a092h000004wx1DAAQ github 'http://localhost'
+
+if [ -z "$TOKEN" ]
+then
+ # source ./auth0_token.secret
+ TOKEN="$(cat ./auth0.token.secret)"
+fi
+
+if [ -z "$TOKEN" ]
+then
+ echo "$0: TOKEN not specified and unable to obtain one"
+ exit 1
+fi
+
+if [ -z "$XACL" ]
+then
+ XACL="$(cat ./x-acl.secret)"
+fi
+
+if [ -z "$XACL" ]
+then
+ echo "$0: XACL not specified and unable to obtain one"
+ exit 2
+fi
+
+if [ -z "$1" ]
+then
+ echo "$0: you need to specify company_sfid as a 1st parameter"
+ exit 1
+fi
+export company_sfid="$1"
+
+if [ -z "$2" ]
+then
+ echo "$0: you need to specify project_sfid as a 2nd parameter"
+ exit 2
+fi
+export project_sfid="$2"
+
+if [ -z "$3" ]
+then
+ echo "$0: you need to specify return_url_type as a 3rd parameter: github|gitlab|gerrit"
+ exit 3
+fi
+export return_url_type="$3"
+
+if [ -z "$4" ]
+then
+ echo "$0: you need to specify return_urlas a 4th parameter"
+ exit 4
+fi
+export return_url="$4"
+
+if [ -z "$API_URL" ]
+then
+ export API_URL="http://localhost:5000"
+fi
+
+if [ ! -z "$DEBUG" ]
+then
+ echo "curl -s -XPOST -H 'X-ACL: ${XACL}' -H 'Authorization: Bearer ${TOKEN}' -H 'Content-Type: application/json' '${API_URL}/v4/request-corporate-signature' -d '{\"project_sfid\":\"${project_sfid}\",\"company_sfid\":\"${company_sfid}\",\"return_url_type\":\"${return_url_type}\",\"return_url\":\"${return_url}\"}' | jq -r '.'"
+fi
+curl -s -XPOST -H "X-ACL: ${XACL}" -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" "${API_URL}/v4/request-corporate-signature" -d "{\"project_sfid\":\"${project_sfid}\",\"company_sfid\":\"${company_sfid}\",\"return_url_type\":\"${return_url_type}\",\"return_url\":\"${return_url}\"}" | jq -r '.'
diff --git a/utils/request_employee_signature_py_post.sh b/utils/request_employee_signature_py_post.sh
new file mode 100755
index 000000000..d07ffc138
--- /dev/null
+++ b/utils/request_employee_signature_py_post.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+# API_URL=https://3f13-147-75-85-27.ngrok-free.app (defaults to localhost:5000)
+# user_id='9dcf5bbc-2492-11ed-97c7-3e2a23ea20b5'
+# company_id='862ff296-6508-4f10-9147-2bc2dd7bfe80'
+# project_id='88ee12de-122b-4c46-9046-19422054ed8d'
+# return_url_type='github'
+# return_url='http://localhost'
+# DEBUG=1 ./utils/request_employee_signature_py_post.sh 9dcf5bbc-2492-11ed-97c7-3e2a23ea20b5 862ff296-6508-4f10-9147-2bc2dd7bfe80 88ee12de-122b-4c46-9046-19422054ed8d github 'http://localhost'
+
+if [ -z "$1" ]
+then
+ echo "$0: you need to specify user_id as a 1st parameter"
+ exit 1
+fi
+export user_id="$1"
+
+if [ -z "$2" ]
+then
+ echo "$0: you need to specify company_id as a 2nd parameter"
+ exit 2
+fi
+export company_id="$2"
+
+if [ -z "$3" ]
+then
+ echo "$0: you need to specify project_id as a 3rd parameter"
+ exit 3
+fi
+export project_id="$3"
+
+if [ -z "$4" ]
+then
+ echo "$0: you need to specify return_url_type as a 4th parameter: github|gitlab|gerrit"
+ exit 4
+fi
+export return_url_type="$4"
+
+if [ -z "$5" ]
+then
+ echo "$0: you need to specify return_url as a 5th parameter"
+ exit 5
+fi
+export return_url="$5"
+
+if [ -z "$API_URL" ]
+then
+ export API_URL="http://localhost:5000"
+fi
+
+if [ ! -z "$DEBUG" ]
+then
+ echo "curl -s -XPOST -H 'Content-Type: application/json' '${API_URL}/v2/request-employee-signature' -d '{\"project_id\":\"${project_id}\",\"user_id\":\"${user_id}\",\"company_id\":\"${company_id}\",\"return_url_type\":\"${return_url_type}\",\"return_url\":\"${return_url}\"}' | jq -r '.'"
+fi
+curl -s -XPOST -H "Content-Type: application/json" "${API_URL}/v2/request-employee-signature" -d "{\"project_id\":\"${project_id}\",\"user_id\":\"${user_id}\",\"company_id\":\"${company_id}\",\"return_url_type\":\"${return_url_type}\",\"return_url\":\"${return_url}\"}" | jq -r '.'
diff --git a/utils/request_individual_signature_go_post.sh b/utils/request_individual_signature_go_post.sh
new file mode 100755
index 000000000..cf3ec5712
--- /dev/null
+++ b/utils/request_individual_signature_go_post.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+# API_URL=https://3f13-147-75-85-27.ngrok-free.app (defaults to localhost:5000)
+# user_id='9dcf5bbc-2492-11ed-97c7-3e2a23ea20b5'
+# project_id='88ee12de-122b-4c46-9046-19422054ed8d'
+# return_url_type='github'
+# return_url='http://localhost'
+# TOKEN='...' - Auth0 JWT bearer token
+# XACL='...' - X-ACL header
+# DEBUG=1 TOKEN="$(cat ./auth0.token.secret)" XACL="$(cat ./x-acl.secret)" ./utils/request_individual_signature_go_post.sh 9dcf5bbc-2492-11ed-97c7-3e2a23ea20b5 88ee12de-122b-4c46-9046-19422054ed8d github 'http://localhost'
+
+if [ -z "$TOKEN" ]
+then
+ # source ./auth0_token.secret
+ TOKEN="$(cat ./auth0.token.secret)"
+fi
+
+if [ -z "$TOKEN" ]
+then
+ echo "$0: TOKEN not specified and unable to obtain one"
+ exit 1
+fi
+
+if [ -z "$XACL" ]
+then
+ XACL="$(cat ./x-acl.secret)"
+fi
+
+if [ -z "$XACL" ]
+then
+ echo "$0: XACL not specified and unable to obtain one"
+ exit 2
+fi
+
+if [ -z "$1" ]
+then
+ echo "$0: you need to specify user_id as a 1st parameter"
+ exit 3
+fi
+export user_id="$1"
+
+if [ -z "$2" ]
+then
+ echo "$0: you need to specify project_id as a 2nd parameter"
+ exit 4
+fi
+export project_id="$2"
+
+if [ -z "$3" ]
+then
+ echo "$0: you need to specify return_url_type as a 3rd parameter: github|gitlab|gerrit"
+ exit 5
+fi
+export return_url_type="$3"
+
+if [ -z "$4" ]
+then
+ echo "$0: you need to specify return_url as a 4th parameter"
+ exit 6
+fi
+export return_url="$4"
+
+if [ -z "$API_URL" ]
+then
+ export API_URL="http://localhost:5000"
+fi
+
+if [ ! -z "$DEBUG" ]
+then
+ echo "curl -s -XPOST -H 'X-ACL: ${XACL}' -H 'Authorization: Bearer ${TOKEN}' -H 'Content-Type: application/json' '${API_URL}/v4/request-individual-signature' -d '{\"project_id\":\"${project_id}\",\"user_id\":\"${user_id}\",\"return_url_type\":\"${return_url_type}\",\"return_url\":\"${return_url}\"}' | jq -r '.'"
+fi
+curl -s -XPOST -H "X-ACL: ${XACL}" -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" "${API_URL}/v4/request-individual-signature" -d "{\"project_id\":\"${project_id}\",\"user_id\":\"${user_id}\",\"return_url_type\":\"${return_url_type}\",\"return_url\":\"${return_url}\"}" | jq -r '.'
diff --git a/utils/request_individual_signature_py_post.sh b/utils/request_individual_signature_py_post.sh
new file mode 100755
index 000000000..b547fa49d
--- /dev/null
+++ b/utils/request_individual_signature_py_post.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# API_URL=https://3f13-147-75-85-27.ngrok-free.app (defaults to localhost:5000)
+# user_id='9dcf5bbc-2492-11ed-97c7-3e2a23ea20b5'
+# project_id='88ee12de-122b-4c46-9046-19422054ed8d'
+# return_url_type='github'
+# return_url='http://localhost'
+# DEBUG=1 ./utils/request_individual_signature_py_post.sh 9dcf5bbc-2492-11ed-97c7-3e2a23ea20b5 88ee12de-122b-4c46-9046-19422054ed8d github 'http://localhost'
+
+if [ -z "$1" ]
+then
+ echo "$0: you need to specify user_id as a 1st parameter"
+ exit 1
+fi
+export user_id="$1"
+
+if [ -z "$2" ]
+then
+ echo "$0: you need to specify project_id as a 2nd parameter"
+ exit 2
+fi
+export project_id="$2"
+
+if [ -z "$3" ]
+then
+ echo "$0: you need to specify return_url_type as a 3rd parameter: github|gitlab|gerrit"
+ exit 3
+fi
+export return_url_type="$3"
+
+if [ -z "$4" ]
+then
+ echo "$0: you need to specify return_url as a 4th parameter"
+ exit 4
+fi
+export return_url="$4"
+
+if [ -z "$API_URL" ]
+then
+ export API_URL="http://localhost:5000"
+fi
+
+if [ ! -z "$DEBUG" ]
+then
+ echo "curl -s -XPOST -H 'Content-Type: application/json' '${API_URL}/v2/request-individual-signature' -d '{\"project_id\":\"${project_id}\",\"user_id\":\"${user_id}\",\"return_url_type\":\"${return_url_type}\",\"return_url\":\"${return_url}\"}' | jq -r '.'"
+fi
+curl -s -XPOST -H "Content-Type: application/json" "${API_URL}/v2/request-individual-signature" -d "{\"project_id\":\"${project_id}\",\"user_id\":\"${user_id}\",\"return_url_type\":\"${return_url_type}\",\"return_url\":\"${return_url}\"}" | jq -r '.'
diff --git a/utils/run_tests.sh b/utils/run_tests.sh
new file mode 100755
index 000000000..6d7d17992
--- /dev/null
+++ b/utils/run_tests.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+# PY=1
+# GO=1
+if [ ! -z "$PY" ]
+then
+ cd cla-backend && pytest "cla/tests" -p no:warnings
+ # pytest -vvv -s cla/tests/unit/test_docusign_models.py -p no:warnings -k test_request_individual_signature
+ cd ..
+else
+ echo "$0: skipping python backend tests, specify PY=1 to run them"
+fi
+
+if [ ! -z "$GO" ]
+then
+ cd cla-backend-go && make test
+ # go test github.com/communitybridge/easycla/cla-backend-go/signatures
+ cd ..
+else
+ echo "$0: skipping golang backend tests, specify GO=1 to run them"
+fi
+
diff --git a/utils/scan_projects.sh b/utils/scan_projects.sh
new file mode 100755
index 000000000..109422e8e
--- /dev/null
+++ b/utils/scan_projects.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+aws --profile lfproduct-dev dynamodb scan --table-name cla-dev-projects --max-items 3
diff --git a/utils/scan_signatures.sh b/utils/scan_signatures.sh
new file mode 100755
index 000000000..478bed2af
--- /dev/null
+++ b/utils/scan_signatures.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+aws --profile lfproduct-dev dynamodb scan --table-name cla-dev-signatures --max-items 1
diff --git a/utils/signature_post.sh b/utils/signature_post.sh
new file mode 100755
index 000000000..d803c9983
--- /dev/null
+++ b/utils/signature_post.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+# API_URL=https://[token].ngrok-free.app (defaults to localhost:5000)
+# TOKEN='...' - Auth0 JWT bearer token
+# BODY='{...}' - signature body
+
+if [ -z "$API_URL" ]
+then
+ export API_URL="http://localhost:5000"
+fi
+
+if [ -z "$TOKEN" ]
+then
+ source ./auth0_token.secret
+fi
+
+if [ -z "$TOKEN" ]
+then
+ echo "$0: TOKEN not specified and unable to obtain one"
+ exit 1
+fi
+
+if [ ! -z "$DEBUG" ]
+then
+ echo "curl -s -XPOST -H 'Authorization: Bearer ${TOKEN}' -H 'Content-Type: application/json' '${API_URL}/v1/signature' -d '${BODY}' | jq -r '.'"
+fi
+curl -s -XPOST -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" "${API_URL}/v1/signature" -d "${BODY}" | jq -r '.'
diff --git a/utils/signatures_to_json.sh b/utils/signatures_to_json.sh
new file mode 100755
index 000000000..32615a660
--- /dev/null
+++ b/utils/signatures_to_json.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+aws --profile lfproduct-dev dynamodb scan --table-name cla-dev-signatures --select ALL_ATTRIBUTES --page-size 500 --max-items 100000 --output json > cla-dev-signatures.json.secret