Skip to content

Commit

Permalink
Merge branch 'main' into crowd-linux
Browse files Browse the repository at this point in the history
  • Loading branch information
gaspergrom committed Sep 15, 2023
2 parents b110d54 + f09901f commit eae857f
Show file tree
Hide file tree
Showing 28 changed files with 430 additions and 264 deletions.
2 changes: 1 addition & 1 deletion backend/src/bin/jobs/memberScoreCoordinator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { PythonWorkerMessageType } from '../../serverless/types/workerTypes'

const job: CrowdJob = {
name: 'Member Score Coordinator',
cronTime: cronGenerator.every(20).minutes(),
cronTime: cronGenerator.every(90).minutes(),
onTrigger: async () => {
await sendPythonWorkerMessage('global', {
type: PythonWorkerMessageType.MEMBERS_SCORE,
Expand Down
24 changes: 21 additions & 3 deletions backend/src/bin/nodejs-worker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Logger, getChildLogger, getServiceLogger } from '@crowd/logging'
import { Logger, getChildLogger, getServiceLogger, logExecutionTimeV2 } from '@crowd/logging'
import { DeleteMessageRequest, Message, ReceiveMessageRequest } from 'aws-sdk/clients/sqs'
import moment from 'moment'
import { timeout } from '@crowd/common'
Expand Down Expand Up @@ -119,7 +119,19 @@ async function handleMessages() {
})

try {
messageLogger.debug('Received a new queue message!')
if (
msg.type === NodeWorkerMessageType.DB_OPERATIONS &&
(msg as any).operation === 'update_members'
) {
messageLogger.warn('Skipping update_members message! TEMPORARY MEASURE!')
await removeFromQueue(message.ReceiptHandle)
return
}

messageLogger.info(
{ messageType: msg.type, messagePayload: JSON.stringify(msg) },
'Received a new queue message!',
)

let processFunction: (msg: NodeWorkerMessageBase, logger?: Logger) => Promise<void>
let keep = false
Expand Down Expand Up @@ -152,7 +164,13 @@ async function handleMessages() {
await removeFromQueue(message.ReceiptHandle)
messagesInProgress.set(message.MessageId, msg)
try {
await processFunction(msg, messageLogger)
await logExecutionTimeV2(
async () => {
await processFunction(msg, messageLogger)
},
messageLogger,
'queueMessageProcessingTime',
)
} catch (err) {
messageLogger.error(err, 'Error while processing queue message!')
} finally {
Expand Down
4 changes: 2 additions & 2 deletions backend/src/cubejs/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
FROM cubejs/cube:v0.32.16
FROM cubejs/cube:v0.33.55

COPY ./ /cube/conf/
COPY ./ /cube/conf/
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
drop index if exists "ix_segmentActivityChannels_segmentId_platform";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
create index if not exists "ix_segmentActivityChannels_segmentId_platform" on "segmentActivityChannels" ("segmentId", platform);
10 changes: 4 additions & 6 deletions backend/src/database/repositories/organizationRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1152,21 +1152,19 @@ class OrganizationRepository {
const query = `
with leaf_segment_ids as (${segmentsSubQuery}),
member_data as (select a."organizationId",
count(distinct m.id) filter ( where mo."dateEnd" is null ) as "memberCount",
count(distinct a."memberId") as "memberCount",
count(distinct a.id) as "activityCount",
case
when array_agg(distinct a.platform) = array [null] then array []::text[]
else array_agg(distinct a.platform) end as "activeOn",
max(a.timestamp) as "lastActive",
min(a.timestamp) filter ( where a.timestamp <> '1970-01-01T00:00:00.000Z' ) as "joinedAt"
from leaf_segment_ids ls
left join activities a
join activities a
on a."segmentId" = ls.id and a."organizationId" = :id and
a."deletedAt" is null
left join members m on a."memberId" = m.id and m."deletedAt" is null
left join "memberOrganizations" mo
on m.id = mo."memberId" and mo."organizationId" = :id
left join "memberIdentities" mi on m.id = mi."memberId"
join members m on a."memberId" = m.id and m."deletedAt" is null
join "memberOrganizations" mo on m.id = mo."memberId" and mo."organizationId" = :id and mo."dateEnd" is null
group by a."organizationId"),
organization_segments as (select "organizationId", array_agg("segmentId") as "segments"
from "organizationSegments"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import htmlToMrkdwn from 'html-to-mrkdwn-ts'
import { integrationLabel } from '@crowd/types'
import { integrationLabel, integrationProfileUrl } from '@crowd/types'
import { API_CONFIG } from '../../../../../../conf'

const defaultAvatarUrl =
'https://uploads-ssl.webflow.com/635150609746eee5c60c4aac/6502afc9d75946873c1efa93_image%20(292).png'

const computeEngagementLevel = (score) => {
if (score <= 1) {
return 'Silent'
Expand Down Expand Up @@ -47,45 +50,61 @@ const truncateText = (text: string, characters: number = 60): string => {
}

export const newActivityBlocks = (activity) => {
const display = htmlToMrkdwn(replaceHeadline(`${activity.display.default}`))
const display = htmlToMrkdwn(replaceHeadline(activity.display.default))
const reach = activity.member.reach?.[activity.platform] || activity.member.reach?.total

const { member } = activity
const memberProperties = []
if (activity.member.attributes.jobTitle?.default) {
memberProperties.push(activity.member.attributes.jobTitle?.default)
if (member.attributes.jobTitle?.default) {
memberProperties.push(`*💼 Job title:* ${member.attributes.jobTitle?.default}`)
}
if (member.organizations.length > 0) {
const orgs = member.organizations.map(
(org) =>
`<${`${API_CONFIG.frontendUrl}/organizations/${org.id}`}|${org.name || org.displayName}>`,
)
memberProperties.push(`*🏢 Organization:* ${orgs.join(' | ')}`)
}
if (reach > 0) {
memberProperties.push(`${reach} followers`)
memberProperties.push(`*👥 Reach:* ${reach} followers`)
}
if (member.attributes?.location?.default) {
memberProperties.push(`*📍 Location:* ${member.attributes?.location?.default}`)
}
if (member.emails.length > 0) {
const [email] = member.emails
memberProperties.push(`*✉️ Email:* <mailto:${email}|${email}>`)
}
const engagementLevel = computeEngagementLevel(activity.member.score || activity.engagement)
if (engagementLevel.length > 0) {
memberProperties.push(`*Engagement level:* ${engagementLevel}`)
memberProperties.push(`*📊 Engagement level:* ${engagementLevel}`)
}
if (activity.member.activeOn) {
const platforms = activity.member.activeOn
.map((platform) => integrationLabel[platform] || platform)
.join(' | ')
memberProperties.push(`*Active on:* ${platforms}`)
memberProperties.push(`*💬 Active on:* ${platforms}`)
}

const profiles = Object.keys(member.username)
.map((p) => {
const username = (member.username?.[p] || []).length > 0 ? member.username[p][0] : null
const url =
member.attributes?.url?.[p] || (username && integrationProfileUrl[p](username)) || null
return {
platform: p,
url,
}
})
.filter((p) => !!p.url)

return {
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: ':satellite_antenna: *New activity*',
},
},
{
type: 'divider',
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*<${API_CONFIG.frontendUrl}/members/${activity.member.id}|${
activity.member.displayName
}>* \n *${truncateText(display.text)}*`,
text: `*<${API_CONFIG.frontendUrl}/members/${activity.member.id}|${activity.member.displayName}>* *${display.text}*`,
},
...(activity.url
? {
Expand All @@ -105,37 +124,72 @@ export const newActivityBlocks = (activity) => {
}
: {}),
},
...(activity.title || activity.body
? [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `>${
activity.title && activity.title !== activity.display.default
? `*${truncateText(htmlToMrkdwn(activity.title).text, 120).replaceAll(
'\n',
'\n>',
)}* \n>`
: ''
}${truncateText(htmlToMrkdwn(activity.body).text, 260).replaceAll('\n', '\n>')}`,
},
},
]
: []),
...(memberProperties.length > 0
? [
{
type: 'divider',
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: memberProperties.join('\n'),
},
accessory: {
type: 'image',
image_url: member.attributes?.avatarUrl?.default ?? defaultAvatarUrl,
alt_text: 'computer thumbnail',
},
},
]
: []),
{
type: 'context',
type: 'actions',
elements: [
{
type: 'mrkdwn',
text: memberProperties.join(' • '),
type: 'button',
text: {
type: 'plain_text',
text: 'View in crowd.dev',
emoji: true,
},
url: `${API_CONFIG.frontendUrl}/members/${member.id}`,
},
...(profiles.length > 0
? [
{
type: 'overflow',
options: profiles.map(({ platform, url }) => ({
text: {
type: 'plain_text',
text: `${integrationLabel[platform] ?? platform} profile`,
emoji: true,
},
url,
})),
},
]
: []),
],
},
],
...(activity.title || activity.body
? {
attachments: [
{
color: '#eeeeee',
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `${
activity.title && activity.title !== activity.display.default
? `*${htmlToMrkdwn(activity.title).text}* \n `
: ''
}${htmlToMrkdwn(activity.body).text}`,
},
},
],
},
],
}
: {}),
}
}
Loading

0 comments on commit eae857f

Please sign in to comment.