diff --git a/Makefile b/Makefile index 6bc03c45..72d88634 100644 --- a/Makefile +++ b/Makefile @@ -23,18 +23,29 @@ test-api: $(eval LPA_UID := "$(shell ./api-test/tester UID)") $(eval TMPFILE := "$(shell mktemp)") + # JWT required JWT_SECRET_KEY=bad ./api-test/tester -expectedStatus=401 REQUEST PUT $(URL)/lpas/$(LPA_UID) '{"version":"1"}' JWT_SECRET_KEY=bad ./api-test/tester -expectedStatus=401 REQUEST POST $(URL)/lpas/$(LPA_UID)/updates '{"type":"BUMP_VERSION","changes":[{"key":"/version","old":"1","new":"2"}]}' JWT_SECRET_KEY=bad ./api-test/tester -expectedStatus=401 REQUEST GET $(URL)/lpas/$(LPA_UID) '' + # create cat ./docs/example-lpa.json | ./api-test/tester -expectedStatus=201 REQUEST PUT $(URL)/lpas/$(LPA_UID) "`xargs -0`" ./api-test/tester -expectedStatus=200 -write REQUEST GET $(URL)/lpas/$(LPA_UID) '' > $(TMPFILE) + # missing fields diff <(jq --sort-keys 'del(.status,.uid,.updatedAt)' < $(TMPFILE)) <(jq --sort-keys . < docs/example-lpa.json) ./api-test/tester -expectedStatus=400 REQUEST PUT $(URL)/lpas/$(LPA_UID) '{"version":"2"}' + # certificate provider sign cat ./docs/certificate-provider-change.json | ./api-test/tester -expectedStatus=201 REQUEST POST $(URL)/lpas/$(LPA_UID)/updates "`xargs -0`" + + # attorney sign + cat ./docs/attorney-change.json | ./api-test/tester -expectedStatus=201 REQUEST POST $(URL)/lpas/$(LPA_UID)/updates "`xargs -0`" + + # get lpa ./api-test/tester -expectedStatus=200 REQUEST GET $(URL)/lpas/$(LPA_UID) '' + + # get lpas ./api-test/tester -expectedStatus=200 REQUEST POST $(URL)/lpas '{"uids": [$(LPA_UID)]}' .PHONY: test-api diff --git a/docs/attorney-change.json b/docs/attorney-change.json new file mode 100644 index 00000000..6e34cc83 --- /dev/null +++ b/docs/attorney-change.json @@ -0,0 +1,30 @@ +{ + "type": "ATTORNEY_SIGN", + "changes": [ + { + "key": "/attorneys/0/mobile", + "new": "07700900000", + "old": null + }, + { + "key": "/attorneys/0/signedAt", + "new": "2024-01-13T22:00:00Z", + "old": null + }, + { + "key": "/attorneys/0/contactLanguagePreference", + "new": "en", + "old": null + }, + { + "key": "/attorneys/0/channel", + "new": "online", + "old": "paper" + }, + { + "key": "/attorneys/0/email", + "new": "b@example.com", + "old": "a@example.com" + } + ] +} diff --git a/docs/example-lpa.json b/docs/example-lpa.json index a61362dc..9556c6fa 100644 --- a/docs/example-lpa.json +++ b/docs/example-lpa.json @@ -24,8 +24,9 @@ "country": "GB" }, "dateOfBirth": "1982-07-24", - "email": "nobody2@not.a.real.domain", - "status": "active" + "email": "a@example.com", + "status": "active", + "channel": "paper" } ], "certificateProvider": { diff --git a/docs/schemas/2024-04/donor-details.json b/docs/schemas/2024-04/donor-details.json index 81aba7e9..5a25e31c 100644 --- a/docs/schemas/2024-04/donor-details.json +++ b/docs/schemas/2024-04/donor-details.json @@ -212,7 +212,7 @@ } ], "type": "object", - "required": ["dateOfBirth", "email", "status"], + "required": ["dateOfBirth", "status"], "properties": { "dateOfBirth": { "type": "string", @@ -225,6 +225,10 @@ "status": { "type": "string", "enum": ["active", "replacement", "removed"] + }, + "channel": { + "type": "string", + "enum": ["paper", "online"] } } }, diff --git a/internal/shared/person.go b/internal/shared/person.go index bbe08c7a..374e6f39 100644 --- a/internal/shared/person.go +++ b/internal/shared/person.go @@ -70,6 +70,7 @@ type Attorney struct { Mobile string `json:"mobile,omitempty"` SignedAt *time.Time `json:"signedAt,omitempty"` ContactLanguagePreference Lang `json:"contactLanguagePreference,omitempty"` + Channel Channel `json:"channel"` } type TrustCorporation struct { diff --git a/lambda/create/validate_test.go b/lambda/create/validate_test.go index 97152460..30e3e12f 100644 --- a/lambda/create/validate_test.go +++ b/lambda/create/validate_test.go @@ -336,6 +336,7 @@ func TestValidateLpaValid(t *testing.T) { }, DateOfBirth: newDate("1977-10-30"), Status: shared.AttorneyStatusActive, + Channel: shared.ChannelOnline, }, }, CertificateProvider: shared.CertificateProvider{ diff --git a/lambda/update/attorney_sign.go b/lambda/update/attorney_sign.go index a1c61cf6..84285ead 100644 --- a/lambda/update/attorney_sign.go +++ b/lambda/update/attorney_sign.go @@ -13,6 +13,8 @@ type AttorneySign struct { Mobile string SignedAt time.Time ContactLanguagePreference shared.Lang + Channel shared.Channel + Email string } func (a AttorneySign) Apply(lpa *shared.Lpa) []shared.FieldError { @@ -23,6 +25,8 @@ func (a AttorneySign) Apply(lpa *shared.Lpa) []shared.FieldError { lpa.Attorneys[*a.Index].Mobile = a.Mobile lpa.Attorneys[*a.Index].SignedAt = &a.SignedAt lpa.Attorneys[*a.Index].ContactLanguagePreference = a.ContactLanguagePreference + lpa.Attorneys[*a.Index].Channel = a.Channel + lpa.Attorneys[*a.Index].Email = a.Email return nil } @@ -47,6 +51,10 @@ func validateAttorneySign(changes []shared.Change) (AttorneySign, []shared.Field Field("/contactLanguagePreference", &data.ContactLanguagePreference, parse.Validate(func() []shared.FieldError { return validate.IsValid("", data.ContactLanguagePreference) })). + Field("/channel", &data.Channel, parse.Validate(func() []shared.FieldError { + return validate.IsValid("", data.Channel) + }), parse.Optional()). + Field("/email", &data.Email, parse.Optional()). Consumed() }). Consumed() diff --git a/lambda/update/attorney_sign_test.go b/lambda/update/attorney_sign_test.go index fa032362..27820786 100644 --- a/lambda/update/attorney_sign_test.go +++ b/lambda/update/attorney_sign_test.go @@ -21,6 +21,7 @@ func TestAttorneySignApply(t *testing.T) { Mobile: "0777", SignedAt: time.Now(), ContactLanguagePreference: shared.LangCy, + Channel: shared.ChannelOnline, } errors := a.Apply(lpa) @@ -28,6 +29,7 @@ func TestAttorneySignApply(t *testing.T) { assert.Equal(t, a.Mobile, lpa.Attorneys[attorneyIndex].Mobile) assert.Equal(t, a.SignedAt, *lpa.Attorneys[attorneyIndex].SignedAt) assert.Equal(t, a.ContactLanguagePreference, lpa.Attorneys[attorneyIndex].ContactLanguagePreference) + assert.Equal(t, a.Channel, lpa.Attorneys[attorneyIndex].Channel) } func TestAttorneySignApplyWhenAlreadySigned(t *testing.T) { @@ -43,11 +45,14 @@ func TestAttorneySignApplyWhenAlreadySigned(t *testing.T) { } func TestValidateUpdateAttorneySign(t *testing.T) { + now := time.Now() + yesterday := time.Now() + testcases := map[string]struct { update shared.Update errors []shared.FieldError }{ - "valid": { + "valid - no previous values": { update: shared.Update{ Type: "ATTORNEY_SIGN", Changes: []shared.Change{ @@ -66,6 +71,48 @@ func TestValidateUpdateAttorneySign(t *testing.T) { New: json.RawMessage(`"cy"`), Old: jsonNull, }, + { + Key: "/attorneys/1/channel", + New: json.RawMessage(`"online"`), + Old: jsonNull, + }, + { + Key: "/attorneys/1/email", + New: json.RawMessage(`"a@example.com"`), + Old: jsonNull, + }, + }, + }, + }, + "valid - with previous values": { + update: shared.Update{ + Type: "ATTORNEY_SIGN", + Changes: []shared.Change{ + { + Key: "/attorneys/1/mobile", + New: json.RawMessage(`"07777"`), + Old: json.RawMessage(`"06666"`), + }, + { + Key: "/attorneys/1/signedAt", + New: json.RawMessage(`"` + now.Format(time.RFC3339) + `"`), + Old: json.RawMessage(`"` + yesterday.Format(time.RFC3339) + `"`), + }, + { + Key: "/attorneys/1/contactLanguagePreference", + New: json.RawMessage(`"cy"`), + Old: jsonNull, + }, + { + Key: "/attorneys/1/channel", + New: json.RawMessage(`"online"`), + Old: json.RawMessage(`"paper"`), + }, + { + Key: "/attorneys/1/email", + New: json.RawMessage(`"b@example.com"`), + Old: json.RawMessage(`"a@example.com"`), + }, }, }, }, @@ -104,6 +151,11 @@ func TestValidateUpdateAttorneySign(t *testing.T) { New: json.RawMessage(`"John"`), Old: jsonNull, }, + { + Key: "/attorneys/1/email", + New: json.RawMessage(`"a@example.com"`), + Old: jsonNull, + }, }, }, errors: []shared.FieldError{ @@ -111,7 +163,7 @@ func TestValidateUpdateAttorneySign(t *testing.T) { {Source: "/changes/4", Detail: "unexpected change provided"}, }, }, - "invalid contact language": { + "invalid contact language and channel": { update: shared.Update{ Type: "ATTORNEY_SIGN", Changes: []shared.Change{ @@ -130,10 +182,21 @@ func TestValidateUpdateAttorneySign(t *testing.T) { New: json.RawMessage(`"xy"`), Old: jsonNull, }, + { + Key: "/attorneys/1/channel", + New: json.RawMessage(`"digital"`), + Old: jsonNull, + }, + { + Key: "/attorneys/1/email", + New: json.RawMessage(`"b@example.com"`), + Old: jsonNull, + }, }, }, errors: []shared.FieldError{ {Source: "/changes/2/new", Detail: "invalid value"}, + {Source: "/changes/3/new", Detail: "invalid value"}, }, }, "multiple attorneys": { @@ -155,6 +218,11 @@ func TestValidateUpdateAttorneySign(t *testing.T) { New: json.RawMessage(`"` + shared.LangCy + `"`), Old: jsonNull, }, + { + Key: "/attorneys/0/email", + New: json.RawMessage(`"a@example.com"`), + Old: jsonNull, + }, }, }, errors: []shared.FieldError{ diff --git a/mock-apigw/main.go b/mock-apigw/main.go index 401af492..dc47e5ee 100644 --- a/mock-apigw/main.go +++ b/mock-apigw/main.go @@ -151,7 +151,8 @@ func handlePactState(r *http.Request) error { "line1": "71 South Western Terrace", "town": "Milton", "country": "AU" - } + }, + "channel": "paper" } ], "certificateProvider": {