Skip to content

Commit

Permalink
feat(comms): Adding email for when a Plaid link is disconnected
Browse files Browse the repository at this point in the history
This email is not sent yet, but is the groundwork for allowing us to
notify users when their plaid link is disconnected and needs to be
reauthenticated.
  • Loading branch information
elliotcourant committed May 27, 2024
1 parent fc5eb8f commit 5534ad1
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 166 deletions.
107 changes: 107 additions & 0 deletions emails/src/PlaidDisconnected.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import * as React from 'react';
import {
Body,
Button,
Container,
Head,
Heading,
Hr,
Html,
Img,
Link,
Preview,
Section,
Tailwind,
Text,
} from '@react-email/components';

// eslint-disable-next-line no-relative-import-paths/no-relative-import-paths
import tailwindConfig from '../tailwind.config.js';

interface PlaidDisconnectedProps {
baseUrl?: string;
firstName?: string;
lastName?: string;
linkName?: string;
linkURL?: string;
supportEmail?: string;
}

export const PlaidDisconnected = ({
baseUrl = '{{ .BaseURL }}',
firstName = '{{ .FirstName }}',
lastName = '{{ .LastName }}',
linkName = '{{ .LinkName }}',
linkURL = '{{ .LinkURL }}',
supportEmail = '{{ .SupportEmail }}',
}: PlaidDisconnectedProps) => {
const previewText = 'One of your linked accounts has been disconnected';

return (
<Html>
<Head />
<Preview>{ previewText }</Preview>
<Tailwind config={ tailwindConfig as any }>
<Body className='bg-white my-auto mx-auto font-sans'>
<Container className='border border-solid border-[#eaeaea] rounded my-10 mx-auto p-5 max-w-xl'>
<Section className='mt-8'>
<Img
src={ `${baseUrl}/logo192.png` }
width='64'
height='64'
alt='monetr'
className='my-0 mx-auto'
/>
</Section>
<Heading className='text-black text-2xl font-normal text-center p-0 my-8 mx-0'>
One of your linked accounts has been disconnected
</Heading>
<Text className='text-black text-sm leading-6'>
Hello {firstName},
</Text>
<Text className='text-black text-sm leading-6'>
Your <strong>{ linkName }</strong> account connected via Plaid needs to be reauthenticated. This account
will not receive automatic updates until the link has been updated.
</Text>
<Section className='text-center mt-9 mb-9'>
<Button
className='bg-purple-500 rounded-lg text-white text-sm font-semibold no-underline text-center'
href={ linkURL }
>
<Text className='text-sm text-white m-2'>
Reconnect { linkName }
</Text>
</Button>
</Section>
<Hr className='border border-solid border-[#eaeaea] my-6 mx-0 w-full' />
<Text className='text-[#666666] text-xs leading-6'>
This message was intended for{' '}
<span className='text-black'>{firstName} {lastName}</span>.
If you did not sign up for <strong>monetr</strong>, you can ignore this email. If you are concerned about
this communication please reach out to{' '}
<Link
href={ `mailto:${ supportEmail }` }
className='text-blue-600 no-underline'
>
{ supportEmail }
</Link>.
</Text>
</Container>
</Body>
</Tailwind>
</Html>
);
};

PlaidDisconnected.PreviewProps = {
baseUrl: 'https://my.monetr.dev',
firstName: 'Elliot',
lastName: 'Courant',
linkName: 'Navy Federal Credit Union',
linkURL: 'https://my.monetr.dev/bank_accounts/bac_123abc',
supportEmail: 'support@monetr.local',
} as PlaidDisconnectedProps;

export default PlaidDisconnected;


33 changes: 30 additions & 3 deletions server/communication/email.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import (
)

const (
VerifyEmailTemplate = "VerifyEmailAddress"
ForgotPasswordTemplate = "ForgotPassword"
PasswordChangedTemplate = "PasswordChanged"
ForgotPasswordTemplate = "ForgotPassword"
PasswordChangedTemplate = "PasswordChanged"
PlaidDisconnectedTemplate = "PlaidDisconnected"
VerifyEmailTemplate = "VerifyEmailAddress"
)

//go:embed email_templates/*
Expand Down Expand Up @@ -53,13 +54,24 @@ type (
LastName string
SupportEmail string
}

PlaidDisconnectedParams struct {
BaseURL string
Email string
FirstName string
LastName string
LinkName string
LinkURL string
SupportEmail string
}
)

//go:generate go run go.uber.org/mock/mockgen@v0.4.0 -source=email.go -package=mockgen -destination=../internal/mockgen/email.go EmailCommunication
type EmailCommunication interface {
SendVerification(ctx context.Context, params VerifyEmailParams) error
SendPasswordReset(ctx context.Context, params PasswordResetParams) error
SendPasswordChanged(ctx context.Context, params PasswordChangedParams) error
SendPlaidDisconnected(ctx context.Context, params PlaidDisconnectedParams) error
}

func NewEmailCommunication(log *logrus.Entry, configuration config.Configuration) EmailCommunication {
Expand Down Expand Up @@ -135,6 +147,21 @@ func (e *emailCommunicationBase) SendPasswordChanged(ctx context.Context, params
return e.sendMessage(span.Context(), m)
}

func (e *emailCommunicationBase) SendPlaidDisconnected(ctx context.Context, params PlaidDisconnectedParams) error {
span := crumbs.StartFnTrace(ctx)
defer span.Finish()

html, text := e.getTemplates(PlaidDisconnectedTemplate)
m := mail.NewMsg()
m.Subject("Account Disconnected")
e.toAddress(m, params.FirstName, params.LastName, params.Email)
e.fromAddress(m)
m.SetBodyTextTemplate(text, params)
m.AddAlternativeHTMLTemplate(html, params)

return e.sendMessage(span.Context(), m)
}

func (e *emailCommunicationBase) getTemplates(name string) (html *htmlTemplate.Template, text *textTemplate.Template) {
{ // HTML template
data, err := templates.ReadFile(fmt.Sprintf("email_templates/%s.html", name))
Expand Down
154 changes: 0 additions & 154 deletions server/communication/smtp.go

This file was deleted.

15 changes: 6 additions & 9 deletions server/controller/plaid_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"strings"
"time"

"github.com/getsentry/sentry-go"
"github.com/golang-jwt/jwt/v4"
"github.com/labstack/echo/v4"
"github.com/monetr/monetr/server/background"
Expand Down Expand Up @@ -156,14 +155,10 @@ func (c *Controller) processWebhook(ctx echo.Context, hook PlaidWebhook) error {
crumbs.Debug(c.getContext(ctx), "Handling webhook from Plaid.", fields)
}

if hub := sentry.GetHubFromContext(c.getContext(ctx)); hub != nil {
hub.ConfigureScope(func(scope *sentry.Scope) {
scope.SetTag("webhook", "plaid")
scope.SetTag("plaid.item_id", hook.ItemId)
scope.SetTag("plaid.webhook.type", hook.WebhookType)
scope.SetTag("plaid.webhook.code", hook.WebhookCode)
})
}
crumbs.AddTag(c.getContext(ctx), "webhook", "plaid")
crumbs.AddTag(c.getContext(ctx), "plaid.item_id", hook.ItemId)
crumbs.AddTag(c.getContext(ctx), "plaid.webhook.type", hook.WebhookType)
crumbs.AddTag(c.getContext(ctx), "plaid.webhook.code", hook.WebhookCode)

repo := c.mustGetUnauthenticatedRepository(ctx)

Expand All @@ -184,6 +179,8 @@ func (c *Controller) processWebhook(ctx echo.Context, hook PlaidWebhook) error {
// Set the user for this webhook for sentry.
crumbs.IncludeUserInScope(c.getContext(ctx), link.AccountId)
crumbs.AddTag(c.getContext(ctx), "linkId", link.LinkId.String())
crumbs.AddTag(c.getContext(ctx), "plaid.institution_id", link.PlaidLink.InstitutionId)
crumbs.AddTag(c.getContext(ctx), "plaid.institution_name", link.PlaidLink.InstitutionName)

if link.PlaidLink != nil {
// If we have the plaid link in scope then add the institution ID onto the sentry scope.
Expand Down
14 changes: 14 additions & 0 deletions server/internal/mockgen/email.go

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

0 comments on commit 5534ad1

Please sign in to comment.