diff --git a/cla-backend-go/signatures/repository.go b/cla-backend-go/signatures/repository.go index cd75a1ac3..c62001022 100644 --- a/cla-backend-go/signatures/repository.go +++ b/cla-backend-go/signatures/repository.go @@ -4628,6 +4628,19 @@ func (repo repository) GetClaGroupCorporateContributors(ctx context.Context, cla totalCountChannel := make(chan int64, 1) go repo.getTotalCorporateContributorCount(ctx, claGroupID, companyID, searchTerm, totalCountChannel) + totalCount := <-totalCountChannel + log.WithFields(f).Debugf("total corporate contributor count: %d", totalCount) + // If the page size is nil, set it to the default + if pageSize == nil { + pageSize = aws.Int64(10) + } + + if *pageSize > totalCount { + pageSize = aws.Int64(totalCount) + } + + log.WithFields(f).Debugf("total corporate contributor count: %d, page size: %d", totalCount, *pageSize) + condition := expression.Key("signature_project_id").Equal(expression.Value(claGroupID)) // if companyID != nil { // sortKey := fmt.Sprintf("%s#%v#%v#%v", utils.ClaTypeECLA, true, true, *companyID) @@ -4660,11 +4673,6 @@ func (repo repository) GetClaGroupCorporateContributors(ctx context.Context, cla return nil, err } - // If the page size is nil, set it to the default - if pageSize == nil { - pageSize = aws.Int64(10) - } - // Assemble the query input parameters queryInput := &dynamodb.QueryInput{ ExpressionAttributeNames: expr.Names(), @@ -4692,7 +4700,9 @@ func (repo repository) GetClaGroupCorporateContributors(ctx context.Context, cla out := &models.CorporateContributorList{List: make([]*models.CorporateContributor, 0)} var lastEvaluatedKey string - for ok := true; ok; ok = lastEvaluatedKey != "" { + currentCount := int64(0) + + for ok := true; ok; ok = lastEvaluatedKey != "" && currentCount < *pageSize { // Make the DynamoDB Query API call log.WithFields(f).Debug("querying signatures...") results, queryErr := repo.dynamoDBClient.Query(queryInput) @@ -4766,26 +4776,28 @@ func (repo repository) GetClaGroupCorporateContributors(ctx context.Context, cla SignatureApproved: sig.SignatureApproved, SignatureSigned: sig.SignatureSigned, }) + + // Increment the current count + currentCount++ + if currentCount >= *pageSize { + break + } } - if results.LastEvaluatedKey["signature_id"] != nil { + if results.LastEvaluatedKey["signature_id"] != nil && currentCount < *pageSize { lastEvaluatedKey = *results.LastEvaluatedKey["signature_id"].S queryInput.ExclusiveStartKey = results.LastEvaluatedKey } else { lastEvaluatedKey = "" } - if int64(len(out.List)) >= *pageSize { - break - } - } sort.Slice(out.List, func(i, j int) bool { return out.List[i].Name < out.List[j].Name }) - out.ResultCount = int64(len(out.List)) - out.TotalCount = <-totalCountChannel + out.ResultCount = currentCount + out.TotalCount = totalCount out.NextKey = lastEvaluatedKey return out, nil diff --git a/cla-backend/cla/models/docusign_models.py b/cla-backend/cla/models/docusign_models.py index 6591827ad..de52401c4 100644 --- a/cla-backend/cla/models/docusign_models.py +++ b/cla-backend/cla/models/docusign_models.py @@ -18,6 +18,7 @@ import xml.etree.ElementTree as ET from typing import Any, Dict, List, Optional from urllib.parse import urlparse +from datetime import datetime import cla import pydocusign # type: ignore @@ -784,6 +785,8 @@ def _save_employee_signature(self,signature): 'signature_approved': {'BOOL': signature.get_signature_approved()}, '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()}, + 'date_created': {'S': datetime.now().isoformat()} } if signature.get_signature_return_url() is not None: diff --git a/cla-backend/cla/tests/unit/test_ecla.py b/cla-backend/cla/tests/unit/test_ecla.py new file mode 100644 index 000000000..42be1c905 --- /dev/null +++ b/cla-backend/cla/tests/unit/test_ecla.py @@ -0,0 +1,53 @@ +import unittest +from unittest.mock import Mock, patch +import datetime + +from cla.models.docusign_models import DocuSign + +def test_save_employee_signature(project, company, user_instance): + """ Test _save_employee_signature """ + # Mock DocuSign method and related class methods + DocuSign.check_and_prepare_employee_signature = Mock(return_value={'success': {'the employee is ready to sign the CCLA'}}) + + # Create an instance of DocuSign and mock its dynamo_client + docusign = DocuSign() + docusign.dynamo_client = Mock() # Mock the dynamo_client on the instance + mock_put_item = docusign.dynamo_client.put_item = Mock() + + # Mock ecla signature object with necessary attributes for the helper method + signature = Mock() + signature.get_signature_id.return_value = "sig_id" + signature.get_signature_project_id.return_value = "proj_id" + signature.get_signature_document_minor_version.return_value = 1 + signature.get_signature_document_major_version.return_value = 2 + signature.get_signature_reference_id.return_value = "ref_id" + signature.get_signature_reference_type.return_value = "user" + signature.get_signature_type.return_value = "cla" + signature.get_signature_signed.return_value = True + signature.get_signature_approved.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 + signature.get_signature_reference_name.return_value = None + + # Call the helper method + docusign._save_employee_signature(signature) + + # Check if dynamo_client.put_item was called + assert mock_put_item.called + + # Extract the 'Item' argument passed to put_item + _, kwargs = mock_put_item.call_args + item = kwargs['Item'] + + # Assert that 'date_modified' and 'date_created' are in the item + assert 'date_modified' in item + assert 'date_created' in item + + + # Optionally, check if they are correctly formatted ISO timestamps + try: + datetime.datetime.fromisoformat(item['date_modified']['S']) + datetime.datetime.fromisoformat(item['date_created']['S']) + except ValueError: + assert False, "date_modified or date_created are not valid ISO format timestamps"