diff --git a/docker/event-logger/Dockerfile b/docker/event-logger/Dockerfile index 2ae919176b..9e46cec61f 100644 --- a/docker/event-logger/Dockerfile +++ b/docker/event-logger/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22.5-alpine as base +FROM golang:1.22.5-alpine AS base ARG ARCH=amd64 @@ -11,7 +11,7 @@ COPY cmd/event-logger ./cmd/event-logger RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /go/bin/event-logger ./cmd/event-logger -FROM scratch as production +FROM scratch AS production COPY --from=base /go/bin/event-logger event-logger diff --git a/docker/event-received/Dockerfile b/docker/event-received/Dockerfile index 2fbdedc68d..fa570acbc3 100644 --- a/docker/event-received/Dockerfile +++ b/docker/event-received/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22.5-alpine as build +FROM golang:1.22.5-alpine AS build WORKDIR /app diff --git a/docker/localstack/Dockerfile b/docker/localstack/Dockerfile index 5d535c3e81..c4543e08bb 100644 --- a/docker/localstack/Dockerfile +++ b/docker/localstack/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22.5-alpine as build +FROM golang:1.22.5-alpine AS build RUN apk add zip @@ -13,7 +13,7 @@ COPY --link internal ./internal RUN GOOS=linux GOOS=${TARGETOS} GOARCH=${TARGETARCH} CGO_ENABLED=0 go build -tags lambda.norpc -o event-received ./cmd/event-received RUN zip event-received.zip event-received -FROM localstack/localstack:3.6.0 as localstack +FROM localstack/localstack:3.6.0 AS localstack COPY --from=build /app/event-received.zip /etc/event-received.zip diff --git a/docker/mock-lpa-store/lpa-store.js b/docker/mock-lpa-store/lpa-store.js index 3971a251a2..2a6aa6d34d 100644 --- a/docker/mock-lpa-store/lpa-store.js +++ b/docker/mock-lpa-store/lpa-store.js @@ -2,11 +2,12 @@ console.log(`Request - ${context.request.method} ${context.request.path}`); const lpaStore = stores.open('lpa'); const pathParts = context.request.path.split('/'); +const lpaUID = pathParts[2] switch (context.request.method) { case 'GET': { if (pathParts.length == 3 && pathParts[1] == 'lpas') { - const lpa = lpaStore.load(pathParts[2]); + const lpa = lpaStore.load(lpaUID); if (lpa) { respond().withContent(lpa); } else { @@ -19,9 +20,9 @@ switch (context.request.method) { } case 'PUT': { let lpa = JSON.parse(context.request.body); - lpa.uid = pathParts[2]; + lpa.uid = lpaUID; lpa.updatedAt = new Date(Date.now()).toISOString(); - lpaStore.save(pathParts[2], JSON.stringify(lpa)); + lpaStore.save(lpaUID, JSON.stringify(lpa)); respond(); break; } @@ -33,7 +34,7 @@ switch (context.request.method) { respond().withContent(JSON.stringify({ lpas: lpas })); } else { let update = JSON.parse(context.request.body); - let lpa = JSON.parse(lpaStore.load(pathParts[2])); + let lpa = JSON.parse(lpaStore.load(lpaUID)); if (!lpa) { respond().withStatusCode(404); break; @@ -81,9 +82,18 @@ switch (context.request.method) { case 'DONOR_WITHDRAW_LPA': lpa.status = 'withdrawn'; break; + + case 'ATTORNEY_OPT_OUT': + const idx = lpa.attorneys.findIndex(item => item.uid === update.subject) + + if (idx >= 0 && lpa.attorneys[idx].signedAt != '') { + lpa.attorneys[idx].status = 'removed' + } + break; + } - lpaStore.save(pathParts[2], JSON.stringify(lpa)); + lpaStore.save(lpaUID, JSON.stringify(lpa)); respond(); } break; diff --git a/docker/mock-notify/Dockerfile b/docker/mock-notify/Dockerfile index 733e5422b2..efaa068888 100644 --- a/docker/mock-notify/Dockerfile +++ b/docker/mock-notify/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22.5-alpine as build-env +FROM golang:1.22.5-alpine AS build-env RUN apk --no-cache add openssl diff --git a/docker/mock-os-api/Dockerfile b/docker/mock-os-api/Dockerfile index 73bee97d48..fd7f63c787 100644 --- a/docker/mock-os-api/Dockerfile +++ b/docker/mock-os-api/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22.5-alpine as build-env +FROM golang:1.22.5-alpine AS build-env RUN apk --no-cache add openssl diff --git a/internal/app/mock_LpaStoreResolvingService_test.go b/internal/app/mock_LpaStoreResolvingService_test.go deleted file mode 100644 index 04543216b9..0000000000 --- a/internal/app/mock_LpaStoreResolvingService_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. - -package app - -import ( - context "context" - - donordata "github.com/ministryofjustice/opg-modernising-lpa/internal/donor/donordata" - "github.com/ministryofjustice/opg-modernising-lpa/internal/lpastore/lpadata" - - mock "github.com/stretchr/testify/mock" -) - -// mockLpaStoreResolvingService is an autogenerated mock type for the LpaStoreResolvingService type -type mockLpaStoreResolvingService struct { - mock.Mock -} - -type mockLpaStoreResolvingService_Expecter struct { - mock *mock.Mock -} - -func (_m *mockLpaStoreResolvingService) EXPECT() *mockLpaStoreResolvingService_Expecter { - return &mockLpaStoreResolvingService_Expecter{mock: &_m.Mock} -} - -// ResolveList provides a mock function with given fields: ctx, donors -func (_m *mockLpaStoreResolvingService) ResolveList(ctx context.Context, donors []*donordata.Provided) ([]*lpadata.Lpa, error) { - ret := _m.Called(ctx, donors) - - if len(ret) == 0 { - panic("no return value specified for ResolveList") - } - - var r0 []*lpadata.Lpa - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []*donordata.Provided) ([]*lpadata.Lpa, error)); ok { - return rf(ctx, donors) - } - if rf, ok := ret.Get(0).(func(context.Context, []*donordata.Provided) []*lpadata.Lpa); ok { - r0 = rf(ctx, donors) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*lpadata.Lpa) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, []*donordata.Provided) error); ok { - r1 = rf(ctx, donors) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockLpaStoreResolvingService_ResolveList_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResolveList' -type mockLpaStoreResolvingService_ResolveList_Call struct { - *mock.Call -} - -// ResolveList is a helper method to define mock.On call -// - ctx context.Context -// - donors []*donordata.Provided -func (_e *mockLpaStoreResolvingService_Expecter) ResolveList(ctx interface{}, donors interface{}) *mockLpaStoreResolvingService_ResolveList_Call { - return &mockLpaStoreResolvingService_ResolveList_Call{Call: _e.mock.On("ResolveList", ctx, donors)} -} - -func (_c *mockLpaStoreResolvingService_ResolveList_Call) Run(run func(ctx context.Context, donors []*donordata.Provided)) *mockLpaStoreResolvingService_ResolveList_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].([]*donordata.Provided)) - }) - return _c -} - -func (_c *mockLpaStoreResolvingService_ResolveList_Call) Return(_a0 []*lpadata.Lpa, _a1 error) *mockLpaStoreResolvingService_ResolveList_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockLpaStoreResolvingService_ResolveList_Call) RunAndReturn(run func(context.Context, []*donordata.Provided) ([]*lpadata.Lpa, error)) *mockLpaStoreResolvingService_ResolveList_Call { - _c.Call.Return(run) - return _c -} - -// newMockLpaStoreResolvingService creates a new instance of mockLpaStoreResolvingService. 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 newMockLpaStoreResolvingService(t interface { - mock.TestingT - Cleanup(func()) -}) *mockLpaStoreResolvingService { - mock := &mockLpaStoreResolvingService{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney.go b/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney.go index beb29941d4..dcec33b48a 100644 --- a/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney.go +++ b/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney.go @@ -19,7 +19,7 @@ type confirmDontWantToBeAttorneyData struct { Lpa *lpadata.Lpa } -func ConfirmDontWantToBeAttorney(tmpl template.Template, lpaStoreResolvingService LpaStoreResolvingService, attorneyStore AttorneyStore, notifyClient NotifyClient, appPublicURL string) Handler { +func ConfirmDontWantToBeAttorney(tmpl template.Template, lpaStoreResolvingService LpaStoreResolvingService, attorneyStore AttorneyStore, notifyClient NotifyClient, appPublicURL string, lpaStoreClient LpaStoreClient) Handler { return func(appData appcontext.Data, w http.ResponseWriter, r *http.Request, attorneyProvidedDetails *attorneydata.Provided) error { lpa, err := lpaStoreResolvingService.Get(r.Context()) if err != nil { @@ -46,11 +46,15 @@ func ConfirmDontWantToBeAttorney(tmpl template.Template, lpaStoreResolvingServic DonorStartPageURL: appPublicURL + page.PathStart.Format(), } - if err := attorneyStore.Delete(r.Context()); err != nil { + if err := notifyClient.SendActorEmail(r.Context(), lpa.CorrespondentEmail(), lpa.LpaUID, email); err != nil { return err } - if err := notifyClient.SendActorEmail(r.Context(), lpa.CorrespondentEmail(), lpa.LpaUID, email); err != nil { + if err := lpaStoreClient.SendAttorneyOptOut(r.Context(), lpa.LpaUID, attorneyProvidedDetails.UID); err != nil { + return err + } + + if err := attorneyStore.Delete(r.Context()); err != nil { return err } diff --git a/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney_logged_out.go b/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney_logged_out.go index 4d1f884a50..75640b848f 100644 --- a/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney_logged_out.go +++ b/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney_logged_out.go @@ -21,7 +21,7 @@ type confirmDontWantToBeAttorneyDataLoggedOut struct { Lpa *lpadata.Lpa } -func ConfirmDontWantToBeAttorneyLoggedOut(tmpl template.Template, shareCodeStore ShareCodeStore, lpaStoreResolvingService LpaStoreResolvingService, sessionStore SessionStore, notifyClient NotifyClient, appPublicURL string) page.Handler { +func ConfirmDontWantToBeAttorneyLoggedOut(tmpl template.Template, shareCodeStore ShareCodeStore, lpaStoreResolvingService LpaStoreResolvingService, sessionStore SessionStore, notifyClient NotifyClient, appPublicURL string, lpaStoreClient LpaStoreClient) page.Handler { return func(appData appcontext.Data, w http.ResponseWriter, r *http.Request) error { session, err := sessionStore.LpaData(r) if err != nil { @@ -64,6 +64,10 @@ func ConfirmDontWantToBeAttorneyLoggedOut(tmpl template.Template, shareCodeStore return err } + if err := lpaStoreClient.SendAttorneyOptOut(r.Context(), lpa.LpaUID, shareCode.ActorUID); err != nil { + return err + } + if err := shareCodeStore.Delete(r.Context(), shareCode); err != nil { return err } diff --git a/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney_logged_out_test.go b/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney_logged_out_test.go index 211cc1f0ce..96514fb8e1 100644 --- a/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney_logged_out_test.go +++ b/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney_logged_out_test.go @@ -43,7 +43,7 @@ func TestGetConfirmDontWantToBeAttorneyLoggedOut(t *testing.T) { }). Return(nil) - err := ConfirmDontWantToBeAttorneyLoggedOut(template.Execute, nil, lpaStoreResolvingService, sessionStore, nil, "example.com")(testAppData, w, r) + err := ConfirmDontWantToBeAttorneyLoggedOut(template.Execute, nil, lpaStoreResolvingService, sessionStore, nil, "example.com", nil)(testAppData, w, r) resp := w.Result() assert.Nil(t, err) @@ -59,7 +59,7 @@ func TestGetConfirmDontWantToBeAttorneyLoggedOutWhenSessionStoreErrors(t *testin LpaData(r). Return(&sesh.LpaDataSession{}, expectedError) - err := ConfirmDontWantToBeAttorneyLoggedOut(nil, nil, nil, sessionStore, nil, "example.com")(testAppData, w, r) + err := ConfirmDontWantToBeAttorneyLoggedOut(nil, nil, nil, sessionStore, nil, "example.com", nil)(testAppData, w, r) resp := w.Result() assert.Equal(t, expectedError, err) @@ -80,7 +80,7 @@ func TestGetConfirmDontWantToBeAttorneyLoggedOutWhenLpaStoreResolvingServiceErro Get(mock.Anything). Return(&lpadata.Lpa{}, expectedError) - err := ConfirmDontWantToBeAttorneyLoggedOut(nil, nil, lpaStoreResolvingService, sessionStore, nil, "example.com")(testAppData, w, r) + err := ConfirmDontWantToBeAttorneyLoggedOut(nil, nil, lpaStoreResolvingService, sessionStore, nil, "example.com", nil)(testAppData, w, r) resp := w.Result() assert.Equal(t, expectedError, err) @@ -106,7 +106,7 @@ func TestGetConfirmDontWantToBeAttorneyLoggedOutWhenTemplateErrors(t *testing.T) Execute(mock.Anything, mock.Anything). Return(expectedError) - err := ConfirmDontWantToBeAttorneyLoggedOut(template.Execute, nil, lpaStoreResolvingService, sessionStore, nil, "example.com")(testAppData, w, r) + err := ConfirmDontWantToBeAttorneyLoggedOut(template.Execute, nil, lpaStoreResolvingService, sessionStore, nil, "example.com", nil)(testAppData, w, r) resp := w.Result() assert.Equal(t, expectedError, err) @@ -214,7 +214,12 @@ func TestPostConfirmDontWantToBeAttorneyLoggedOut(t *testing.T) { testAppData.Localizer = localizer - err := ConfirmDontWantToBeAttorneyLoggedOut(nil, shareCodeStore, lpaStoreResolvingService, sessionStore, notifyClient, "example.com")(testAppData, w, r) + lpaStoreClient := newMockLpaStoreClient(t) + lpaStoreClient.EXPECT(). + SendAttorneyOptOut(r.Context(), "lpa-uid", tc.uid). + Return(nil) + + err := ConfirmDontWantToBeAttorneyLoggedOut(nil, shareCodeStore, lpaStoreResolvingService, sessionStore, notifyClient, "example.com", lpaStoreClient)(testAppData, w, r) resp := w.Result() @@ -258,7 +263,7 @@ func TestPostConfirmDontWantToBeAttorneyLoggedOutWhenAttorneyNotFound(t *testing Type: lpadata.LpaTypePersonalWelfare, }, nil) - err := ConfirmDontWantToBeAttorneyLoggedOut(nil, shareCodeStore, lpaStoreResolvingService, sessionStore, nil, "example.com")(testAppData, w, r) + err := ConfirmDontWantToBeAttorneyLoggedOut(nil, shareCodeStore, lpaStoreResolvingService, sessionStore, nil, "example.com", nil)(testAppData, w, r) assert.EqualError(t, err, "attorney not found") } @@ -287,6 +292,7 @@ func TestPostConfirmDontWantToBeAttorneyLoggedOutErrors(t *testing.T) { localizer func(*testing.T) *mockLocalizer shareCodeStore func(*testing.T) *mockShareCodeStore notifyClient func(*testing.T) *mockNotifyClient + lpaStoreClient func(*testing.T) *mockLpaStoreClient }{ "when shareCodeStore.Get() error": { sessionStore: func(t *testing.T) *mockSessionStore { @@ -314,7 +320,7 @@ func TestPostConfirmDontWantToBeAttorneyLoggedOutErrors(t *testing.T) { return shareCodeStore }, }, - "when shareCodeStore.Delete() error": { + "when notifyClient.SendActorEmail() error": { sessionStore: func(t *testing.T) *mockSessionStore { sessionStore := newMockSessionStore(t) sessionStore.EXPECT(). @@ -337,10 +343,45 @@ func TestPostConfirmDontWantToBeAttorneyLoggedOutErrors(t *testing.T) { shareCodeStore.EXPECT(). Get(mock.Anything, mock.Anything, mock.Anything). Return(shareCodeData, nil) - shareCodeStore.EXPECT(). - Delete(mock.Anything, mock.Anything). + + return shareCodeStore + }, + notifyClient: func(t *testing.T) *mockNotifyClient { + client := newMockNotifyClient(t) + client.EXPECT(). + EmailGreeting(mock.Anything). + Return("Dear donor") + client.EXPECT(). + SendActorEmail(mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(expectedError) + return client + }, + }, + "when lpaStoreClient.SendAttorneyOptOut() error": { + sessionStore: func(t *testing.T) *mockSessionStore { + sessionStore := newMockSessionStore(t) + sessionStore.EXPECT(). + LpaData(r). + Return(&sesh.LpaDataSession{LpaID: "lpa-id"}, nil) + + return sessionStore + }, + lpaStoreResolvingService: func(t *testing.T) *mockLpaStoreResolvingService { + lpaStoreResolvingService := newMockLpaStoreResolvingService(t) + lpaStoreResolvingService.EXPECT(). + Get(ctx). + Return(&signedLPA, nil) + + return lpaStoreResolvingService + }, + localizer: localizer, + shareCodeStore: func(t *testing.T) *mockShareCodeStore { + shareCodeStore := newMockShareCodeStore(t) + shareCodeStore.EXPECT(). + Get(mock.Anything, mock.Anything, mock.Anything). + Return(shareCodeData, nil) + return shareCodeStore }, notifyClient: func(t *testing.T) *mockNotifyClient { @@ -354,8 +395,15 @@ func TestPostConfirmDontWantToBeAttorneyLoggedOutErrors(t *testing.T) { return client }, + lpaStoreClient: func(t *testing.T) *mockLpaStoreClient { + client := newMockLpaStoreClient(t) + client.EXPECT(). + SendAttorneyOptOut(mock.Anything, mock.Anything, mock.Anything). + Return(expectedError) + return client + }, }, - "when notifyClient.SendActorEmail() error": { + "when shareCodeStore.Delete() error": { sessionStore: func(t *testing.T) *mockSessionStore { sessionStore := newMockSessionStore(t) sessionStore.EXPECT(). @@ -378,6 +426,9 @@ func TestPostConfirmDontWantToBeAttorneyLoggedOutErrors(t *testing.T) { shareCodeStore.EXPECT(). Get(mock.Anything, mock.Anything, mock.Anything). Return(shareCodeData, nil) + shareCodeStore.EXPECT(). + Delete(mock.Anything, mock.Anything). + Return(expectedError) return shareCodeStore }, @@ -388,10 +439,17 @@ func TestPostConfirmDontWantToBeAttorneyLoggedOutErrors(t *testing.T) { Return("Dear donor") client.EXPECT(). SendActorEmail(mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(expectedError) + Return(nil) return client }, + lpaStoreClient: func(t *testing.T) *mockLpaStoreClient { + client := newMockLpaStoreClient(t) + client.EXPECT(). + SendAttorneyOptOut(mock.Anything, mock.Anything, mock.Anything). + Return(nil) + return client + }, }, } @@ -401,7 +459,7 @@ func TestPostConfirmDontWantToBeAttorneyLoggedOutErrors(t *testing.T) { testAppData.Localizer = evalT(tc.localizer, t) - err := ConfirmDontWantToBeAttorneyLoggedOut(nil, evalT(tc.shareCodeStore, t), evalT(tc.lpaStoreResolvingService, t), evalT(tc.sessionStore, t), evalT(tc.notifyClient, t), "example.com")(testAppData, w, r) + err := ConfirmDontWantToBeAttorneyLoggedOut(nil, evalT(tc.shareCodeStore, t), evalT(tc.lpaStoreResolvingService, t), evalT(tc.sessionStore, t), evalT(tc.notifyClient, t), "example.com", evalT(tc.lpaStoreClient, t))(testAppData, w, r) resp := w.Result() diff --git a/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney_test.go b/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney_test.go index 4ccc6dc37d..35ad7db56e 100644 --- a/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney_test.go +++ b/internal/attorney/attorneypage/confirm_dont_want_to_be_attorney_test.go @@ -36,7 +36,7 @@ func TestGetConfirmDontWantToBeAttorney(t *testing.T) { }). Return(nil) - err := ConfirmDontWantToBeAttorney(template.Execute, lpaStoreResolvingService, nil, nil, "example.com")(testAppData, w, r, &attorneydata.Provided{}) + err := ConfirmDontWantToBeAttorney(template.Execute, lpaStoreResolvingService, nil, nil, "example.com", nil)(testAppData, w, r, &attorneydata.Provided{}) resp := w.Result() assert.Nil(t, err) @@ -52,7 +52,7 @@ func TestGetConfirmDontWantToBeAttorneyWhenLpaStoreResolvingServiceErrors(t *tes Get(mock.Anything). Return(&lpadata.Lpa{}, expectedError) - err := ConfirmDontWantToBeAttorney(nil, lpaStoreResolvingService, nil, nil, "example.com")(testAppData, w, r, &attorneydata.Provided{}) + err := ConfirmDontWantToBeAttorney(nil, lpaStoreResolvingService, nil, nil, "example.com", nil)(testAppData, w, r, &attorneydata.Provided{}) resp := w.Result() assert.Equal(t, expectedError, err) @@ -73,7 +73,7 @@ func TestGetConfirmDontWantToBeAttorneyWhenTemplateErrors(t *testing.T) { Execute(mock.Anything, mock.Anything). Return(expectedError) - err := ConfirmDontWantToBeAttorney(template.Execute, lpaStoreResolvingService, nil, nil, "example.com")(testAppData, w, r, &attorneydata.Provided{}) + err := ConfirmDontWantToBeAttorney(template.Execute, lpaStoreResolvingService, nil, nil, "example.com", nil)(testAppData, w, r, &attorneydata.Provided{}) resp := w.Result() assert.Equal(t, expectedError, err) @@ -129,7 +129,12 @@ func TestPostConfirmDontWantToBeAttorney(t *testing.T) { }). Return(nil) - err := ConfirmDontWantToBeAttorney(nil, lpaStoreResolvingService, certificateProviderStore, notifyClient, "example.com")(testAppData, w, r, &attorneydata.Provided{ + lpaStoreClient := newMockLpaStoreClient(t) + lpaStoreClient.EXPECT(). + SendAttorneyOptOut(r.Context(), "lpa-uid", uid). + Return(nil) + + err := ConfirmDontWantToBeAttorney(nil, lpaStoreResolvingService, certificateProviderStore, notifyClient, "example.com", lpaStoreClient)(testAppData, w, r, &attorneydata.Provided{ UID: uid, }) @@ -157,7 +162,7 @@ func TestPostConfirmDontWantToBeAttorneyWhenAttorneyNotFound(t *testing.T) { Type: lpadata.LpaTypePersonalWelfare, }, nil) - err := ConfirmDontWantToBeAttorney(nil, lpaStoreResolvingService, nil, nil, "example.com")(testAppData, w, r, &attorneydata.Provided{ + err := ConfirmDontWantToBeAttorney(nil, lpaStoreResolvingService, nil, nil, "example.com", nil)(testAppData, w, r, &attorneydata.Provided{ UID: uid, }) assert.EqualError(t, err, "attorney not found") @@ -167,35 +172,58 @@ func TestPostConfirmDontWantToBeAttorneyErrors(t *testing.T) { r, _ := http.NewRequest(http.MethodPost, "/?referenceNumber=123", nil) testcases := map[string]struct { - certificateProviderStore func(*testing.T) *mockAttorneyStore - notifyClient func(*testing.T) *mockNotifyClient + attorneyStore func(*testing.T) *mockAttorneyStore + notifyClient func(*testing.T) *mockNotifyClient + lpaStoreClient func(*testing.T) *mockLpaStoreClient }{ - "when attorneyStore.Delete() error": { - certificateProviderStore: func(t *testing.T) *mockAttorneyStore { - certificateProviderStore := newMockAttorneyStore(t) - certificateProviderStore.EXPECT(). - Delete(mock.Anything). + "when notifyClient.SendActorEmail() error": { + notifyClient: func(t *testing.T) *mockNotifyClient { + client := newMockNotifyClient(t) + client.EXPECT(). + EmailGreeting(mock.Anything). + Return("") + client.EXPECT(). + SendActorEmail(mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(expectedError) - return certificateProviderStore + return client + }, + }, + "when lpaStoreClient.SendAttorneyOptOut() error": { + lpaStoreClient: func(t *testing.T) *mockLpaStoreClient { + client := newMockLpaStoreClient(t) + client.EXPECT(). + SendAttorneyOptOut(mock.Anything, mock.Anything, mock.Anything). + Return(expectedError) + return client }, notifyClient: func(t *testing.T) *mockNotifyClient { client := newMockNotifyClient(t) client.EXPECT(). EmailGreeting(mock.Anything). Return("") + client.EXPECT(). + SendActorEmail(mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(nil) return client }, }, - "when notifyClient.SendActorEmail() error": { - certificateProviderStore: func(t *testing.T) *mockAttorneyStore { - certificateProviderStore := newMockAttorneyStore(t) - certificateProviderStore.EXPECT(). - Delete(mock.Anything). + "when attorneyStore.Delete() error": { + lpaStoreClient: func(t *testing.T) *mockLpaStoreClient { + client := newMockLpaStoreClient(t) + client.EXPECT(). + SendAttorneyOptOut(mock.Anything, mock.Anything, mock.Anything). Return(nil) + return client + }, + attorneyStore: func(t *testing.T) *mockAttorneyStore { + attorneyStore := newMockAttorneyStore(t) + attorneyStore.EXPECT(). + Delete(mock.Anything). + Return(expectedError) - return certificateProviderStore + return attorneyStore }, notifyClient: func(t *testing.T) *mockNotifyClient { client := newMockNotifyClient(t) @@ -204,7 +232,7 @@ func TestPostConfirmDontWantToBeAttorneyErrors(t *testing.T) { Return("") client.EXPECT(). SendActorEmail(mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(expectedError) + Return(nil) return client }, @@ -227,7 +255,7 @@ func TestPostConfirmDontWantToBeAttorneyErrors(t *testing.T) { testAppData.Localizer = localizer - err := ConfirmDontWantToBeAttorney(nil, lpaStoreResolvingService, evalT(tc.certificateProviderStore, t), evalT(tc.notifyClient, t), "example.com")(testAppData, w, r, &attorneydata.Provided{}) + err := ConfirmDontWantToBeAttorney(nil, lpaStoreResolvingService, evalT(tc.attorneyStore, t), evalT(tc.notifyClient, t), "example.com", evalT(tc.lpaStoreClient, t))(testAppData, w, r, &attorneydata.Provided{}) resp := w.Result() diff --git a/internal/attorney/attorneypage/mock_LpaStoreClient_test.go b/internal/attorney/attorneypage/mock_LpaStoreClient_test.go index 63e31a23af..09655d476a 100644 --- a/internal/attorney/attorneypage/mock_LpaStoreClient_test.go +++ b/internal/attorney/attorneypage/mock_LpaStoreClient_test.go @@ -3,10 +3,11 @@ package attorneypage import ( - context "context" - + actoruid "github.com/ministryofjustice/opg-modernising-lpa/internal/actor/actoruid" attorneydata "github.com/ministryofjustice/opg-modernising-lpa/internal/attorney/attorneydata" + context "context" + lpadata "github.com/ministryofjustice/opg-modernising-lpa/internal/lpastore/lpadata" mock "github.com/stretchr/testify/mock" @@ -73,6 +74,54 @@ func (_c *mockLpaStoreClient_SendAttorney_Call) RunAndReturn(run func(context.Co return _c } +// SendAttorneyOptOut provides a mock function with given fields: ctx, lpaUID, attorneyUID +func (_m *mockLpaStoreClient) SendAttorneyOptOut(ctx context.Context, lpaUID string, attorneyUID actoruid.UID) error { + ret := _m.Called(ctx, lpaUID, attorneyUID) + + if len(ret) == 0 { + panic("no return value specified for SendAttorneyOptOut") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, actoruid.UID) error); ok { + r0 = rf(ctx, lpaUID, attorneyUID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// mockLpaStoreClient_SendAttorneyOptOut_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendAttorneyOptOut' +type mockLpaStoreClient_SendAttorneyOptOut_Call struct { + *mock.Call +} + +// SendAttorneyOptOut is a helper method to define mock.On call +// - ctx context.Context +// - lpaUID string +// - attorneyUID actoruid.UID +func (_e *mockLpaStoreClient_Expecter) SendAttorneyOptOut(ctx interface{}, lpaUID interface{}, attorneyUID interface{}) *mockLpaStoreClient_SendAttorneyOptOut_Call { + return &mockLpaStoreClient_SendAttorneyOptOut_Call{Call: _e.mock.On("SendAttorneyOptOut", ctx, lpaUID, attorneyUID)} +} + +func (_c *mockLpaStoreClient_SendAttorneyOptOut_Call) Run(run func(ctx context.Context, lpaUID string, attorneyUID actoruid.UID)) *mockLpaStoreClient_SendAttorneyOptOut_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(actoruid.UID)) + }) + return _c +} + +func (_c *mockLpaStoreClient_SendAttorneyOptOut_Call) Return(_a0 error) *mockLpaStoreClient_SendAttorneyOptOut_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *mockLpaStoreClient_SendAttorneyOptOut_Call) RunAndReturn(run func(context.Context, string, actoruid.UID) error) *mockLpaStoreClient_SendAttorneyOptOut_Call { + _c.Call.Return(run) + return _c +} + // newMockLpaStoreClient creates a new instance of mockLpaStoreClient. 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 newMockLpaStoreClient(t interface { diff --git a/internal/attorney/attorneypage/register.go b/internal/attorney/attorneypage/register.go index 9fb9860eb5..a984606137 100644 --- a/internal/attorney/attorneypage/register.go +++ b/internal/attorney/attorneypage/register.go @@ -10,6 +10,7 @@ import ( "github.com/ministryofjustice/opg-go-common/template" "github.com/ministryofjustice/opg-modernising-lpa/internal/actor" + "github.com/ministryofjustice/opg-modernising-lpa/internal/actor/actoruid" "github.com/ministryofjustice/opg-modernising-lpa/internal/appcontext" "github.com/ministryofjustice/opg-modernising-lpa/internal/attorney" "github.com/ministryofjustice/opg-modernising-lpa/internal/attorney/attorneydata" @@ -80,6 +81,7 @@ type DashboardStore interface { type LpaStoreClient interface { SendAttorney(context.Context, *lpadata.Lpa, *attorneydata.Provided) error + SendAttorneyOptOut(ctx context.Context, lpaUID string, attorneyUID actoruid.UID) error } type NotifyClient interface { @@ -115,7 +117,7 @@ func Register( handleRoot(page.PathAttorneyEnterReferenceNumberOptOut, None, EnterReferenceNumberOptOut(tmpls.Get("enter_reference_number_opt_out.gohtml"), shareCodeStore, sessionStore)) handleRoot(page.PathAttorneyConfirmDontWantToBeAttorneyLoggedOut, None, - ConfirmDontWantToBeAttorneyLoggedOut(tmpls.Get("confirm_dont_want_to_be_attorney.gohtml"), shareCodeStore, lpaStoreResolvingService, sessionStore, notifyClient, appPublicURL)) + ConfirmDontWantToBeAttorneyLoggedOut(tmpls.Get("confirm_dont_want_to_be_attorney.gohtml"), shareCodeStore, lpaStoreResolvingService, sessionStore, notifyClient, appPublicURL, lpaStoreClient)) handleRoot(page.PathAttorneyYouHaveDecidedNotToBeAttorney, None, page.Guidance(tmpls.Get("you_have_decided_not_to_be_attorney.gohtml"))) @@ -147,7 +149,7 @@ func Register( Progress(tmpls.Get("progress.gohtml"), lpaStoreResolvingService)) handleAttorney(attorney.PathConfirmDontWantToBeAttorney, CanGoBack, - ConfirmDontWantToBeAttorney(tmpls.Get("confirm_dont_want_to_be_attorney.gohtml"), lpaStoreResolvingService, attorneyStore, notifyClient, appPublicURL)) + ConfirmDontWantToBeAttorney(tmpls.Get("confirm_dont_want_to_be_attorney.gohtml"), lpaStoreResolvingService, attorneyStore, notifyClient, appPublicURL, lpaStoreClient)) } type handleOpt byte diff --git a/internal/dashboard/mock_DynamoClient_test.go b/internal/dashboard/mock_DynamoClient_test.go index f42176b652..feeb3dfd53 100644 --- a/internal/dashboard/mock_DynamoClient_test.go +++ b/internal/dashboard/mock_DynamoClient_test.go @@ -83,55 +83,6 @@ func (_c *mockDynamoClient_AllByKeys_Call) RunAndReturn(run func(context.Context return _c } -// AllByPartialSK provides a mock function with given fields: ctx, pk, partialSK, v -func (_m *mockDynamoClient) AllByPartialSK(ctx context.Context, pk dynamo.PK, partialSK dynamo.SK, v interface{}) error { - ret := _m.Called(ctx, pk, partialSK, v) - - if len(ret) == 0 { - panic("no return value specified for AllByPartialSK") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, dynamo.PK, dynamo.SK, interface{}) error); ok { - r0 = rf(ctx, pk, partialSK, v) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_AllByPartialSK_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AllByPartialSK' -type mockDynamoClient_AllByPartialSK_Call struct { - *mock.Call -} - -// AllByPartialSK is a helper method to define mock.On call -// - ctx context.Context -// - pk dynamo.PK -// - partialSK dynamo.SK -// - v interface{} -func (_e *mockDynamoClient_Expecter) AllByPartialSK(ctx interface{}, pk interface{}, partialSK interface{}, v interface{}) *mockDynamoClient_AllByPartialSK_Call { - return &mockDynamoClient_AllByPartialSK_Call{Call: _e.mock.On("AllByPartialSK", ctx, pk, partialSK, v)} -} - -func (_c *mockDynamoClient_AllByPartialSK_Call) Run(run func(ctx context.Context, pk dynamo.PK, partialSK dynamo.SK, v interface{})) *mockDynamoClient_AllByPartialSK_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(dynamo.PK), args[2].(dynamo.SK), args[3].(interface{})) - }) - return _c -} - -func (_c *mockDynamoClient_AllByPartialSK_Call) Return(_a0 error) *mockDynamoClient_AllByPartialSK_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_AllByPartialSK_Call) RunAndReturn(run func(context.Context, dynamo.PK, dynamo.SK, interface{}) error) *mockDynamoClient_AllByPartialSK_Call { - _c.Call.Return(run) - return _c -} - // AllBySK provides a mock function with given fields: ctx, sk, v func (_m *mockDynamoClient) AllBySK(ctx context.Context, sk dynamo.SK, v interface{}) error { ret := _m.Called(ctx, sk, v) @@ -180,688 +131,6 @@ func (_c *mockDynamoClient_AllBySK_Call) RunAndReturn(run func(context.Context, return _c } -// AllKeysByPK provides a mock function with given fields: ctx, pk -func (_m *mockDynamoClient) AllKeysByPK(ctx context.Context, pk dynamo.PK) ([]dynamo.Keys, error) { - ret := _m.Called(ctx, pk) - - if len(ret) == 0 { - panic("no return value specified for AllKeysByPK") - } - - var r0 []dynamo.Keys - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, dynamo.PK) ([]dynamo.Keys, error)); ok { - return rf(ctx, pk) - } - if rf, ok := ret.Get(0).(func(context.Context, dynamo.PK) []dynamo.Keys); ok { - r0 = rf(ctx, pk) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]dynamo.Keys) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, dynamo.PK) error); ok { - r1 = rf(ctx, pk) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// mockDynamoClient_AllKeysByPK_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AllKeysByPK' -type mockDynamoClient_AllKeysByPK_Call struct { - *mock.Call -} - -// AllKeysByPK is a helper method to define mock.On call -// - ctx context.Context -// - pk dynamo.PK -func (_e *mockDynamoClient_Expecter) AllKeysByPK(ctx interface{}, pk interface{}) *mockDynamoClient_AllKeysByPK_Call { - return &mockDynamoClient_AllKeysByPK_Call{Call: _e.mock.On("AllKeysByPK", ctx, pk)} -} - -func (_c *mockDynamoClient_AllKeysByPK_Call) Run(run func(ctx context.Context, pk dynamo.PK)) *mockDynamoClient_AllKeysByPK_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(dynamo.PK)) - }) - return _c -} - -func (_c *mockDynamoClient_AllKeysByPK_Call) Return(_a0 []dynamo.Keys, _a1 error) *mockDynamoClient_AllKeysByPK_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *mockDynamoClient_AllKeysByPK_Call) RunAndReturn(run func(context.Context, dynamo.PK) ([]dynamo.Keys, error)) *mockDynamoClient_AllKeysByPK_Call { - _c.Call.Return(run) - return _c -} - -// BatchPut provides a mock function with given fields: ctx, items -func (_m *mockDynamoClient) BatchPut(ctx context.Context, items []interface{}) error { - ret := _m.Called(ctx, items) - - if len(ret) == 0 { - panic("no return value specified for BatchPut") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, []interface{}) error); ok { - r0 = rf(ctx, items) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_BatchPut_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BatchPut' -type mockDynamoClient_BatchPut_Call struct { - *mock.Call -} - -// BatchPut is a helper method to define mock.On call -// - ctx context.Context -// - items []interface{} -func (_e *mockDynamoClient_Expecter) BatchPut(ctx interface{}, items interface{}) *mockDynamoClient_BatchPut_Call { - return &mockDynamoClient_BatchPut_Call{Call: _e.mock.On("BatchPut", ctx, items)} -} - -func (_c *mockDynamoClient_BatchPut_Call) Run(run func(ctx context.Context, items []interface{})) *mockDynamoClient_BatchPut_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].([]interface{})) - }) - return _c -} - -func (_c *mockDynamoClient_BatchPut_Call) Return(_a0 error) *mockDynamoClient_BatchPut_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_BatchPut_Call) RunAndReturn(run func(context.Context, []interface{}) error) *mockDynamoClient_BatchPut_Call { - _c.Call.Return(run) - return _c -} - -// Create provides a mock function with given fields: ctx, v -func (_m *mockDynamoClient) Create(ctx context.Context, v interface{}) error { - ret := _m.Called(ctx, v) - - if len(ret) == 0 { - panic("no return value specified for Create") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, interface{}) error); ok { - r0 = rf(ctx, v) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' -type mockDynamoClient_Create_Call struct { - *mock.Call -} - -// Create is a helper method to define mock.On call -// - ctx context.Context -// - v interface{} -func (_e *mockDynamoClient_Expecter) Create(ctx interface{}, v interface{}) *mockDynamoClient_Create_Call { - return &mockDynamoClient_Create_Call{Call: _e.mock.On("Create", ctx, v)} -} - -func (_c *mockDynamoClient_Create_Call) Run(run func(ctx context.Context, v interface{})) *mockDynamoClient_Create_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(interface{})) - }) - return _c -} - -func (_c *mockDynamoClient_Create_Call) Return(_a0 error) *mockDynamoClient_Create_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_Create_Call) RunAndReturn(run func(context.Context, interface{}) error) *mockDynamoClient_Create_Call { - _c.Call.Return(run) - return _c -} - -// DeleteKeys provides a mock function with given fields: ctx, keys -func (_m *mockDynamoClient) DeleteKeys(ctx context.Context, keys []dynamo.Keys) error { - ret := _m.Called(ctx, keys) - - if len(ret) == 0 { - panic("no return value specified for DeleteKeys") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, []dynamo.Keys) error); ok { - r0 = rf(ctx, keys) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_DeleteKeys_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteKeys' -type mockDynamoClient_DeleteKeys_Call struct { - *mock.Call -} - -// DeleteKeys is a helper method to define mock.On call -// - ctx context.Context -// - keys []dynamo.Keys -func (_e *mockDynamoClient_Expecter) DeleteKeys(ctx interface{}, keys interface{}) *mockDynamoClient_DeleteKeys_Call { - return &mockDynamoClient_DeleteKeys_Call{Call: _e.mock.On("DeleteKeys", ctx, keys)} -} - -func (_c *mockDynamoClient_DeleteKeys_Call) Run(run func(ctx context.Context, keys []dynamo.Keys)) *mockDynamoClient_DeleteKeys_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].([]dynamo.Keys)) - }) - return _c -} - -func (_c *mockDynamoClient_DeleteKeys_Call) Return(_a0 error) *mockDynamoClient_DeleteKeys_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_DeleteKeys_Call) RunAndReturn(run func(context.Context, []dynamo.Keys) error) *mockDynamoClient_DeleteKeys_Call { - _c.Call.Return(run) - return _c -} - -// DeleteOne provides a mock function with given fields: ctx, pk, sk -func (_m *mockDynamoClient) DeleteOne(ctx context.Context, pk dynamo.PK, sk dynamo.SK) error { - ret := _m.Called(ctx, pk, sk) - - if len(ret) == 0 { - panic("no return value specified for DeleteOne") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, dynamo.PK, dynamo.SK) error); ok { - r0 = rf(ctx, pk, sk) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_DeleteOne_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteOne' -type mockDynamoClient_DeleteOne_Call struct { - *mock.Call -} - -// DeleteOne is a helper method to define mock.On call -// - ctx context.Context -// - pk dynamo.PK -// - sk dynamo.SK -func (_e *mockDynamoClient_Expecter) DeleteOne(ctx interface{}, pk interface{}, sk interface{}) *mockDynamoClient_DeleteOne_Call { - return &mockDynamoClient_DeleteOne_Call{Call: _e.mock.On("DeleteOne", ctx, pk, sk)} -} - -func (_c *mockDynamoClient_DeleteOne_Call) Run(run func(ctx context.Context, pk dynamo.PK, sk dynamo.SK)) *mockDynamoClient_DeleteOne_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(dynamo.PK), args[2].(dynamo.SK)) - }) - return _c -} - -func (_c *mockDynamoClient_DeleteOne_Call) Return(_a0 error) *mockDynamoClient_DeleteOne_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_DeleteOne_Call) RunAndReturn(run func(context.Context, dynamo.PK, dynamo.SK) error) *mockDynamoClient_DeleteOne_Call { - _c.Call.Return(run) - return _c -} - -// LatestForActor provides a mock function with given fields: ctx, sk, v -func (_m *mockDynamoClient) LatestForActor(ctx context.Context, sk dynamo.SK, v interface{}) error { - ret := _m.Called(ctx, sk, v) - - if len(ret) == 0 { - panic("no return value specified for LatestForActor") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, dynamo.SK, interface{}) error); ok { - r0 = rf(ctx, sk, v) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_LatestForActor_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestForActor' -type mockDynamoClient_LatestForActor_Call struct { - *mock.Call -} - -// LatestForActor is a helper method to define mock.On call -// - ctx context.Context -// - sk dynamo.SK -// - v interface{} -func (_e *mockDynamoClient_Expecter) LatestForActor(ctx interface{}, sk interface{}, v interface{}) *mockDynamoClient_LatestForActor_Call { - return &mockDynamoClient_LatestForActor_Call{Call: _e.mock.On("LatestForActor", ctx, sk, v)} -} - -func (_c *mockDynamoClient_LatestForActor_Call) Run(run func(ctx context.Context, sk dynamo.SK, v interface{})) *mockDynamoClient_LatestForActor_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(dynamo.SK), args[2].(interface{})) - }) - return _c -} - -func (_c *mockDynamoClient_LatestForActor_Call) Return(_a0 error) *mockDynamoClient_LatestForActor_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_LatestForActor_Call) RunAndReturn(run func(context.Context, dynamo.SK, interface{}) error) *mockDynamoClient_LatestForActor_Call { - _c.Call.Return(run) - return _c -} - -// One provides a mock function with given fields: ctx, pk, sk, v -func (_m *mockDynamoClient) One(ctx context.Context, pk dynamo.PK, sk dynamo.SK, v interface{}) error { - ret := _m.Called(ctx, pk, sk, v) - - if len(ret) == 0 { - panic("no return value specified for One") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, dynamo.PK, dynamo.SK, interface{}) error); ok { - r0 = rf(ctx, pk, sk, v) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_One_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'One' -type mockDynamoClient_One_Call struct { - *mock.Call -} - -// One is a helper method to define mock.On call -// - ctx context.Context -// - pk dynamo.PK -// - sk dynamo.SK -// - v interface{} -func (_e *mockDynamoClient_Expecter) One(ctx interface{}, pk interface{}, sk interface{}, v interface{}) *mockDynamoClient_One_Call { - return &mockDynamoClient_One_Call{Call: _e.mock.On("One", ctx, pk, sk, v)} -} - -func (_c *mockDynamoClient_One_Call) Run(run func(ctx context.Context, pk dynamo.PK, sk dynamo.SK, v interface{})) *mockDynamoClient_One_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(dynamo.PK), args[2].(dynamo.SK), args[3].(interface{})) - }) - return _c -} - -func (_c *mockDynamoClient_One_Call) Return(_a0 error) *mockDynamoClient_One_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_One_Call) RunAndReturn(run func(context.Context, dynamo.PK, dynamo.SK, interface{}) error) *mockDynamoClient_One_Call { - _c.Call.Return(run) - return _c -} - -// OneByPK provides a mock function with given fields: ctx, pk, v -func (_m *mockDynamoClient) OneByPK(ctx context.Context, pk dynamo.PK, v interface{}) error { - ret := _m.Called(ctx, pk, v) - - if len(ret) == 0 { - panic("no return value specified for OneByPK") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, dynamo.PK, interface{}) error); ok { - r0 = rf(ctx, pk, v) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_OneByPK_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OneByPK' -type mockDynamoClient_OneByPK_Call struct { - *mock.Call -} - -// OneByPK is a helper method to define mock.On call -// - ctx context.Context -// - pk dynamo.PK -// - v interface{} -func (_e *mockDynamoClient_Expecter) OneByPK(ctx interface{}, pk interface{}, v interface{}) *mockDynamoClient_OneByPK_Call { - return &mockDynamoClient_OneByPK_Call{Call: _e.mock.On("OneByPK", ctx, pk, v)} -} - -func (_c *mockDynamoClient_OneByPK_Call) Run(run func(ctx context.Context, pk dynamo.PK, v interface{})) *mockDynamoClient_OneByPK_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(dynamo.PK), args[2].(interface{})) - }) - return _c -} - -func (_c *mockDynamoClient_OneByPK_Call) Return(_a0 error) *mockDynamoClient_OneByPK_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_OneByPK_Call) RunAndReturn(run func(context.Context, dynamo.PK, interface{}) error) *mockDynamoClient_OneByPK_Call { - _c.Call.Return(run) - return _c -} - -// OneByPartialSK provides a mock function with given fields: ctx, pk, partialSK, v -func (_m *mockDynamoClient) OneByPartialSK(ctx context.Context, pk dynamo.PK, partialSK dynamo.SK, v interface{}) error { - ret := _m.Called(ctx, pk, partialSK, v) - - if len(ret) == 0 { - panic("no return value specified for OneByPartialSK") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, dynamo.PK, dynamo.SK, interface{}) error); ok { - r0 = rf(ctx, pk, partialSK, v) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_OneByPartialSK_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OneByPartialSK' -type mockDynamoClient_OneByPartialSK_Call struct { - *mock.Call -} - -// OneByPartialSK is a helper method to define mock.On call -// - ctx context.Context -// - pk dynamo.PK -// - partialSK dynamo.SK -// - v interface{} -func (_e *mockDynamoClient_Expecter) OneByPartialSK(ctx interface{}, pk interface{}, partialSK interface{}, v interface{}) *mockDynamoClient_OneByPartialSK_Call { - return &mockDynamoClient_OneByPartialSK_Call{Call: _e.mock.On("OneByPartialSK", ctx, pk, partialSK, v)} -} - -func (_c *mockDynamoClient_OneByPartialSK_Call) Run(run func(ctx context.Context, pk dynamo.PK, partialSK dynamo.SK, v interface{})) *mockDynamoClient_OneByPartialSK_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(dynamo.PK), args[2].(dynamo.SK), args[3].(interface{})) - }) - return _c -} - -func (_c *mockDynamoClient_OneByPartialSK_Call) Return(_a0 error) *mockDynamoClient_OneByPartialSK_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_OneByPartialSK_Call) RunAndReturn(run func(context.Context, dynamo.PK, dynamo.SK, interface{}) error) *mockDynamoClient_OneByPartialSK_Call { - _c.Call.Return(run) - return _c -} - -// OneBySK provides a mock function with given fields: ctx, sk, v -func (_m *mockDynamoClient) OneBySK(ctx context.Context, sk dynamo.SK, v interface{}) error { - ret := _m.Called(ctx, sk, v) - - if len(ret) == 0 { - panic("no return value specified for OneBySK") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, dynamo.SK, interface{}) error); ok { - r0 = rf(ctx, sk, v) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_OneBySK_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OneBySK' -type mockDynamoClient_OneBySK_Call struct { - *mock.Call -} - -// OneBySK is a helper method to define mock.On call -// - ctx context.Context -// - sk dynamo.SK -// - v interface{} -func (_e *mockDynamoClient_Expecter) OneBySK(ctx interface{}, sk interface{}, v interface{}) *mockDynamoClient_OneBySK_Call { - return &mockDynamoClient_OneBySK_Call{Call: _e.mock.On("OneBySK", ctx, sk, v)} -} - -func (_c *mockDynamoClient_OneBySK_Call) Run(run func(ctx context.Context, sk dynamo.SK, v interface{})) *mockDynamoClient_OneBySK_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(dynamo.SK), args[2].(interface{})) - }) - return _c -} - -func (_c *mockDynamoClient_OneBySK_Call) Return(_a0 error) *mockDynamoClient_OneBySK_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_OneBySK_Call) RunAndReturn(run func(context.Context, dynamo.SK, interface{}) error) *mockDynamoClient_OneBySK_Call { - _c.Call.Return(run) - return _c -} - -// OneByUID provides a mock function with given fields: ctx, uid, v -func (_m *mockDynamoClient) OneByUID(ctx context.Context, uid string, v interface{}) error { - ret := _m.Called(ctx, uid, v) - - if len(ret) == 0 { - panic("no return value specified for OneByUID") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, interface{}) error); ok { - r0 = rf(ctx, uid, v) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_OneByUID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OneByUID' -type mockDynamoClient_OneByUID_Call struct { - *mock.Call -} - -// OneByUID is a helper method to define mock.On call -// - ctx context.Context -// - uid string -// - v interface{} -func (_e *mockDynamoClient_Expecter) OneByUID(ctx interface{}, uid interface{}, v interface{}) *mockDynamoClient_OneByUID_Call { - return &mockDynamoClient_OneByUID_Call{Call: _e.mock.On("OneByUID", ctx, uid, v)} -} - -func (_c *mockDynamoClient_OneByUID_Call) Run(run func(ctx context.Context, uid string, v interface{})) *mockDynamoClient_OneByUID_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(interface{})) - }) - return _c -} - -func (_c *mockDynamoClient_OneByUID_Call) Return(_a0 error) *mockDynamoClient_OneByUID_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_OneByUID_Call) RunAndReturn(run func(context.Context, string, interface{}) error) *mockDynamoClient_OneByUID_Call { - _c.Call.Return(run) - return _c -} - -// Put provides a mock function with given fields: ctx, v -func (_m *mockDynamoClient) Put(ctx context.Context, v interface{}) error { - ret := _m.Called(ctx, v) - - if len(ret) == 0 { - panic("no return value specified for Put") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, interface{}) error); ok { - r0 = rf(ctx, v) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_Put_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Put' -type mockDynamoClient_Put_Call struct { - *mock.Call -} - -// Put is a helper method to define mock.On call -// - ctx context.Context -// - v interface{} -func (_e *mockDynamoClient_Expecter) Put(ctx interface{}, v interface{}) *mockDynamoClient_Put_Call { - return &mockDynamoClient_Put_Call{Call: _e.mock.On("Put", ctx, v)} -} - -func (_c *mockDynamoClient_Put_Call) Run(run func(ctx context.Context, v interface{})) *mockDynamoClient_Put_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(interface{})) - }) - return _c -} - -func (_c *mockDynamoClient_Put_Call) Return(_a0 error) *mockDynamoClient_Put_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_Put_Call) RunAndReturn(run func(context.Context, interface{}) error) *mockDynamoClient_Put_Call { - _c.Call.Return(run) - return _c -} - -// Update provides a mock function with given fields: ctx, pk, sk, values, expression -func (_m *mockDynamoClient) Update(ctx context.Context, pk dynamo.PK, sk dynamo.SK, values map[string]types.AttributeValue, expression string) error { - ret := _m.Called(ctx, pk, sk, values, expression) - - if len(ret) == 0 { - panic("no return value specified for Update") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, dynamo.PK, dynamo.SK, map[string]types.AttributeValue, string) error); ok { - r0 = rf(ctx, pk, sk, values, expression) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' -type mockDynamoClient_Update_Call struct { - *mock.Call -} - -// Update is a helper method to define mock.On call -// - ctx context.Context -// - pk dynamo.PK -// - sk dynamo.SK -// - values map[string]types.AttributeValue -// - expression string -func (_e *mockDynamoClient_Expecter) Update(ctx interface{}, pk interface{}, sk interface{}, values interface{}, expression interface{}) *mockDynamoClient_Update_Call { - return &mockDynamoClient_Update_Call{Call: _e.mock.On("Update", ctx, pk, sk, values, expression)} -} - -func (_c *mockDynamoClient_Update_Call) Run(run func(ctx context.Context, pk dynamo.PK, sk dynamo.SK, values map[string]types.AttributeValue, expression string)) *mockDynamoClient_Update_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(dynamo.PK), args[2].(dynamo.SK), args[3].(map[string]types.AttributeValue), args[4].(string)) - }) - return _c -} - -func (_c *mockDynamoClient_Update_Call) Return(_a0 error) *mockDynamoClient_Update_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_Update_Call) RunAndReturn(run func(context.Context, dynamo.PK, dynamo.SK, map[string]types.AttributeValue, string) error) *mockDynamoClient_Update_Call { - _c.Call.Return(run) - return _c -} - -// WriteTransaction provides a mock function with given fields: ctx, transaction -func (_m *mockDynamoClient) WriteTransaction(ctx context.Context, transaction *dynamo.Transaction) error { - ret := _m.Called(ctx, transaction) - - if len(ret) == 0 { - panic("no return value specified for WriteTransaction") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *dynamo.Transaction) error); ok { - r0 = rf(ctx, transaction) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// mockDynamoClient_WriteTransaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WriteTransaction' -type mockDynamoClient_WriteTransaction_Call struct { - *mock.Call -} - -// WriteTransaction is a helper method to define mock.On call -// - ctx context.Context -// - transaction *dynamo.Transaction -func (_e *mockDynamoClient_Expecter) WriteTransaction(ctx interface{}, transaction interface{}) *mockDynamoClient_WriteTransaction_Call { - return &mockDynamoClient_WriteTransaction_Call{Call: _e.mock.On("WriteTransaction", ctx, transaction)} -} - -func (_c *mockDynamoClient_WriteTransaction_Call) Run(run func(ctx context.Context, transaction *dynamo.Transaction)) *mockDynamoClient_WriteTransaction_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*dynamo.Transaction)) - }) - return _c -} - -func (_c *mockDynamoClient_WriteTransaction_Call) Return(_a0 error) *mockDynamoClient_WriteTransaction_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *mockDynamoClient_WriteTransaction_Call) RunAndReturn(run func(context.Context, *dynamo.Transaction) error) *mockDynamoClient_WriteTransaction_Call { - _c.Call.Return(run) - return _c -} - // newMockDynamoClient creates a new instance of mockDynamoClient. 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 newMockDynamoClient(t interface { diff --git a/internal/lpastore/update.go b/internal/lpastore/update.go index 529631018a..945fa8614f 100644 --- a/internal/lpastore/update.go +++ b/internal/lpastore/update.go @@ -191,12 +191,12 @@ func (c *Client) SendAttorney(ctx context.Context, lpa *lpadata.Lpa, attorney *a return c.sendUpdate(ctx, lpa.LpaUID, attorney.UID, body) } -func (c *Client) SendCertificateProviderOptOut(ctx context.Context, lpaUID string, actorUID actoruid.UID) error { +func (c *Client) SendCertificateProviderOptOut(ctx context.Context, lpaUID string, certificateProviderUid actoruid.UID) error { body := updateRequest{ Type: "CERTIFICATE_PROVIDER_OPT_OUT", } - return c.sendUpdate(ctx, lpaUID, actorUID, body) + return c.sendUpdate(ctx, lpaUID, certificateProviderUid, body) } func (c *Client) SendDonorConfirmIdentity(ctx context.Context, donor *donordata.Provided) error { @@ -222,3 +222,11 @@ func (c *Client) SendCertificateProviderConfirmIdentity(ctx context.Context, lpa return c.sendUpdate(ctx, lpaUID, certificateProvider.UID, body) } + +func (c *Client) SendAttorneyOptOut(ctx context.Context, lpaUID string, attorneyUID actoruid.UID) error { + body := updateRequest{ + Type: "ATTORNEY_OPT_OUT", + } + + return c.sendUpdate(ctx, lpaUID, attorneyUID, body) +} diff --git a/internal/lpastore/update_test.go b/internal/lpastore/update_test.go index 5aa8163ac1..0c193d8971 100644 --- a/internal/lpastore/update_test.go +++ b/internal/lpastore/update_test.go @@ -464,3 +464,39 @@ func TestClientSendCertificateProviderConfirmIdentity(t *testing.T) { assert.Nil(t, err) } + +func TestClientSendAttorneyOptOut(t *testing.T) { + json := `{"type":"ATTORNEY_OPT_OUT","changes":null}` + + ctx := context.Background() + + secretsClient := newMockSecretsClient(t) + secretsClient.EXPECT(). + Secret(ctx, secrets.LpaStoreJwtSecretKey). + Return("secret", nil) + + var body []byte + doer := newMockDoer(t) + doer.EXPECT(). + Do(mock.MatchedBy(func(req *http.Request) bool { + if body == nil { + body, _ = io.ReadAll(req.Body) + } + + return assert.Equal(t, ctx, req.Context()) && + assert.Equal(t, http.MethodPost, req.Method) && + assert.Equal(t, "http://base/lpas/lpa-uid/updates", req.URL.String()) && + assert.Equal(t, "application/json", req.Header.Get("Content-Type")) && + assert.Equal(t, "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJvcGcucG9hcy5tYWtlcmVnaXN0ZXIiLCJzdWIiOiJ1cm46b3BnOnBvYXM6bWFrZXJlZ2lzdGVyOnVzZXJzOmRjNDg3ZWJiLWIzOWQtNDVlZC1iYjZhLTdmOTUwZmQzNTVjOSIsImlhdCI6OTQ2NzgyMjQ1fQ.MIHlxYV520Wpx-pP2XVvYdbUGFh3CkmCjFR99XBOX9k", req.Header.Get("X-Jwt-Authorization")) && + assert.JSONEq(t, json, string(body)) + })). + Return(&http.Response{StatusCode: http.StatusCreated, Body: io.NopCloser(strings.NewReader(""))}, nil) + + client := New("http://base", secretsClient, doer) + client.now = func() time.Time { return time.Date(2000, time.January, 2, 3, 4, 5, 6, time.UTC) } + + uid, _ := actoruid.Parse("dc487ebb-b39d-45ed-bb6a-7f950fd355c9") + err := client.SendAttorneyOptOut(ctx, "lpa-uid", uid) + + assert.Nil(t, err) +} diff --git a/internal/sesh/sesh.go b/internal/sesh/sesh.go index 818c3dad33..ff2ab5e519 100644 --- a/internal/sesh/sesh.go +++ b/internal/sesh/sesh.go @@ -67,8 +67,12 @@ func (e InvalidSessionError) Error() string { return fmt.Sprintf("%s session invalid", string(e)) } +type cookieStore interface { + sessions.Store +} + type Store struct { - s sessions.Store + s cookieStore } func NewStore(keyPairs [][]byte) *Store {