From db56fb821b3c60554e0c4b9367e9b69a342102f3 Mon Sep 17 00:00:00 2001 From: Alex Saunders Date: Tue, 3 Sep 2024 16:46:25 +0100 Subject: [PATCH 1/3] MLPAB-2134 track failed vouches, vary what happens next --- internal/app/app.go | 1 + internal/donor/donordata/provided.go | 171 +++++++++--------- internal/donor/donordata/provided_test.go | 18 +- .../donor/donorpage/what_you_can_do_now.go | 48 +++-- .../donorpage/what_you_can_do_now_test.go | 66 +++++-- .../identity_with_one_login_callback.go | 13 +- .../identity_with_one_login_callback_test.go | 114 +++++++++++- .../voucherpage/mock_DonorStore_test.go | 142 +++++++++++++++ internal/voucher/voucherpage/register.go | 11 +- internal/voucher/voucherpage/register_test.go | 2 +- .../voucherpage/verify_donor_details.go | 13 +- .../voucherpage/verify_donor_details_test.go | 91 ++++++++-- lang/cy.json | 6 +- lang/en.json | 8 +- web/template/donor/what_you_can_do_now.gohtml | 24 ++- 15 files changed, 586 insertions(+), 142 deletions(-) create mode 100644 internal/voucher/voucherpage/mock_DonorStore_test.go diff --git a/internal/app/app.go b/internal/app/app.go index 03628c2af4..ac93fa5696 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -170,6 +170,7 @@ func App( lpaStoreResolvingService, notifyClient, appPublicURL, + donorStore, ) supporterpage.Register( diff --git a/internal/donor/donordata/provided.go b/internal/donor/donordata/provided.go index 4b472bed64..138628369f 100644 --- a/internal/donor/donordata/provided.go +++ b/internal/donor/donordata/provided.go @@ -135,6 +135,8 @@ type Provided struct { WantVoucher form.YesNo // Voucher is a person the donor has nominated to vouch for their identity Voucher Voucher + // FailedVouchAttempts are the number of unsuccessful attempts a voucher has made to confirm the Donors ID + FailedVouchAttempts int // Codes used for the certificate provider to witness signing CertificateProviderCodes WitnessCodes @@ -159,8 +161,8 @@ type Provided struct { HasSentApplicationUpdatedEvent bool `hash:"-"` } -func (d *Provided) HashInclude(field string, _ any) (bool, error) { - if d.HashVersion > currentHashVersion { +func (p *Provided) HashInclude(field string, _ any) (bool, error) { + if p.HashVersion > currentHashVersion { return false, errors.New("HashVersion too high") } @@ -202,57 +204,58 @@ func (c toCheck) HashInclude(field string, _ any) (bool, error) { "PreviousFee", "RegisteringWithCourtOfProtection", "WantVoucher", - "Voucher": + "Voucher", + "FailedVouchAttempts": return false, nil } return true, nil } -func (l *Provided) NamesChanged(firstNames, lastName, otherNames string) bool { - return l.Donor.FirstNames != firstNames || l.Donor.LastName != lastName || l.Donor.OtherNames != otherNames +func (p *Provided) NamesChanged(firstNames, lastName, otherNames string) bool { + return p.Donor.FirstNames != firstNames || p.Donor.LastName != lastName || p.Donor.OtherNames != otherNames } -func (l *Provided) HashChanged() bool { - hash, _ := l.generateHash() +func (p *Provided) HashChanged() bool { + hash, _ := p.generateHash() - return hash != l.Hash + return hash != p.Hash } -func (l *Provided) UpdateHash() (err error) { - l.HashVersion = currentHashVersion - l.Hash, err = l.generateHash() +func (p *Provided) UpdateHash() (err error) { + p.HashVersion = currentHashVersion + p.Hash, err = p.generateHash() return err } -func (l *Provided) generateHash() (uint64, error) { - return hashstructure.Hash(l, hashstructure.FormatV2, nil) +func (p *Provided) generateHash() (uint64, error) { + return hashstructure.Hash(p, hashstructure.FormatV2, nil) } -func (l *Provided) CheckedHashChanged() bool { - hash, _ := l.generateCheckedHash() +func (p *Provided) CheckedHashChanged() bool { + hash, _ := p.generateCheckedHash() - return hash != l.CheckedHash + return hash != p.CheckedHash } -func (l *Provided) UpdateCheckedHash() (err error) { - l.CheckedHashVersion = currentCheckedHashVersion - l.CheckedHash, err = l.generateCheckedHash() +func (p *Provided) UpdateCheckedHash() (err error) { + p.CheckedHashVersion = currentCheckedHashVersion + p.CheckedHash, err = p.generateCheckedHash() return err } -func (l *Provided) generateCheckedHash() (uint64, error) { - return hashstructure.Hash(toCheck(*l), hashstructure.FormatV2, nil) +func (p *Provided) generateCheckedHash() (uint64, error) { + return hashstructure.Hash(toCheck(*p), hashstructure.FormatV2, nil) } -func (l *Provided) DonorIdentityConfirmed() bool { - return l.DonorIdentityUserData.Status.IsConfirmed() && - l.DonorIdentityUserData.MatchName(l.Donor.FirstNames, l.Donor.LastName) && - l.DonorIdentityUserData.DateOfBirth.Equals(l.Donor.DateOfBirth) +func (p *Provided) DonorIdentityConfirmed() bool { + return p.DonorIdentityUserData.Status.IsConfirmed() && + p.DonorIdentityUserData.MatchName(p.Donor.FirstNames, p.Donor.LastName) && + p.DonorIdentityUserData.DateOfBirth.Equals(p.Donor.DateOfBirth) } -func (l *Provided) AttorneysAndCpSigningDeadline() time.Time { - return l.SignedAt.Add((24 * time.Hour) * 28) +func (p *Provided) AttorneysAndCpSigningDeadline() time.Time { + return p.SignedAt.Add((24 * time.Hour) * 28) } type Under18ActorDetails struct { @@ -262,11 +265,11 @@ type Under18ActorDetails struct { Type actor.Type } -func (l *Provided) Under18ActorDetails() []Under18ActorDetails { +func (p *Provided) Under18ActorDetails() []Under18ActorDetails { var data []Under18ActorDetails eighteenYearsAgo := date.Today().AddDate(-18, 0, 0) - for _, a := range l.Attorneys.Attorneys { + for _, a := range p.Attorneys.Attorneys { if a.DateOfBirth.After(eighteenYearsAgo) { data = append(data, Under18ActorDetails{ FullName: a.FullName(), @@ -277,7 +280,7 @@ func (l *Provided) Under18ActorDetails() []Under18ActorDetails { } } - for _, ra := range l.ReplacementAttorneys.Attorneys { + for _, ra := range p.ReplacementAttorneys.Attorneys { if ra.DateOfBirth.After(eighteenYearsAgo) { data = append(data, Under18ActorDetails{ FullName: ra.FullName(), @@ -291,32 +294,32 @@ func (l *Provided) Under18ActorDetails() []Under18ActorDetails { return data } -func (l *Provided) CorrespondentEmail() string { - if l.Correspondent.Email == "" { - return l.Donor.Email +func (p *Provided) CorrespondentEmail() string { + if p.Correspondent.Email == "" { + return p.Donor.Email } - return l.Correspondent.Email + return p.Correspondent.Email } -func (l *Provided) ActorAddresses() []place.Address { +func (p *Provided) ActorAddresses() []place.Address { var addresses []place.Address - if l.Donor.Address.String() != "" { - addresses = append(addresses, l.Donor.Address) + if p.Donor.Address.String() != "" { + addresses = append(addresses, p.Donor.Address) } - if l.CertificateProvider.Address.String() != "" && !slices.Contains(addresses, l.CertificateProvider.Address) { - addresses = append(addresses, l.CertificateProvider.Address) + if p.CertificateProvider.Address.String() != "" && !slices.Contains(addresses, p.CertificateProvider.Address) { + addresses = append(addresses, p.CertificateProvider.Address) } - for _, address := range l.Attorneys.Addresses() { + for _, address := range p.Attorneys.Addresses() { if address.String() != "" && !slices.Contains(addresses, address) { addresses = append(addresses, address) } } - for _, address := range l.ReplacementAttorneys.Addresses() { + for _, address := range p.ReplacementAttorneys.Addresses() { if address.String() != "" && !slices.Contains(addresses, address) { addresses = append(addresses, address) } @@ -325,86 +328,86 @@ func (l *Provided) ActorAddresses() []place.Address { return addresses } -func (l *Provided) AllLayAttorneysFirstNames() []string { +func (p *Provided) AllLayAttorneysFirstNames() []string { var names []string - for _, a := range l.Attorneys.Attorneys { + for _, a := range p.Attorneys.Attorneys { names = append(names, a.FirstNames) } - for _, a := range l.ReplacementAttorneys.Attorneys { + for _, a := range p.ReplacementAttorneys.Attorneys { names = append(names, a.FirstNames) } return names } -func (l *Provided) AllLayAttorneysFullNames() []string { +func (p *Provided) AllLayAttorneysFullNames() []string { var names []string - for _, a := range l.Attorneys.Attorneys { + for _, a := range p.Attorneys.Attorneys { names = append(names, a.FullName()) } - for _, a := range l.ReplacementAttorneys.Attorneys { + for _, a := range p.ReplacementAttorneys.Attorneys { names = append(names, a.FullName()) } return names } -func (l *Provided) TrustCorporationsNames() []string { +func (p *Provided) TrustCorporationsNames() []string { var names []string - if l.Attorneys.TrustCorporation.Name != "" { - names = append(names, l.Attorneys.TrustCorporation.Name) + if p.Attorneys.TrustCorporation.Name != "" { + names = append(names, p.Attorneys.TrustCorporation.Name) } - if l.ReplacementAttorneys.TrustCorporation.Name != "" { - names = append(names, l.ReplacementAttorneys.TrustCorporation.Name) + if p.ReplacementAttorneys.TrustCorporation.Name != "" { + names = append(names, p.ReplacementAttorneys.TrustCorporation.Name) } return names } -func (l *Provided) Cost() int { - if l.Tasks.PayForLpa.IsDenied() { +func (p *Provided) Cost() int { + if p.Tasks.PayForLpa.IsDenied() { return 8200 } - return pay.Cost(l.FeeType, l.PreviousFee) + return pay.Cost(p.FeeType, p.PreviousFee) } -func (l *Provided) FeeAmount() pay.AmountPence { +func (p *Provided) FeeAmount() pay.AmountPence { paid := 0 - for _, payment := range l.PaymentDetails { + for _, payment := range p.PaymentDetails { paid += payment.Amount } - return pay.AmountPence(l.Cost() - paid) + return pay.AmountPence(p.Cost() - paid) } // CertificateProviderSharesDetails will return true if the last name or address // of the certificate provider matches that of the donor or one of the // attorneys. For a match of the last name we break on '-' to account for // double-barrelled names. -func (l *Provided) CertificateProviderSharesDetails() bool { - certificateProviderParts := strings.Split(l.CertificateProvider.LastName, "-") +func (p *Provided) CertificateProviderSharesDetails() bool { + certificateProviderParts := strings.Split(p.CertificateProvider.LastName, "-") - donorParts := strings.Split(l.Donor.LastName, "-") + donorParts := strings.Split(p.Donor.LastName, "-") for _, certificateProviderPart := range certificateProviderParts { if slices.Contains(donorParts, certificateProviderPart) { return true } - if l.CertificateProvider.Address.Line1 == l.Donor.Address.Line1 && - l.CertificateProvider.Address.Postcode == l.Donor.Address.Postcode { + if p.CertificateProvider.Address.Line1 == p.Donor.Address.Line1 && + p.CertificateProvider.Address.Postcode == p.Donor.Address.Postcode { return true } } - for _, attorney := range append(l.Attorneys.Attorneys, l.ReplacementAttorneys.Attorneys...) { + for _, attorney := range append(p.Attorneys.Attorneys, p.ReplacementAttorneys.Attorneys...) { attorneyParts := strings.Split(attorney.LastName, "-") for _, certificateProviderPart := range certificateProviderParts { @@ -412,8 +415,8 @@ func (l *Provided) CertificateProviderSharesDetails() bool { return true } - if l.CertificateProvider.Address.Line1 == attorney.Address.Line1 && - l.CertificateProvider.Address.Postcode == attorney.Address.Postcode { + if p.CertificateProvider.Address.Line1 == attorney.Address.Line1 && + p.CertificateProvider.Address.Postcode == attorney.Address.Postcode { return true } } @@ -424,27 +427,27 @@ func (l *Provided) CertificateProviderSharesDetails() bool { // Actors returns an iterator over all human actors named on the LPA (i.e. this // excludes trust corporations, the correspondent, and the voucher). -func (l *Provided) Actors() iter.Seq[actor.Actor] { +func (p *Provided) Actors() iter.Seq[actor.Actor] { return func(yield func(actor.Actor) bool) { if !yield(actor.Actor{ Type: actor.TypeDonor, - UID: l.Donor.UID, - FirstNames: l.Donor.FirstNames, - LastName: l.Donor.LastName, + UID: p.Donor.UID, + FirstNames: p.Donor.FirstNames, + LastName: p.Donor.LastName, }) { return } if !yield(actor.Actor{ Type: actor.TypeCertificateProvider, - UID: l.CertificateProvider.UID, - FirstNames: l.CertificateProvider.FirstNames, - LastName: l.CertificateProvider.LastName, + UID: p.CertificateProvider.UID, + FirstNames: p.CertificateProvider.FirstNames, + LastName: p.CertificateProvider.LastName, }) { return } - for _, attorney := range l.Attorneys.Attorneys { + for _, attorney := range p.Attorneys.Attorneys { if !yield(actor.Actor{ Type: actor.TypeAttorney, UID: attorney.UID, @@ -455,7 +458,7 @@ func (l *Provided) Actors() iter.Seq[actor.Actor] { } } - for _, attorney := range l.ReplacementAttorneys.Attorneys { + for _, attorney := range p.ReplacementAttorneys.Attorneys { if !yield(actor.Actor{ Type: actor.TypeReplacementAttorney, UID: attorney.UID, @@ -466,7 +469,7 @@ func (l *Provided) Actors() iter.Seq[actor.Actor] { } } - for _, person := range l.PeopleToNotify { + for _, person := range p.PeopleToNotify { if !yield(actor.Actor{ Type: actor.TypePersonToNotify, UID: person.UID, @@ -477,24 +480,28 @@ func (l *Provided) Actors() iter.Seq[actor.Actor] { } } - if l.AuthorisedSignatory.FirstNames != "" { + if p.AuthorisedSignatory.FirstNames != "" { if !yield(actor.Actor{ Type: actor.TypeAuthorisedSignatory, - FirstNames: l.AuthorisedSignatory.FirstNames, - LastName: l.AuthorisedSignatory.LastName, + FirstNames: p.AuthorisedSignatory.FirstNames, + LastName: p.AuthorisedSignatory.LastName, }) { return } } - if l.IndependentWitness.FirstNames != "" { + if p.IndependentWitness.FirstNames != "" { if !yield(actor.Actor{ Type: actor.TypeIndependentWitness, - FirstNames: l.IndependentWitness.FirstNames, - LastName: l.IndependentWitness.LastName, + FirstNames: p.IndependentWitness.FirstNames, + LastName: p.IndependentWitness.LastName, }) { return } } } } + +func (p *Provided) CanHaveVoucher() bool { + return p.FailedVouchAttempts < 2 +} diff --git a/internal/donor/donordata/provided_test.go b/internal/donor/donordata/provided_test.go index 12a2ae0ca0..aecdd22e3b 100644 --- a/internal/donor/donordata/provided_test.go +++ b/internal/donor/donordata/provided_test.go @@ -36,14 +36,14 @@ func TestGenerateHash(t *testing.T) { } // DO change this value to match the updates - const modified uint64 = 0x4765981bee80f0a4 + const modified uint64 = 0xa66eaae2dbca5f95 // DO NOT change these initial hash values. If a field has been added/removed // you will need to handle the version gracefully by modifying // (*Provided).HashInclude and adding another testcase for the new // version. testcases := map[uint8]uint64{ - 0: 0x2d6528866eb5ccbf, + 0: 0x19fb86f631b8b355, } for version, initial := range testcases { @@ -470,3 +470,17 @@ func TestProvidedActors(t *testing.T) { LastName: "Wit", }}, actors) } + +func TestProvidedCanHaveVoucher(t *testing.T) { + provided := Provided{} + assert.True(t, provided.CanHaveVoucher()) + + provided.FailedVouchAttempts++ + assert.True(t, provided.CanHaveVoucher()) + + provided.FailedVouchAttempts++ + assert.False(t, provided.CanHaveVoucher()) + + provided.FailedVouchAttempts++ + assert.False(t, provided.CanHaveVoucher()) +} diff --git a/internal/donor/donorpage/what_you_can_do_now.go b/internal/donor/donorpage/what_you_can_do_now.go index 826a30f78f..c264c2c9d6 100644 --- a/internal/donor/donorpage/what_you_can_do_now.go +++ b/internal/donor/donorpage/what_you_can_do_now.go @@ -14,9 +14,12 @@ import ( ) type whatYouCanDoNowData struct { - App appcontext.Data - Errors validation.List - Form *whatYouCanDoNowForm + App appcontext.Data + Errors validation.List + Form *whatYouCanDoNowForm + NewVoucherLabel string + BannerContent string + FailedVouchAttempts int } func WhatYouCanDoNow(tmpl template.Template, donorStore DonorStore) Handler { @@ -24,12 +27,14 @@ func WhatYouCanDoNow(tmpl template.Template, donorStore DonorStore) Handler { data := &whatYouCanDoNowData{ App: appData, Form: &whatYouCanDoNowForm{ - Options: donordata.NoVoucherDecisionValues, + Options: donordata.NoVoucherDecisionValues, + CanHaveVoucher: provided.CanHaveVoucher(), }, + FailedVouchAttempts: provided.FailedVouchAttempts, } if r.Method == http.MethodPost { - data.Form = readWhatYouCanDoNowForm(r) + data.Form = readWhatYouCanDoNowForm(r, provided) data.Errors = data.Form.Validate() if data.Errors.None() { @@ -57,23 +62,36 @@ func WhatYouCanDoNow(tmpl template.Template, donorStore DonorStore) Handler { } } + switch provided.FailedVouchAttempts { + case 0: + data.BannerContent = "youHaveNotChosenAnyoneToVouchForYou" + data.NewVoucherLabel = "iHaveSomeoneWhoCanVouch" + case 1: + data.BannerContent = "thePersonYouAskedToVouchHasBeenUnableToContinue" + data.NewVoucherLabel = "iHaveSomeoneElseWhoCanVouch" + default: + data.BannerContent = "thePersonYouAskedToVouchHasBeenUnableToContinueSecondAttempt" + } + return tmpl(w, data) } } type whatYouCanDoNowForm struct { - DoNext donordata.NoVoucherDecision - Error error - Options donordata.NoVoucherDecisionOptions + DoNext donordata.NoVoucherDecision + Error error + Options donordata.NoVoucherDecisionOptions + CanHaveVoucher bool } -func readWhatYouCanDoNowForm(r *http.Request) *whatYouCanDoNowForm { +func readWhatYouCanDoNowForm(r *http.Request, provided *donordata.Provided) *whatYouCanDoNowForm { doNext, err := donordata.ParseNoVoucherDecision(page.PostFormString(r, "do-next")) return &whatYouCanDoNowForm{ - DoNext: doNext, - Error: err, - Options: donordata.NoVoucherDecisionValues, + DoNext: doNext, + Error: err, + Options: donordata.NoVoucherDecisionValues, + CanHaveVoucher: provided.CanHaveVoucher(), } } @@ -83,5 +101,11 @@ func (f *whatYouCanDoNowForm) Validate() validation.List { errors.Error("do-next", "whatYouWouldLikeToDo", f.Error, validation.Selected()) + if !f.CanHaveVoucher && f.DoNext.IsSelectNewVoucher() { + errors.Add("do-next", validation.CustomError{ + Label: "youCannotAskAnotherPersonToVouchForYou", + }) + } + return errors } diff --git a/internal/donor/donorpage/what_you_can_do_now_test.go b/internal/donor/donorpage/what_you_can_do_now_test.go index 28239890ae..92fb55e877 100644 --- a/internal/donor/donorpage/what_you_can_do_now_test.go +++ b/internal/donor/donorpage/what_you_can_do_now_test.go @@ -4,6 +4,7 @@ import ( "net/http" "net/http/httptest" "net/url" + "strconv" "strings" "testing" @@ -18,22 +19,51 @@ import ( ) func TestGetWhatYouCanDoNow(t *testing.T) { - w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/", nil) + testcases := map[int]struct { + BannerContent string + NewVoucherLabel string + CanHaveVoucher bool + }{ + 0: { + BannerContent: "youHaveNotChosenAnyoneToVouchForYou", + NewVoucherLabel: "iHaveSomeoneWhoCanVouch", + CanHaveVoucher: true, + }, + 1: { + BannerContent: "thePersonYouAskedToVouchHasBeenUnableToContinue", + NewVoucherLabel: "iHaveSomeoneElseWhoCanVouch", + CanHaveVoucher: true, + }, + 2: { + BannerContent: "thePersonYouAskedToVouchHasBeenUnableToContinueSecondAttempt", + }, + } - template := newMockTemplate(t) - template.EXPECT(). - Execute(w, &whatYouCanDoNowData{ - App: testAppData, - Form: &whatYouCanDoNowForm{ - Options: donordata.NoVoucherDecisionValues, - }, - }). - Return(nil) + for failedVouchAttempts, tc := range testcases { + t.Run(strconv.Itoa(failedVouchAttempts), func(t *testing.T) { + w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodGet, "/", nil) + + template := newMockTemplate(t) + template.EXPECT(). + Execute(w, &whatYouCanDoNowData{ + App: testAppData, + Form: &whatYouCanDoNowForm{ + Options: donordata.NoVoucherDecisionValues, + CanHaveVoucher: tc.CanHaveVoucher, + }, + FailedVouchAttempts: failedVouchAttempts, + BannerContent: tc.BannerContent, + NewVoucherLabel: tc.NewVoucherLabel, + }). + Return(nil) - err := WhatYouCanDoNow(template.Execute, nil)(testAppData, w, r, &donordata.Provided{}) + err := WhatYouCanDoNow(template.Execute, nil)(testAppData, w, r, &donordata.Provided{FailedVouchAttempts: failedVouchAttempts}) + + assert.Nil(t, err) + }) + } - assert.Nil(t, err) } func TestGetWhatYouCanDoNowWhenTemplateError(t *testing.T) { @@ -166,7 +196,7 @@ func TestReadWhatYouCanDoNowForm(t *testing.T) { r, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(form.Encode())) r.Header.Add("Content-Type", page.FormUrlEncoded) - result := readWhatYouCanDoNowForm(r) + result := readWhatYouCanDoNowForm(r, &donordata.Provided{}) assert.Equal(donordata.WithdrawLPA, result.DoNext) assert.Nil(result.Error) @@ -190,6 +220,14 @@ func TestWhatYouCanDoNowFormValidate(t *testing.T) { errors: validation. With("do-next", validation.SelectError{Label: "whatYouWouldLikeToDo"}), }, + "not allowed another vouch": { + form: &whatYouCanDoNowForm{ + DoNext: donordata.SelectNewVoucher, + CanHaveVoucher: false, + }, + errors: validation. + With("do-next", validation.CustomError{Label: "youCannotAskAnotherPersonToVouchForYou"}), + }, } for name, tc := range testCases { diff --git a/internal/voucher/voucherpage/identity_with_one_login_callback.go b/internal/voucher/voucherpage/identity_with_one_login_callback.go index 4bc49588a0..284ccf8d12 100644 --- a/internal/voucher/voucherpage/identity_with_one_login_callback.go +++ b/internal/voucher/voucherpage/identity_with_one_login_callback.go @@ -12,7 +12,7 @@ import ( "github.com/ministryofjustice/opg-modernising-lpa/internal/voucher/voucherdata" ) -func IdentityWithOneLoginCallback(oneLoginClient OneLoginClient, sessionStore SessionStore, voucherStore VoucherStore, lpaStoreResolvingService LpaStoreResolvingService, notifyClient NotifyClient, appPublicURL string) Handler { +func IdentityWithOneLoginCallback(oneLoginClient OneLoginClient, sessionStore SessionStore, voucherStore VoucherStore, lpaStoreResolvingService LpaStoreResolvingService, notifyClient NotifyClient, appPublicURL string, donorStore DonorStore) Handler { return func(appData appcontext.Data, w http.ResponseWriter, r *http.Request, provided *voucherdata.Provided) error { lpa, err := lpaStoreResolvingService.Get(r.Context()) if err != nil { @@ -56,6 +56,17 @@ func IdentityWithOneLoginCallback(oneLoginClient OneLoginClient, sessionStore Se } if !provided.IdentityConfirmed() { + donor, err := donorStore.GetAny(r.Context()) + if err != nil { + return err + } + + donor.FailedVouchAttempts++ + + if err := donorStore.Put(r.Context(), donor); err != nil { + return err + } + if !lpa.SignedAt.IsZero() { if err = notifyClient.SendActorEmail(r.Context(), lpa.CorrespondentEmail(), lpa.LpaUID, notify.VoucherFailedIdentityCheckEmail{ Greeting: notifyClient.EmailGreeting(lpa), diff --git a/internal/voucher/voucherpage/identity_with_one_login_callback_test.go b/internal/voucher/voucherpage/identity_with_one_login_callback_test.go index a09f4c1e3c..4a4b9f84c9 100644 --- a/internal/voucher/voucherpage/identity_with_one_login_callback_test.go +++ b/internal/voucher/voucherpage/identity_with_one_login_callback_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/ministryofjustice/opg-modernising-lpa/internal/donor/donordata" "github.com/ministryofjustice/opg-modernising-lpa/internal/identity" "github.com/ministryofjustice/opg-modernising-lpa/internal/lpastore/lpadata" "github.com/ministryofjustice/opg-modernising-lpa/internal/notify" @@ -90,7 +91,7 @@ func TestGetIdentityWithOneLoginCallback(t *testing.T) { ParseIdentityClaim(r.Context(), userInfo). Return(userData, nil) - err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, nil, "www.example.com")(testAppData, w, r, &voucherdata.Provided{ + err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, nil, "www.example.com", nil)(testAppData, w, r, &voucherdata.Provided{ LpaID: "lpa-id", FirstNames: "John", LastName: "Doe", @@ -164,7 +165,15 @@ func TestGetIdentityWithOneLoginCallbackWhenFailedIdentityCheck(t *testing.T) { }). Return(nil) - err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, notifyClient, "www.example.com")(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) + donorStore := newMockDonorStore(t) + donorStore.EXPECT(). + GetAny(r.Context()). + Return(&donordata.Provided{}, nil) + donorStore.EXPECT(). + Put(r.Context(), &donordata.Provided{FailedVouchAttempts: 1}). + Return(nil) + + err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, notifyClient, "www.example.com", donorStore)(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) resp := w.Result() assert.Nil(t, err) @@ -211,6 +220,14 @@ func TestGetIdentityWithOneLoginCallbackWhenSendingEmailError(t *testing.T) { ParseIdentityClaim(mock.Anything, mock.Anything). Return(userData, nil) + donorStore := newMockDonorStore(t) + donorStore.EXPECT(). + GetAny(r.Context()). + Return(&donordata.Provided{}, nil) + donorStore.EXPECT(). + Put(r.Context(), &donordata.Provided{FailedVouchAttempts: 1}). + Return(nil) + localizer := newMockLocalizer(t) localizer.EXPECT(). T(mock.Anything). @@ -226,7 +243,7 @@ func TestGetIdentityWithOneLoginCallbackWhenSendingEmailError(t *testing.T) { SendActorEmail(mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(expectedError) - err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, notifyClient, "www.example.com")(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) + err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, notifyClient, "www.example.com", donorStore)(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) resp := w.Result() assert.Equal(t, expectedError, err) @@ -250,11 +267,15 @@ func TestGetIdentityWithOneLoginCallbackWhenIdentityNotConfirmed(t *testing.T) { voucherIgnored := func(t *testing.T) *mockVoucherStore { return nil } + donorIgnored := func(t *testing.T) *mockDonorStore { + return nil + } testCases := map[string]struct { oneLoginClient func(t *testing.T) *mockOneLoginClient sessionStore func(*testing.T) *mockSessionStore voucherStore func(t *testing.T) *mockVoucherStore + donorStore func(t *testing.T) *mockDonorStore url string error error expectedRedirectURL string @@ -287,6 +308,16 @@ func TestGetIdentityWithOneLoginCallbackWhenIdentityNotConfirmed(t *testing.T) { return voucherStore }, + donorStore: func(t *testing.T) *mockDonorStore { + d := newMockDonorStore(t) + d.EXPECT(). + GetAny(mock.Anything). + Return(&donordata.Provided{}, nil) + d.EXPECT(). + Put(mock.Anything, mock.Anything). + Return(nil) + return d + }, expectedRedirectURL: voucher.PathUnableToConfirmIdentity.Format("lpa-id"), expectedStatus: http.StatusFound, }, @@ -308,6 +339,7 @@ func TestGetIdentityWithOneLoginCallbackWhenIdentityNotConfirmed(t *testing.T) { sessionStore: sessionRetrieved, error: expectedError, voucherStore: voucherIgnored, + donorStore: donorIgnored, expectedStatus: http.StatusOK, }, "errored on userinfo": { @@ -325,6 +357,7 @@ func TestGetIdentityWithOneLoginCallbackWhenIdentityNotConfirmed(t *testing.T) { sessionStore: sessionRetrieved, error: expectedError, voucherStore: voucherIgnored, + donorStore: donorIgnored, expectedStatus: http.StatusOK, }, "errored on exchange": { @@ -339,6 +372,7 @@ func TestGetIdentityWithOneLoginCallbackWhenIdentityNotConfirmed(t *testing.T) { sessionStore: sessionRetrieved, error: expectedError, voucherStore: voucherIgnored, + donorStore: donorIgnored, expectedStatus: http.StatusOK, }, "errored on session store": { @@ -355,6 +389,7 @@ func TestGetIdentityWithOneLoginCallbackWhenIdentityNotConfirmed(t *testing.T) { }, error: expectedError, voucherStore: voucherIgnored, + donorStore: donorIgnored, expectedStatus: http.StatusOK, }, "provider access denied": { @@ -365,6 +400,7 @@ func TestGetIdentityWithOneLoginCallbackWhenIdentityNotConfirmed(t *testing.T) { sessionStore: sessionIgnored, error: errors.New("access denied"), voucherStore: voucherIgnored, + donorStore: donorIgnored, expectedStatus: http.StatusOK, }, } @@ -382,7 +418,7 @@ func TestGetIdentityWithOneLoginCallbackWhenIdentityNotConfirmed(t *testing.T) { sessionStore := tc.sessionStore(t) oneLoginClient := tc.oneLoginClient(t) - err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, tc.voucherStore(t), lpaStoreResolvingService, nil, "www.example.com")(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) + err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, tc.voucherStore(t), lpaStoreResolvingService, nil, "www.example.com", tc.donorStore(t))(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) resp := w.Result() assert.Equal(t, tc.error, err) @@ -401,7 +437,7 @@ func TestGetIdentityWithOneLoginCallbackWhenGetLpaStoreResolvingServiceError(t * Get(r.Context()). Return(&lpadata.Lpa{Voucher: lpadata.Voucher{}}, expectedError) - err := IdentityWithOneLoginCallback(nil, nil, nil, lpaStoreResolvingService, nil, "www.example.com")(testAppData, w, r, &voucherdata.Provided{}) + err := IdentityWithOneLoginCallback(nil, nil, nil, lpaStoreResolvingService, nil, "www.example.com", nil)(testAppData, w, r, &voucherdata.Provided{}) assert.Equal(t, expectedError, err) } @@ -437,7 +473,73 @@ func TestGetIdentityWithOneLoginCallbackWhenPutVoucherStoreError(t *testing.T) { ParseIdentityClaim(mock.Anything, mock.Anything). Return(identity.UserData{Status: identity.StatusConfirmed}, nil) - err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, nil, "www.example.com")(testAppData, w, r, &voucherdata.Provided{}) + err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, nil, "www.example.com", nil)(testAppData, w, r, &voucherdata.Provided{}) assert.Equal(t, expectedError, err) } + +func TestGetIdentityWithOneLoginCallbackFailedIdentityWhenDonorStoreGetAnyError(t *testing.T) { + testcases := map[string]struct { + donorStore func(t *testing.T) *mockDonorStore + }{ + "GetAny": { + donorStore: func(t *testing.T) *mockDonorStore { + d := newMockDonorStore(t) + d.EXPECT(). + GetAny(mock.Anything). + Return(&donordata.Provided{}, expectedError) + return d + }, + }, + "Put": { + donorStore: func(t *testing.T) *mockDonorStore { + d := newMockDonorStore(t) + d.EXPECT(). + GetAny(mock.Anything). + Return(&donordata.Provided{}, nil) + d.EXPECT(). + Put(mock.Anything, mock.Anything). + Return(expectedError) + return d + }, + }, + } + + for donorStoreFuncName, tc := range testcases { + t.Run(donorStoreFuncName, func(t *testing.T) { + w := httptest.NewRecorder() + r, _ := http.NewRequest(http.MethodGet, "/?code=a-code", nil) + userInfo := onelogin.UserInfo{CoreIdentityJWT: "an-identity-jwt"} + + voucherStore := newMockVoucherStore(t) + voucherStore.EXPECT(). + Put(r.Context(), mock.Anything). + Return(nil) + + lpaStoreResolvingService := newMockLpaStoreResolvingService(t) + lpaStoreResolvingService.EXPECT(). + Get(r.Context()). + Return(&lpadata.Lpa{Voucher: lpadata.Voucher{}}, nil) + + sessionStore := newMockSessionStore(t) + sessionStore.EXPECT(). + OneLogin(mock.Anything). + Return(&sesh.OneLoginSession{State: "a-state", Nonce: "a-nonce", Redirect: "/redirect"}, nil) + + oneLoginClient := newMockOneLoginClient(t) + oneLoginClient.EXPECT(). + Exchange(mock.Anything, mock.Anything, mock.Anything). + Return("id-token", "a-jwt", nil) + oneLoginClient.EXPECT(). + UserInfo(mock.Anything, mock.Anything). + Return(userInfo, nil) + oneLoginClient.EXPECT(). + ParseIdentityClaim(mock.Anything, mock.Anything). + Return(identity.UserData{Status: identity.StatusFailed}, nil) + + err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, nil, "www.example.com", tc.donorStore(t))(testAppData, w, r, &voucherdata.Provided{}) + + assert.Equal(t, expectedError, err) + }) + } +} diff --git a/internal/voucher/voucherpage/mock_DonorStore_test.go b/internal/voucher/voucherpage/mock_DonorStore_test.go new file mode 100644 index 0000000000..57a2ed4620 --- /dev/null +++ b/internal/voucher/voucherpage/mock_DonorStore_test.go @@ -0,0 +1,142 @@ +// Code generated by mockery v2.45.0. DO NOT EDIT. + +package voucherpage + +import ( + context "context" + + donordata "github.com/ministryofjustice/opg-modernising-lpa/internal/donor/donordata" + mock "github.com/stretchr/testify/mock" +) + +// mockDonorStore is an autogenerated mock type for the DonorStore type +type mockDonorStore struct { + mock.Mock +} + +type mockDonorStore_Expecter struct { + mock *mock.Mock +} + +func (_m *mockDonorStore) EXPECT() *mockDonorStore_Expecter { + return &mockDonorStore_Expecter{mock: &_m.Mock} +} + +// GetAny provides a mock function with given fields: ctx +func (_m *mockDonorStore) GetAny(ctx context.Context) (*donordata.Provided, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAny") + } + + var r0 *donordata.Provided + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*donordata.Provided, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *donordata.Provided); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*donordata.Provided) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockDonorStore_GetAny_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAny' +type mockDonorStore_GetAny_Call struct { + *mock.Call +} + +// GetAny is a helper method to define mock.On call +// - ctx context.Context +func (_e *mockDonorStore_Expecter) GetAny(ctx interface{}) *mockDonorStore_GetAny_Call { + return &mockDonorStore_GetAny_Call{Call: _e.mock.On("GetAny", ctx)} +} + +func (_c *mockDonorStore_GetAny_Call) Run(run func(ctx context.Context)) *mockDonorStore_GetAny_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *mockDonorStore_GetAny_Call) Return(_a0 *donordata.Provided, _a1 error) *mockDonorStore_GetAny_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockDonorStore_GetAny_Call) RunAndReturn(run func(context.Context) (*donordata.Provided, error)) *mockDonorStore_GetAny_Call { + _c.Call.Return(run) + return _c +} + +// Put provides a mock function with given fields: ctx, donor +func (_m *mockDonorStore) Put(ctx context.Context, donor *donordata.Provided) error { + ret := _m.Called(ctx, donor) + + if len(ret) == 0 { + panic("no return value specified for Put") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *donordata.Provided) error); ok { + r0 = rf(ctx, donor) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockDonorStore_Put_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Put' +type mockDonorStore_Put_Call struct { + *mock.Call +} + +// Put is a helper method to define mock.On call +// - ctx context.Context +// - donor *donordata.Provided +func (_e *mockDonorStore_Expecter) Put(ctx interface{}, donor interface{}) *mockDonorStore_Put_Call { + return &mockDonorStore_Put_Call{Call: _e.mock.On("Put", ctx, donor)} +} + +func (_c *mockDonorStore_Put_Call) Run(run func(ctx context.Context, donor *donordata.Provided)) *mockDonorStore_Put_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*donordata.Provided)) + }) + return _c +} + +func (_c *mockDonorStore_Put_Call) Return(_a0 error) *mockDonorStore_Put_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockDonorStore_Put_Call) RunAndReturn(run func(context.Context, *donordata.Provided) error) *mockDonorStore_Put_Call { + _c.Call.Return(run) + return _c +} + +// newMockDonorStore creates a new instance of mockDonorStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockDonorStore(t interface { + mock.TestingT + Cleanup(func()) +}) *mockDonorStore { + mock := &mockDonorStore{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/voucher/voucherpage/register.go b/internal/voucher/voucherpage/register.go index 43a9c7c85a..d2fc9d0f08 100644 --- a/internal/voucher/voucherpage/register.go +++ b/internal/voucher/voucherpage/register.go @@ -11,6 +11,7 @@ import ( "github.com/ministryofjustice/opg-modernising-lpa/internal/actor" "github.com/ministryofjustice/opg-modernising-lpa/internal/appcontext" "github.com/ministryofjustice/opg-modernising-lpa/internal/dashboard/dashboarddata" + "github.com/ministryofjustice/opg-modernising-lpa/internal/donor/donordata" "github.com/ministryofjustice/opg-modernising-lpa/internal/identity" "github.com/ministryofjustice/opg-modernising-lpa/internal/lpastore/lpadata" "github.com/ministryofjustice/opg-modernising-lpa/internal/notify" @@ -37,6 +38,11 @@ type LpaStoreResolvingService interface { Get(ctx context.Context) (*lpadata.Lpa, error) } +type DonorStore interface { + GetAny(ctx context.Context) (*donordata.Provided, error) + Put(ctx context.Context, donor *donordata.Provided) error +} + type NotifyClient interface { EmailGreeting(lpa *lpadata.Lpa) string SendActorEmail(ctx context.Context, to, lpaUID string, email notify.Email) error @@ -94,6 +100,7 @@ func Register( lpaStoreResolvingService LpaStoreResolvingService, notifyClient NotifyClient, appPublicURL string, + donorStore DonorStore, ) { handleRoot := makeHandle(rootMux, sessionStore, errorHandler) @@ -117,7 +124,7 @@ func Register( ConfirmAllowedToVouch(tmpls.Get("confirm_allowed_to_vouch.gohtml"), lpaStoreResolvingService, voucherStore)) handleVoucher(voucher.PathVerifyDonorDetails, None, - VerifyDonorDetails(tmpls.Get("verify_donor_details.gohtml"), lpaStoreResolvingService, voucherStore)) + VerifyDonorDetails(tmpls.Get("verify_donor_details.gohtml"), lpaStoreResolvingService, voucherStore, donorStore)) handleVoucher(voucher.PathDonorDetailsDoNotMatch, None, Guidance(tmpls.Get("donor_details_do_not_match.gohtml"), lpaStoreResolvingService)) @@ -126,7 +133,7 @@ func Register( handleVoucher(voucher.PathIdentityWithOneLogin, None, IdentityWithOneLogin(oneLoginClient, sessionStore, random.String)) handleVoucher(voucher.PathIdentityWithOneLoginCallback, None, - IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, notifyClient, appPublicURL)) + IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, notifyClient, appPublicURL, donorStore)) handleVoucher(voucher.PathOneLoginIdentityDetails, None, Guidance(tmpls.Get("one_login_identity_details.gohtml"), lpaStoreResolvingService)) handleVoucher(voucher.PathUnableToConfirmIdentity, None, diff --git a/internal/voucher/voucherpage/register_test.go b/internal/voucher/voucherpage/register_test.go index 6fb52faa00..639abf4430 100644 --- a/internal/voucher/voucherpage/register_test.go +++ b/internal/voucher/voucherpage/register_test.go @@ -19,7 +19,7 @@ import ( func TestRegister(t *testing.T) { mux := http.NewServeMux() - Register(mux, &mockLogger{}, template.Templates{}, &mockSessionStore{}, &mockVoucherStore{}, &mockOneLoginClient{}, &mockShareCodeStore{}, &mockDashboardStore{}, nil, &mockLpaStoreResolvingService{}, &mockNotifyClient{}, "http://app") + Register(mux, &mockLogger{}, template.Templates{}, &mockSessionStore{}, &mockVoucherStore{}, &mockOneLoginClient{}, &mockShareCodeStore{}, &mockDashboardStore{}, nil, &mockLpaStoreResolvingService{}, &mockNotifyClient{}, "http://app", &mockDonorStore{}) assert.Implements(t, (*http.Handler)(nil), mux) } diff --git a/internal/voucher/voucherpage/verify_donor_details.go b/internal/voucher/voucherpage/verify_donor_details.go index 5ab8d25ce7..3ca7cef04f 100644 --- a/internal/voucher/voucherpage/verify_donor_details.go +++ b/internal/voucher/voucherpage/verify_donor_details.go @@ -20,7 +20,7 @@ type verifyDonorDetailsData struct { Lpa *lpadata.Lpa } -func VerifyDonorDetails(tmpl template.Template, lpaStoreResolvingService LpaStoreResolvingService, voucherStore VoucherStore) Handler { +func VerifyDonorDetails(tmpl template.Template, lpaStoreResolvingService LpaStoreResolvingService, voucherStore VoucherStore, donorStore DonorStore) Handler { return func(appData appcontext.Data, w http.ResponseWriter, r *http.Request, provided *voucherdata.Provided) error { lpa, err := lpaStoreResolvingService.Get(r.Context()) if err != nil { @@ -45,6 +45,17 @@ func VerifyDonorDetails(tmpl template.Template, lpaStoreResolvingService LpaStor } if data.Form.YesNo.IsNo() { + donor, err := donorStore.GetAny(r.Context()) + if err != nil { + return err + } + + donor.FailedVouchAttempts++ + + if err := donorStore.Put(r.Context(), donor); err != nil { + return err + } + return voucher.PathDonorDetailsDoNotMatch.Redirect(w, r, appData, appData.LpaID) } diff --git a/internal/voucher/voucherpage/verify_donor_details_test.go b/internal/voucher/voucherpage/verify_donor_details_test.go index 29f7195f6a..80fba42b50 100644 --- a/internal/voucher/voucherpage/verify_donor_details_test.go +++ b/internal/voucher/voucherpage/verify_donor_details_test.go @@ -1,12 +1,14 @@ package voucherpage import ( + "context" "net/http" "net/http/httptest" "net/url" "strings" "testing" + "github.com/ministryofjustice/opg-modernising-lpa/internal/donor/donordata" "github.com/ministryofjustice/opg-modernising-lpa/internal/form" "github.com/ministryofjustice/opg-modernising-lpa/internal/lpastore/lpadata" "github.com/ministryofjustice/opg-modernising-lpa/internal/page" @@ -39,7 +41,7 @@ func TestGetVerifyDonorDetails(t *testing.T) { }). Return(nil) - err := VerifyDonorDetails(template.Execute, lpaStoreResolvingService, nil)(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) + err := VerifyDonorDetails(template.Execute, lpaStoreResolvingService, nil, nil)(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) resp := w.Result() assert.Nil(t, err) @@ -57,7 +59,7 @@ func TestGetVerifyDonorDetailsWhenLpaStoreResolvingServiceErrors(t *testing.T) { Get(r.Context()). Return(donor, expectedError) - err := VerifyDonorDetails(nil, lpaStoreResolvingService, nil)(testAppData, w, r, nil) + err := VerifyDonorDetails(nil, lpaStoreResolvingService, nil, nil)(testAppData, w, r, nil) assert.Equal(t, expectedError, err) } @@ -76,25 +78,44 @@ func TestGetVerifyDonorDetailsWhenTemplateErrors(t *testing.T) { Execute(w, mock.Anything). Return(expectedError) - err := VerifyDonorDetails(template.Execute, lpaStoreResolvingService, nil)(testAppData, w, r, &voucherdata.Provided{}) + err := VerifyDonorDetails(template.Execute, lpaStoreResolvingService, nil, nil)(testAppData, w, r, &voucherdata.Provided{}) assert.Equal(t, expectedError, err) } func TestPostVerifyDonorDetails(t *testing.T) { - testcases := map[form.YesNo]voucher.Path{ - form.Yes: voucher.PathTaskList, - form.No: voucher.PathDonorDetailsDoNotMatch, + + testcases := map[form.YesNo]struct { + expectedRedirect voucher.Path + donorStore func() *mockDonorStore + }{ + form.Yes: { + expectedRedirect: voucher.PathTaskList, + donorStore: func() *mockDonorStore { return newMockDonorStore(t) }, + }, + form.No: { + expectedRedirect: voucher.PathDonorDetailsDoNotMatch, + donorStore: func() *mockDonorStore { + d := newMockDonorStore(t) + d.EXPECT(). + GetAny(context.Background()). + Return(&donordata.Provided{}, nil) + d.EXPECT(). + Put(context.Background(), &donordata.Provided{FailedVouchAttempts: 1}). + Return(nil) + return d + }, + }, } - for yesNo, redirect := range testcases { + for yesNo, tc := range testcases { t.Run(yesNo.String(), func(t *testing.T) { f := url.Values{ form.FieldNames.YesNo: {yesNo.String()}, } - w := httptest.NewRecorder() r, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(f.Encode())) + w := httptest.NewRecorder() r.Header.Add("Content-Type", page.FormUrlEncoded) lpaStoreResolvingService := newMockLpaStoreResolvingService(t) @@ -111,12 +132,12 @@ func TestPostVerifyDonorDetails(t *testing.T) { }). Return(nil) - err := VerifyDonorDetails(nil, lpaStoreResolvingService, voucherStore)(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) + err := VerifyDonorDetails(nil, lpaStoreResolvingService, voucherStore, tc.donorStore())(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) resp := w.Result() assert.Nil(t, err) assert.Equal(t, http.StatusFound, resp.StatusCode) - assert.Equal(t, redirect.Format("lpa-id"), resp.Header.Get("Location")) + assert.Equal(t, tc.expectedRedirect.Format("lpa-id"), resp.Header.Get("Location")) }) } } @@ -140,6 +161,54 @@ func TestPostVerifyDonorDetailsWhenStoreErrors(t *testing.T) { Put(r.Context(), mock.Anything). Return(expectedError) - err := VerifyDonorDetails(nil, lpaStoreResolvingService, voucherStore)(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) + err := VerifyDonorDetails(nil, lpaStoreResolvingService, voucherStore, nil)(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) assert.Equal(t, expectedError, err) } + +func TestPostVerifyDonorDetailsWhenDonorStoreErrors(t *testing.T) { + testcases := map[string]func() *mockDonorStore{ + "GetAny": func() *mockDonorStore { + d := newMockDonorStore(t) + d.EXPECT(). + GetAny(mock.Anything). + Return(&donordata.Provided{}, expectedError) + return d + }, + "Put": func() *mockDonorStore { + d := newMockDonorStore(t) + d.EXPECT(). + GetAny(mock.Anything). + Return(&donordata.Provided{}, nil) + d.EXPECT(). + Put(mock.Anything, mock.Anything). + Return(expectedError) + return d + }, + } + + for name, donorStore := range testcases { + t.Run(name, func(t *testing.T) { + f := url.Values{ + form.FieldNames.YesNo: {form.No.String()}, + } + + w := httptest.NewRecorder() + r, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(f.Encode())) + r.Header.Add("Content-Type", page.FormUrlEncoded) + + lpaStoreResolvingService := newMockLpaStoreResolvingService(t) + lpaStoreResolvingService.EXPECT(). + Get(r.Context()). + Return(&lpadata.Lpa{}, nil) + + voucherStore := newMockVoucherStore(t) + voucherStore.EXPECT(). + Put(r.Context(), mock.Anything). + Return(nil) + + err := VerifyDonorDetails(nil, lpaStoreResolvingService, voucherStore, donorStore())(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) + assert.Equal(t, expectedError, err) + }) + } + +} diff --git a/lang/cy.json b/lang/cy.json index ae0ccb43e6..48e6cde5de 100644 --- a/lang/cy.json +++ b/lang/cy.json @@ -1369,5 +1369,9 @@ "yourConfirmedIdentityHasExpired": "

Welsh

Welsh

", "returnToOneLoginToConfirmYourIdentityContent": "

Welsh

", "askSomeoneToVouchForYouContent": "

Welsh

", - "iWillReturnToOneLogin": "Welsh" + "iWillReturnToOneLogin": "Welsh", + "tryVouchingAgainContent": "

Welsh

Welsh

Welsh
Welsh
Welsh
", + "iHaveSomeoneElseWhoCanVouch": "Welsh", + "thePersonYouAskedToVouchHasBeenUnableToContinue": "

Welsh

", + "thePersonYouAskedToVouchHasBeenUnableToContinueSecondAttempt": "

Welsh

Welsh

" } diff --git a/lang/en.json b/lang/en.json index 0ba610e9d5..8ae20053d5 100644 --- a/lang/en.json +++ b/lang/en.json @@ -1162,7 +1162,7 @@ "iNoLongerWantToMakeThisLpaHint": "I understand that I will not get a refund for the LPA fee.", "iWillApplyToCourtOfProtectionToRegisterThisLpa": "I will apply to the Court of Protection to register this LPA", "iWillApplyToCourtOfProtectionToRegisterThisLpaHint": "I understand that I will have to pay and wait several months.", - "youHaveNotChosenAnyoneToVouchForYou": "You have not chosen anyone to vouch for you", + "youHaveNotChosenAnyoneToVouchForYou": "

You have not chosen anyone to vouch for you

", "whatYouCanDoNow": "What you can do now", "whatYouCanDoNowContent": "

The Office of the Public Guardian (OPG) will not be able to register your LPA until you have confirmed your identity.

", "replaceFindOrGetNewIDContent": "

Replace, find or get new ID documents

For example, you could:

", @@ -1298,5 +1298,9 @@ "yourConfirmedIdentityHasExpired": "

Your confirmed identity has expired

You must sign your LPA within 6 months of confirming your identity.

", "returnToOneLoginToConfirmYourIdentityContent": "

Return to GOV.UK One Login to confirm your identity

You will need either:

", "askSomeoneToVouchForYouContent": "

Ask someone to vouch for you

Vouching allows someone you know well to confirm your identity. The person you ask to vouch for you will also need to confirm their own identity using GOV.UK One Login.

", - "iWillReturnToOneLogin": "I will return to GOV.UK One Login and confirm my identity" + "iWillReturnToOneLogin": "I will return to GOV.UK One Login and confirm my identity", + "tryVouchingAgainContent": "

Try vouching again

As you have previously attempted vouching, you will only able to select this option one more time.

About vouching attempts
A vouching attempt is made once the person vouching for you enters the code you gave them.
If they cannot or do not complete the vouching process after entering the code, this counts as a failed attempt.
", + "iHaveSomeoneElseWhoCanVouch": "I have someone else who can vouch for me", + "thePersonYouAskedToVouchHasBeenUnableToContinue": "

The person you asked to vouch for you has been unable to continue

", + "thePersonYouAskedToVouchHasBeenUnableToContinueSecondAttempt": "

The person you asked to vouch for you has been unable to continue

You cannot ask another person to vouch for you as only 2 attempts can be made of having a someone vouch for your identity.

" } diff --git a/web/template/donor/what_you_can_do_now.gohtml b/web/template/donor/what_you_can_do_now.gohtml index 1fd05c055c..e8bcc3433b 100644 --- a/web/template/donor/what_you_can_do_now.gohtml +++ b/web/template/donor/what_you_can_do_now.gohtml @@ -5,12 +5,13 @@ {{ define "main" }}
- {{ template "notification-banner" ( notificationBanner .App "important" (trHtml .App "youHaveNotChosenAnyoneToVouchForYou") "heading" ) }} + {{ template "notification-banner" ( notificationBanner .App "important" (trHtml .App .BannerContent) "contents" "1" ) }}

{{ tr .App "whatYouCanDoNow" }}

{{ trHtml .App "whatYouCanDoNowContent" }} {{ trHtml .App "replaceFindOrGetNewIDContent" }} + {{ if eq 1 .FailedVouchAttempts }} {{ trHtml .App "tryVouchingAgainContent" }} {{ end }} {{ trHtml .App "registerYourLPAThroughTheCOPContent" }} {{ template "warning" (content .App "onceYouSelectThisOptionYouCannotChangeYourMindWarning") }} @@ -22,12 +23,21 @@ {{ template "error-message" (errorMessage . "do-next") }} - {{ template "radios" (items . "do-next" "" - (item .Form.Options.ProveOwnID.String "iWillGetOrFindID") - (item .Form.Options.SelectNewVoucher.String "iHaveSomeoneWhoCanVouch") - (item .Form.Options.WithdrawLPA.String "iNoLongerWantToMakeThisLPA" "hint" "iUnderstandIWillNotGetRefundHint" "orDivider" "1") - (item .Form.Options.ApplyToCOP.String "iWillApplyToCOPToRegister" "hint" "iUnderstandICannotChangeMyMind") - ) }} + {{ if .Form.CanHaveVoucher }} + {{ template "radios" (items . "do-next" "" + (item .Form.Options.ProveOwnID.String "iWillGetOrFindID") + (item .Form.Options.SelectNewVoucher.String .NewVoucherLabel) + (item .Form.Options.WithdrawLPA.String "iNoLongerWantToMakeThisLPA" "hint" "iUnderstandIWillNotGetRefundHint" "orDivider" "1") + (item .Form.Options.ApplyToCOP.String "iWillApplyToCOPToRegister" "hint" "iUnderstandICannotChangeMyMind") + ) }} + {{ else }} + {{ template "radios" (items . "do-next" "" + (item .Form.Options.ProveOwnID.String "iWillGetOrFindID") + (item .Form.Options.WithdrawLPA.String "iNoLongerWantToMakeThisLPA" "hint" "iUnderstandIWillNotGetRefundHint" "orDivider" "1") + (item .Form.Options.ApplyToCOP.String "iWillApplyToCOPToRegister" "hint" "iUnderstandICannotChangeMyMind") + ) }} + {{ end }} +
From 2295c97111c4de991cb75feb6fd19290285772ad Mon Sep 17 00:00:00 2001 From: Alex Saunders Date: Tue, 3 Sep 2024 16:48:29 +0100 Subject: [PATCH 2/3] MLPAB-2134 update deps --- go.sum | 52 ---------------------------------------------------- 1 file changed, 52 deletions(-) diff --git a/go.sum b/go.sum index dc978b96e5..4652c976d5 100644 --- a/go.sum +++ b/go.sum @@ -8,16 +8,10 @@ github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDag github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 h1:70PVAiL15/aBMh5LThwgXdSQorVr91L127ttckI9QQU= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4/go.mod h1:/MQxMqci8tlqDH+pjmoLu1i0tbWCUP1hhyMRuFxpQCw= -github.com/aws/aws-sdk-go-v2/config v1.27.28 h1:OTxWGW/91C61QlneCtnD62NLb4W616/NM1jA8LhJqbg= -github.com/aws/aws-sdk-go-v2/config v1.27.28/go.mod h1:uzVRVtJSU5EFv6Fu82AoVFKozJi2ZCY6WRCXj06rbvs= github.com/aws/aws-sdk-go-v2/config v1.27.30 h1:AQF3/+rOgeJBQP3iI4vojlPib5X6eeOYoa/af7OxAYg= github.com/aws/aws-sdk-go-v2/config v1.27.30/go.mod h1:yxqvuubha9Vw8stEgNiStO+yZpP68Wm9hLmcm+R/Qk4= -github.com/aws/aws-sdk-go-v2/credentials v1.17.28 h1:m8+AHY/ND8CMHJnPoH7PJIRakWGa4gbfbxuY9TGTUXM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.28/go.mod h1:6TF7dSc78ehD1SL6KpRIPKMA1GyyWflIkjqg+qmf4+c= github.com/aws/aws-sdk-go-v2/credentials v1.17.29 h1:CwGsupsXIlAFYuDVHv1nnK0wnxO0wZ/g1L8DSK/xiIw= github.com/aws/aws-sdk-go-v2/credentials v1.17.29/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.11 h1:KUHQows9JhDp+RJRs9KLN+ljsK5D+oLV13Wr/TwlSr4= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.11/go.mod h1:4kdmcGnKW4R9l2ddj6hNgKnJoxztjvJNCoI9eikMgvI= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.12 h1:R8nvub089lfNl3+j6Yf+m8kS64Zois56Bu5ku6KAXNE= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.12/go.mod h1:bswOrGH35stnF9k41t5gKQ8b+j6B4SLe6cF3xHuJG6E= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE= @@ -30,16 +24,10 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvK github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16 h1:mimdLQkIX1zr8GIPY1ZtALdBQGxcASiBd2MOp8m/dMc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16/go.mod h1:YHk6owoSwrIsok+cAH9PENCOGoH5PU2EllX4vLtSrsY= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.5 h1:Cm77yt+/CV7A6DglkENsWA3H1hq8+4ItJnFKrhxHkvg= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.5/go.mod h1:s2fYaueBuCnwv1XQn6T8TfShxJWusv5tWPMcL+GY6+g= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.6 h1:LKZuRTlh8RszjuWcUwEDvCGwjx5olHPp6ZOepyZV5p8= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.6/go.mod h1:s2fYaueBuCnwv1XQn6T8TfShxJWusv5tWPMcL+GY6+g= -github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.4 h1:qOvCqaiLTc0MnIdZr0LbdtJKetiRscHxi+9XjjtlEAs= -github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.4/go.mod h1:3YxVsEoCNYOLIbdA+cCXSp1fom9hrhyB1DsCiYryCaQ= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.5 h1:sM/SaWUKPtsCcXE0bHZPUG4jjCbFbxakyptXQbYLrdU= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.5/go.mod h1:3YxVsEoCNYOLIbdA+cCXSp1fom9hrhyB1DsCiYryCaQ= -github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.4 h1:GWRTbj0tiFfk6lIwUcHv7F9bPdty0TGwr3ruK0jyBUc= -github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.4/go.mod h1:AudiowtxywCESLsT3fvGcAEEcN4l7nusiW2nZMaCo+g= github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.5 h1:wL8V4pdudr0mHbZ/tj9YacfRak5klKz9omV0uXBt5Sk= github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.5/go.mod h1:AudiowtxywCESLsT3fvGcAEEcN4l7nusiW2nZMaCo+g= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= @@ -52,24 +40,16 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHC github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16 h1:jg16PhLPUiHIj8zYIW6bqzeQSuHVEiWnGA0Brz5Xv2I= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16/go.mod h1:Uyk1zE1VVdsHSU7096h/rwnXDzOzYQVl+FNPhPw7ShY= -github.com/aws/aws-sdk-go-v2/service/s3 v1.59.0 h1:Cso4Ev/XauMVsbwdhYEoxg8rxZWw43CFqqaPB5w3W2c= -github.com/aws/aws-sdk-go-v2/service/s3 v1.59.0/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1 h1:mx2ucgtv+MWzJesJY9Ig/8AFHgoE5FwLXwUVgW/FGdI= github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.5 h1:UDXu9dqpCZYonj7poM4kFISjzTdWI0v3WUusM+w+Gfc= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.5/go.mod h1:5NPkI3RsTOhwz1CuG7VVSgJCm3CINKkoIaUbUZWQ67w= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.6 h1:3TZlWvCC813uhS1Z4fVTmBhg41OYUrgSlvXqIDDkurw= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.6/go.mod h1:5NPkI3RsTOhwz1CuG7VVSgJCm3CINKkoIaUbUZWQ67w= -github.com/aws/aws-sdk-go-v2/service/sqs v1.34.4 h1:FXPO72iKC5YmYNEANltl763bUj8A6qT20wx8Jwvxlsw= -github.com/aws/aws-sdk-go-v2/service/sqs v1.34.4/go.mod h1:7idt3XszF6sE9WPS1GqZRiDJOxw4oPtlRBXodWnCGjU= github.com/aws/aws-sdk-go-v2/service/sqs v1.34.5 h1:HYyVDOC2/PIg+3oBX1q0wtDU5kONki6lrgIG0afrBkY= github.com/aws/aws-sdk-go-v2/service/sqs v1.34.5/go.mod h1:7idt3XszF6sE9WPS1GqZRiDJOxw4oPtlRBXodWnCGjU= github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c= github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 h1:iAckBT2OeEK/kBDyN/jDtpEExhjeeA/Im2q4X0rJZT8= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.4/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 h1:OMsEmCyz2i89XwRwPouAJvhj81wINh+4UK+k/0Yo/q8= github.com/aws/aws-sdk-go-v2/service/sts v1.30.5/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= @@ -114,12 +94,8 @@ github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyE github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= -github.com/gorilla/sessions v1.3.0 h1:XYlkq7KcpOB2ZhHBPv5WpjMIxrQosiZanfoy1HLZFzg= -github.com/gorilla/sessions v1.3.0/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= @@ -214,8 +190,6 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/vektra/mockery/v2 v2.44.1 h1:lfvocO3HklLp68gezPBVaHl+5rKXloGCO7eTEXh71dA= -github.com/vektra/mockery/v2 v2.44.1/go.mod h1:XNTE9RIu3deGAGQRVjP1VZxGpQNm0YedZx4oDs3prr8= github.com/vektra/mockery/v2 v2.45.0 h1:TDKO9y0CPv+/gm7KVBOJfzMcBeK7Y044jvaNdgBBVik= github.com/vektra/mockery/v2 v2.45.0/go.mod h1:XNTE9RIu3deGAGQRVjP1VZxGpQNm0YedZx4oDs3prr8= github.com/wI2L/jsondiff v0.6.0 h1:zrsH3FbfVa3JO9llxrcDy/XLkYPLgoMX6Mz3T2PP2AI= @@ -226,44 +200,24 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -go.opentelemetry.io/contrib/detectors/aws/ecs v1.28.0 h1:m5PcF0VJ5BcX9AQmPQl9nNmm268s1JCVkQKeQPmavKc= -go.opentelemetry.io/contrib/detectors/aws/ecs v1.28.0/go.mod h1:M3swUI/YXREpfrK9HoVP3CnXtxc7EHSDpKNI+Tjr7Mw= go.opentelemetry.io/contrib/detectors/aws/ecs v1.29.0 h1:IgPZK3rwSFzQwAvlHFYn5NLo+V+008PWO34t9Y1fRzY= go.opentelemetry.io/contrib/detectors/aws/ecs v1.29.0/go.mod h1:MxiZZB92HEa02+p+EpvG95qyKsVyYAYGBHnNz3mv2Go= -go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.53.0 h1:1B6+VGkx6SYIB3c2NxGCOscCDRn5MGZGBa+HakVOl1s= -go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.53.0/go.mod h1:BwIY9dxFVSGry/WRhvUmpbvT9JFmBdDUcLHoHmPqy/s= go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.54.0 h1:By10h8DrrjRcZjy10wBEkRdwhe4kOFuNTfprm8RXQQk= go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.54.0/go.mod h1:EtfcBqee4PFJSl+TXvfhg8ADvLWGFXwwX7SYNHG/VGM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= -go.opentelemetry.io/contrib/propagators/aws v1.28.0 h1:acyTl4oyin/iLr5Nz3u7p/PKHUbLh42w/fqg9LblExk= -go.opentelemetry.io/contrib/propagators/aws v1.28.0/go.mod h1:5WgIv6yG9DvLlSY2uIHrYSeVVwCDCqp4jhwinNNyeT4= go.opentelemetry.io/contrib/propagators/aws v1.29.0 h1:mqadbdNBhn/MVOcNx0dEZAaOaomKKdnsM0QNBmFegiI= go.opentelemetry.io/contrib/propagators/aws v1.29.0/go.mod h1:3RCUqtGbLbVr6REZv3pQbtqql9GNEpvyB7GiTJhP/nk= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= @@ -286,8 +240,6 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= @@ -298,12 +250,8 @@ golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= From 08d1f869be25dc6fa9333cbdea756103a05bf34f Mon Sep 17 00:00:00 2001 From: Alex Saunders Date: Wed, 4 Sep 2024 10:54:16 +0100 Subject: [PATCH 3/3] MLPAB-2134 protect against incrementing on failed email sends --- go.sum | 66 ------------------- .../identity_with_one_login_callback.go | 22 +++---- .../identity_with_one_login_callback_test.go | 10 +-- 3 files changed, 12 insertions(+), 86 deletions(-) diff --git a/go.sum b/go.sum index 24aaead426..c318a8991b 100644 --- a/go.sum +++ b/go.sum @@ -8,22 +8,10 @@ github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDag github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 h1:70PVAiL15/aBMh5LThwgXdSQorVr91L127ttckI9QQU= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4/go.mod h1:/MQxMqci8tlqDH+pjmoLu1i0tbWCUP1hhyMRuFxpQCw= -github.com/aws/aws-sdk-go-v2/config v1.27.28 h1:OTxWGW/91C61QlneCtnD62NLb4W616/NM1jA8LhJqbg= -github.com/aws/aws-sdk-go-v2/config v1.27.28/go.mod h1:uzVRVtJSU5EFv6Fu82AoVFKozJi2ZCY6WRCXj06rbvs= -github.com/aws/aws-sdk-go-v2/config v1.27.30 h1:AQF3/+rOgeJBQP3iI4vojlPib5X6eeOYoa/af7OxAYg= -github.com/aws/aws-sdk-go-v2/config v1.27.30/go.mod h1:yxqvuubha9Vw8stEgNiStO+yZpP68Wm9hLmcm+R/Qk4= github.com/aws/aws-sdk-go-v2/config v1.27.31 h1:kxBoRsjhT3pq0cKthgj6RU6bXTm/2SgdoUMyrVw0rAI= github.com/aws/aws-sdk-go-v2/config v1.27.31/go.mod h1:z04nZdSWFPaDwK3DdJOG2r+scLQzMYuJeW0CujEm9FM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.28 h1:m8+AHY/ND8CMHJnPoH7PJIRakWGa4gbfbxuY9TGTUXM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.28/go.mod h1:6TF7dSc78ehD1SL6KpRIPKMA1GyyWflIkjqg+qmf4+c= -github.com/aws/aws-sdk-go-v2/credentials v1.17.29 h1:CwGsupsXIlAFYuDVHv1nnK0wnxO0wZ/g1L8DSK/xiIw= -github.com/aws/aws-sdk-go-v2/credentials v1.17.29/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g= github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q= github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.11 h1:KUHQows9JhDp+RJRs9KLN+ljsK5D+oLV13Wr/TwlSr4= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.11/go.mod h1:4kdmcGnKW4R9l2ddj6hNgKnJoxztjvJNCoI9eikMgvI= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.12 h1:R8nvub089lfNl3+j6Yf+m8kS64Zois56Bu5ku6KAXNE= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.12/go.mod h1:bswOrGH35stnF9k41t5gKQ8b+j6B4SLe6cF3xHuJG6E= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.15.0 h1:zExbglw6JfQeXPLHmWg6vxOXdkvuZkEKRVo69scPd4M= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.15.0/go.mod h1:bswOrGH35stnF9k41t5gKQ8b+j6B4SLe6cF3xHuJG6E= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE= @@ -36,16 +24,10 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvK github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16 h1:mimdLQkIX1zr8GIPY1ZtALdBQGxcASiBd2MOp8m/dMc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16/go.mod h1:YHk6owoSwrIsok+cAH9PENCOGoH5PU2EllX4vLtSrsY= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.5 h1:Cm77yt+/CV7A6DglkENsWA3H1hq8+4ItJnFKrhxHkvg= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.5/go.mod h1:s2fYaueBuCnwv1XQn6T8TfShxJWusv5tWPMcL+GY6+g= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.6 h1:LKZuRTlh8RszjuWcUwEDvCGwjx5olHPp6ZOepyZV5p8= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.6/go.mod h1:s2fYaueBuCnwv1XQn6T8TfShxJWusv5tWPMcL+GY6+g= -github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.4 h1:qOvCqaiLTc0MnIdZr0LbdtJKetiRscHxi+9XjjtlEAs= -github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.4/go.mod h1:3YxVsEoCNYOLIbdA+cCXSp1fom9hrhyB1DsCiYryCaQ= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.5 h1:sM/SaWUKPtsCcXE0bHZPUG4jjCbFbxakyptXQbYLrdU= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.5/go.mod h1:3YxVsEoCNYOLIbdA+cCXSp1fom9hrhyB1DsCiYryCaQ= -github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.4 h1:GWRTbj0tiFfk6lIwUcHv7F9bPdty0TGwr3ruK0jyBUc= -github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.4/go.mod h1:AudiowtxywCESLsT3fvGcAEEcN4l7nusiW2nZMaCo+g= github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.5 h1:wL8V4pdudr0mHbZ/tj9YacfRak5klKz9omV0uXBt5Sk= github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.5/go.mod h1:AudiowtxywCESLsT3fvGcAEEcN4l7nusiW2nZMaCo+g= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= @@ -58,28 +40,16 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHC github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16 h1:jg16PhLPUiHIj8zYIW6bqzeQSuHVEiWnGA0Brz5Xv2I= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16/go.mod h1:Uyk1zE1VVdsHSU7096h/rwnXDzOzYQVl+FNPhPw7ShY= -github.com/aws/aws-sdk-go-v2/service/s3 v1.59.0 h1:Cso4Ev/XauMVsbwdhYEoxg8rxZWw43CFqqaPB5w3W2c= -github.com/aws/aws-sdk-go-v2/service/s3 v1.59.0/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= -github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1 h1:mx2ucgtv+MWzJesJY9Ig/8AFHgoE5FwLXwUVgW/FGdI= -github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0 h1:Wb544Wh+xfSXqJ/j3R4aX9wrKUoZsJNmilBYZb3mKQ4= github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.5 h1:UDXu9dqpCZYonj7poM4kFISjzTdWI0v3WUusM+w+Gfc= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.5/go.mod h1:5NPkI3RsTOhwz1CuG7VVSgJCm3CINKkoIaUbUZWQ67w= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.6 h1:3TZlWvCC813uhS1Z4fVTmBhg41OYUrgSlvXqIDDkurw= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.6/go.mod h1:5NPkI3RsTOhwz1CuG7VVSgJCm3CINKkoIaUbUZWQ67w= -github.com/aws/aws-sdk-go-v2/service/sqs v1.34.4 h1:FXPO72iKC5YmYNEANltl763bUj8A6qT20wx8Jwvxlsw= -github.com/aws/aws-sdk-go-v2/service/sqs v1.34.4/go.mod h1:7idt3XszF6sE9WPS1GqZRiDJOxw4oPtlRBXodWnCGjU= -github.com/aws/aws-sdk-go-v2/service/sqs v1.34.5 h1:HYyVDOC2/PIg+3oBX1q0wtDU5kONki6lrgIG0afrBkY= -github.com/aws/aws-sdk-go-v2/service/sqs v1.34.5/go.mod h1:7idt3XszF6sE9WPS1GqZRiDJOxw4oPtlRBXodWnCGjU= github.com/aws/aws-sdk-go-v2/service/sqs v1.34.6 h1:DbjODDHumQBdJ3T+EO7AXVoFUeUhAsJYOdjStH5Ws4A= github.com/aws/aws-sdk-go-v2/service/sqs v1.34.6/go.mod h1:7idt3XszF6sE9WPS1GqZRiDJOxw4oPtlRBXodWnCGjU= github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c= github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 h1:iAckBT2OeEK/kBDyN/jDtpEExhjeeA/Im2q4X0rJZT8= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.4/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 h1:OMsEmCyz2i89XwRwPouAJvhj81wINh+4UK+k/0Yo/q8= github.com/aws/aws-sdk-go-v2/service/sts v1.30.5/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= @@ -124,12 +94,8 @@ github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyE github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= -github.com/gorilla/sessions v1.3.0 h1:XYlkq7KcpOB2ZhHBPv5WpjMIxrQosiZanfoy1HLZFzg= -github.com/gorilla/sessions v1.3.0/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= @@ -163,8 +129,6 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/ministryofjustice/opg-go-common v1.8.0 h1:Uj+ALL/ZuNsG4tmf2fhlNJ1b6BKxBFWD0L/TG9/IhRE= -github.com/ministryofjustice/opg-go-common v1.8.0/go.mod h1:qqspbBfGAq7A5tvl8mPQwWhlYw2FJWT0EkIGo9kHuYw= github.com/ministryofjustice/opg-go-common v1.10.0 h1:OH5I8bdp9HKn1CSbVvO66Yi2aoLE/nv1yJlCYtEJZI4= github.com/ministryofjustice/opg-go-common v1.10.0/go.mod h1:1r3Zdxf6ddL7LdRz+CJUvdhTcs0q3DK0Hf/GrspDSGY= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -173,8 +137,6 @@ github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4 github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/opensearch-project/opensearch-go/v4 v4.1.0 h1:YXNaMpMU0PC7suGyP13EuczkDT3K54QajgDnLKCZAz8= -github.com/opensearch-project/opensearch-go/v4 v4.1.0/go.mod h1:aSTMFGSLEoiG19US6Oo5udvWCjHap3mRcWBNV8rAFak= github.com/opensearch-project/opensearch-go/v4 v4.2.0 h1:uaBexfVdeSU15yOUPYF+IY059koVP0oNQPyoSde6N/A= github.com/opensearch-project/opensearch-go/v4 v4.2.0/go.mod h1:9v6a0OHRIeHwLPQlHOia18bw6R5XKECoXy93TWjX/10= github.com/pact-foundation/pact-go/v2 v2.0.7 h1:4yELx7b54ampFcSD+qhU1wFULGxxxlXWI8dhoLr6Adk= @@ -228,8 +190,6 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/vektra/mockery/v2 v2.44.1 h1:lfvocO3HklLp68gezPBVaHl+5rKXloGCO7eTEXh71dA= -github.com/vektra/mockery/v2 v2.44.1/go.mod h1:XNTE9RIu3deGAGQRVjP1VZxGpQNm0YedZx4oDs3prr8= github.com/vektra/mockery/v2 v2.45.0 h1:TDKO9y0CPv+/gm7KVBOJfzMcBeK7Y044jvaNdgBBVik= github.com/vektra/mockery/v2 v2.45.0/go.mod h1:XNTE9RIu3deGAGQRVjP1VZxGpQNm0YedZx4oDs3prr8= github.com/wI2L/jsondiff v0.6.0 h1:zrsH3FbfVa3JO9llxrcDy/XLkYPLgoMX6Mz3T2PP2AI= @@ -240,44 +200,24 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -go.opentelemetry.io/contrib/detectors/aws/ecs v1.28.0 h1:m5PcF0VJ5BcX9AQmPQl9nNmm268s1JCVkQKeQPmavKc= -go.opentelemetry.io/contrib/detectors/aws/ecs v1.28.0/go.mod h1:M3swUI/YXREpfrK9HoVP3CnXtxc7EHSDpKNI+Tjr7Mw= go.opentelemetry.io/contrib/detectors/aws/ecs v1.29.0 h1:IgPZK3rwSFzQwAvlHFYn5NLo+V+008PWO34t9Y1fRzY= go.opentelemetry.io/contrib/detectors/aws/ecs v1.29.0/go.mod h1:MxiZZB92HEa02+p+EpvG95qyKsVyYAYGBHnNz3mv2Go= -go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.53.0 h1:1B6+VGkx6SYIB3c2NxGCOscCDRn5MGZGBa+HakVOl1s= -go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.53.0/go.mod h1:BwIY9dxFVSGry/WRhvUmpbvT9JFmBdDUcLHoHmPqy/s= go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.54.0 h1:By10h8DrrjRcZjy10wBEkRdwhe4kOFuNTfprm8RXQQk= go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.54.0/go.mod h1:EtfcBqee4PFJSl+TXvfhg8ADvLWGFXwwX7SYNHG/VGM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= -go.opentelemetry.io/contrib/propagators/aws v1.28.0 h1:acyTl4oyin/iLr5Nz3u7p/PKHUbLh42w/fqg9LblExk= -go.opentelemetry.io/contrib/propagators/aws v1.28.0/go.mod h1:5WgIv6yG9DvLlSY2uIHrYSeVVwCDCqp4jhwinNNyeT4= go.opentelemetry.io/contrib/propagators/aws v1.29.0 h1:mqadbdNBhn/MVOcNx0dEZAaOaomKKdnsM0QNBmFegiI= go.opentelemetry.io/contrib/propagators/aws v1.29.0/go.mod h1:3RCUqtGbLbVr6REZv3pQbtqql9GNEpvyB7GiTJhP/nk= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= @@ -300,8 +240,6 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= @@ -312,12 +250,8 @@ golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= diff --git a/internal/voucher/voucherpage/identity_with_one_login_callback.go b/internal/voucher/voucherpage/identity_with_one_login_callback.go index 284ccf8d12..7623a3ea4d 100644 --- a/internal/voucher/voucherpage/identity_with_one_login_callback.go +++ b/internal/voucher/voucherpage/identity_with_one_login_callback.go @@ -56,17 +56,6 @@ func IdentityWithOneLoginCallback(oneLoginClient OneLoginClient, sessionStore Se } if !provided.IdentityConfirmed() { - donor, err := donorStore.GetAny(r.Context()) - if err != nil { - return err - } - - donor.FailedVouchAttempts++ - - if err := donorStore.Put(r.Context(), donor); err != nil { - return err - } - if !lpa.SignedAt.IsZero() { if err = notifyClient.SendActorEmail(r.Context(), lpa.CorrespondentEmail(), lpa.LpaUID, notify.VoucherFailedIdentityCheckEmail{ Greeting: notifyClient.EmailGreeting(lpa), @@ -79,6 +68,17 @@ func IdentityWithOneLoginCallback(oneLoginClient OneLoginClient, sessionStore Se } } + donor, err := donorStore.GetAny(r.Context()) + if err != nil { + return err + } + + donor.FailedVouchAttempts++ + + if err := donorStore.Put(r.Context(), donor); err != nil { + return err + } + return voucher.PathUnableToConfirmIdentity.Redirect(w, r, appData, appData.LpaID) } diff --git a/internal/voucher/voucherpage/identity_with_one_login_callback_test.go b/internal/voucher/voucherpage/identity_with_one_login_callback_test.go index 4a4b9f84c9..1d24bd97f1 100644 --- a/internal/voucher/voucherpage/identity_with_one_login_callback_test.go +++ b/internal/voucher/voucherpage/identity_with_one_login_callback_test.go @@ -220,14 +220,6 @@ func TestGetIdentityWithOneLoginCallbackWhenSendingEmailError(t *testing.T) { ParseIdentityClaim(mock.Anything, mock.Anything). Return(userData, nil) - donorStore := newMockDonorStore(t) - donorStore.EXPECT(). - GetAny(r.Context()). - Return(&donordata.Provided{}, nil) - donorStore.EXPECT(). - Put(r.Context(), &donordata.Provided{FailedVouchAttempts: 1}). - Return(nil) - localizer := newMockLocalizer(t) localizer.EXPECT(). T(mock.Anything). @@ -243,7 +235,7 @@ func TestGetIdentityWithOneLoginCallbackWhenSendingEmailError(t *testing.T) { SendActorEmail(mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(expectedError) - err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, notifyClient, "www.example.com", donorStore)(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) + err := IdentityWithOneLoginCallback(oneLoginClient, sessionStore, voucherStore, lpaStoreResolvingService, notifyClient, "www.example.com", nil)(testAppData, w, r, &voucherdata.Provided{LpaID: "lpa-id"}) resp := w.Result() assert.Equal(t, expectedError, err)