Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Saving sms conversations in CrmActivity #98

Merged
merged 1 commit into from
Dec 21, 2023

Conversation

VSydor
Copy link
Contributor

@VSydor VSydor commented Dec 7, 2022

No description provided.

@VSydor VSydor requested a review from brmeyer December 7, 2022 12:24
@VSydor VSydor self-assigned this Dec 7, 2022
@VSydor VSydor force-pushed the feature/save-sms-conversation-in-crm-task branch 5 times, most recently from 2dc2edf to 11fa2b6 Compare December 12, 2022 10:33
@@ -255,6 +296,9 @@ public EnvironmentConfig.CRMFieldDefinitions getFieldDefinitions() {
}

protected void setTaskFields(SObject task, CrmTask crmTask) {
if (crmTask != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@VSydor Would this ever be null? And if so, there are uses of crmTask below that fall outside of this check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should have been crmTask.id check. Will update this line.

@Path("/webhook/message/onMessageAdded") // TODO: replace with the correct url
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_XML) //TODO: define what type to return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Twilio webhooks expect APPLICATION_JSON I believe, although this method should simply return a 200 response.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will update to json and ok empty response

addMessage(crmTask, messageSid);
upsertCrmTask(env, crmTask);

return Response.ok().build(); // TODO: what to return?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine as-is

@brmeyer brmeyer force-pushed the feature/save-sms-conversation-in-crm-task branch from ddddff8 to 58ec129 Compare December 18, 2022 17:41
@@ -206,6 +206,7 @@ public static class Salesforce extends Platform {
public SalesforceCustomFields customQueryFields = new SalesforceCustomFields();

public String defaultCampaignId = "";
public String defaultTaskAssignee = "";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer needed and we're unlikely to need this in practice -- remove?

@@ -258,11 +308,22 @@ public EnvironmentConfig.CRMFieldDefinitions getFieldDefinitions() {
}

protected void setTaskFields(SObject task, CrmTask crmTask) {
if (crmTask.id != null) {
task.setField("Id", crmTask.id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't set the ID in this method. Instead, have updateTask set it prior to calling setTaskFields. It's a precedent we've set in these services in general, separating the core logic from the specific fields.

@VSydor VSydor force-pushed the feature/save-sms-conversation-in-crm-task branch from 29c5e8f to 4742f1f Compare May 31, 2023 09:20
@VSydor VSydor force-pushed the feature/save-sms-conversation-in-crm-task branch 5 times, most recently from e7fbd7e to 1d17e0e Compare June 21, 2023 14:32
@VSydor VSydor requested a review from brmeyer June 21, 2023 14:35
@@ -221,6 +221,8 @@ default void batchFlush() throws Exception {
// MISC
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
String insertTask(CrmTask crmTask) throws Exception;
String updateTask(CrmTask crmTask) throws Exception;
Optional<CrmTask> getTaskBySubject(String subject) throws Exception;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@VSydor Picky, but precedent setting:

Could we name this something like getTaskByExtRef ("external reference")? It's essentially a way to look up a subject based on an external notion, like a Twilio Conversation ID?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure - will rename the method

@@ -774,6 +774,13 @@ public Optional<SObject> getUserByEmail(String email, String... extraFields) thr
return querySingle(query);
}

protected static final String TASK_FIELDS = "Id, WhoId, OwnerId, Subject, description, status, priority, activityDate";

public Optional<SObject> getTaskBySubject(String subject) throws ConnectionException, InterruptedException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In EnvironmentConfig, could we instead define a new fieldname that must be set, allowing activities to have a external reference ID (ex: Twilio Conference ID) set as a custom field? Similar to what we do with Stripe charges and the paymentGatewayTransactionId field name definition.

Just concerned about tying this to Subject long-term.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do

@Context HttpServletRequest request
) throws Exception {
Environment env = envFactory.init(request);
SecurityUtil.verifyApiKey(env); //TODO: not needed?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, kill this line. No auth for inbound, write-only webhook APIs.

SMS,
inboundMessageWebhookData.message,
inboundMessageWebhookData.externalReferenceId,
null); // TODO: use customParams to contain conversation id?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify this one for me?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In MBT webhook we don't have conversation id (as we have in Twilio webhook)
So need to get it from somewhere (mb it's possible to configure custom params on MBT side?)

@Context HttpServletRequest request
) throws Exception {
Environment env = envFactory.init(request);
SecurityUtil.verifyApiKey(env); //TODO: not needed?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

Environment env = envFactory.init(request);
//SecurityUtil.verifyApiKey(env); //TODO: not needed?

log.info("Mailchimp message event batch received. Batch size: {}.", webhookPayload.events.size());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oy! This is actually pretty refreshing! Cool to see they're batching them...


@Path("/mailchimp")
public class MailchimpController {

private static final Logger log = LogManager.getLogger(MailchimpController.class);

private static final Set<String> SUPPORTED_EVENT_TYPES = Set.of( //TODO: move to env config?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eh, maybe at some point, but the types are strongly tied to chunks of code, so making this config-driven would be tough. Same issue in StripeController

if (event == null) {
return;
}
if (!SUPPORTED_EVENT_TYPES.contains(event.eventType)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the array of types and this if block really necessary? Since you're explicitly looking for "send" and then doing a "skipping event type..." log for everything else, this whole block technically isn't needed? Same pattern as StripeController

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will follow the pattern from Stripe controller

EMAIL,
event.message.subject,
event.message.id,
event.message.email);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm, this will store the actual email body, right? Desirable as a paper trail...

Copy link
Contributor Author

@VSydor VSydor Jun 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"event.message.email" is used here as a conversation id key (same way as explicit conversation sid in Twilio Controller) to have all the messages sent to the same email address in 1 CrmActivity. Can be too much for 1 activity so we can introduce some additional value (like date for example to contain messages for specific time window)
event.message.email = email address of the recipient

@@ -16,16 +18,25 @@ public CrmTask() {
}

public CrmTask(String targetId, String assignTo, String subject, String description,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Picky, and I'm sorry if we went back and forth on this:

Should we call this something like CrmActivity? Logically, these are all activities. Only in SFDC land are they modeled as "tasks" (which I still think was a weird design choice on their part)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure - will rename to CrmActivity.

@VSydor VSydor changed the title Saving sms conversations into crm task #2 (Removed CrmActivity) Saving sms conversations into crm task Jun 27, 2023
@VSydor VSydor force-pushed the feature/save-sms-conversation-in-crm-task branch 4 times, most recently from 11dc384 to 8c31782 Compare June 29, 2023 20:42
@VSydor VSydor changed the title Saving sms conversations into crm task Saving sms conversations in CrmActivity Jun 29, 2023
@VSydor VSydor requested a review from brmeyer June 29, 2023 20:45
@brmeyer brmeyer force-pushed the feature/save-sms-conversation-in-crm-task branch 2 times, most recently from d4cc3cc to 7331b7e Compare September 4, 2023 20:38
@brmeyer brmeyer force-pushed the feature/save-sms-conversation-in-crm-task branch from 61bd24c to b1005af Compare December 21, 2023 00:26
…roller for manual testing

Twilio Conversation webhook added (onMessageAdded)

Code review comments

pulled logic into MessagingService, convering the controller endpoint into a generic conversations webhook

Removed unsuned task config property; Setting task id in update method

Added MBT inbound/message-status webhooks; Saving inbound messages into crm activity (tasks)

Added basic processing of Mailchimp message webhooks

Code review comments

Using combinations of webhook data fields as a converstion key for MBT and Mailchimp

minor fixes

moved the logic to a new ActivityService
@brmeyer brmeyer force-pushed the feature/save-sms-conversation-in-crm-task branch from b1005af to a9127ce Compare December 21, 2023 00:43
@brmeyer brmeyer merged commit 977ddf0 into master Dec 21, 2023
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants