Skip to content

Commit 062b740

Browse files
Update: [AEA-6262] - Less Strict Feedback Formatting (#392)
## Summary Less strict Feedback requirement when providing feedback message in Slack ### Details **What this pattern matches:** - The word "feedback" must appear: It specifically looks for that exact sequence of letters. - Surrounded by symbols: It allows up to 10 non-alphanumeric characters (like !, @, #, $, or *) before and after the word. - Surrounded by underscores: It explicitly includes underscores, which are often used for formatting. - Surrounded by whitespace: It allows spaces, tabs, or newlines to sit between the word and the start of the string. **Real-world examples of what it allows:** - Bold or Italic styles: **feedback** or __feedback__ - Stylized headers: ### feedback - Common symbols: [feedback], {feedback}, or !feedback! - Spaced out headers: feedback - Bullet points: * feedback - Html Encoded: &#42;feedback&#42; <img width="621" height="871" alt="image" src="https://github.com/user-attachments/assets/9ae352a8-fd3f-40f7-8287-b83fac984adb" />
1 parent 9348d99 commit 062b740

File tree

3 files changed

+168
-2
lines changed

3 files changed

+168
-2
lines changed

packages/slackBotFunction/app/core/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class Constants:
119119

120120

121121
constants = Constants(
122-
FEEDBACK_PREFIX="feedback:",
122+
FEEDBACK_PREFIX=r"^[\W\s_]{0,10}(feedback)[\W\s_]{0,10}",
123123
CONTEXT_TYPE_DM="DM",
124124
CONTEXT_TYPE_THREAD="thread",
125125
CHANNEL_TYPE_IM="im",

packages/slackBotFunction/app/slack/slack_events.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import time
88
import traceback
99
import json
10+
import html
1011
from datetime import datetime
1112
from concurrent.futures import ThreadPoolExecutor
1213
from typing import Any, Dict
@@ -413,7 +414,9 @@ def process_async_slack_event(event: Dict[str, Any], event_id: str, client: WebC
413414
logger.error(f"Can not find pull request details: {e}", extra={"error": traceback.format_exc()})
414415
post_error_message(channel=channel_id, thread_ts=thread_ts, client=client)
415416
return
416-
if message_text.lower().startswith(constants.FEEDBACK_PREFIX):
417+
# Unescape HTML entities to handle cases where Slack formats the message with entities (e.g., &lt; instead of <)
418+
feedback_formatted_text = html.unescape(message_text)
419+
if re.match(constants.FEEDBACK_PREFIX, feedback_formatted_text, re.IGNORECASE | re.DOTALL | re.MULTILINE):
417420
process_feedback_event(
418421
message_text=message_text,
419422
conversation_key=conversation_key,
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
"""
2+
Unit tests for the feedback regex pattern.
3+
Tests validate the FEEDBACK_PREFIX regex against various input formats.
4+
"""
5+
6+
import html
7+
import re
8+
import pytest
9+
from app.core.config import constants
10+
11+
12+
class TestFeedbackRegex:
13+
"""Test suite for the FEEDBACK_PREFIX regex pattern"""
14+
15+
def isMatch(self, pattern, text):
16+
"""Helper method to check if the pattern matches the text"""
17+
formatted_text = html.unescape(text)
18+
return re.match(pattern, formatted_text, re.IGNORECASE | re.DOTALL | re.MULTILINE) is not None
19+
20+
@pytest.fixture
21+
def feedback_pattern(self):
22+
"""Fixture providing the feedback regex pattern"""
23+
return constants.FEEDBACK_PREFIX
24+
25+
def test_simple_feedback_with_colon(self, feedback_pattern):
26+
"""Test simple 'feedback:' format with text after colon"""
27+
text = "feedback: um dolor sit amet, consectetur adipiscing elit"
28+
assert self.isMatch(feedback_pattern, text)
29+
30+
def test_feedback_with_hyphen(self, feedback_pattern):
31+
"""Test 'feedback -' format with text after hyphen"""
32+
text = "feedback - um dolor sit amet, consectetur adipiscing elit"
33+
assert self.isMatch(feedback_pattern, text)
34+
35+
def test_feedback_no_space_colon(self, feedback_pattern):
36+
"""Test 'feedback:' with no space after colon"""
37+
text = "feedback:um dolor sit amet, consectetur adipiscing elit"
38+
assert self.isMatch(feedback_pattern, text)
39+
40+
def test_feedback_multiple_colons(self, feedback_pattern):
41+
"""Test 'feedback::' with double colon"""
42+
text = "feedback::um dolor sit amet, consectetur adipiscing elit"
43+
assert self.isMatch(feedback_pattern, text)
44+
45+
def test_feedback_newline_before_text(self, feedback_pattern):
46+
"""Test 'feedback' with newline before text"""
47+
text = "feedback \n- um dolor sit amet, consectetur adipiscing elit"
48+
assert self.isMatch(feedback_pattern, text)
49+
50+
def test_feedback_parentheses(self, feedback_pattern):
51+
"""Test '(FeedBack)' format with parentheses"""
52+
text = "(FeedBack) um dolor sit amet, consectetur adipiscing elit"
53+
assert self.isMatch(feedback_pattern, text)
54+
55+
def test_feedback_parentheses_encoded(self, feedback_pattern):
56+
"""Test '&#40;FeedBack&#41;' format with encoded parentheses"""
57+
text = "&#40;FeedBack&#41; um dolor sit amet, consectetur adipiscing elit"
58+
assert self.isMatch(feedback_pattern, text)
59+
60+
def test_feedback_brackets(self, feedback_pattern):
61+
"""Test '[feedback]:' format with brackets"""
62+
text = "[feedback]: um dolor sit amet, consectetur adipiscing elit"
63+
assert self.isMatch(feedback_pattern, text)
64+
65+
def test_feedback_brackets_encoded(self, feedback_pattern):
66+
"""Test '&#91;feedback&#93;:' format with encoded brackets"""
67+
text = "&#91;feedback&#93;: um dolor sit amet, consectetur adipiscing elit"
68+
assert self.isMatch(feedback_pattern, text)
69+
70+
def test_feedback_angle_brackets(self, feedback_pattern):
71+
"""Test '<feedback> -' format with angle brackets"""
72+
text = "<feedback> - um dolor sit amet, consectetur adipiscing elit"
73+
assert self.isMatch(feedback_pattern, text)
74+
75+
def test_feedback_angle_brackets_encoded(self, feedback_pattern):
76+
"""Test '&lt;feedback> -' format with angle brackets"""
77+
text = "&lt;feedback&gt; - um dolor sit amet, consectetur adipiscing elit"
78+
assert self.isMatch(feedback_pattern, text)
79+
80+
def test_feedback_bold(self, feedback_pattern):
81+
"""Test '**feedback** -' format with bold text"""
82+
text = "**feedback** - um dolor sit amet, consectetur adipiscing elit"
83+
assert self.isMatch(feedback_pattern, text)
84+
85+
def test_feedback_bold_encoded(self, feedback_pattern):
86+
"""Test '&#42;&#42;feedback&#42;&#42; -' format with encoded bold text"""
87+
text = "&#42;&#42;feedback&#42;&#42; - um dolor sit amet, consectetur adipiscing elit"
88+
assert self.isMatch(feedback_pattern, text)
89+
90+
def test_feedback_underscore(self, feedback_pattern):
91+
"""Test '_feedback_' format with underscores"""
92+
text = "_feedback_ - um dolor sit amet, consectetur adipiscing elit"
93+
assert self.isMatch(feedback_pattern, text)
94+
95+
def test_feedback_underscore_encoded(self, feedback_pattern):
96+
"""Test '&#95;feedback&#95;' format with encoded underscores"""
97+
text = "&#95;feedback&#95; - um dolor sit amet, consectetur adipiscing elit"
98+
assert self.isMatch(feedback_pattern, text)
99+
100+
def test_feedback_italic(self, feedback_pattern):
101+
"""Test '*feedback*' format with italics"""
102+
text = "*feedback* - um dolor sit amet, consectetur adipiscing elit"
103+
assert self.isMatch(feedback_pattern, text)
104+
105+
def test_feedback_italic_encoded(self, feedback_pattern):
106+
"""Test '&#42;feedback&#42;' format with encoded italics"""
107+
text = "&#42;feedback&#42; - um dolor sit amet, consectetur adipiscing elit"
108+
assert self.isMatch(feedback_pattern, text)
109+
110+
def test_feedback_case_insensitive_uppercase(self, feedback_pattern):
111+
"""Test case insensitivity with uppercase FEEDBACK"""
112+
text = "FEEDBACK: test feedback message"
113+
assert self.isMatch(feedback_pattern, text)
114+
115+
def test_feedback_case_insensitive_mixed(self, feedback_pattern):
116+
"""Test case insensitivity with mixed case FeedBack"""
117+
text = "FeedBack: test feedback message"
118+
assert self.isMatch(feedback_pattern, text)
119+
120+
def test_feedback_with_leading_spaces(self, feedback_pattern):
121+
"""Test feedback with leading spaces before the keyword"""
122+
text = " feedback: test message"
123+
assert self.isMatch(feedback_pattern, text)
124+
125+
def test_not_feedback_wrong_keyword(self, feedback_pattern):
126+
"""Test that non-feedback keywords don't match"""
127+
text = "question: what is the answer"
128+
assert not self.isMatch(feedback_pattern, text)
129+
130+
def test_not_feedback_partial_match(self, feedback_pattern):
131+
"""Test that partial feedback keyword doesn't match at start"""
132+
text = "my feedback on this"
133+
assert not self.isMatch(feedback_pattern, text)
134+
135+
def test_feedback_empty_text_after(self, feedback_pattern):
136+
"""Test feedback with no text after the delimiter"""
137+
text = "feedback:"
138+
assert self.isMatch(feedback_pattern, text)
139+
140+
def test_feedback_only_whitespace_after(self, feedback_pattern):
141+
"""Test feedback with only whitespace after"""
142+
text = "feedback: "
143+
assert self.isMatch(feedback_pattern, text)
144+
145+
def test_feedback_with_emoji(self, feedback_pattern):
146+
"""Test feedback with emoji delimiter"""
147+
text = "feedback: 👍 test"
148+
assert self.isMatch(feedback_pattern, text)
149+
150+
def test_feedback_tab_delimiter(self, feedback_pattern):
151+
"""Test feedback with tab as delimiter"""
152+
text = "feedback\ttest message"
153+
assert self.isMatch(feedback_pattern, text)
154+
155+
def test_feedback_with_many_leading_spaces(self, feedback_pattern):
156+
"""Test feedback with maximum allowed leading spaces (up to 10)"""
157+
text = " feedback: test message" # 10 spaces
158+
assert self.isMatch(feedback_pattern, text)
159+
160+
def test_feedback_with_many_trailing_spaces(self, feedback_pattern):
161+
"""Test feedback with spaces after the keyword"""
162+
text = "feedback : test message"
163+
assert self.isMatch(feedback_pattern, text)

0 commit comments

Comments
 (0)