Skip to content

Commit e12d402

Browse files
authored
Fix slack interactions by normalising emoji text (#1600)
Fixes OPS-2996. ## Additional Notes Button text is being normalised by Slack in the response payload and this lead to the conflict to resume the flow. Now we match the normalised text response from slack with the normalised original action text and then we return the original text in the updated message. For multi select, we are already sending the userSelection.value which slack doesn't normalise and need not be fixed. ## For future reference - I've first added emoji: false prop to SlackText and although this fixes the bug, Slack wouldn't render emojis in the UI when user uses emoji in colon notation like ":emoji:" - I've then tried normalisation in request action and then compare it with original action in wait for interaction and then send the emojified string back to the user. - We've decided to send back the original text (either emoji or text notation) to the user. - So I've moved the normalisation to wait for interaction module and return the original action to the user. For multi - select (Arrays), we already return the value prop which slack doesn't normalise. - As as alternate fix, I've tried #1615, but this would require user to add value prop for actions when using send message action. So we ignore this method although it would've been the cleanest approach.
1 parent 5370bb6 commit e12d402

9 files changed

Lines changed: 675 additions & 13 deletions

File tree

THIRD_PARTY_LICENSES.txt

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8011,6 +8011,37 @@ This software is provided by the copyright holders and contributors “as is”
80118011

80128012
-----------
80138013

8014+
The following npm package may be included in this product:
8015+
8016+
- node-emoji@2.2.0
8017+
8018+
This package contains the following license:
8019+
8020+
# MIT License
8021+
8022+
Copyright (c) 2014-2023 Daniel Bugl
8023+
8024+
Permission is hereby granted, free of charge, to any person obtaining
8025+
a copy of this software and associated documentation files (the
8026+
'Software'), to deal in the Software without restriction, including
8027+
without limitation the rights to use, copy, modify, merge, publish,
8028+
distribute, sublicense, and/or sell copies of the Software, and to
8029+
permit persons to whom the Software is furnished to do so, subject to
8030+
the following conditions:
8031+
8032+
The above copyright notice and this permission notice shall be
8033+
included in all copies or substantial portions of the Software.
8034+
8035+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
8036+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
8037+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
8038+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
8039+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
8040+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
8041+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8042+
8043+
-----------
8044+
80148045
The following npm packages may be included in this product:
80158046

80168047
- webidl-conversions@3.0.1
@@ -16716,6 +16747,7 @@ The following npm packages may be included in this product:
1671616747
- punycode@1.4.1
1671716748
- punycode@2.3.1
1671816749
- uc.micro@2.1.0
16750+
- unicode-emoji-modifier-base@1.0.0
1671916751

1672016752
These packages each contain the following license:
1672116753

@@ -25618,6 +25650,7 @@ SOFTWARE.
2561825650

2561925651
The following npm packages may be included in this product:
2562025652

25653+
- @sindresorhus/is@4.6.0
2562125654
- ansi-regex@6.0.1
2562225655
- ansi-styles@6.2.1
2562325656
- chalk@5.3.0
@@ -25757,6 +25790,7 @@ The following npm packages may be included in this product:
2575725790
- restore-cursor@3.1.0
2575825791
- screenfull@5.2.0
2575925792
- shebang-regex@3.0.0
25793+
- skin-tone@2.0.0
2576025794
- string-width@4.2.3
2576125795
- strip-ansi@6.0.1
2576225796
- supports-color@5.5.0
@@ -26044,6 +26078,36 @@ OTHER DEALINGS IN THE SOFTWARE.
2604426078

2604526079
-----------
2604626080

26081+
The following npm package may be included in this product:
26082+
26083+
- char-regex@1.0.2
26084+
26085+
This package contains the following license:
26086+
26087+
MIT License
26088+
26089+
Copyright (c) 2019 Richie Bendall
26090+
26091+
Permission is hereby granted, free of charge, to any person obtaining a copy
26092+
of this software and associated documentation files (the "Software"), to deal
26093+
in the Software without restriction, including without limitation the rights
26094+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26095+
copies of the Software, and to permit persons to whom the Software is
26096+
furnished to do so, subject to the following conditions:
26097+
26098+
The above copyright notice and this permission notice shall be included in all
26099+
copies or substantial portions of the Software.
26100+
26101+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26102+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26103+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26104+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26105+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26106+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26107+
SOFTWARE.
26108+
26109+
-----------
26110+
2604726111
The following npm packages may be included in this product:
2604826112

2604926113
- @selderee/plugin-htmlparser2@0.11.0
@@ -28574,6 +28638,36 @@ SOFTWARE.
2857428638

2857528639
-----------
2857628640

28641+
The following npm package may be included in this product:
28642+
28643+
- emojilib@2.4.0
28644+
28645+
This package contains the following license:
28646+
28647+
The MIT License (MIT)
28648+
28649+
Copyright (c) 2014 Mu-An Chiou
28650+
28651+
Permission is hereby granted, free of charge, to any person obtaining a copy
28652+
of this software and associated documentation files (the "Software"), to deal
28653+
in the Software without restriction, including without limitation the rights
28654+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28655+
copies of the Software, and to permit persons to whom the Software is
28656+
furnished to do so, subject to the following conditions:
28657+
28658+
The above copyright notice and this permission notice shall be included in all
28659+
copies or substantial portions of the Software.
28660+
28661+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28662+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28663+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28664+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28665+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28666+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28667+
SOFTWARE.
28668+
28669+
-----------
28670+
2857728671
The following npm package may be included in this product:
2857828672

2857928673
- object-hash@3.0.0

package-lock.json

Lines changed: 55 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@
235235
"msgpackr": "1.11.5",
236236
"nanoid": "3.3.8",
237237
"node-cron": "3.0.3",
238+
"node-emoji": "2.2.0",
238239
"nodemailer": "6.9.9",
239240
"npm": "10.8.2",
240241
"nx-cloud": "19.1.0",

packages/blocks/slack/jest.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ export default {
66
transform: {
77
'^.+\\.ts$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
88
},
9-
moduleFileExtensions: ['ts', 'js', 'html'],
9+
moduleFileExtensions: ['ts', 'js', 'html', 'json'],
1010
coverageDirectory: '../../../coverage/packages/blocks/slack',
1111
};

packages/blocks/slack/src/lib/common/utils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
import { Property, WorkflowFile } from '@openops/blocks-framework';
99
import { logger } from '@openops/server-shared';
1010
import { isEmpty } from '@openops/shared';
11+
import * as emoji from 'node-emoji';
1112
import { MessageInfo } from './message-result';
1213

1314
export const slackSendMessage = async ({
@@ -450,3 +451,7 @@ export function createMessageBlocksWithActions(
450451
},
451452
];
452453
}
454+
455+
export function normalizeEmojiString(str: string): string {
456+
return emoji.unemojify(str);
457+
}

packages/blocks/slack/src/lib/common/wait-for-interaction.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
UserSelection,
1313
} from './message-interactions';
1414
import { MessageInfo } from './message-result';
15-
import { slackUpdateMessage } from './utils';
15+
import { normalizeEmojiString, slackUpdateMessage } from './utils';
1616

1717
export interface WaitForInteractionResult {
1818
user: string;
@@ -77,9 +77,17 @@ export async function onReceivedInteraction(
7777

7878
const userSelection = JSON.parse(resumePayload.actionClicked);
7979

80-
const isResumeForActionOnThisMessage =
81-
actions.includes(resumePayload.actionType) ||
82-
actions.includes((userSelection as UserSelection)?.value);
80+
const targetValues = new Set(
81+
[resumePayload.actionType, (userSelection as UserSelection)?.value].filter(
82+
Boolean,
83+
),
84+
);
85+
86+
const matchedOriginalAction = actions.find((original) =>
87+
targetValues.has(normalizeEmojiString(original)),
88+
);
89+
90+
const isResumeForActionOnThisMessage = Boolean(matchedOriginalAction);
8391

8492
const isResumeForThisMessage =
8593
resumePayload.path === currentExecutionPath &&
@@ -119,7 +127,7 @@ export async function onReceivedInteraction(
119127
user: resumePayload.userName,
120128
action: Array.isArray(userSelection)
121129
? userSelection.map((opt) => opt.value)
122-
: userSelection.value,
130+
: matchedOriginalAction || '',
123131
message: updatedMessage,
124132
userSelection,
125133
isExpired: false,

packages/blocks/slack/test/wait-for-action.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
const pauseMock = jest.fn();
22
const slackUpdateMessageMock = jest.fn();
3-
jest.mock('../src/lib/common/utils', () => {
4-
return {
5-
slackUpdateMessage: slackUpdateMessageMock,
6-
};
7-
});
3+
jest.mock('../src/lib/common/utils', () => ({
4+
...jest.requireActual('../src/lib/common/utils'),
5+
slackUpdateMessage: slackUpdateMessageMock,
6+
}));
87

98
import { StoreScope } from '@openops/blocks-framework';
109
import { ExecutionType } from '@openops/shared';

0 commit comments

Comments
 (0)