Skip to content

Commit 535d651

Browse files
committed
[#4468] Bug/Ecla Records
- Script that fixes invalid dates for ecla records Signed-off-by: Harold Wanyama <hwanyama@contractor.linuxfoundation.org>
1 parent 373849c commit 535d651

3 files changed

Lines changed: 289 additions & 0 deletions

File tree

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
// Copyright The Linux Foundation and each contributor to CommunityBridge.
2+
// SPDX-License-Identifier: MIT
3+
4+
package main
5+
6+
import (
7+
"context"
8+
// "fmt"
9+
"os"
10+
"sync"
11+
12+
// "sync"
13+
14+
"github.com/aws/aws-sdk-go/aws"
15+
"github.com/aws/aws-sdk-go/aws/session"
16+
"github.com/communitybridge/easycla/cla-backend-go/company"
17+
18+
// "github.com/aws/aws-sdk-go/service/dynamodb/expression"
19+
"github.com/communitybridge/easycla/cla-backend-go/events"
20+
"github.com/communitybridge/easycla/cla-backend-go/gen/v1/models"
21+
eventOps "github.com/communitybridge/easycla/cla-backend-go/gen/v1/restapi/operations/events"
22+
log "github.com/communitybridge/easycla/cla-backend-go/logging"
23+
"github.com/communitybridge/easycla/cla-backend-go/project/repository"
24+
"github.com/communitybridge/easycla/cla-backend-go/projects_cla_groups"
25+
"github.com/communitybridge/easycla/cla-backend-go/repositories"
26+
"github.com/communitybridge/easycla/cla-backend-go/signatures"
27+
"github.com/communitybridge/easycla/cla-backend-go/users"
28+
"github.com/sirupsen/logrus"
29+
)
30+
31+
var stage string
32+
var eventsRepo events.Repository
33+
var eventsService events.Service
34+
var signatureRepo signatures.SignatureRepository
35+
var v1ProjectRepo repository.ProjectRepository
36+
var usersRepo users.UserRepository
37+
var companyRepo company.IRepository
38+
var ghRepo repositories.Repository
39+
var projectClaGroup projects_cla_groups.Repository
40+
var awsSession = session.Must(session.NewSession(&aws.Config{}))
41+
42+
type combinedRepo struct {
43+
users.UserRepository
44+
company.IRepository
45+
repository.ProjectRepository
46+
projects_cla_groups.Repository
47+
}
48+
49+
func init() {
50+
stage = os.Getenv("STAGE")
51+
if stage == "" {
52+
log.Fatal("STAGE environment variable not set")
53+
}
54+
55+
log.Infof("STAGE: %s", stage)
56+
companyRepo = company.NewRepository(awsSession, stage)
57+
usersRepo = users.NewRepository(awsSession, stage)
58+
ghRepo = *repositories.NewRepository(awsSession, stage)
59+
projectClaGroup = projects_cla_groups.NewRepository(awsSession, stage)
60+
v1ProjectRepo = repository.NewRepository(awsSession, stage, &ghRepo, nil, projectClaGroup)
61+
eventsRepo = events.NewRepository(awsSession, stage)
62+
eventsService = events.NewService(eventsRepo, combinedRepo{
63+
usersRepo,
64+
companyRepo,
65+
v1ProjectRepo,
66+
projectClaGroup,
67+
})
68+
signatureRepo = signatures.NewRepository(awsSession, stage, companyRepo, usersRepo, eventsService, &ghRepo, nil, nil, nil)
69+
70+
log.Infof("initializing migrate_ecla")
71+
}
72+
73+
func main() {
74+
f := logrus.Fields{
75+
"functionName": "main",
76+
"stage": stage,
77+
}
78+
log.WithFields(f).Info("migrate_ecla started")
79+
80+
ctx := context.Background()
81+
// Fetch all the companies
82+
companies, err := companyRepo.GetCompanies(ctx)
83+
if err != nil {
84+
log.WithFields(f).WithError(err).Warn("problem fetching companies")
85+
return
86+
}
87+
88+
invalidSignatures := make([]*signatures.ItemSignature, 0)
89+
90+
log.WithFields(f).Infof("processing %d companies", len(companies.Companies))
91+
// Fetch the ecla records
92+
93+
for _, company := range companies.Companies {
94+
// log.WithFields(f).Infof("processing company: %s", company.CompanyName)
95+
// Fetch the ecla records for the company
96+
invalidCompanyEcla := make([]*signatures.ItemSignature, 0)
97+
eclaRecords, err := signatureRepo.GetCompanyECLASignatures(ctx, company.CompanyID)
98+
if err != nil {
99+
log.WithFields(f).WithError(err).Warn("problem fetching ecla records")
100+
return
101+
}
102+
// log.WithFields(f).Infof("processing %d records for company: %s", len(eclaRecords), company.CompanyID)
103+
104+
if len(eclaRecords) == 0 {
105+
log.WithFields(f).Infof("no records for company: %s", company.CompanyID)
106+
continue
107+
}
108+
109+
var wg sync.WaitGroup
110+
var mu sync.Mutex
111+
for _, eclaRecord := range eclaRecords {
112+
wg.Add(1)
113+
go func(eclaRecord *signatures.ItemSignature) {
114+
defer wg.Done()
115+
// log.WithFields(f).Infof("processing signature record: %s", eclaRecord.SignatureID)
116+
if eclaRecord.DateCreated == "" {
117+
log.WithFields(f).Warnf("invalid signature record: %s", eclaRecord.SignatureID)
118+
mu.Lock()
119+
invalidCompanyEcla = append(invalidCompanyEcla, eclaRecord)
120+
mu.Unlock()
121+
return
122+
}
123+
}(eclaRecord)
124+
}
125+
wg.Wait()
126+
127+
invalidSignatures = append(invalidSignatures, invalidCompanyEcla...)
128+
129+
log.WithFields(f).Debugf("Found %d invalid eclas for company: %s", len(invalidCompanyEcla), company.CompanyID)
130+
}
131+
132+
log.WithFields(f).Infof("Processesing %d invalid records ", len(invalidSignatures))
133+
// For each ecla record, check the events table for the corresponding event and update the signature table
134+
update := 0
135+
136+
for _, eclaRecord := range invalidSignatures {
137+
events, err := getEvents(ctx, *eclaRecord)
138+
if err != nil {
139+
log.WithFields(f).WithError(err).Warnf("problem fetching events for ecla record: %s", eclaRecord.SignatureID)
140+
return
141+
}
142+
143+
if len(events) == 0 {
144+
log.WithFields(f).Warnf("no events found for ecla record: %s and user_id: %s", eclaRecord.SignatureID, eclaRecord.SignatureReferenceID)
145+
continue
146+
}
147+
148+
log.WithFields(f).Infof("found %d events for ecla record: %s", len(events), eclaRecord.SignatureID)
149+
150+
latestEvent := getLatestEvent(events)
151+
if latestEvent == nil {
152+
log.WithFields(f).Warnf("no latest event found for ecla record: %s", eclaRecord.SignatureID)
153+
continue
154+
}
155+
156+
log.Debugf("Found event:%s for user %s", latestEvent.EventID, eclaRecord.SignatureReferenceID)
157+
158+
// Update the signature record
159+
update++
160+
161+
update := map[string]interface{}{
162+
"date_created": latestEvent.EventTime,
163+
"date_modified": latestEvent.EventTime,
164+
}
165+
166+
log.WithFields(f).Infof("updating signature record: %s with : %+v", eclaRecord.SignatureID, update)
167+
168+
err = signatureRepo.UpdateSignature(ctx, eclaRecord.SignatureID, update)
169+
if err != nil {
170+
log.WithFields(f).WithError(err).Warnf("problem updating signature record: %s", eclaRecord.SignatureID)
171+
return
172+
}
173+
174+
log.WithFields(f).Infof("updated signature record: %s", eclaRecord.SignatureID)
175+
}
176+
177+
log.WithFields(f).Infof("updated :%d records", update)
178+
}
179+
180+
func getEvents(ctx context.Context, ecla signatures.ItemSignature) ([]*models.Event, error) {
181+
182+
f := logrus.Fields{
183+
"functionName": "getEvents",
184+
"companyID": ecla.SignatureUserCompanyID,
185+
"projectID": ecla.SignatureProjectID,
186+
"userID": ecla.SignatureReferenceID,
187+
}
188+
189+
log.WithFields(f).Debug("searching events")
190+
191+
eventType := "EmployeeSignatureCreated"
192+
193+
claGroupModel, err := v1ProjectRepo.GetCLAGroupByID(ctx, ecla.SignatureProjectID, false)
194+
if err != nil {
195+
log.WithFields(f).Debugf("Unable to fetch cla group model")
196+
return nil, err
197+
}
198+
199+
eventParams := eventOps.SearchEventsParams{
200+
UserID: &ecla.SignatureReferenceID,
201+
ProjectSFID: &claGroupModel.ProjectExternalID,
202+
EventType: &eventType,
203+
CompanyID: &ecla.SignatureUserCompanyID,
204+
}
205+
206+
events, err := eventsService.SearchEvents(&eventParams)
207+
if err != nil {
208+
log.WithFields(f).WithError(err).Infof("Unable to get clagroup by id: %s", claGroupModel.ProjectID)
209+
return nil, err
210+
}
211+
212+
return events.Events, nil
213+
214+
}
215+
216+
func getLatestEvent(events []*models.Event) *models.Event {
217+
// Fetch the latest event from the list of events
218+
var latestEvent *models.Event
219+
for _, event := range events {
220+
if latestEvent == nil {
221+
latestEvent = event
222+
continue
223+
}
224+
if event.EventTime > latestEvent.EventTime {
225+
latestEvent = event
226+
}
227+
}
228+
return latestEvent
229+
}

cla-backend-go/signatures/mocks/mock_repo.go

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

cla-backend-go/signatures/repository.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ type SignatureRepository interface {
106106
EclaAutoCreate(ctx context.Context, signatureID string, autoCreateECLA bool) error
107107
ActivateSignature(ctx context.Context, signatureID string) error
108108
GetICLAByDate(ctx context.Context, startDate string) ([]ItemSignature, error)
109+
GetCompanyECLASignatures(ctx context.Context, companyID string) ([]*ItemSignature, error)
109110
}
110111

111112
type iclaSignatureWithDetails struct {
@@ -173,6 +174,50 @@ func (repo repository) CreateSignature(ctx context.Context, signature *ItemSigna
173174

174175
}
175176

177+
func (repo repository) GetCompanyECLASignatures(ctx context.Context, companyID string) ([]*ItemSignature, error) {
178+
f := logrus.Fields{
179+
"functionName": "v1.signatures.repository.GetCompanyECLASignatures",
180+
"companyID": companyID,
181+
}
182+
log.WithFields(f).Debugf("fetching company ecla records")
183+
var itemSignatures []*ItemSignature
184+
185+
condition := expression.Key("signature_user_ccla_company_id").Equal(expression.Value(companyID))
186+
filter := expression.Name("signature_signed").Equal(expression.Value(true)).And(expression.Name("signature_approved").Equal(expression.Value(true)))
187+
188+
expr, err := expression.NewBuilder().WithKeyCondition(condition).WithFilter(filter).Build()
189+
if err != nil {
190+
return nil, err
191+
}
192+
193+
// Assemble the query input parameters
194+
queryInput := &dynamodb.QueryInput{
195+
ExpressionAttributeNames: expr.Names(),
196+
ExpressionAttributeValues: expr.Values(),
197+
KeyConditionExpression: expr.KeyCondition(),
198+
FilterExpression: expr.Filter(),
199+
TableName: aws.String(repo.signatureTableName),
200+
IndexName: aws.String("signature-user-ccla-company-index"),
201+
}
202+
203+
results, err := repo.dynamoDBClient.Query(queryInput)
204+
if err != nil {
205+
return nil, err
206+
}
207+
208+
// No match, didn't find it
209+
if *results.Count == 0 {
210+
return nil, nil
211+
}
212+
213+
err = dynamodbattribute.UnmarshalListOfMaps(results.Items, &itemSignatures)
214+
if err != nil {
215+
return nil, err
216+
}
217+
218+
return itemSignatures, nil
219+
}
220+
176221
// GetItemSignature returns the signature for the specified signature id
177222
func (repo repository) GetItemSignature(ctx context.Context, signatureID string) (*ItemSignature, error) {
178223
f := logrus.Fields{

0 commit comments

Comments
 (0)