From f47ab15a3b9b0f68a8968737c69150ff33123d4a Mon Sep 17 00:00:00 2001
From: soyombo <40427263+soyombo-baterdene@users.noreply.github.com>
Date: Wed, 29 Jul 2020 11:14:19 +0800
Subject: [PATCH 1/6] productBoard integration
---
src/debuggers.ts | 1 +
src/index.ts | 4 ++++
src/productBoard/controller.ts | 40 ++++++++++++++++++++++++++++++++++
3 files changed, 45 insertions(+)
create mode 100644 src/productBoard/controller.ts
diff --git a/src/debuggers.ts b/src/debuggers.ts
index ccdd2492..c5cb7911 100644
--- a/src/debuggers.ts
+++ b/src/debuggers.ts
@@ -15,6 +15,7 @@ export const debugWhatsapp = debug('erxes-integrations:whatsapp');
export const debugExternalRequests = debug('erxes-integrations:external-requests');
export const debugDaily = debug('erxes-integrations:daily');
export const debugSmooch = debug('erxes-integrations:smooch');
+export const debugProductBoard = debug('erxes-integrations:productBoard');
export const debugRequest = (debugInstance, req) =>
debugInstance(`
diff --git a/src/index.ts b/src/index.ts
index c620188a..6de81aef 100755
--- a/src/index.ts
+++ b/src/index.ts
@@ -11,6 +11,7 @@ import { initConsumer, rabbitMQStatus } from './messageBroker';
import Accounts from './models/Accounts';
import Configs from './models/Configs';
import { initNylas } from './nylas/controller';
+import initProductBoard from './productBoard/controller';
import { initRedis, redisStatus } from './redisClient';
import initSmooch from './smooch/controller';
import { init } from './startup';
@@ -149,6 +150,9 @@ initDaily(app);
// init smooch
initSmooch(app);
+// init product board
+initProductBoard(app);
+
// Error handling middleware
app.use((error, _req, res, _next) => {
console.error(error.stack);
diff --git a/src/productBoard/controller.ts b/src/productBoard/controller.ts
new file mode 100644
index 00000000..ddc632f7
--- /dev/null
+++ b/src/productBoard/controller.ts
@@ -0,0 +1,40 @@
+import { debugProductBoard, debugRequest } from '../debuggers';
+import { getConfig, getEnv, sendRequest } from '../utils';
+
+const init = async app => {
+ app.post('/productBoard/create-note', async (req, res, next) => {
+ debugRequest(debugProductBoard, req);
+
+ const PRODUCT_BOARD_TOKEN = await getConfig('PRODUCT_BOARD_TOKEN');
+ const MAIN_APP_DOMAIN = getEnv({ name: 'MAIN_APP_DOMAIN' });
+
+ const { customer, content, tags } = req.body;
+
+ try {
+ await sendRequest({
+ url: 'https://api.productboard.com/notes',
+ method: 'POST',
+ headerParams: {
+ authorization: `Bearer ${PRODUCT_BOARD_TOKEN}`,
+ },
+ body: {
+ title: `Erxes message from ${customer.firstName}`,
+ content,
+ customer_email: customer.email,
+ display_url: `${MAIN_APP_DOMAIN}/inbox/?_id=${customer._id}`,
+ source: {
+ origin: 'erxes inbox',
+ customerId: customer._id,
+ },
+ tags,
+ },
+ });
+ } catch (e) {
+ next(e);
+ }
+
+ return res.json({ status: 'ok' });
+ });
+};
+
+export default init;
From bd795a469235390f45189fad4b26a1ac5e762524 Mon Sep 17 00:00:00 2001
From: soyombo <40427263+soyombo-baterdene@users.noreply.github.com>
Date: Wed, 29 Jul 2020 20:05:45 +0800
Subject: [PATCH 2/6] Update controller.ts
---
src/productBoard/controller.ts | 43 ++++++++++++++++++++++++++--------
1 file changed, 33 insertions(+), 10 deletions(-)
diff --git a/src/productBoard/controller.ts b/src/productBoard/controller.ts
index ddc632f7..b3a2a2c9 100644
--- a/src/productBoard/controller.ts
+++ b/src/productBoard/controller.ts
@@ -8,32 +8,55 @@ const init = async app => {
const PRODUCT_BOARD_TOKEN = await getConfig('PRODUCT_BOARD_TOKEN');
const MAIN_APP_DOMAIN = getEnv({ name: 'MAIN_APP_DOMAIN' });
- const { customer, content, tags } = req.body;
+ const { customer, messages, tags, erxesApiConversationId, user } = req.body;
+
+ let content = '';
+
+ for (const message of messages) {
+ const messageDate = new Date(message.createdAt).toUTCString();
+
+ if (message.customerId) {
+ content = content.concat(`${customer.primaryEmail} ${messageDate}
${message.content}
`);
+ } else {
+ content = content.concat(`${user.details.fullName} ${messageDate}${message.content}
`);
+ }
+
+ if (message.attachments) {
+ for (const attachment of message.attachments) {
+ content = content.concat(`${attachment.name}
`);
+ }
+ }
+ }
+
+ const origin = messages[messages.length - 1].content;
try {
- await sendRequest({
+ const result = await sendRequest({
url: 'https://api.productboard.com/notes',
method: 'POST',
headerParams: {
authorization: `Bearer ${PRODUCT_BOARD_TOKEN}`,
},
body: {
- title: `Erxes message from ${customer.firstName}`,
+ title: messages[0].content,
content,
- customer_email: customer.email,
- display_url: `${MAIN_APP_DOMAIN}/inbox/?_id=${customer._id}`,
+ customer_email: customer.primaryEmail,
+ display_url: `${MAIN_APP_DOMAIN}/inbox/?_id=${erxesApiConversationId}`,
source: {
- origin: 'erxes inbox',
- customerId: customer._id,
+ origin,
+ record_id: erxesApiConversationId,
},
- tags,
+ tags: tags.map(tag => tag.name),
},
});
+
+ return res.send(result.links.html);
} catch (e) {
+ if (e.statusCode === 422) {
+ next(new Error('already exists'));
+ }
next(e);
}
-
- return res.json({ status: 'ok' });
});
};
From 4b0b3614580d590677783d06f791f73e31e3a5e5 Mon Sep 17 00:00:00 2001
From: soyombo <40427263+soyombo-baterdene@users.noreply.github.com>
Date: Thu, 30 Jul 2020 03:13:48 +0800
Subject: [PATCH 3/6] fix
---
src/productBoard/controller.ts | 18 +++++++++++++
src/productBoard/models.ts | 47 ++++++++++++++++++++++++++++++++++
src/whatsapp/store.ts | 1 -
3 files changed, 65 insertions(+), 1 deletion(-)
create mode 100644 src/productBoard/models.ts
diff --git a/src/productBoard/controller.ts b/src/productBoard/controller.ts
index b3a2a2c9..c54ef8e2 100644
--- a/src/productBoard/controller.ts
+++ b/src/productBoard/controller.ts
@@ -1,7 +1,19 @@
import { debugProductBoard, debugRequest } from '../debuggers';
import { getConfig, getEnv, sendRequest } from '../utils';
+import { Conversations } from './models';
const init = async app => {
+ app.get('/productBoard/note', async (req, res) => {
+ const { erxesApiId } = req.query;
+ try {
+ const conversation = await Conversations.findOne({ erxesApiId });
+
+ return res.send(conversation.productBoardLink);
+ } catch (e) {
+ return res.send('');
+ }
+ });
+
app.post('/productBoard/create-note', async (req, res, next) => {
debugRequest(debugProductBoard, req);
@@ -50,6 +62,12 @@ const init = async app => {
},
});
+ await Conversations.create({
+ timestamp: new Date(),
+ erxesApiId: erxesApiConversationId,
+ productBoardLink: result.links.html,
+ });
+
return res.send(result.links.html);
} catch (e) {
if (e.statusCode === 422) {
diff --git a/src/productBoard/models.ts b/src/productBoard/models.ts
new file mode 100644
index 00000000..aa0afeb0
--- /dev/null
+++ b/src/productBoard/models.ts
@@ -0,0 +1,47 @@
+import { Document, Model, model, Schema } from 'mongoose';
+import { field } from '../models/utils';
+
+export interface IConversation {
+ erxesApiId?: string;
+ timestamp: Date;
+ productBoardLink?: string;
+}
+
+export interface IConversationDocument extends IConversation, Document {}
+
+export const conversationSchema = new Schema({
+ _id: field({ pkey: true }),
+ erxesApiId: String,
+ timestamp: Date,
+ productBoardLink: String,
+});
+
+// conversationSchema.index({ instanceId: 1, recipientId: 1 }, { unique: true });
+
+export interface IConversationModel extends Model {
+ getConversation(selector): Promise;
+}
+
+export const loadConversationClass = () => {
+ class Conversation {
+ public static async getConversation(selector) {
+ const conversation = await Conversations.findOne(selector);
+
+ if (!conversation) {
+ throw new Error('Conversation not found');
+ }
+
+ return conversation;
+ }
+ }
+
+ conversationSchema.loadClass(Conversation);
+
+ return conversationSchema;
+};
+
+// tslint:disable-next-line:variable-name
+export const Conversations = model(
+ 'conversations_productboard',
+ conversationSchema,
+);
diff --git a/src/whatsapp/store.ts b/src/whatsapp/store.ts
index 04f5294f..2cf006d2 100644
--- a/src/whatsapp/store.ts
+++ b/src/whatsapp/store.ts
@@ -122,7 +122,6 @@ export const createMessage = async (message, conversationIds) => {
let attachments = [];
if (message.type !== 'chat') {
- console.log('body: ', message.body);
attachments = [{ type: message.type, url: message.body }];
message.body = '';
}
From 2770818335bbf6a77b4e631c33ab9a47e3b916e7 Mon Sep 17 00:00:00 2001
From: soyombo <40427263+soyombo-baterdene@users.noreply.github.com>
Date: Thu, 30 Jul 2020 09:56:04 +0800
Subject: [PATCH 4/6] Update controller.ts
---
src/productBoard/controller.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/productBoard/controller.ts b/src/productBoard/controller.ts
index c54ef8e2..3a89077e 100644
--- a/src/productBoard/controller.ts
+++ b/src/productBoard/controller.ts
@@ -72,6 +72,8 @@ const init = async app => {
} catch (e) {
if (e.statusCode === 422) {
next(new Error('already exists'));
+ } else if (e.statusCode === 401) {
+ next(new Error('Please enter the product board access token in system config.'));
}
next(e);
}
From a83b59d16901c0e0ea919cc533891046094e569c Mon Sep 17 00:00:00 2001
From: soyombo <40427263+soyombo-baterdene@users.noreply.github.com>
Date: Fri, 7 Aug 2020 15:44:15 +0800
Subject: [PATCH 5/6] Update controller.ts
---
src/productBoard/controller.ts | 47 +++++++++++++++++++++++++++++-----
1 file changed, 41 insertions(+), 6 deletions(-)
diff --git a/src/productBoard/controller.ts b/src/productBoard/controller.ts
index 3a89077e..5d86c6d4 100644
--- a/src/productBoard/controller.ts
+++ b/src/productBoard/controller.ts
@@ -1,8 +1,11 @@
import { debugProductBoard, debugRequest } from '../debuggers';
+import { Integrations } from '../models';
import { getConfig, getEnv, sendRequest } from '../utils';
-import { Conversations } from './models';
+import { ALL_MODELS, Conversations } from './models';
const init = async app => {
+ const mailIntegrations = ['office365', 'yahoo', 'outlook', 'imap', 'exchange', 'gmail'];
+
app.get('/productBoard/note', async (req, res) => {
const { erxesApiId } = req.query;
try {
@@ -20,11 +23,39 @@ const init = async app => {
const PRODUCT_BOARD_TOKEN = await getConfig('PRODUCT_BOARD_TOKEN');
const MAIN_APP_DOMAIN = getEnv({ name: 'MAIN_APP_DOMAIN' });
- const { customer, messages, tags, erxesApiConversationId, user } = req.body;
-
+ const { customer, tags, erxesApiConversationId, user, integrationId } = req.body;
+ let { messages } = req.body;
let content = '';
+ let title = '';
+
+ const integration = await Integrations.findOne({ erxesApiId: integrationId }).lean();
+
+ let origin = messages[messages.length - 1].content;
+
+ if (integration) {
+ if (integration.kind !== 'facebook-post') {
+ const conversations = ALL_MODELS[integration.kind].conversations;
+ const conversation = await conversations.findOne({ erxesApiId: erxesApiConversationId }).lean();
+
+ const conversationMessages = ALL_MODELS[integration.kind].conversationMessages;
+ messages = await conversationMessages.find({ conversationId: conversation._id });
+ } else {
+ const post = await ALL_MODELS['facebook-post'].posts.findOne({ erxesApiId: integrationId }).lean();
+
+ const comments = await ALL_MODELS['facebook-post'].comments.find({ postId: post._id });
+
+ for (const comment of comments) {
+ const commentDate = new Date(comment.timestamp).toUTCString();
+ content = content.concat(`${commentDate}${comment.content}
`);
+ }
+ origin = post.postId;
+ title = post.content;
+ }
+ }
for (const message of messages) {
+ title = messages[0].content;
+
const messageDate = new Date(message.createdAt).toUTCString();
if (message.customerId) {
@@ -38,9 +69,13 @@ const init = async app => {
content = content.concat(`${attachment.name}
`);
}
}
- }
- const origin = messages[messages.length - 1].content;
+ if (mailIntegrations.some(i => integration.kind === i)) {
+ title = messages[0].subject;
+ content = content.concat(`${message.from[0]} ${messageDate}${message.body}
`);
+ origin = messages[messages.length - 1].subject;
+ }
+ }
try {
const result = await sendRequest({
@@ -50,7 +85,7 @@ const init = async app => {
authorization: `Bearer ${PRODUCT_BOARD_TOKEN}`,
},
body: {
- title: messages[0].content,
+ title,
content,
customer_email: customer.primaryEmail,
display_url: `${MAIN_APP_DOMAIN}/inbox/?_id=${erxesApiConversationId}`,
From 646c0cd0b49d3205649c097c68bcc952494d58cc Mon Sep 17 00:00:00 2001
From: soyombo <40427263+soyombo-baterdene@users.noreply.github.com>
Date: Fri, 7 Aug 2020 15:44:24 +0800
Subject: [PATCH 6/6] Update models.ts
---
src/productBoard/models.ts | 124 ++++++++++++++++++++++++++++++++++++-
1 file changed, 123 insertions(+), 1 deletion(-)
diff --git a/src/productBoard/models.ts b/src/productBoard/models.ts
index aa0afeb0..73cec3b8 100644
--- a/src/productBoard/models.ts
+++ b/src/productBoard/models.ts
@@ -1,6 +1,56 @@
import { Document, Model, model, Schema } from 'mongoose';
+import {
+ Comments,
+ ConversationMessages as FacebookMessengerConversationMessages,
+ Conversations as FacebookMessengerConversations,
+ Customers as FacebookMessengerCustomers,
+ Posts,
+} from '../facebook/models';
import { field } from '../models/utils';
-
+import {
+ NylasExchangeConversationMessages,
+ NylasExchangeConversations,
+ NylasExchangeCustomers,
+ NylasGmailConversationMessages,
+ NylasGmailConversations,
+ NylasGmailCustomers,
+ NylasImapConversationMessages,
+ NylasImapConversations,
+ NylasImapCustomers,
+ NylasOffice365ConversationMessages,
+ NylasOffice365Conversations,
+ NylasOffice365Customers,
+ NylasOutlookConversationMessages,
+ NylasOutlookConversations,
+ NylasOutlookCustomers,
+ NylasYahooConversationMessages,
+ NylasYahooConversations,
+ NylasYahooCustomers,
+} from '../nylas/models';
+import {
+ SmoochLineConversationMessages,
+ SmoochLineConversations,
+ SmoochLineCustomers,
+ SmoochTelegramConversationMessages,
+ SmoochTelegramConversations,
+ SmoochTelegramCustomers,
+ SmoochTwilioConversationMessages,
+ SmoochTwilioConversations,
+ SmoochTwilioCustomers,
+ SmoochViberConversationMessages,
+ SmoochViberConversations,
+ SmoochViberCustomers,
+} from '../smooch/models';
+import {
+ ConversationMessages as TwitterConversationMessages,
+ Conversations as TwitterConversations,
+ Customers as TwitterCustomers,
+} from '../twitter/models';
+import {
+ ConversationMessages as WhatsAppConversationMessages,
+ Conversations as WhatsAppConversations,
+ Customers as WhatsAppCustomers,
+} from '../whatsapp/models';
export interface IConversation {
erxesApiId?: string;
timestamp: Date;
@@ -45,3 +95,75 @@ export const Conversations = model(
'conversations_productboard',
conversationSchema,
);
+
+export const ALL_MODELS = {
+ gmail: {
+ customers: NylasGmailCustomers,
+ conversations: NylasGmailConversations,
+ conversationMessages: NylasGmailConversationMessages,
+ },
+ exchange: {
+ customers: NylasExchangeCustomers,
+ conversations: NylasExchangeConversations,
+ conversationMessages: NylasExchangeConversationMessages,
+ },
+ imap: {
+ customers: NylasImapCustomers,
+ conversations: NylasImapConversations,
+ conversationMessages: NylasImapConversationMessages,
+ },
+ outlook: {
+ customers: NylasOutlookCustomers,
+ conversations: NylasOutlookConversations,
+ conversationMessages: NylasOutlookConversationMessages,
+ },
+ yahoo: {
+ customers: NylasYahooCustomers,
+ conversations: NylasYahooConversations,
+ conversationMessages: NylasYahooConversationMessages,
+ },
+ office365: {
+ customers: NylasOffice365Customers,
+ conversations: NylasOffice365Conversations,
+ conversationMessages: NylasOffice365ConversationMessages,
+ },
+ telegram: {
+ customers: SmoochTelegramCustomers,
+ conversations: SmoochTelegramConversations,
+ conversationMessages: SmoochTelegramConversationMessages,
+ },
+ viber: {
+ customers: SmoochViberCustomers,
+ conversations: SmoochViberConversations,
+ conversationMessages: SmoochViberConversationMessages,
+ },
+ line: {
+ customers: SmoochLineCustomers,
+ conversations: SmoochLineConversations,
+ conversationMessages: SmoochLineConversationMessages,
+ },
+ twilio: {
+ customers: SmoochTwilioCustomers,
+ conversations: SmoochTwilioConversations,
+ conversationMessages: SmoochTwilioConversationMessages,
+ },
+ whatsapp: {
+ customers: WhatsAppCustomers,
+ conversations: WhatsAppConversations,
+ conversationMessages: WhatsAppConversationMessages,
+ },
+ twitter: {
+ customers: TwitterCustomers,
+ conversations: TwitterConversations,
+ conversationMessages: TwitterConversationMessages,
+ },
+ 'facebook-messenger': {
+ customers: FacebookMessengerCustomers,
+ conversations: FacebookMessengerConversations,
+ conversationMessages: FacebookMessengerConversationMessages,
+ },
+ 'facebook-post': {
+ posts: Posts,
+ comments: Comments,
+ },
+};