Skip to content

Commit 8c2a0da

Browse files
authored
Merge pull request #2942 from objectcomputing/bugfix-2933/fix-kudos-urls-and-channels
Converted Slack message links to external links
2 parents 7cecfb9 + 4be32c9 commit 8c2a0da

File tree

2 files changed

+87
-22
lines changed

2 files changed

+87
-22
lines changed

server/src/main/java/com/objectcomputing/checkins/services/slack/kudos/SlackKudosCreator.java

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.micronaut.core.io.Readable;
1616
import io.micronaut.core.io.IOUtils;
1717

18+
import org.jetbrains.annotations.NotNull;
1819
import org.slf4j.Logger;
1920
import org.slf4j.LoggerFactory;
2021

@@ -97,27 +98,19 @@ private MemberProfile lookupUser(String userId) {
9798

9899
private String processText(String text, List<UUID> recipients) {
99100
// First, process user references.
100-
StringBuffer buffer = new StringBuffer(text.length());
101-
Pattern userRef = Pattern.compile("<@([^>]+)>");
102-
Matcher action = userRef.matcher(StringEscapeUtils.unescapeHtml4(text));
103-
while (action.find()) {
104-
// Pull out the recipient user id, get the profile and add it to
105-
// the list of recipients.
106-
String userId = action.group(1);
107-
MemberProfile profile = lookupUser(userId);
108-
recipients.add(profile.getId());
109-
110-
// Replace the user reference with their full name.
111-
action.appendReplacement(buffer, Matcher.quoteReplacement(
112-
MemberProfileUtils.getFullName(profile)));
113-
}
114-
action.appendTail(buffer);
115-
text = buffer.toString();
101+
text = populateRecipientNames(text, recipients);
116102

117103
// Next, translate channel references to channel names.
104+
text = populateChannelNames(text);
105+
106+
return text;
107+
}
108+
109+
@NotNull
110+
private String populateChannelNames(String text) {
118111
Pattern channelRef = Pattern.compile("<#([^>]+)\\|>");
119-
buffer = new StringBuffer(text.length());
120-
action = channelRef.matcher(text);
112+
StringBuffer buffer = new StringBuffer(text.length());
113+
Matcher action = channelRef.matcher(text);
121114
while (action.find()) {
122115
// Get the name of the channel.
123116
String channelId = action.group(1);
@@ -131,7 +124,29 @@ private String processText(String text, List<UUID> recipients) {
131124
action.appendReplacement(buffer, Matcher.quoteReplacement(name));
132125
}
133126
action.appendTail(buffer);
134-
return buffer.toString();
127+
text = buffer.toString();
128+
return text;
129+
}
130+
131+
@NotNull
132+
private String populateRecipientNames(String text, List<UUID> recipients) {
133+
StringBuffer buffer = new StringBuffer(text.length());
134+
Pattern userRef = Pattern.compile("<@([^>]+)>");
135+
Matcher action = userRef.matcher(StringEscapeUtils.unescapeHtml4(text));
136+
while (action.find()) {
137+
// Pull out the recipient user id, get the profile and add it to
138+
// the list of recipients.
139+
String userId = action.group(1);
140+
MemberProfile profile = lookupUser(userId);
141+
recipients.add(profile.getId());
142+
143+
// Replace the user reference with their full name.
144+
action.appendReplacement(buffer, Matcher.quoteReplacement(
145+
MemberProfileUtils.getFullName(profile)));
146+
}
147+
action.appendTail(buffer);
148+
text = buffer.toString();
149+
return text;
135150
}
136151

137152
private void requestAction() {

web-ui/src/components/kudos/PublicKudosCard.jsx

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,61 @@ const KudosCard = ({ kudos }) => {
124124
return names;
125125
};
126126

127-
const linkNames = kudos => {
127+
const linkSlackUrls = textLine => {
128+
// Regex to find <url> or <url|text>
129+
// Group 1: URL
130+
// Group 2: Optional Link Text (undefined if not present)
131+
const slackLinkRegex = /<([^<>|]*)(?:\|([^<>]*))?>/g;
132+
const components = [];
133+
let lastIndex = 0;
134+
let match;
135+
136+
// Find all matches in the text line
137+
while ((match = slackLinkRegex.exec(textLine)) !== null) {
138+
const url = match[1];
139+
const linkText = match[2]; // Will be undefined if there's no |text part
140+
const precedingText = textLine.slice(lastIndex, match.index);
141+
142+
// Add the text before the match (if any)
143+
if (precedingText) {
144+
components.push(precedingText);
145+
}
146+
147+
// Create and add the link component
148+
components.push(
149+
<a
150+
key={`slack-link-${match.index}`} // Unique key based on position
151+
href={url}
152+
target="_blank" // Open in new tab
153+
rel="noopener noreferrer" // Security measure
154+
>
155+
{linkText || url}
156+
</a>
157+
);
158+
159+
// Update the index for the next slice
160+
lastIndex = slackLinkRegex.lastIndex;
161+
}
162+
163+
// Add any remaining text after the last match
164+
const remainingText = textLine.slice(lastIndex);
165+
if (remainingText) {
166+
components.push(remainingText);
167+
}
168+
169+
// If no links were found at all, return the original line in an array
170+
if (components.length === 0) {
171+
return [textLine];
172+
}
173+
174+
return components;
175+
};
176+
177+
const createLinks = kudos => {
128178
const lines = [];
129179
let index = 0;
130180
for (let line of kudos.message.split('\n')) {
131-
const components = [line];
181+
const components = linkSlackUrls(line);
132182
for (let member of kudos.recipientMembers) {
133183
const names = searchNames(member, kudos.recipientMembers);
134184
for (let name of names) {
@@ -228,7 +278,7 @@ const KudosCard = ({ kudos }) => {
228278
subheaderTypographyProps={{ variant: 'subtitle1' }}
229279
/>
230280
<CardContent>
231-
<>{linkNames(kudos)}</>
281+
<>{createLinks(kudos)}</>
232282
{kudos.recipientTeam && (
233283
<AvatarGroup
234284
max={12}

0 commit comments

Comments
 (0)