Skip to content

Commit

Permalink
MLPAB-1223 Use lpastore to retrieve lpa data for non-donors (#1160)
Browse files Browse the repository at this point in the history
On donor-submission-completed events insert a PK=LPA#random-uuid,SK=#DONOR#PAPER record so we can track the UID has been paid for and checked.

Replaces the use of DonorStore in attorney and certificate provider pages with a new lpastore.ResolvingService that will get the latest data from the store, then add additional data depending on whether it is digital or paper. This returns a new lpastore.Lpa type, so we can ensure that we aren't trying to use data that won't exist for paper applications.

Moves the definition of our various keys to a new file in internal/dynamo.
  • Loading branch information
hawx authored Apr 4, 2024
1 parent 8b6391b commit b162266
Show file tree
Hide file tree
Showing 147 changed files with 3,299 additions and 2,018 deletions.
27 changes: 23 additions & 4 deletions cmd/event-received/cloud_watch_event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type factory interface {
type cloudWatchEventHandler struct {
dynamoClient dynamodbClient
now func() time.Time
uuidString func() string
factory factory
}

Expand Down Expand Up @@ -84,7 +85,7 @@ func (h *cloudWatchEventHandler) Handle(ctx context.Context, cloudWatchEvent eve
return err
}

return handleDonorSubmissionCompleted(ctx, h.dynamoClient, cloudWatchEvent, shareCodeSender, appData, lpaStoreClient)
return handleDonorSubmissionCompleted(ctx, h.dynamoClient, cloudWatchEvent, shareCodeSender, appData, lpaStoreClient, h.uuidString, h.now)

case "certificate-provider-submission-completed":
return handleCertificateProviderSubmissionCompleted(ctx, cloudWatchEvent, h.factory)
Expand Down Expand Up @@ -127,7 +128,7 @@ func handleEvidenceReceived(ctx context.Context, client dynamodbClient, event ev
return fmt.Errorf("PK missing from LPA in response")
}

if err := client.Put(ctx, map[string]string{"PK": key.PK, "SK": "#EVIDENCE_RECEIVED"}); err != nil {
if err := client.Put(ctx, map[string]string{"PK": key.PK, "SK": dynamo.EvidenceReceivedKey()}); err != nil {
return fmt.Errorf("failed to persist evidence received: %w", err)
}

Expand Down Expand Up @@ -202,7 +203,7 @@ func handleFeeDenied(ctx context.Context, client dynamodbClient, event events.Cl
return nil
}

func handleDonorSubmissionCompleted(ctx context.Context, client dynamodbClient, event events.CloudWatchEvent, shareCodeSender ShareCodeSender, appData page.AppData, lpaStoreClient LpaStoreClient) error {
func handleDonorSubmissionCompleted(ctx context.Context, client dynamodbClient, event events.CloudWatchEvent, shareCodeSender ShareCodeSender, appData page.AppData, lpaStoreClient LpaStoreClient, uuidString func() string, now func() time.Time) error {
var v uidEvent
if err := json.Unmarshal(event.Detail, &v); err != nil {
return fmt.Errorf("failed to unmarshal detail: %w", err)
Expand All @@ -213,13 +214,31 @@ func handleDonorSubmissionCompleted(ctx context.Context, client dynamodbClient,
return err
}

lpaID := uuidString()

if err := client.Put(ctx, &actor.DonorProvidedDetails{
PK: dynamo.LpaKey(lpaID),
SK: dynamo.DonorKey("PAPER"),
LpaID: lpaID,
LpaUID: v.UID,
CreatedAt: now(),
Version: 1,
}); err != nil {
return err
}

donor, err := lpaStoreClient.Lpa(ctx, v.UID)
if err != nil {
return err
}

if donor.CertificateProvider.CarryOutBy.IsOnline() {
if err := shareCodeSender.SendCertificateProviderInvite(ctx, appData, donor); err != nil {
if err := shareCodeSender.SendCertificateProviderInvite(ctx, appData, page.CertificateProviderInvite{
LpaUID: donor.LpaUID,
Type: donor.Type,
Donor: donor.Donor,
CertificateProvider: donor.CertificateProvider,
}); err != nil {
return fmt.Errorf("failed to send share code to certificate provider: %w", err)
}
}
Expand Down
106 changes: 59 additions & 47 deletions cmd/event-received/cloud_watch_event_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/ministryofjustice/opg-modernising-lpa/internal/actor"
"github.com/ministryofjustice/opg-modernising-lpa/internal/date"
"github.com/ministryofjustice/opg-modernising-lpa/internal/dynamo"
"github.com/ministryofjustice/opg-modernising-lpa/internal/lpastore"
"github.com/ministryofjustice/opg-modernising-lpa/internal/page"
"github.com/ministryofjustice/opg-modernising-lpa/internal/uid"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -454,15 +455,15 @@ func TestHandleFeeDeniedWhenPutError(t *testing.T) {
assert.Equal(t, fmt.Errorf("failed to update LPA task status: %w", expectedError), err)
}

func TestHandleDonorSubmissionCompleted(t *testing.T) {
event := events.CloudWatchEvent{
DetailType: "donor-submission-completed",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
}
var donorSubmissionCompletedEvent = events.CloudWatchEvent{
DetailType: "donor-submission-completed",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
}

func TestHandleDonorSubmissionCompleted(t *testing.T) {
appData := page.AppData{}

donor := &actor.DonorProvidedDetails{
donor := &lpastore.Lpa{
CertificateProvider: actor.CertificateProvider{
CarryOutBy: actor.Online,
},
Expand All @@ -472,6 +473,16 @@ func TestHandleDonorSubmissionCompleted(t *testing.T) {
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(dynamo.NotFoundError{})
client.EXPECT().
Put(ctx, &actor.DonorProvidedDetails{
PK: dynamo.LpaKey(testUuidString),
SK: dynamo.DonorKey("PAPER"),
LpaID: testUuidString,
LpaUID: "M-1111-2222-3333",
CreatedAt: testNow,
Version: 1,
}).
Return(nil)

lpaStoreClient := newMockLpaStoreClient(t)
lpaStoreClient.EXPECT().
Expand All @@ -480,22 +491,19 @@ func TestHandleDonorSubmissionCompleted(t *testing.T) {

shareCodeSender := newMockShareCodeSender(t)
shareCodeSender.EXPECT().
SendCertificateProviderInvite(ctx, appData, donor).
SendCertificateProviderInvite(ctx, appData, page.CertificateProviderInvite{
CertificateProvider: donor.CertificateProvider,
}).
Return(nil)

err := handleDonorSubmissionCompleted(ctx, client, event, shareCodeSender, appData, lpaStoreClient)
err := handleDonorSubmissionCompleted(ctx, client, donorSubmissionCompletedEvent, shareCodeSender, appData, lpaStoreClient, testUuidStringFn, testNowFn)
assert.Nil(t, err)
}

func TestHandleDonorSubmissionCompletedWhenPaperCertificateProvider(t *testing.T) {
event := events.CloudWatchEvent{
DetailType: "donor-submission-completed",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
}

appData := page.AppData{}

donor := &actor.DonorProvidedDetails{
donor := &lpastore.Lpa{
CertificateProvider: actor.CertificateProvider{
CarryOutBy: actor.Paper,
},
Expand All @@ -505,59 +513,62 @@ func TestHandleDonorSubmissionCompletedWhenPaperCertificateProvider(t *testing.T
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(dynamo.NotFoundError{})
client.EXPECT().
Put(ctx, mock.Anything).
Return(nil)

lpaStoreClient := newMockLpaStoreClient(t)
lpaStoreClient.EXPECT().
Lpa(ctx, "M-1111-2222-3333").
Return(donor, nil)

err := handleDonorSubmissionCompleted(ctx, client, event, nil, appData, lpaStoreClient)
err := handleDonorSubmissionCompleted(ctx, client, donorSubmissionCompletedEvent, nil, appData, lpaStoreClient, testUuidStringFn, testNowFn)
assert.Nil(t, err)
}

func TestHandleDonorSubmissionCompletedWhenDynamoExists(t *testing.T) {
event := events.CloudWatchEvent{
DetailType: "donor-submission-completed",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
}

appData := page.AppData{}

client := newMockDynamodbClient(t)
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(nil)

err := handleDonorSubmissionCompleted(ctx, client, event, nil, appData, nil)
err := handleDonorSubmissionCompleted(ctx, client, donorSubmissionCompletedEvent, nil, appData, nil, nil, nil)
assert.Nil(t, err)
}

func TestHandleDonorSubmissionCompletedWhenDynamoError(t *testing.T) {
event := events.CloudWatchEvent{
DetailType: "donor-submission-completed",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
}
func TestHandleDonorSubmissionCompletedWhenDynamoOneByUIDError(t *testing.T) {
appData := page.AppData{}

client := newMockDynamodbClient(t)
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(expectedError)

err := handleDonorSubmissionCompleted(ctx, client, donorSubmissionCompletedEvent, nil, appData, nil, nil, nil)
assert.Equal(t, expectedError, err)
}

func TestHandleDonorSubmissionCompletedWhenDynamoPutError(t *testing.T) {
appData := page.AppData{}

client := newMockDynamodbClient(t)
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(dynamo.NotFoundError{})
client.EXPECT().
Put(ctx, mock.Anything).
Return(expectedError)

err := handleDonorSubmissionCompleted(ctx, client, event, nil, appData, nil)
err := handleDonorSubmissionCompleted(ctx, client, donorSubmissionCompletedEvent, nil, appData, nil, testUuidStringFn, testNowFn)
assert.Equal(t, expectedError, err)
}

func TestHandleDonorSubmissionCompletedWhenLpaStoreError(t *testing.T) {
event := events.CloudWatchEvent{
DetailType: "donor-submission-completed",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
}

appData := page.AppData{}

donor := &actor.DonorProvidedDetails{
donor := &lpastore.Lpa{
CertificateProvider: actor.CertificateProvider{
CarryOutBy: actor.Online,
},
Expand All @@ -567,25 +578,23 @@ func TestHandleDonorSubmissionCompletedWhenLpaStoreError(t *testing.T) {
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(dynamo.NotFoundError{})
client.EXPECT().
Put(ctx, mock.Anything).
Return(nil)

lpaStoreClient := newMockLpaStoreClient(t)
lpaStoreClient.EXPECT().
Lpa(ctx, "M-1111-2222-3333").
Return(donor, expectedError)

err := handleDonorSubmissionCompleted(ctx, client, event, nil, appData, lpaStoreClient)
err := handleDonorSubmissionCompleted(ctx, client, donorSubmissionCompletedEvent, nil, appData, lpaStoreClient, testUuidStringFn, testNowFn)
assert.Equal(t, expectedError, err)
}

func TestHandleDonorSubmissionCompletedWhenShareCodeSenderError(t *testing.T) {
event := events.CloudWatchEvent{
DetailType: "donor-submission-completed",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
}

appData := page.AppData{}

donor := &actor.DonorProvidedDetails{
donor := &lpastore.Lpa{
CertificateProvider: actor.CertificateProvider{
CarryOutBy: actor.Online,
},
Expand All @@ -595,6 +604,9 @@ func TestHandleDonorSubmissionCompletedWhenShareCodeSenderError(t *testing.T) {
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(dynamo.NotFoundError{})
client.EXPECT().
Put(ctx, mock.Anything).
Return(nil)

lpaStoreClient := newMockLpaStoreClient(t)
lpaStoreClient.EXPECT().
Expand All @@ -603,10 +615,10 @@ func TestHandleDonorSubmissionCompletedWhenShareCodeSenderError(t *testing.T) {

shareCodeSender := newMockShareCodeSender(t)
shareCodeSender.EXPECT().
SendCertificateProviderInvite(ctx, appData, donor).
SendCertificateProviderInvite(ctx, mock.Anything, mock.Anything).
Return(expectedError)

err := handleDonorSubmissionCompleted(ctx, client, event, shareCodeSender, appData, lpaStoreClient)
err := handleDonorSubmissionCompleted(ctx, client, donorSubmissionCompletedEvent, shareCodeSender, appData, lpaStoreClient, testUuidStringFn, testNowFn)
assert.Equal(t, fmt.Errorf("failed to send share code to certificate provider: %w", expectedError), err)
}

Expand All @@ -618,7 +630,7 @@ var certificateProviderSubmissionCompletedEvent = events.CloudWatchEvent{
func TestHandleCertificateProviderSubmissionCompleted(t *testing.T) {
appData := page.AppData{}

donor := &actor.DonorProvidedDetails{
donor := &lpastore.Lpa{
CertificateProvider: actor.CertificateProvider{
CarryOutBy: actor.Paper,
},
Expand Down Expand Up @@ -650,7 +662,7 @@ func TestHandleCertificateProviderSubmissionCompleted(t *testing.T) {
}

func TestHandleCertificateProviderSubmissionCompletedWhenOnline(t *testing.T) {
donor := &actor.DonorProvidedDetails{
donor := &lpastore.Lpa{
CertificateProvider: actor.CertificateProvider{
CarryOutBy: actor.Online,
},
Expand Down Expand Up @@ -702,7 +714,7 @@ func TestHandleCertificateProviderSubmissionCompletedWhenShareCodeSenderErrors(t
lpaStoreClient := newMockLpaStoreClient(t)
lpaStoreClient.EXPECT().
Lpa(ctx, "M-1111-2222-3333").
Return(&actor.DonorProvidedDetails{
Return(&lpastore.Lpa{
CertificateProvider: actor.CertificateProvider{
CarryOutBy: actor.Paper,
},
Expand Down Expand Up @@ -733,7 +745,7 @@ func TestHandleCertificateProviderSubmissionCompletedWhenShareCodeSenderFactoryE
lpaStoreClient := newMockLpaStoreClient(t)
lpaStoreClient.EXPECT().
Lpa(ctx, "M-1111-2222-3333").
Return(&actor.DonorProvidedDetails{
Return(&lpastore.Lpa{
CertificateProvider: actor.CertificateProvider{
CarryOutBy: actor.Paper,
},
Expand All @@ -756,7 +768,7 @@ func TestHandleCertificateProviderSubmissionCompletedWhenAppDataFactoryErrors(t
lpaStoreClient := newMockLpaStoreClient(t)
lpaStoreClient.EXPECT().
Lpa(ctx, "M-1111-2222-3333").
Return(&actor.DonorProvidedDetails{
Return(&lpastore.Lpa{
CertificateProvider: actor.CertificateProvider{
CarryOutBy: actor.Paper,
},
Expand Down
6 changes: 3 additions & 3 deletions cmd/event-received/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ type LambdaClient interface {

type LpaStoreClient interface {
SendLpa(ctx context.Context, donor *actor.DonorProvidedDetails) error
Lpa(ctx context.Context, uid string) (*actor.DonorProvidedDetails, error)
Lpa(ctx context.Context, uid string) (*lpastore.Lpa, error)
}

type SecretsClient interface {
Secret(ctx context.Context, name string) (string, error)
}

type ShareCodeSender interface {
SendCertificateProviderInvite(context.Context, page.AppData, *actor.DonorProvidedDetails) error
SendCertificateProviderInvite(context.Context, page.AppData, page.CertificateProviderInvite) error
SendCertificateProviderPrompt(context.Context, page.AppData, *actor.DonorProvidedDetails) error
SendAttorneys(context.Context, page.AppData, *actor.DonorProvidedDetails) error
SendAttorneys(context.Context, page.AppData, *lpastore.Lpa) error
}

type UidStore interface {
Expand Down
13 changes: 11 additions & 2 deletions cmd/event-received/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@ import (
"context"
"errors"
"testing"
"time"

"github.com/aws/aws-lambda-go/events"
"github.com/stretchr/testify/assert"
)

var expectedError = errors.New("err")
var ctx = context.Background()
var (
expectedError = errors.New("err")
ctx = context.Background()

testNow = time.Date(2023, time.April, 2, 3, 4, 5, 6, time.UTC)
testNowFn = func() time.Time { return testNow }

testUuidString = "a-uuid"
testUuidStringFn = func() string { return testUuidString }
)

func TestIsS3Event(t *testing.T) {
s3Event := Event{S3Event: events.S3Event{Records: []events.S3EventRecord{{}, {}}}}
Expand Down
Loading

0 comments on commit b162266

Please sign in to comment.