diff --git a/cla-backend-go/swagger/cla.v2.yaml b/cla-backend-go/swagger/cla.v2.yaml index a267a8851..16217eeec 100644 --- a/cla-backend-go/swagger/cla.v2.yaml +++ b/cla-backend-go/swagger/cla.v2.yaml @@ -2445,6 +2445,49 @@ paths: tags: - signatures + /user/{userID}/active-signature: + parameters: + - $ref: "#/parameters/x-request-id" + - name: userID + description: the user ID + in: path + type: string + required: true + pattern: '^[a-fA-F0-9]{8}-?[a-fA-F0-9]{4}-?4[a-fA-F0-9]{3}-?[89ab][a-fA-F0-9]{3}-?[a-fA-F0-9]{12}$' # uuidv4 + get: + summary: | + Returns all metadata associated with a user's active signature. + { + 'user_id': , + 'project_id': , + 'repository_id': (as string), + 'pull_request_id': (PR number as string), + *'merge_request_id': (optional MR number as string - this property can be missing in JSON), + 'return_url': (for example itHub PR path)' + } + Returns null if the user does not have an active signature. + security: [ ] + operationId: getUserActiveSignature + 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/user-active-signature' + '400': + $ref: '#/responses/invalid-request' + '401': + $ref: '#/responses/unauthorized' + '403': + $ref: '#/responses/forbidden' + '404': + $ref: '#/responses/not-found' + tags: + - sign + /signatures/project/{projectSFID}/company/{companyID}/employee: get: summary: Get project company signatures for the employees @@ -5006,6 +5049,9 @@ definitions: user: $ref: './common/user.yaml' + user-active-signature: + $ref: './common/user-active-signature.yaml' + signatures: $ref: './common/signatures.yaml' diff --git a/cla-backend-go/swagger/common/user-active-signature.yaml b/cla-backend-go/swagger/common/user-active-signature.yaml new file mode 100644 index 000000000..f24d75034 --- /dev/null +++ b/cla-backend-go/swagger/common/user-active-signature.yaml @@ -0,0 +1,34 @@ +# Copyright The Linux Foundation and each contributor to CommunityBridge. +# SPDX-License-Identifier: MIT + +type: object +x-nullable: true +title: User Active Signature +description: > + Returns all metadata associated with a user's active signature. + Returns `null` if the user does not have an active signature. +properties: + user_id: + $ref: './common/properties/internal-id.yaml' + description: The unique internal UUID of the user + project_id: + $ref: './common/properties/internal-id.yaml' + description: The unique UUID of the associated project + repository_id: + type: string + description: The unique ID of the associated repository (number stored as string) + example: '168926425' + pull_request_id: + type: string + description: The pull request ID related to the signature (number stored as string) + example: '456' + merge_request_id: + type: string + description: The merge request ID related to the signature (optional number stored as string, thsi property can be missing in JSON) + example: '456' + x-nullable: true + return_url: + type: string + format: uri + description: The return URL where the user initiated the signature (for example GitHub PR path) + example: https://github.com/veer-missingid2/repo03/pull/3 diff --git a/cla-backend-go/v2/sign/handlers.go b/cla-backend-go/v2/sign/handlers.go index 74a44da81..dcd319b24 100644 --- a/cla-backend-go/v2/sign/handlers.go +++ b/cla-backend-go/v2/sign/handlers.go @@ -24,6 +24,8 @@ import ( "github.com/linuxfoundation/easycla/cla-backend-go/gen/v2/restapi/operations/sign" "github.com/linuxfoundation/easycla/cla-backend-go/utils" "github.com/linuxfoundation/easycla/cla-backend-go/v2/organization-service/client/organizations" + + "github.com/go-openapi/runtime" ) var ( @@ -248,6 +250,35 @@ func Configure(api *operations.EasyclaAPI, service Service, userService users.Se return sign.NewCclaCallbackOK() }) + api.SignGetUserActiveSignatureHandler = sign.GetUserActiveSignatureHandlerFunc( + func(params sign.GetUserActiveSignatureParams) middleware.Responder { + reqId := utils.GetRequestID(params.XREQUESTID) + ctx := context.WithValue(params.HTTPRequest.Context(), utils.XREQUESTIDKey, reqId) + f := logrus.Fields{ + "functionName": "v2.sign.handlers.SignGetUserActiveSignatureHandler", + utils.XREQUESTID: ctx.Value(utils.XREQUESTID), + "userID": params.UserID, + } + var resp *models.UserActiveSignature + var err error + + log.WithFields(f).Debug("getting user active signature") + resp, err = service.GetUserActiveSignature(ctx, params.UserID) + if err != nil { + return sign.NewGetUserActiveSignatureBadRequest().WithPayload(errorResponse(reqId, err)) + } + if resp == nil { + return middleware.ResponderFunc(func(w http.ResponseWriter, _ runtime.Producer) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + if _, err := w.Write([]byte("null")); err != nil { + log.WithFields(f).WithError(err).Warn("failed to write null response") + } + }) + } + return sign.NewGetUserActiveSignatureOK().WithPayload(resp) + }) + } type codedResponse interface { diff --git a/cla-backend-go/v2/sign/service.go b/cla-backend-go/v2/sign/service.go index 00d4cf8c5..424affc15 100644 --- a/cla-backend-go/v2/sign/service.go +++ b/cla-backend-go/v2/sign/service.go @@ -90,6 +90,7 @@ type Service interface { SignedIndividualCallbackGitlab(ctx context.Context, payload []byte, userID, organizationID, repositoryID, mergeRequestID string) error SignedIndividualCallbackGerrit(ctx context.Context, payload []byte, userID string) error SignedCorporateCallback(ctx context.Context, payload []byte, companyID, projectID string) error + GetUserActiveSignature(ctx context.Context, userID string) (*models.UserActiveSignature, error) } // service @@ -1539,7 +1540,7 @@ func (s *service) getIndividualSignatureCallbackURLGitlab(ctx context.Context, u if found, ok := metadata["merge_request_id"].(string); ok { mergeRequestID = found } else { - log.WithFields(f).WithError(err).Warnf("unable to get pull request ID for user: %s", userID) + log.WithFields(f).WithError(err).Warnf("unable to get merge request ID for user: %s", userID) return "", err } @@ -1607,11 +1608,28 @@ func (s *service) getIndividualSignatureCallbackURL(ctx context.Context, userID log.WithFields(f).Debugf("found pull request ID: %s", pullRequestID) // Get installation ID through a helper function - log.WithFields(f).Debugf("getting repository...") + installationId, err = s.getInstallationIDFromRepositoryID(ctx, repositoryID) + if err != nil { + log.WithFields(f).WithError(err).Warnf("unable to get github organization for repository ID: %s", repositoryID) + return "", err + } + + callbackURL := fmt.Sprintf("%s/v4/signed/individual/%d/%s/%s", s.ClaV4ApiURL, installationId, repositoryID, pullRequestID) + return callbackURL, nil +} + +func (s *service) getInstallationIDFromRepositoryID(ctx context.Context, repositoryID string) (int64, error) { + var installationId int64 + f := logrus.Fields{ + "functionName": "sign.getInstallationIDFromRepositoryID", + "repositoryID": repositoryID, + } + // Get installation ID through a helper function + log.WithFields(f).Debugf("getting repository for ID=%s...", repositoryID) githubRepository, err := s.repositoryService.GetRepositoryByExternalID(ctx, repositoryID) if err != nil { log.WithFields(f).WithError(err).Warnf("unable to get installation ID for repository ID: %s", repositoryID) - return "", err + return 0, err } // Get github organization @@ -1620,17 +1638,16 @@ func (s *service) getIndividualSignatureCallbackURL(ctx context.Context, userID if err != nil { log.WithFields(f).WithError(err).Warnf("unable to get github organization for repository ID: %s", repositoryID) - return "", err + return 0, err } installationId = githubOrg.OrganizationInstallationID if installationId == 0 { - log.WithFields(f).WithError(err).Warnf("unable to get installation ID for repository ID: %s", repositoryID) - return "", err + log.WithFields(f).Warnf("unable to get installation ID for repository ID: %s", repositoryID) + return 0, err } - callbackURL := fmt.Sprintf("%s/v4/signed/individual/%d/%s/%s", s.ClaV4ApiURL, installationId, repositoryID, pullRequestID) - return callbackURL, nil + return installationId, nil } //nolint:gocyclo @@ -2769,3 +2786,117 @@ func claSignatoryEmailContent(params ClaSignatoryEmailParams) (string, string) { return emailSubject, emailBody } + +func (s *service) getActiveSignatureReturnURL(ctx context.Context, userID string, metadata map[string]interface{}) (string, error) { + + f := logrus.Fields{ + "functionName": "sign.getActiveSignatureReturnURL", + } + + var returnURL, rId string + var err, err2 error + var pullRequestID int + var repositoryID int64 + var installationID int64 + + if found, ok := metadata["pull_request_id"]; ok && found != nil { + prId := fmt.Sprintf("%v", found) + pullRequestID, err2 = strconv.Atoi(prId) + if err2 != nil { + log.WithFields(f).WithError(err2).Warnf("unable to get pull request ID for user: %s", userID) + return "", err2 + } + } else { + err2 = errors.New("missing pull_request_id in metadata") + log.WithFields(f).WithError(err2).Warnf("unable to get pull request ID for user: %s", userID) + return "", err2 + } + + if found, ok := metadata["repository_id"]; ok && found != nil { + rId = fmt.Sprintf("%v", found) + repositoryID, err2 = strconv.ParseInt(rId, 10, 64) + if err2 != nil { + log.WithFields(f).WithError(err2).Warnf("unable to get repository ID for user: %s", userID) + return "", err2 + } + } else { + err2 = errors.New("missing repository_id in metadata") + log.WithFields(f).WithError(err2).Warnf("unable to get repository ID for user: %s", userID) + return "", err2 + } + + // Get installation ID through a helper function + installationID, err = s.getInstallationIDFromRepositoryID(ctx, rId) + if err != nil { + log.WithFields(f).WithError(err).Warnf("unable to get github organization for repository ID: %v", repositoryID) + return "", err + } + + returnURL, err = github.GetReturnURL(ctx, installationID, repositoryID, pullRequestID) + + if err != nil { + return "", err + } + + return returnURL, nil +} + +func (s *service) GetUserActiveSignature(ctx context.Context, userID string) (*models.UserActiveSignature, error) { + f := logrus.Fields{ + "functionName": "sign.GetUserActiveSignature", + utils.XREQUESTID: ctx.Value(utils.XREQUESTID), + "userID": userID, + } + activeSignatureMetadata, err := s.storeRepository.GetActiveSignatureMetaData(ctx, userID) + if err != nil { + log.WithFields(f).WithError(err).Warnf("unable to get active signature meta data for user: %s", userID) + return nil, err + } + log.WithFields(f).Debugf("active signature metadata: %+v", activeSignatureMetadata) + if len(activeSignatureMetadata) == 0 { + return nil, nil + } + var ( + mergeRequestId *string + isGitlab bool + returnURL string + pullRequestId string + repositoryId string + ) + if mrId, ok := activeSignatureMetadata["merge_request_id"]; ok && mrId != nil { + mrStr := fmt.Sprintf("%v", mrId) + mergeRequestId = &mrStr + isGitlab = true + } + if isGitlab { + var ok bool + returnURL, ok = activeSignatureMetadata["return_url"].(string) + if !ok { + log.WithFields(f).Warnf("missing return_url in metadata while merge_request_id is present: %+v", activeSignatureMetadata) + } + } else { + returnURL, err = s.getActiveSignatureReturnURL(ctx, userID, activeSignatureMetadata) + if err != nil { + log.WithFields(f).WithError(err).Warnf("unable to get active signature return url for user: %s", userID) + return nil, err + } + } + projectId, ok := activeSignatureMetadata["project_id"].(string) + if !ok { + log.WithFields(f).Warnf("missing project_id in metadata: %+v", activeSignatureMetadata) + } + if val, ok := activeSignatureMetadata["pull_request_id"]; ok && val != nil { + pullRequestId = fmt.Sprintf("%v", val) + } + if val, ok := activeSignatureMetadata["repository_id"]; ok && val != nil { + repositoryId = fmt.Sprintf("%v", val) + } + return &models.UserActiveSignature{ + MergeRequestID: mergeRequestId, + ProjectID: projectId, + PullRequestID: pullRequestId, + RepositoryID: repositoryId, + ReturnURL: strfmt.URI(returnURL), + UserID: userID, + }, nil +} diff --git a/cla-backend/cla/routes.py b/cla-backend/cla/routes.py index d9683759c..4141f1dea 100755 --- a/cla-backend/cla/routes.py +++ b/cla-backend/cla/routes.py @@ -232,6 +232,7 @@ def request_company_ccla( # return cla.controllers.user.request_company_admin_access(str(user_id), str(company_id)) +# LG: This is ported to golang and no longer used in dev (still used in prod) @hug.get("/user/{user_id}/active-signature", versions=2) def get_user_active_signature(user_id: hug.types.uuid): """ @@ -773,7 +774,7 @@ def get_projects(auth_user: check_auth): del project["project_external_id"] return projects - +# LG: This is ported to golang and no longer used in dev (still used in prod). @hug.get("/project/{project_id}", versions=2) def get_project(project_id: hug.types.uuid): """ diff --git a/tests/py2go/README.md b/tests/py2go/README.md index 6c5b0e6b2..83d49fb6a 100644 --- a/tests/py2go/README.md +++ b/tests/py2go/README.md @@ -21,3 +21,6 @@ - Manually via `cURL`: `` curl -s -XGET http://127.0.0.1:5001/v4/project-compat/01af041c-fa69-4052-a23c-fb8c1d3bef24 | jq . ``. - To manually see given project values if APIs differ (to dewbug): `` aws --region us-east-1 --profile lfproduct-dev dynamodb get-item --table-name cla-dev-projects --key '{"project_id": {"S": "4a855799-0aea-4e01-98b7-ef3da09df478"}}' | jq '.Item' ``. - And `` aws --region us-east-1 --profile lfproduct-dev dynamodb query --table-name cla-dev-projects-cla-groups --index-name cla-group-id-index --key-condition-expression "cla_group_id = :project_id" --expression-attribute-values '{":project_id":{"S":"4a855799-0aea-4e01-98b7-ef3da09df478"}}' | jq '.Items' ``. +- `` DEBUG='' USER_UUID=b817eb57-045a-4fe0-8473-fbb416a01d70 PY_API_URL=https://api.lfcla.dev.platform.linuxfoundation.org go test -v -run '^TestUserActiveSignatureAPI$' ``. +- `` REPO_ID=466156917 PR_ID=3 DEBUG=1 go test -v -run '^TestUserActiveSignatureAPI$' ``. +- `` MAX_PARALLEL=2 DEBUG='' go test -v -run '^TestAllUserActiveSignatureAPI$' ``. diff --git a/tests/py2go/api_test.go b/tests/py2go/api_test.go index bde05c18d..af89de49c 100644 --- a/tests/py2go/api_test.go +++ b/tests/py2go/api_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io" + "math/rand" "net/http" "os" "sort" @@ -17,6 +18,11 @@ import ( "github.com/stretchr/testify/assert" ) +const ( + ExampleRepoID = 466156917 + ExamplePRNumber = 3 +) + var ( TOKEN string XACL string @@ -25,6 +31,9 @@ var ( DEBUG bool MAX_PARALLEL int PROJECT_UUID string + USER_UUID string + REPO_ID int64 + PR_ID int64 ProjectAPIPath = [3]string{"/v2/project/%s", "/v4/project/%s", "/v4/project-compat/%s"} ProjectAPIKeyMapping = map[string]string{ "date_created": "dateCreated", @@ -75,6 +84,16 @@ var ( "gitlab_repos": "repository_name", "gerrit_repos": "gerrit_url", } + UserActiveSignatureAPIPath = [2]string{"/v2/user/%s/active-signature", "/v4/user/%s/active-signature"} + // Optional field: true means the key may be missing in both APIs and still be valid + UserActiveSignatureAPIKeyMapping = map[string]interface{}{ + "project_id": nil, + "pull_request_id": nil, + "repository_id": nil, + "return_url": nil, + "user_id": nil, + "merge_request_id": true, + } ) func init() { @@ -103,6 +122,28 @@ func init() { } } PROJECT_UUID = os.Getenv("PROJECT_UUID") + USER_UUID = os.Getenv("USER_UUID") + REPO_ID = ExampleRepoID + par = os.Getenv("REPO_ID") + if par != "" { + iPar, err := strconv.ParseInt(par, 10, 64) + if err != nil { + fmt.Printf("REPO_ID environment value should be integer >= 1\n") + } else if iPar > 0 { + REPO_ID = iPar + } + } + PR_ID = ExamplePRNumber + par = os.Getenv("PR_ID") + if par != "" { + iPar, err := strconv.ParseInt(par, 10, 64) + if err != nil { + fmt.Printf("PR_ID environment value should be integer >= 1\n") + } else if iPar > 0 { + PR_ID = iPar + } + } + rand.Seed(time.Now().UnixNano()) } func tryParseTime(val interface{}) (time.Time, bool) { @@ -173,12 +214,19 @@ func sortByKey(arr []interface{}, key string) { func compareNestedFields(t *testing.T, pyData, goData, keyMapping map[string]interface{}, sortMap map[string]string) { for k, v := range keyMapping { - if v == nil { + bV, bVOK := v.(bool) + if v == nil || bVOK { Debugf("checking values of '%s'\n", k) } pyVal, pyOk := pyData[k] goVal, goOk := goData[k] + + // true means fields are optional (nullable), so if v is true and fileds are missing in both Py and go then this is OK + if bVOK && bV && !pyOk && !goOk { + Debugf("'%s' is not set in both responses, this is ok\n", k) + continue + } if !pyOk { t.Errorf("Missing key in Python response: %s", k) continue @@ -484,3 +532,146 @@ func TestProjectAPI(t *testing.T) { Debugf("new keys: %+v\n", nky) } } + +func runUserActiveSignatureAPIForUser(t *testing.T, userId string) { + apiURL := PY_API_URL + fmt.Sprintf(UserActiveSignatureAPIPath[0], userId) + Debugf("Py API call: %s\n", apiURL) + oldResp, err := http.Get(apiURL) + if err != nil { + t.Fatalf("Failed to call API: %v", err) + } + assert.Equal(t, http.StatusOK, oldResp.StatusCode, "Expected 200 from PY API") + defer oldResp.Body.Close() + oldBody, _ := io.ReadAll(oldResp.Body) + var oldJSON interface{} + err = json.Unmarshal(oldBody, &oldJSON) + assert.NoError(t, err) + Debugf("Py raw response: %+v\n", string(oldBody)) + Debugf("Py response: %+v\n", oldJSON) + + apiURL = GO_API_URL + fmt.Sprintf(UserActiveSignatureAPIPath[1], userId) + Debugf("Go API call: %s\n", apiURL) + newResp, err := http.Get(apiURL) + if err != nil { + t.Fatalf("Failed to call API: %v", err) + } + assert.Equal(t, http.StatusOK, newResp.StatusCode, "Expected 200 from GO API") + defer newResp.Body.Close() + newBody, _ := io.ReadAll(newResp.Body) + var newJSON interface{} + err = json.Unmarshal(newBody, &newJSON) + assert.NoError(t, err) + Debugf("Go raw Response: %+v\n", string(newBody)) + Debugf("Go response: %+v\n", newJSON) + + if string(oldBody) == "null" && string(newBody) == "null" { + return + } + + oldMap, ok1 := oldJSON.(map[string]interface{}) + newMap, ok2 := newJSON.(map[string]interface{}) + + if !ok1 || !ok2 { + t.Fatalf("Expected both responses to be JSON objects") + } + compareNestedFields(t, oldMap, newMap, UserActiveSignatureAPIKeyMapping, map[string]string{}) + + if DEBUG { + oky := []string{} + for k, _ := range oldMap { + oky = append(oky, k) + } + sort.Strings(oky) + nky := []string{} + for k, _ := range newMap { + nky = append(nky, k) + } + sort.Strings(nky) + Debugf("old keys: %+v\n", oky) + Debugf("new keys: %+v\n", nky) + } +} + +func TestUserActiveSignatureAPI(t *testing.T) { + userId := USER_UUID + if userId == "" { + userId = uuid.New().String() + projectId := uuid.New().String() + key := "active_signature:" + userId + expire := time.Now().Add(time.Hour).Unix() + iValue := map[string]interface{}{ + "user_id": userId, + "project_id": projectId, + "repository_id": fmt.Sprintf("%d", REPO_ID), + "pull_request_id": fmt.Sprintf("%d", PR_ID), + } + if rand.Intn(2) == 0 { + mrId := rand.Intn(100) + iValue["merge_request_id"] = fmt.Sprintf("%d", mrId) + iValue["return_url"] = fmt.Sprintf("https://gitlab.com/gitlab-org/gitlab/-/merge_requests/%d", mrId) + } + value, err := json.Marshal(iValue) + if err != nil { + t.Fatalf("failed to marshal value: %+v", err) + } + putTestItem("projects", "project_id", projectId, "S", map[string]interface{}{}, DEBUG) + putTestItem("store", "key", key, "S", map[string]interface{}{ + "value": string(value), + "expire": expire, + }, DEBUG) + defer deleteTestItem("projects", "project_id", projectId, "S", DEBUG) + defer deleteTestItem("store", "key", key, "S", DEBUG) + } + + runUserActiveSignatureAPIForUser(t, userId) +} + +func TestAllUserActiveSignatureAPI(t *testing.T) { + allUserActiveSignatures := getAllPrimaryKeys("store", "key", "S") + + var failed []string + var mtx sync.Mutex + sem := make(chan struct{}, MAX_PARALLEL) + var wg sync.WaitGroup + + for _, key := range allUserActiveSignatures { + ky, ok := key.(string) + if !ok { + t.Errorf("Expected string key, got: %T", key) + continue + } + if !strings.HasPrefix(ky, "active_signature:") { + continue + } + userId := strings.TrimPrefix(ky, "active_signature:") + + wg.Add(1) + sem <- struct{}{} + + go func(userId string) { + defer wg.Done() + defer func() { <-sem }() + + t.Run(fmt.Sprintf("UserId=%s", userId), func(t *testing.T) { + runUserActiveSignatureAPIForUser(t, userId) + if t.Failed() { + mtx.Lock() + failed = append(failed, userId) + mtx.Unlock() + } + }) + }(userId) + } + + wg.Wait() + + if len(failed) > 0 { + fmt.Fprintf(os.Stderr, "\nFailed User IDs (%d):\n%s\n\n", + len(failed), + strings.Join(failed, "\n"), + ) + t.Fail() + } else { + fmt.Println("\nAll user active signatures passed.") + } +} diff --git a/tests/py2go/dynamo.go b/tests/py2go/dynamo.go index c4bc8c86b..f9b26548b 100644 --- a/tests/py2go/dynamo.go +++ b/tests/py2go/dynamo.go @@ -143,8 +143,11 @@ func getAllPrimaryKeys(tableName, keyName, keyType string) []interface{} { for { input := &dynamodb.ScanInput{ TableName: aws.String(tName), - ProjectionExpression: aws.String(keyName), - ExclusiveStartKey: lastEvaluatedKey, + ProjectionExpression: aws.String("#k"), + ExpressionAttributeNames: map[string]string{ + "#k": keyName, + }, + ExclusiveStartKey: lastEvaluatedKey, } output, err := client.Scan(context.TODO(), input) diff --git a/utils/active_signature_go.sh b/utils/active_signature_go.sh new file mode 100755 index 000000000..f468e67ff --- /dev/null +++ b/utils/active_signature_go.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# user_id='9dcf5bbc-2492-11ed-97c7-3e2a23ea20b5' +# select key, data:expire from fivetran_ingest.dynamodb_product_us_east1_dev.cla_dev_store where key like 'active_signature:%' order by data:expire desc limit 1; +# select key, data:expire from fivetran_ingest.dynamodb_product_us_east_1.cla_prod_store where key like 'active_signature:%' order by data:expire desc limit 1; +# API_URL=https://api-gw.dev.platform.linuxfoundation.org/cla-service DEBUG=1 ./utils/active_signature_go.sh '4b344ac4-f8d9-11ed-ac9b-b29c4ace74e9' +# API_URL=https://api-gw.dev.platform.linuxfoundation.org/cla-service DEBUG=1 ./utils/active_signature_go.sh '4b344ac4-f8d9-11ed-ac9b-b29c4ace74e9' +# API_URL=http://localhost:5001 DEBUG='' ./utils/active_signature_go.sh '564e571e-12d7-4857-abd4-898939accdd7' +# ./utils/add_store_active_signature.sh b817eb57-045a-4fe0-8473-fbb416a01d70 d8cead54-92b7-48c5-a2c8-b1e295e8f7f1 +# DEBUG='' ./utils/active_signature_go.sh b817eb57-045a-4fe0-8473-fbb416a01d70 | jq '.' + +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 "$API_URL" ] +then + export API_URL="http://localhost:5001" +fi + +if [ ! -z "$DEBUG" ] +then + echo "curl -s -XGET -H 'Content-Type: application/json' \"${API_URL}/v4/user/${user_id}/active-signature\"" + curl -s -XGET -H "Content-Type: application/json" "${API_URL}/v4/user/${user_id}/active-signature" +else + curl -s -XGET -H "Content-Type: application/json" "${API_URL}/v4/user/${user_id}/active-signature" | jq -r '.' +fi diff --git a/utils/active_signature_py.sh b/utils/active_signature_py.sh index a08b6b2fc..57bec1567 100755 --- a/utils/active_signature_py.sh +++ b/utils/active_signature_py.sh @@ -5,6 +5,8 @@ # API_URL=https://api.lfcla.dev.platform.linuxfoundation.org DEBUG=1 ./utils/active_signature_py.sh '4b344ac4-f8d9-11ed-ac9b-b29c4ace74e9' # API_URL=https://api.lfcla.dev.platform.linuxfoundation.org DEBUG=1 ./utils/active_signature_py.sh '4b344ac4-f8d9-11ed-ac9b-b29c4ace74e9' # API_URL=https://api.easycla.lfx.linuxfoundation.org DEBUG='' ./utils/active_signature_py.sh '564e571e-12d7-4857-abd4-898939accdd7' +# ./utils/add_store_active_signature.sh b817eb57-045a-4fe0-8473-fbb416a01d70 d8cead54-92b7-48c5-a2c8-b1e295e8f7f1 +# DEBUG='' ./utils/active_signature_py.sh b817eb57-045a-4fe0-8473-fbb416a01d70 | jq '.' if [ -z "$1" ] then diff --git a/utils/add_store_active_signature.sh b/utils/add_store_active_signature.sh new file mode 100755 index 000000000..5756eef2b --- /dev/null +++ b/utils/add_store_active_signature.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# repo: aws --region us-east-1 --profile lfproduct-dev dynamodb scan --table-name "cla-dev-repositories" +if [ -z "$STAGE" ] +then + STAGE=dev +fi +if [ -z "${1}" ] +then + echo "$0: you must specify user ID value as a 1st argument, like: 'b817eb57-045a-4fe0-8473-fbb416a01d70'" + exit 1 +fi +if [ -z "${2}" ] +then + echo "$0: you must specify project ID value as a 2nd argument, like: 'd8cead54-92b7-48c5-a2c8-b1e295e8f7f1'" + exit 2 +fi +EXPIRE_TS=$(date -d 'tomorrow' +%s) +aws --profile "lfproduct-${STAGE}" dynamodb put-item --table-name "cla-${STAGE}-store" --item '{ + "key": { + "S": "active_signature:'"${1}"'" + }, + "value": { + "S": "{\"user_id\": \"'"${1}"'\", \"project_id\": \"'"${2}"'\", \"repository_id\": \"466156917\", \"pull_request_id\": \"3\"}" + }, + "expire": { + "N": "'"${EXPIRE_TS}"'" + } + }' diff --git a/utils/scan_store.sh b/utils/scan_store.sh new file mode 100755 index 000000000..dac1c1771 --- /dev/null +++ b/utils/scan_store.sh @@ -0,0 +1,10 @@ +#!/bin/bash +if [ -z "$STAGE" ] +then + STAGE=dev +fi +if [ ! -z "${DEBUG}" ] +then + echo "aws --profile \"lfproduct-${STAGE}\" dynamodb scan --table-name \"cla-${STAGE}-store\" --max-items 100 | jq -r '.Items'" +fi +aws --profile "lfproduct-${STAGE}" dynamodb scan --table-name "cla-${STAGE}-store" --max-items 100 | jq -r '.Items' diff --git a/utils/set_store_expire.sh b/utils/set_store_expire.sh new file mode 100755 index 000000000..2c1c1be2f --- /dev/null +++ b/utils/set_store_expire.sh @@ -0,0 +1,15 @@ +#!/bin/bash +if [ -z "$STAGE" ] +then + STAGE=dev +fi +if [ -z "${1}" ] +then + echo "$0: you must specify ID value as a 1st argument, like: 'b817eb57-045a-4fe0-8473-fbb416a01d70'" + exit 1 +fi +if [ ! -z "${DEBUG}" ] +then + echo "aws --profile \"lfproduct-${STAGE}\" dynamodb update-item --table-name \"cla-${STAGE}-store\" --key '{\"key\": {\"S\": \"${1}\"}}' --update-expression \"SET expire = :newval\" --expression-attribute-values '{\":newval\": {\"N\": \"'\"$(date -d '+1 day' +%s)\"'\"}}'" +fi +aws --profile "lfproduct-${STAGE}" dynamodb update-item --table-name "cla-${STAGE}-store" --key "{\"key\": {\"S\": \"${1}\"}}" --update-expression "SET expire = :newval" --expression-attribute-values '{":newval": {"N": "'"$(date -d '+1 day' +%s)"'"}}'