Skip to content

Commit

Permalink
Merge 2893a84 into 78fe0ba
Browse files Browse the repository at this point in the history
  • Loading branch information
acsauk authored Feb 10, 2025
2 parents 78fe0ba + 2893a84 commit 73c9dc2
Show file tree
Hide file tree
Showing 14 changed files with 642 additions and 49 deletions.
17 changes: 17 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,23 @@ emit-object-tags-added-without-virus: ##@events emits a ObjectTagging:Put event
--function-name event-received text \
--payload '{"Records":[{"eventSource":"aws:s3","eventTime":"2023-10-23T15:58:33.081Z","eventName":"ObjectTagging:Put","s3":{"bucket":{"name":"uploads-opg-modernising-lpa-eu-west-1"},"object":{"key":"$(key)"}}}]}'

emit-immaterial-change-confirmed: ##@events emits a immaterial-change-confirmed event with the given LpaUID, actor type an actor UID e.g. emit-immaterial-change-confirmed uid=abc-123 actorType=donor actorUid=def-456
$(eval BODY := $(shell echo '{"version":"0","id":"63eb7e5f-1f10-4744-bba9-e16d327c3b98","detail-type":"immaterial-change-confirmed","source":"opg.poas.sirius","account":"653761790766","time":"2023-08-30T13:40:30Z","region":"eu-west-1","resources":[],"detail":{"uid":"$(uid)","actorType":"$(actorType)","actorUid":"$(actorUid)","sentDate":"2024-01-02T12:13:14.000006Z"}}' | sed 's/"/\\"/g'))

docker compose -f docker/docker-compose.yml exec localstack awslocal lambda invoke \
--endpoint-url=http://localhost:4566 \
--region eu-west-1 \
--function-name event-received text \
--payload '{"Records": [{"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78", "body": "$(BODY)"}]}'

emit-material-change-confirmed: ##@events emits a material-change-confirmed event with the given LpaUID, actor type an actor UID e.g. emit-material-change-confirmed uid=abc-123 actorType=donor actorUid=def-456
$(eval BODY := $(shell echo '{"version":"0","id":"63eb7e5f-1f10-4744-bba9-e16d327c3b98","detail-type":"material-change-confirmed","source":"opg.poas.sirius","account":"653761790766","time":"2023-08-30T13:40:30Z","region":"eu-west-1","resources":[],"detail":{"uid":"$(uid)","actorType":"$(actorType)","actorUid":"$(actorUid)","sentDate":"2024-01-02T12:13:14.000006Z"}}' | sed 's/"/\\"/g'))

docker compose -f docker/docker-compose.yml exec localstack awslocal lambda invoke \
--endpoint-url=http://localhost:4566 \
--region eu-west-1 \
--function-name event-received text \
--payload '{"Records": [{"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78", "body": "$(BODY)"}]}'

set-uploads-clean: ##@events calls emit-object-tags-added-without-virus for all documents on a given lpa e.g. set-uploads-clean lpaId=abc
for k in $$(docker compose -f docker/docker-compose.yml exec localstack awslocal dynamodb --region eu-west-1 query --table-name lpas --key-condition-expression 'PK = :pk and begins_with(SK, :sk)' --expression-attribute-values '{":pk": {"S": "LPA#$(lpaId)"}, ":sk": {"S": "DOCUMENT#"}}' | jq -c -r '.Items[] | .Key[]'); do \
Expand Down
25 changes: 25 additions & 0 deletions cmd/event-received/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/aws/aws-lambda-go/events"
"github.com/ministryofjustice/opg-modernising-lpa/internal/certificateprovider/certificateproviderdata"
"github.com/ministryofjustice/opg-modernising-lpa/internal/donor/donordata"
"github.com/ministryofjustice/opg-modernising-lpa/internal/dynamo"
)
Expand Down Expand Up @@ -78,3 +79,27 @@ func getDonorByLpaUID(ctx context.Context, client dynamodbClient, uid string) (*

return &donor, nil
}

func putCertificateProvider(ctx context.Context, certificateProvider *certificateproviderdata.Provided, now func() time.Time, client dynamodbClient) error {
certificateProvider.UpdatedAt = now()

return client.Put(ctx, certificateProvider)
}

func getCertificateProviderByLpaUID(ctx context.Context, client dynamodbClient, uid string) (*certificateproviderdata.Provided, error) {
var key dynamo.Keys
if err := client.OneByUID(ctx, uid, &key); err != nil {
return nil, fmt.Errorf("failed to resolve uid: %w", err)
}

if key.PK == nil {
return nil, fmt.Errorf("PK missing from LPA in response")
}

var certificateProvider certificateproviderdata.Provided
if err := client.OneByPartialSK(ctx, key.PK, dynamo.CertificateProviderKey(""), &certificateProvider); err != nil {
return nil, fmt.Errorf("failed to get certificate provider: %w", err)
}

return &certificateProvider, nil
}
147 changes: 109 additions & 38 deletions cmd/event-received/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/ministryofjustice/opg-modernising-lpa/internal/certificateprovider/certificateproviderdata"
"github.com/ministryofjustice/opg-modernising-lpa/internal/donor/donordata"
"github.com/ministryofjustice/opg-modernising-lpa/internal/dynamo"
"github.com/ministryofjustice/opg-modernising-lpa/internal/task"
Expand Down Expand Up @@ -183,32 +184,26 @@ func TestHandleObjectTagsAddedWhenDocumentStoreUpdateScanResultsError(t *testing
assert.Equal(t, fmt.Errorf("failed to update scan results: %w", expectedError), err)
}

func TestGetLpaByUID(t *testing.T) {
func TestGetDonorByLPAUID(t *testing.T) {
expectedDonor := &donordata.Provided{PK: dynamo.LpaKey("123"), SK: dynamo.LpaOwnerKey(dynamo.DonorKey("456"))}

client := newMockDynamodbClient(t)
client.
On("OneByUID", ctx, "M-1111-2222-3333", mock.Anything).
Return(func(ctx context.Context, uid string, v interface{}) error {
b, _ := json.Marshal(dynamo.Keys{PK: dynamo.LpaKey("123"), SK: dynamo.DonorKey("456")})
json.Unmarshal(b, v)
return nil
})
client.
On("One", ctx, dynamo.LpaKey("123"), dynamo.DonorKey("456"), mock.Anything).
Return(func(ctx context.Context, pk dynamo.PK, sk dynamo.SK, v interface{}) error {
b, _ := json.Marshal(expectedDonor)
json.Unmarshal(b, v)
return nil
})
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(nil).
SetData(dynamo.Keys{PK: dynamo.LpaKey("123"), SK: dynamo.DonorKey("456")})
client.EXPECT().
One(ctx, dynamo.LpaKey("123"), dynamo.DonorKey("456"), mock.Anything).
Return(nil).
SetData(expectedDonor)

lpa, err := getDonorByLpaUID(ctx, client, "M-1111-2222-3333")
donor, err := getDonorByLpaUID(ctx, client, "M-1111-2222-3333")

assert.Equal(t, expectedDonor, lpa)
assert.Equal(t, expectedDonor, donor)
assert.Nil(t, err)
}

func TestGetLpaByUIDWhenClientOneByUidError(t *testing.T) {
func TestGetDonorByLPAUIDWhenClientOneByUidError(t *testing.T) {
client := newMockDynamodbClient(t)
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Expand All @@ -220,37 +215,113 @@ func TestGetLpaByUIDWhenClientOneByUidError(t *testing.T) {
assert.Equal(t, fmt.Errorf("failed to resolve uid: %w", expectedError), err)
}

func TestGetLpaByUIDWhenPKMissing(t *testing.T) {
func TestGetDonorByLPAUIDWhenPKMissing(t *testing.T) {
client := newMockDynamodbClient(t)
client.
On("OneByUID", ctx, "M-1111-2222-3333", mock.Anything).
Return(func(ctx context.Context, uid string, v interface{}) error {
b, _ := json.Marshal(dynamo.Keys{SK: dynamo.DonorKey("456")})
json.Unmarshal(b, v)
return nil
})
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(nil).
SetData(dynamo.Keys{SK: dynamo.DonorKey("456")})

lpa, err := getDonorByLpaUID(ctx, client, "M-1111-2222-3333")
donor, err := getDonorByLpaUID(ctx, client, "M-1111-2222-3333")

assert.Nil(t, lpa)
assert.Nil(t, donor)
assert.Equal(t, errors.New("PK missing from LPA in response"), err)
}

func TestGetLpaByUIDWhenClientOneError(t *testing.T) {
func TestGetDonorByLPAUIDWhenClientOneError(t *testing.T) {
client := newMockDynamodbClient(t)
client.
On("OneByUID", ctx, "M-1111-2222-3333", mock.Anything).
Return(func(ctx context.Context, uid string, v interface{}) error {
b, _ := json.Marshal(dynamo.Keys{PK: dynamo.LpaKey("123"), SK: dynamo.DonorKey("456")})
json.Unmarshal(b, v)
return nil
})
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(nil).
SetData(dynamo.Keys{PK: dynamo.LpaKey("123"), SK: dynamo.DonorKey("456")})
client.EXPECT().
One(ctx, dynamo.LpaKey("123"), dynamo.DonorKey("456"), mock.Anything).
Return(expectedError)

lpa, err := getDonorByLpaUID(ctx, client, "M-1111-2222-3333")
donor, err := getDonorByLpaUID(ctx, client, "M-1111-2222-3333")

assert.Nil(t, lpa)
assert.Nil(t, donor)
assert.Equal(t, fmt.Errorf("failed to get LPA: %w", expectedError), err)
}

func TestGetCertificateProviderByLpaUID(t *testing.T) {
expectedCertificateProvider := certificateproviderdata.Provided{PK: dynamo.LpaKey("123"), SK: dynamo.CertificateProviderKey("")}

client := newMockDynamodbClient(t)
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(nil).
SetData(dynamo.Keys{PK: dynamo.LpaKey("123"), SK: dynamo.CertificateProviderKey("456")})
client.EXPECT().
OneByPartialSK(ctx, dynamo.LpaKey("123"), dynamo.CertificateProviderKey(""), mock.Anything).
Return(nil).
SetData(expectedCertificateProvider)

certificateProvider, err := getCertificateProviderByLpaUID(ctx, client, "M-1111-2222-3333")

assert.Nil(t, err)
assert.Equal(t, &expectedCertificateProvider, certificateProvider)
}

func TestGetCertificateProviderByLpaUIDWhenClientOneByUidError(t *testing.T) {
client := newMockDynamodbClient(t)
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(expectedError)

certificateProvider, err := getCertificateProviderByLpaUID(ctx, client, "M-1111-2222-3333")

assert.Nil(t, certificateProvider)
assert.Equal(t, fmt.Errorf("failed to resolve uid: %w", expectedError), err)
}

func TestGetCertificateProviderByLpaUIDWhenPKMissing(t *testing.T) {
client := newMockDynamodbClient(t)
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(nil).
SetData(dynamo.Keys{SK: dynamo.CertificateProviderKey("456")})

certificateProvider, err := getCertificateProviderByLpaUID(ctx, client, "M-1111-2222-3333")

assert.Nil(t, certificateProvider)
assert.Equal(t, errors.New("PK missing from LPA in response"), err)
}

func TestGetCertificateProviderByLpaUIDWhenClientOneByPartialSKError(t *testing.T) {
client := newMockDynamodbClient(t)
client.EXPECT().
OneByUID(ctx, "M-1111-2222-3333", mock.Anything).
Return(nil).
SetData(dynamo.Keys{PK: dynamo.LpaKey("123"), SK: dynamo.CertificateProviderKey("456")})
client.EXPECT().
OneByPartialSK(ctx, dynamo.LpaKey("123"), dynamo.CertificateProviderKey(""), mock.Anything).
Return(expectedError)

certificateProvider, err := getCertificateProviderByLpaUID(ctx, client, "M-1111-2222-3333")

assert.Nil(t, certificateProvider)
assert.Equal(t, fmt.Errorf("failed to get certificate provider: %w", expectedError), err)
}

func TestPutCertificateProvider(t *testing.T) {
client := newMockDynamodbClient(t)
client.EXPECT().
Put(ctx, &certificateproviderdata.Provided{PK: dynamo.LpaKey("123"), UpdatedAt: testNow}).
Return(nil)

err := putCertificateProvider(ctx, &certificateproviderdata.Provided{PK: dynamo.LpaKey("123"), UpdatedAt: testNow}, testNowFn, client)

assert.Nil(t, err)
}

func TestPutCertificateProviderWhenClientError(t *testing.T) {
client := newMockDynamodbClient(t)
client.EXPECT().
Put(ctx, &certificateproviderdata.Provided{PK: dynamo.LpaKey("123"), UpdatedAt: testNow}).
Return(expectedError)

err := putCertificateProvider(ctx, &certificateproviderdata.Provided{PK: dynamo.LpaKey("123"), UpdatedAt: testNow}, testNowFn, client)

assert.Equal(t, expectedError, err)
}
11 changes: 9 additions & 2 deletions cmd/event-received/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,21 @@ func (c *mockDynamodbClient_OneByUID_Call) SetData(data any) {
}

func (c *mockDynamodbClient_One_Call) SetData(data any) {
c.Run(func(_ context.Context, _ dynamo.PK, _ dynamo.SK, v interface{}) {
c.Run(func(_ context.Context, _ dynamo.PK, _ dynamo.SK, v any) {
b, _ := attributevalue.Marshal(data)
attributevalue.Unmarshal(b, v)
})
}

func (c *mockDynamodbClient_AllByLpaUIDAndPartialSK_Call) SetData(data any) {
c.Run(func(_ context.Context, _ string, _ dynamo.SK, v interface{}) {
c.Run(func(_ context.Context, _ string, _ dynamo.SK, v any) {
b, _ := attributevalue.Marshal(data)
attributevalue.Unmarshal(b, v)
})
}

func (c *mockDynamodbClient_OneByPartialSK_Call) SetData(data any) {
c.Run(func(_ context.Context, _ dynamo.PK, _ dynamo.SK, v any) {
b, _ := attributevalue.Marshal(data)
attributevalue.Unmarshal(b, v)
})
Expand Down
71 changes: 66 additions & 5 deletions cmd/event-received/sirius_event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/aws/aws-lambda-go/events"
"github.com/ministryofjustice/opg-modernising-lpa/internal/actor"
"github.com/ministryofjustice/opg-modernising-lpa/internal/appcontext"
"github.com/ministryofjustice/opg-modernising-lpa/internal/certificateprovider/certificateproviderdata"
"github.com/ministryofjustice/opg-modernising-lpa/internal/donor/donordata"
Expand Down Expand Up @@ -76,6 +77,12 @@ func (h *siriusEventHandler) Handle(ctx context.Context, factory factory, cloudW
case "priority-correspondence-sent":
return handlePriorityCorrespondenceSent(ctx, factory.DynamoClient(), cloudWatchEvent, factory.Now())

case "immaterial-change-confirmed":
return handleChangeConfirmed(ctx, factory.DynamoClient(), cloudWatchEvent, factory.Now(), false)

case "material-change-confirmed":
return handleChangeConfirmed(ctx, factory.DynamoClient(), cloudWatchEvent, factory.Now(), true)

default:
return fmt.Errorf("unknown sirius event")
}
Expand Down Expand Up @@ -120,7 +127,7 @@ func handleFeeApproved(

donor, err := getDonorByLpaUID(ctx, client, v.UID)
if err != nil {
return err
return fmt.Errorf("failed to get donor: %w", err)
}

if donor.Tasks.PayForLpa.IsCompleted() || donor.Tasks.PayForLpa.IsApproved() {
Expand Down Expand Up @@ -168,7 +175,7 @@ func handleFurtherInfoRequested(ctx context.Context, client dynamodbClient, even

donor, err := getDonorByLpaUID(ctx, client, v.UID)
if err != nil {
return err
return fmt.Errorf("failed to get donor: %w", err)
}

if donor.Tasks.PayForLpa.IsMoreEvidenceRequired() {
Expand All @@ -193,7 +200,7 @@ func handleFeeDenied(ctx context.Context, client dynamodbClient, event *events.C

donor, err := getDonorByLpaUID(ctx, client, v.UID)
if err != nil {
return err
return fmt.Errorf("failed to get donor: %w", err)
}

if donor.Tasks.PayForLpa.IsDenied() {
Expand Down Expand Up @@ -333,13 +340,67 @@ func handlePriorityCorrespondenceSent(ctx context.Context, client dynamodbClient

donor, err := getDonorByLpaUID(ctx, client, v.UID)
if err != nil {
return fmt.Errorf("failed to get lpa: %w", err)
return fmt.Errorf("failed to get donor: %w", err)
}

donor.PriorityCorrespondenceSentAt = v.SentDate

if err := putDonor(ctx, donor, now, client); err != nil {
return fmt.Errorf("failed to update lpa: %w", err)
return fmt.Errorf("failed to update donor: %w", err)
}

return nil
}

type changeConfirmedEvent struct {
UID string `json:"uid"`
ActorType actor.Type `json:"actorType"`
ActorUID string `json:"actorUID"`
}

func handleChangeConfirmed(ctx context.Context, client dynamodbClient, event *events.CloudWatchEvent, now func() time.Time, materialChange bool) error {
var v changeConfirmedEvent
if err := json.Unmarshal(event.Detail, &v); err != nil {
return fmt.Errorf("failed to unmarshal detail: %w", err)
}

switch v.ActorType {
case actor.TypeDonor:
donor, err := getDonorByLpaUID(ctx, client, v.UID)
if err != nil {
return fmt.Errorf("failed to get donor: %w", err)
}

if donor.Tasks.ConfirmYourIdentity.IsProblem() {
if materialChange {
donor.MaterialChangeConfirmedAt = now()
} else {
donor.Tasks.ConfirmYourIdentity = task.IdentityStateCompleted
}

if err := putDonor(ctx, donor, now, client); err != nil {
return fmt.Errorf("failed to update donor: %w", err)
}
}
case actor.TypeCertificateProvider:
certificateProvider, err := getCertificateProviderByLpaUID(ctx, client, v.UID)
if err != nil {
return fmt.Errorf("failed to get certificate provider: %w", err)
}

if certificateProvider.Tasks.ConfirmYourIdentity.IsProblem() {
if materialChange {
certificateProvider.MaterialChangeConfirmedAt = now()
} else {
certificateProvider.Tasks.ConfirmYourIdentity = task.IdentityStateCompleted
}

if err := putCertificateProvider(ctx, certificateProvider, now, client); err != nil {
return fmt.Errorf("failed to update certificate provider: %w", err)
}
}
default:
return fmt.Errorf("invalid actorType, got %s, want donor or certificateProvider", v.ActorType.String())
}

return nil
Expand Down
Loading

0 comments on commit 73c9dc2

Please sign in to comment.