Skip to content

Commit

Permalink
MLPAB-1596 Send attorney invite after certificate is provided (#902)
Browse files Browse the repository at this point in the history
  • Loading branch information
hawx authored Dec 6, 2023
1 parent e76c43b commit 3b87b71
Show file tree
Hide file tree
Showing 18 changed files with 394 additions and 257 deletions.
9 changes: 5 additions & 4 deletions .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ coverage:
ignore:
- "**/*_test.go"
- "**/enum_*.go"
- "./mocks/*"
- "./internal/identity/yoti*"
- "./internal/telemetry"
- "./internal/page/fixtures"
- "./cmd/event-logger/main.go"
- "./cmd/event-received/main.go"
- "./cmd/mlpa/main.go"
- "./cmd/mock-notify/main.go"
- "./cmd/mock-onelogin/main.go"
- "./cmd/mock-os-api/main.go"
- "./internal/identity/yoti*"
- "./internal/notify/emails.go"
- "./internal/page/fixtures"
- "./internal/telemetry"
- "./mocks/*"
status:
project:
default:
Expand Down
1 change: 1 addition & 0 deletions internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ func App(
notFoundHandler,
addressClient,
notifyClient,
shareCodeSender,
)

attorney.Register(
Expand Down
99 changes: 62 additions & 37 deletions internal/notify/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,48 +16,36 @@ import (
type Template uint8

const (
AttorneyInviteEmail Template = iota
CertificateProviderActingDigitallyHasNotConfirmedPersonalDetailsLPADetailsChangedPromptSMS
CertificateProviderActingDigitallyHasNotConfirmedPersonalDetailsLPADetailsChangedPromptSMS Template = iota
CertificateProviderActingDigitallyHasConfirmedPersonalDetailsLPADetailsChangedPromptSMS
CertificateProviderCertificateProvidedEmail
CertificateProviderInviteEmail
CertificateProviderActingOnPaperDetailsChangedSMS
CertificateProviderActingOnPaperMeetingPromptSMS
CertificateProviderProvideCertificatePromptEmail
ReplacementAttorneyInviteEmail
ReplacementTrustCorporationInviteEmail
TrustCorporationInviteEmail
WitnessCodeSMS
)

var (
productionTemplates = map[Template]string{
AttorneyInviteEmail: "9aaedb70-df4a-42a8-9c28-de435cb3d453",
CertificateProviderCertificateProvidedEmail: "2915acb9-2a52-4b62-812a-b31b19c6a94b",
CertificateProviderCertificateProvidedEmail: "2915acb9-2a52-4b62-812a-b31b19c6a94b",
CertificateProviderActingDigitallyHasNotConfirmedPersonalDetailsLPADetailsChangedPromptSMS: "19948d7d-a2df-4e85-930b-5d800978f41f",
CertificateProviderActingDigitallyHasConfirmedPersonalDetailsLPADetailsChangedPromptSMS: "71d21daa-11f9-4a2a-9ae2-bb5c2247bfb7",
CertificateProviderInviteEmail: "13df4493-20b0-4c20-b742-cab3844e69b2",
CertificateProviderActingOnPaperDetailsChangedSMS: "ab90c6be-806e-411a-a354-de10f7a70c47",
CertificateProviderActingOnPaperMeetingPromptSMS: "b5cd2c1b-e9b4-4f3e-8cf1-504aff93b16d",
CertificateProviderProvideCertificatePromptEmail: "eada8a4f-5e7c-4f6b-b3fb-d4e92eeeb0ed",
ReplacementAttorneyInviteEmail: "1c4d5b24-fc7d-45ee-be40-f1ccda96f101",
ReplacementTrustCorporationInviteEmail: "1c4d5b24-fc7d-45ee-be40-f1ccda96f101",
TrustCorporationInviteEmail: "9aaedb70-df4a-42a8-9c28-de435cb3d453",
WitnessCodeSMS: "e39849c0-ecab-4e16-87ec-6b22afb9d535",
CertificateProviderInviteEmail: "13df4493-20b0-4c20-b742-cab3844e69b2",
CertificateProviderActingOnPaperDetailsChangedSMS: "ab90c6be-806e-411a-a354-de10f7a70c47",
CertificateProviderActingOnPaperMeetingPromptSMS: "b5cd2c1b-e9b4-4f3e-8cf1-504aff93b16d",
CertificateProviderProvideCertificatePromptEmail: "eada8a4f-5e7c-4f6b-b3fb-d4e92eeeb0ed",
WitnessCodeSMS: "e39849c0-ecab-4e16-87ec-6b22afb9d535",
}
testingTemplates = map[Template]string{
AttorneyInviteEmail: "9be88a99-21c0-4808-8d6a-52af366e44aa",
CertificateProviderCertificateProvidedEmail: "c916f964-bf30-4dee-a9f3-b9bf0043e64d",
CertificateProviderCertificateProvidedEmail: "c916f964-bf30-4dee-a9f3-b9bf0043e64d",
CertificateProviderActingDigitallyHasNotConfirmedPersonalDetailsLPADetailsChangedPromptSMS: "d7513751-49ba-4276-aef5-ad67361d29c4",
CertificateProviderActingDigitallyHasConfirmedPersonalDetailsLPADetailsChangedPromptSMS: "359fffa0-e1ec-444c-a886-6f046af374ab",
CertificateProviderInviteEmail: "4ab51290-5ac6-44ea-88f4-a27c37f285f8",
CertificateProviderActingOnPaperDetailsChangedSMS: "94477364-281a-4032-9a88-b215f969cd12",
CertificateProviderActingOnPaperMeetingPromptSMS: "ee39cd81-5802-44bb-b967-27da7e25e897",
CertificateProviderProvideCertificatePromptEmail: "a445edda-dea1-4554-be9b-ad11adad9e89",
ReplacementAttorneyInviteEmail: "bf79859b-72b7-4701-bfd3-22ac6f0908c8",
ReplacementTrustCorporationInviteEmail: "bf79859b-72b7-4701-bfd3-22ac6f0908c8",
TrustCorporationInviteEmail: "9be88a99-21c0-4808-8d6a-52af366e44aa",
WitnessCodeSMS: "dfa15e16-1f23-494a-bffb-a475513df6cc",
CertificateProviderInviteEmail: "4ab51290-5ac6-44ea-88f4-a27c37f285f8",
CertificateProviderActingOnPaperDetailsChangedSMS: "94477364-281a-4032-9a88-b215f969cd12",
CertificateProviderActingOnPaperMeetingPromptSMS: "ee39cd81-5802-44bb-b967-27da7e25e897",
CertificateProviderProvideCertificatePromptEmail: "a445edda-dea1-4554-be9b-ad11adad9e89",
WitnessCodeSMS: "dfa15e16-1f23-494a-bffb-a475513df6cc",
}
)

Expand All @@ -67,12 +55,13 @@ type Doer interface {
}

type Client struct {
baseURL string
doer Doer
issuer string
secretKey []byte
now func() time.Time
templates map[Template]string
baseURL string
doer Doer
issuer string
secretKey []byte
now func() time.Time
templates map[Template]string
isProduction bool
}

func New(isProduction bool, baseURL, apiKey string, httpClient Doer) (*Client, error) {
Expand All @@ -87,12 +76,13 @@ func New(isProduction bool, baseURL, apiKey string, httpClient Doer) (*Client, e
}

return &Client{
baseURL: baseURL,
doer: httpClient,
issuer: strings.Join(keyParts[1:6], "-"),
secretKey: []byte(strings.Join(keyParts[6:11], "-")),
now: time.Now,
templates: templates,
baseURL: baseURL,
doer: httpClient,
issuer: strings.Join(keyParts[1:6], "-"),
secretKey: []byte(strings.Join(keyParts[6:11], "-")),
now: time.Now,
templates: templates,
isProduction: isProduction,
}, nil
}

Expand Down Expand Up @@ -155,6 +145,41 @@ func (c *Client) Email(ctx context.Context, email Email) (string, error) {
return resp.ID, nil
}

type SendableEmail interface {
emailID(bool) string
}

type emailWrapper struct {
EmailAddress string `json:"email_address"`
TemplateID string `json:"template_id"`
Personalisation any `json:"personalisation,omitempty"`
}

func (c *Client) SendEmail(ctx context.Context, to string, email SendableEmail) (string, error) {
wrapper := emailWrapper{
EmailAddress: to,
TemplateID: email.emailID(c.isProduction),
Personalisation: email,
}

var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(wrapper); err != nil {
return "", err
}

req, err := c.request(ctx, "/v2/notifications/email", &buf)
if err != nil {
return "", err
}

resp, err := c.doRequest(req)
if err != nil {
return "", err
}

return resp.ID, nil
}

func (c *Client) Sms(ctx context.Context, sms Sms) (string, error) {
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(sms); err != nil {
Expand Down
53 changes: 53 additions & 0 deletions internal/notify/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,59 @@ func TestEmailWhenError(t *testing.T) {
assert.Equal(`error sending message: This happened: Plus this`, err.Error())
}

type testSendableEmail struct {
A string
}

func (e testSendableEmail) emailID(bool) string { return "template-id" }

func TestSendEmail(t *testing.T) {
assert := assert.New(t)
ctx := context.Background()

doer := newMockDoer(t)
doer.
On("Do", mock.MatchedBy(func(req *http.Request) bool {
var buf bytes.Buffer
io.Copy(&buf, req.Body)
req.Body = ioutil.NopCloser(&buf)

var v map[string]any
json.Unmarshal(buf.Bytes(), &v)

return assert.Equal("[email protected]", v["email_address"].(string)) &&
assert.Equal("template-id", v["template_id"].(string)) &&
assert.Equal(map[string]any{"A": "value"}, v["personalisation"].(map[string]any))
})).
Return(&http.Response{
Body: io.NopCloser(strings.NewReader(`{"id":"xyz"}`)),
}, nil)

client, _ := New(true, "", "my_client-f33517ff-2a88-4f6e-b855-c550268ce08a-740e5834-3a29-46b4-9a6f-16142fde533a", doer)
client.now = func() time.Time { return time.Date(2020, time.January, 2, 3, 4, 5, 6, time.UTC) }

id, err := client.SendEmail(ctx, "[email protected]", testSendableEmail{A: "value"})
assert.Nil(err)
assert.Equal("xyz", id)
}

func TestSendEmailWhenError(t *testing.T) {
assert := assert.New(t)
ctx := context.Background()

doer := newMockDoer(t)
doer.
On("Do", mock.Anything).
Return(&http.Response{
Body: io.NopCloser(strings.NewReader(`{"errors":[{"error":"SomeError","message":"This happened"}, {"error":"AndError","message":"Plus this"}]}`)),
}, nil)

client, _ := New(true, "", "my_client-f33517ff-2a88-4f6e-b855-c550268ce08a-740e5834-3a29-46b4-9a6f-16142fde533a", doer)

_, err := client.SendEmail(ctx, "[email protected]", testSendableEmail{})
assert.Equal(`error sending message: This happened: Plus this`, err.Error())
}

func TestTemplateID(t *testing.T) {
production, _ := New(true, "", "my_client-f33517ff-2a88-4f6e-b855-c550268ce08a-740e5834-3a29-46b4-9a6f-16142fde533a", nil)
assert.Equal(t, "e39849c0-ecab-4e16-87ec-6b22afb9d535", production.TemplateID(WitnessCodeSMS))
Expand Down
19 changes: 19 additions & 0 deletions internal/notify/emails.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package notify

type InitialOriginalAttorneyEmail struct {
DonorFullName string
LpaType string
AttorneyFullName string
DonorFirstNames string
AttorneyStartPageURL string
ShareCode string
DonorFirstNamesPossessive string
}

func (e InitialOriginalAttorneyEmail) emailID(isProduction bool) string {
if isProduction {
return "080071dc-0434-4b13-adb7-c4e5612c4b47"
}

return "376d7ef2-7941-46c2-b372-bacca0e00c1d"
}
47 changes: 47 additions & 0 deletions internal/page/certificateprovider/mock_ShareCodeSender_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion internal/page/certificateprovider/provide_certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type provideCertificateData struct {
Form *provideCertificateForm
}

func ProvideCertificate(tmpl template.Template, donorStore DonorStore, now func() time.Time, certificateProviderStore CertificateProviderStore, notifyClient NotifyClient) page.Handler {
func ProvideCertificate(tmpl template.Template, donorStore DonorStore, now func() time.Time, certificateProviderStore CertificateProviderStore, notifyClient NotifyClient, shareCodeSender ShareCodeSender) page.Handler {
return func(appData page.AppData, w http.ResponseWriter, r *http.Request) error {
donor, err := donorStore.GetAny(r.Context())
if err != nil {
Expand Down Expand Up @@ -71,6 +71,10 @@ func ProvideCertificate(tmpl template.Template, donorStore DonorStore, now func(
return fmt.Errorf("email failed: %w", err)
}

if err := shareCodeSender.SendAttorneys(r.Context(), appData, donor); err != nil {
return err
}

return page.Paths.CertificateProvider.CertificateProvided.Redirect(w, r, appData, certificateProvider.LpaID)
}
}
Expand Down
Loading

0 comments on commit 3b87b71

Please sign in to comment.