diff --git a/public/auth-callback.html b/public/auth-callback.html index ab2d5f0..43bb27d 100644 --- a/public/auth-callback.html +++ b/public/auth-callback.html @@ -131,7 +131,7 @@ function interceptAuthCallback() { const hash = window.location.hash; const {access_token, refresh_token, type} = getUrlParams(); - window.location.href = `../#/auth-callback?access_token=${access_token}&refresh_token=${refresh_token}&type=${type}`; + window.location.href = `./#/auth-callback?access_token=${access_token}&refresh_token=${refresh_token}&type=${type}`; } // Call the function to intercept the auth callback diff --git a/src/tests/supabase/functions/postmark.spec.ts b/src/tests/supabase/functions/postmark.spec.ts index 772b6ea..8b02144 100644 --- a/src/tests/supabase/functions/postmark.spec.ts +++ b/src/tests/supabase/functions/postmark.spec.ts @@ -1,5 +1,5 @@ -import { getExpectedAuthorization } from '../../../../supabase/functions/postmark/getExpectedAuthorization.js'; import { extractMailContactData } from '../../../../supabase/functions/postmark/extractMailContactData.js'; +import { getExpectedAuthorization } from '../../../../supabase/functions/postmark/getExpectedAuthorization.js'; describe('getExpectedAuthorization', () => { it('should return the expected Authorization header from provided user and password', () => { @@ -16,15 +16,17 @@ describe('extractMailContactData', () => { Name: 'Firstname Lastname', }, ]); - expect(result).toEqual({ - firstName: 'Firstname', - lastName: 'Lastname', - email: 'firstname.lastname@marmelab.com', - domain: 'marmelab.com', - }); + expect(result).toEqual([ + { + firstName: 'Firstname', + lastName: 'Lastname', + email: 'firstname.lastname@marmelab.com', + domain: 'marmelab.com', + }, + ]); }); - it('should ignore extra recipients', () => { + it('should support extra recipients', () => { const result = extractMailContactData([ { Email: 'firstname.lastname@marmelab.com', @@ -35,12 +37,20 @@ describe('extractMailContactData', () => { Name: 'John Doe', }, ]); - expect(result).toEqual({ - firstName: 'Firstname', - lastName: 'Lastname', - email: 'firstname.lastname@marmelab.com', - domain: 'marmelab.com', - }); + expect(result).toEqual([ + { + firstName: 'Firstname', + lastName: 'Lastname', + email: 'firstname.lastname@marmelab.com', + domain: 'marmelab.com', + }, + { + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@marmelab.com', + domain: 'marmelab.com', + }, + ]); }); it('should use a single word name as last name', () => { @@ -50,12 +60,14 @@ describe('extractMailContactData', () => { Name: 'Name', }, ]); - expect(result).toEqual({ - firstName: '', - lastName: 'Name', - email: 'name@marmelab.com', - domain: 'marmelab.com', - }); + expect(result).toEqual([ + { + firstName: '', + lastName: 'Name', + email: 'name@marmelab.com', + domain: 'marmelab.com', + }, + ]); }); it('should support multi word last name', () => { @@ -65,12 +77,14 @@ describe('extractMailContactData', () => { Name: 'Multi Word Name', }, ]); - expect(result).toEqual({ - firstName: 'Multi', - lastName: 'Word Name', - email: 'multi.word.name@marmelab.com', - domain: 'marmelab.com', - }); + expect(result).toEqual([ + { + firstName: 'Multi', + lastName: 'Word Name', + email: 'multi.word.name@marmelab.com', + domain: 'marmelab.com', + }, + ]); }); it('should support multiple @ in email', () => { @@ -81,12 +95,14 @@ describe('extractMailContactData', () => { Name: 'John Doe', }, ]); - expect(result).toEqual({ - firstName: 'John', - lastName: 'Doe', - email: '"john@doe"@marmelab.com', - domain: 'marmelab.com', - }); + expect(result).toEqual([ + { + firstName: 'John', + lastName: 'Doe', + email: '"john@doe"@marmelab.com', + domain: 'marmelab.com', + }, + ]); }); it('should use first part of email when Name is empty', () => { @@ -96,12 +112,14 @@ describe('extractMailContactData', () => { Name: '', }, ]); - expect(result).toEqual({ - firstName: 'john', - lastName: 'doe', - email: 'john.doe@marmelab.com', - domain: 'marmelab.com', - }); + expect(result).toEqual([ + { + firstName: 'john', + lastName: 'doe', + email: 'john.doe@marmelab.com', + domain: 'marmelab.com', + }, + ]); }); it('should use first part of email when Name is empty and support single word', () => { @@ -111,12 +129,14 @@ describe('extractMailContactData', () => { Name: '', }, ]); - expect(result).toEqual({ - firstName: '', - lastName: 'john', - email: 'john@marmelab.com', - domain: 'marmelab.com', - }); + expect(result).toEqual([ + { + firstName: '', + lastName: 'john', + email: 'john@marmelab.com', + domain: 'marmelab.com', + }, + ]); }); it('should use first part of email when Name is empty and support multiple words', () => { @@ -126,12 +146,14 @@ describe('extractMailContactData', () => { Name: '', }, ]); - expect(result).toEqual({ - firstName: 'john', - lastName: 'doe multi', - email: 'john.doe.multi@marmelab.com', - domain: 'marmelab.com', - }); + expect(result).toEqual([ + { + firstName: 'john', + lastName: 'doe multi', + email: 'john.doe.multi@marmelab.com', + domain: 'marmelab.com', + }, + ]); }); it('should support empty Name and multiple @ in email', () => { @@ -142,11 +164,13 @@ describe('extractMailContactData', () => { Name: '', }, ]); - expect(result).toEqual({ - firstName: '"john', - lastName: 'doe"', - email: '"john@doe"@marmelab.com', - domain: 'marmelab.com', - }); + expect(result).toEqual([ + { + firstName: '"john', + lastName: 'doe"', + email: '"john@doe"@marmelab.com', + domain: 'marmelab.com', + }, + ]); }); }); diff --git a/supabase/functions/postmark/addNoteToContact.ts b/supabase/functions/postmark/addNoteToContact.ts index 0148a43..605800e 100644 --- a/supabase/functions/postmark/addNoteToContact.ts +++ b/supabase/functions/postmark/addNoteToContact.ts @@ -123,5 +123,8 @@ export const addNoteToContact = async ({ { status: 500 } ); - return new Response('OK'); + await supabaseAdmin + .from('contacts') + .update({ last_seen: new Date() }) + .eq('id', contact.id); }; diff --git a/supabase/functions/postmark/extractMailContactData.ts b/supabase/functions/postmark/extractMailContactData.ts index ed96ffa..b434d13 100644 --- a/supabase/functions/postmark/extractMailContactData.ts +++ b/supabase/functions/postmark/extractMailContactData.ts @@ -24,19 +24,22 @@ export const extractMailContactData = ( Name: string; }[] ) => { - // We only support one recipient for now - const contact = ToFull[0]; - - const domain = contact.Email.split('@').at(-1); - const fullName = - contact.Name || - contact.Email.split('@').slice(0, -1).join(' ').split('.').join(' '); - let firstName = ''; - let lastName = fullName; - if (fullName && fullName.includes(' ')) { - const parts = fullName.split(' '); - firstName = parts[0]; - lastName = parts.slice(1).join(' '); - } - return { firstName, lastName, email: contact.Email, domain }; + return ToFull.map(contact => { + const domain = contact.Email.split('@').at(-1)!; + const fullName = + contact.Name || + contact.Email.split('@') + .slice(0, -1) + .join(' ') + .split('.') + .join(' '); + let firstName = ''; + let lastName = fullName; + if (fullName && fullName.includes(' ')) { + const parts = fullName.split(' '); + firstName = parts[0]; + lastName = parts.slice(1).join(' '); + } + return { firstName, lastName, email: contact.Email, domain }; + }); }; diff --git a/supabase/functions/postmark/index.ts b/supabase/functions/postmark/index.ts index a95fd51..c18e603 100644 --- a/supabase/functions/postmark/index.ts +++ b/supabase/functions/postmark/index.ts @@ -4,9 +4,9 @@ // Setup type definitions for built-in Supabase Runtime APIs import 'jsr:@supabase/functions-js/edge-runtime.d.ts'; -import { getExpectedAuthorization } from './getExpectedAuthorization.ts'; -import { extractMailContactData } from './extractMailContactData.ts'; import { addNoteToContact } from './addNoteToContact.ts'; +import { extractMailContactData } from './extractMailContactData.ts'; +import { getExpectedAuthorization } from './getExpectedAuthorization.ts'; import { getNoteContent } from './getNoteContent.ts'; const webhookUser = Deno.env.get('POSTMARK_WEBHOOK_USER'); @@ -46,24 +46,31 @@ Deno.serve(async req => { ); } - const { firstName, lastName, email, domain } = - extractMailContactData(ToFull); - if (!email) { - // Return a 403 to let Postmark know that it's no use to retry this request - // https://postmarkapp.com/developer/webhooks/inbound-webhook#errors-and-retries - return new Response(`Could not extract email from ToFull: ${ToFull}`, { - status: 403, + const contacts = extractMailContactData(ToFull); + + for (const { firstName, lastName, email, domain } of contacts) { + if (!email) { + // Return a 403 to let Postmark know that it's no use to retry this request + // https://postmarkapp.com/developer/webhooks/inbound-webhook#errors-and-retries + return new Response( + `Could not extract email from ToFull: ${ToFull}`, + { + status: 403, + } + ); + } + + await addNoteToContact({ + salesEmail, + email, + domain, + firstName, + lastName, + noteContent, }); } - return await addNoteToContact({ - salesEmail, - email, - domain, - firstName, - lastName, - noteContent, - }); + return new Response('OK'); }); const checkRequestTypeAndHeaders = (req: Request) => { diff --git a/supabase/templates/invite.html b/supabase/templates/invite.html index 5bb1ddc..7cb5fbc 100644 --- a/supabase/templates/invite.html +++ b/supabase/templates/invite.html @@ -62,11 +62,6 @@

Confirm your account

class="button" >Confirm my account -

- Warning: If the password reset request did - not originate from you, please contact us immediately as - this may be a fraudulent attempt. -

See you soon!

Atomic CRM team

diff --git a/supabase/templates/recovery.html b/supabase/templates/recovery.html index 33558a1..ee60380 100644 --- a/supabase/templates/recovery.html +++ b/supabase/templates/recovery.html @@ -49,7 +49,7 @@
-

Reset your password

+

Reset Your Atomic CRM Password

Hello,