From 50d7f126d2984bb85b6c9c07eb4482a55070c2c0 Mon Sep 17 00:00:00 2001 From: Will Franklin Date: Mon, 3 Feb 2025 16:51:48 +0100 Subject: [PATCH 1/2] Add active user tag --- packages/core/src/data/options/defaults.ts | 1 + packages/core/src/lib/mailchimp.ts | 4 +- .../providers/newsletter/MailchimpProvider.ts | 42 +++++++++++++++---- .../src/providers/newsletter/NoneProvider.ts | 4 ++ .../core/src/services/NewsletterService.ts | 3 +- packages/core/src/type/newsletter-provider.ts | 4 ++ .../src/type/update-newsletter-contact.ts | 1 + 7 files changed, 48 insertions(+), 11 deletions(-) diff --git a/packages/core/src/data/options/defaults.ts b/packages/core/src/data/options/defaults.ts index eb1289f0a..bac6feceb 100644 --- a/packages/core/src/data/options/defaults.ts +++ b/packages/core/src/data/options/defaults.ts @@ -38,6 +38,7 @@ export default { "footer-twitter-link-url": "", "email-templates": "{}", "newsletter-active-member-tag": "Active member", + "newsletter-active-user-tag": "Active user", "newsletter-default-status": NewsletterStatus.None, "newsletter-groups": "[]", "newsletter-resync-status": "", diff --git a/packages/core/src/lib/mailchimp.ts b/packages/core/src/lib/mailchimp.ts index 40b1d4a7a..708565368 100644 --- a/packages/core/src/lib/mailchimp.ts +++ b/packages/core/src/lib/mailchimp.ts @@ -232,6 +232,7 @@ export function mcMemberToNlContact(member: MCMember): NewsletterContact { const activeMemberTag = OptionsService.getText( "newsletter-active-member-tag" ); + const activeUserTag = OptionsService.getText("newsletter-active-user-tag"); return { email: normalizeEmailAddress(member.email_address), firstname: FNAME || "", @@ -248,6 +249,7 @@ export function mcMemberToNlContact(member: MCMember): NewsletterContact { tags: member.tags.map((tag) => tag.name), fields, isActiveMember: - member.tags.findIndex((t) => t.name === activeMemberTag) !== -1 + member.tags.findIndex((t) => t.name === activeMemberTag) !== -1, + isActiveUser: member.tags.findIndex((t) => t.name === activeUserTag) !== -1 }; } diff --git a/packages/core/src/providers/newsletter/MailchimpProvider.ts b/packages/core/src/providers/newsletter/MailchimpProvider.ts index 5d15af8b7..61c06df94 100644 --- a/packages/core/src/providers/newsletter/MailchimpProvider.ts +++ b/packages/core/src/providers/newsletter/MailchimpProvider.ts @@ -180,26 +180,50 @@ export default class MailchimpProvider implements NewsletterProvider { contact: UpdateNewsletterContact, oldEmail = contact.email ): Promise { + log.info("Upsert contact " + contact.email); + const updatedContact = await this.upsertContactOrTryPending( contact, oldEmail ); // Add/remove the active member tag if the statuses don't match - if (updatedContact.isActiveMember !== contact.isActiveMember) { - const tag = OptionsService.getText("newsletter-active-member-tag"); - if (contact.isActiveMember) { - log.info(`Adding active member tag for ${contact.email}`); - await this.addTagToContacts([updatedContact.email], tag); - } else { - log.info(`Removing active member tag for ${contact.email}`); - await this.removeTagFromContacts([updatedContact.email], tag); - } + if ( + updatedContact.isActiveMember !== contact.isActiveMember || + updatedContact.isActiveUser !== contact.isActiveUser + ) { + this.updateContactTags(updatedContact.email, { + [OptionsService.getText("newsletter-active-member-tag")]: + contact.isActiveMember, + [OptionsService.getText("newsletter-active-user-tag")]: + contact.isActiveUser + }); } return updatedContact; } + /** + * Update a contact with the given tags. This will overwrite any existing tags + * but will not remove any tags that are not provided. + * + * @param email The email address of the contact + * @param tags The tags to add or remove + */ + async updateContactTags( + email: string, + tags: Record + ): Promise { + log.info("Update tags for " + email, { tags }); + + await this.api.instance.post(getMCMemberUrl(this.listId, email) + "/tags", { + tags: Object.entries(tags).map(([name, active]) => ({ + name, + status: active ? "active" : "inactive" + })) + }); + } + /** * Update a contact with the given fields. This will overwrite any existing fields * but will not remove any fields that are not provided. diff --git a/packages/core/src/providers/newsletter/NoneProvider.ts b/packages/core/src/providers/newsletter/NoneProvider.ts index 4bcef387a..94b5a3767 100644 --- a/packages/core/src/providers/newsletter/NoneProvider.ts +++ b/packages/core/src/providers/newsletter/NoneProvider.ts @@ -26,4 +26,8 @@ export default class NoneProvider implements NewsletterProvider { email: string, fields: Record ): Promise {} + async updateContactTags( + email: string, + tags: Record + ): Promise {} } diff --git a/packages/core/src/services/NewsletterService.ts b/packages/core/src/services/NewsletterService.ts index 337aa6c18..d6e5c7c26 100644 --- a/packages/core/src/services/NewsletterService.ts +++ b/packages/core/src/services/NewsletterService.ts @@ -60,7 +60,8 @@ async function contactToNlUpdate( C_MNTHAMT: contact.contributionMonthlyAmount?.toFixed(2) || "", C_PERIOD: contact.contributionPeriod || "" }, - isActiveMember: contact.membership?.isActive || false + isActiveMember: contact.membership?.isActive || false, + isActiveUser: !!contact.password.hash }; } diff --git a/packages/core/src/type/newsletter-provider.ts b/packages/core/src/type/newsletter-provider.ts index 7d31cccce..a4860e972 100644 --- a/packages/core/src/type/newsletter-provider.ts +++ b/packages/core/src/type/newsletter-provider.ts @@ -10,6 +10,10 @@ export interface NewsletterProvider { contact: UpdateNewsletterContact, oldEmail?: string ): Promise; + updateContactTags( + email: string, + tags: Record + ): Promise; updateContactFields( email: string, fields: Record diff --git a/packages/core/src/type/update-newsletter-contact.ts b/packages/core/src/type/update-newsletter-contact.ts index 8eff3fe8f..4f7dafbe0 100644 --- a/packages/core/src/type/update-newsletter-contact.ts +++ b/packages/core/src/type/update-newsletter-contact.ts @@ -8,4 +8,5 @@ export interface UpdateNewsletterContact { groups: string[]; fields: Record; isActiveMember: boolean; + isActiveUser: boolean; } From 8c07f2fb023066ead09c703271df010b41314169 Mon Sep 17 00:00:00 2001 From: Will Franklin Date: Mon, 3 Feb 2025 16:54:18 +0100 Subject: [PATCH 2/2] Simpler execution of updateContactFields (for consistency) --- .../src/providers/newsletter/MailchimpProvider.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/core/src/providers/newsletter/MailchimpProvider.ts b/packages/core/src/providers/newsletter/MailchimpProvider.ts index 61c06df94..95976c5af 100644 --- a/packages/core/src/providers/newsletter/MailchimpProvider.ts +++ b/packages/core/src/providers/newsletter/MailchimpProvider.ts @@ -235,15 +235,11 @@ export default class MailchimpProvider implements NewsletterProvider { email: string, fields: Record ): Promise { - await this.api.dispatchOperations([ - { - method: "PATCH", - path: getMCMemberUrl(this.listId, email), - params: { skip_merge_validation: "true" }, - body: JSON.stringify({ merge_fields: fields }), - operation_id: `update_fields_${email}` - } - ]); + await this.api.instance.patch( + getMCMemberUrl(this.listId, email), + { merge_fields: fields }, + { params: { skip_merge_validation: "true" } } + ); } /**