@nodebb/nodebb-plugin-reactions 3.1.2 → 3.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/helpers.js +7 -5
- package/library.js +70 -17
- package/package-lock.json +1330 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/test/index.js +6 -13
package/helpers.js
CHANGED
|
@@ -46,10 +46,6 @@ function resolveByName(name) {
|
|
|
46
46
|
return null;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
/**
|
|
50
|
-
* Resolve FEP-c0e0 reaction content (unicode grapheme, `:shortcode:`, bare name,
|
|
51
|
-
* or a custom-emoji `tag`) to a local emoji name. Returns null when unresolvable.
|
|
52
|
-
*/
|
|
53
49
|
function resolveReaction(content, tag) {
|
|
54
50
|
if (typeof content !== 'string' || !content.trim()) {
|
|
55
51
|
return null;
|
|
@@ -90,7 +86,13 @@ function resolveReaction(content, tag) {
|
|
|
90
86
|
if (!reaction && Array.isArray(tag)) {
|
|
91
87
|
const emojiTag = tag.find(t => t && t.type === 'Emoji' && typeof t.name === 'string');
|
|
92
88
|
if (emojiTag) {
|
|
93
|
-
|
|
89
|
+
const name = emojiTag.name.replace(/^:|:$/g, '');
|
|
90
|
+
// Try to resolve as a local emoji first
|
|
91
|
+
reaction = resolveByName(name);
|
|
92
|
+
// If not local, return the tag so the caller can cache the custom emoji
|
|
93
|
+
if (!reaction) {
|
|
94
|
+
return { emoji: name, emojiTag };
|
|
95
|
+
}
|
|
94
96
|
}
|
|
95
97
|
}
|
|
96
98
|
|
package/library.js
CHANGED
|
@@ -30,6 +30,28 @@ function parse(name) {
|
|
|
30
30
|
return emoji ? emojiParser.buildEmoji(emoji, '') : '';
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
async function parseReaction(name, sourceUrl) {
|
|
34
|
+
const emoji = nameToEmoji(name) || helpers.getEmojiTable()[helpers.getEmojiAliases()[name]];
|
|
35
|
+
if (emoji) {
|
|
36
|
+
return emojiParser.buildEmoji(emoji, '');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (typeof sourceUrl === 'string') {
|
|
40
|
+
try {
|
|
41
|
+
const url = new URL(sourceUrl);
|
|
42
|
+
const hostname = url.hostname;
|
|
43
|
+
const metadata = await activitypub.emoji.getEmoji(name, hostname);
|
|
44
|
+
if (metadata) {
|
|
45
|
+
const proxyUrl = activitypub.emoji.getProxyUrl(name, hostname);
|
|
46
|
+
return `<img class="not-responsive emoji" src="${proxyUrl}" title=":${name}:" />`;
|
|
47
|
+
}
|
|
48
|
+
} catch (e) {
|
|
49
|
+
// Not a valid URL — skip custom emoji lookup
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return '';
|
|
53
|
+
}
|
|
54
|
+
|
|
33
55
|
const ReactionsPlugin = module.exports;
|
|
34
56
|
|
|
35
57
|
ReactionsPlugin.init = async function (params) {
|
|
@@ -150,7 +172,7 @@ ReactionsPlugin.getPostReactions = async function (data) {
|
|
|
150
172
|
for (const reaction of reactions) {
|
|
151
173
|
const reactionSet = `pid:${post.pid}:reaction:${reaction}`;
|
|
152
174
|
const uids = reactionSetToUsersMap.get(reactionSet);
|
|
153
|
-
const reactionImage =
|
|
175
|
+
const reactionImage = await parseReaction(reaction, post.pid);
|
|
154
176
|
if (Array.isArray(uids) && reactionImage) {
|
|
155
177
|
post.reactions.push({
|
|
156
178
|
pid: post.pid,
|
|
@@ -215,7 +237,7 @@ ReactionsPlugin.getMessageReactions = async function (data) {
|
|
|
215
237
|
for (const reaction of reactions) {
|
|
216
238
|
const reactionSet = `mid:${msg.mid}:reaction:${reaction}`;
|
|
217
239
|
const uids = reactionSetToUsersMap.get(reactionSet);
|
|
218
|
-
const reactionImage =
|
|
240
|
+
const reactionImage = await parseReaction(reaction, msg.mid);
|
|
219
241
|
if (Array.isArray(uids) && reactionImage) {
|
|
220
242
|
msg.reactions.push({
|
|
221
243
|
mid: msg.mid,
|
|
@@ -290,7 +312,7 @@ async function sendPostEvent(data, eventName) {
|
|
|
290
312
|
reaction: data.reaction,
|
|
291
313
|
reactionCount,
|
|
292
314
|
totalReactions,
|
|
293
|
-
reactionImage:
|
|
315
|
+
reactionImage: await parseReaction(data.reaction, data.pid),
|
|
294
316
|
});
|
|
295
317
|
} catch (e) {
|
|
296
318
|
console.error(e);
|
|
@@ -314,7 +336,7 @@ async function sendMessageEvent(data, eventName) {
|
|
|
314
336
|
reaction: data.reaction,
|
|
315
337
|
reactionCount,
|
|
316
338
|
totalReactions,
|
|
317
|
-
reactionImage:
|
|
339
|
+
reactionImage: await parseReaction(data.reaction, data.mid),
|
|
318
340
|
});
|
|
319
341
|
} catch (e) {
|
|
320
342
|
console.error(e);
|
|
@@ -501,13 +523,36 @@ ReactionsPlugin.applyEmojiReact = async function (activity) {
|
|
|
501
523
|
|
|
502
524
|
const id = await resolveReactionPost(object);
|
|
503
525
|
if (!id) {
|
|
504
|
-
return;
|
|
526
|
+
return false;
|
|
505
527
|
}
|
|
506
528
|
|
|
507
|
-
const
|
|
508
|
-
if (!
|
|
529
|
+
const resolved = helpers.resolveReaction(content, tag);
|
|
530
|
+
if (!resolved) {
|
|
509
531
|
activitypub.helpers.log(`[reactions/ap] Unresolvable reaction content (${JSON.stringify(content)}), ignoring.`);
|
|
510
|
-
return;
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
let reaction;
|
|
536
|
+
let emojiTag;
|
|
537
|
+
if (typeof resolved === 'object' && resolved.emoji) {
|
|
538
|
+
reaction = resolved.emoji;
|
|
539
|
+
emojiTag = resolved.emojiTag;
|
|
540
|
+
} else {
|
|
541
|
+
reaction = resolved;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (emojiTag) {
|
|
545
|
+
const cacheTag = { name: emojiTag.name };
|
|
546
|
+
if (emojiTag.icon && emojiTag.icon.url) {
|
|
547
|
+
cacheTag.icon = emojiTag.icon;
|
|
548
|
+
} else if (emojiTag.id) {
|
|
549
|
+
cacheTag.icon = { url: emojiTag.id, mediaType: emojiTag.mediaType || null };
|
|
550
|
+
} else {
|
|
551
|
+
cacheTag = null;
|
|
552
|
+
}
|
|
553
|
+
if (cacheTag) {
|
|
554
|
+
await activitypub.emoji.cacheEmoji(cacheTag);
|
|
555
|
+
}
|
|
511
556
|
}
|
|
512
557
|
|
|
513
558
|
const allowed = await privileges.posts.can('posts:upvote', id, activitypub._constants.uid);
|
|
@@ -519,6 +564,7 @@ ReactionsPlugin.applyEmojiReact = async function (activity) {
|
|
|
519
564
|
activitypub.helpers.log(`[reactions/ap] id ${id} (${reaction}) via ${actor}`);
|
|
520
565
|
await ReactionsPlugin.addPostReaction(id, actor, reaction);
|
|
521
566
|
await activitypub.feps.announce(object.id, activity);
|
|
567
|
+
return true;
|
|
522
568
|
};
|
|
523
569
|
|
|
524
570
|
ReactionsPlugin.undoEmojiReact = async function (activity) {
|
|
@@ -526,19 +572,22 @@ ReactionsPlugin.undoEmojiReact = async function (activity) {
|
|
|
526
572
|
|
|
527
573
|
const id = await resolveReactionPost(object);
|
|
528
574
|
if (!id) {
|
|
529
|
-
return;
|
|
575
|
+
return false;
|
|
530
576
|
}
|
|
531
577
|
|
|
532
|
-
const
|
|
533
|
-
if (!
|
|
578
|
+
const resolved = helpers.resolveReaction(content, tag);
|
|
579
|
+
if (!resolved) {
|
|
534
580
|
activitypub.helpers.log(`[reactions/ap] Unresolvable reaction content in undo, ignoring.`);
|
|
535
|
-
return;
|
|
581
|
+
return false;
|
|
536
582
|
}
|
|
537
583
|
|
|
584
|
+
const reaction = typeof resolved === 'object' ? resolved.emoji : resolved;
|
|
585
|
+
|
|
538
586
|
activitypub.helpers.log(`[reactions/ap] undo id ${id} (${reaction}) via ${actor}`);
|
|
539
587
|
await ReactionsPlugin.removePostReaction(id, actor, reaction);
|
|
540
588
|
await ReactionsPlugin.rescindPostReaction(id, actor, reaction);
|
|
541
589
|
await activitypub.feps.announce(object.id, activity);
|
|
590
|
+
return true;
|
|
542
591
|
};
|
|
543
592
|
|
|
544
593
|
ReactionsPlugin.handleEmojiReact = async function (context) {
|
|
@@ -547,10 +596,11 @@ ReactionsPlugin.handleEmojiReact = async function (context) {
|
|
|
547
596
|
};
|
|
548
597
|
|
|
549
598
|
ReactionsPlugin.handleLike = async function (context) {
|
|
550
|
-
// FEP-c0e0: a Like with content is an emoji reaction; a plain Like falls through to core
|
|
551
599
|
if (typeof context.activity.content === 'string' && context.activity.content.trim()) {
|
|
552
|
-
await ReactionsPlugin.applyEmojiReact(context.activity);
|
|
553
|
-
|
|
600
|
+
const applied = await ReactionsPlugin.applyEmojiReact(context.activity);
|
|
601
|
+
if (applied) {
|
|
602
|
+
return { ...context, claimed: true };
|
|
603
|
+
}
|
|
554
604
|
}
|
|
555
605
|
return context;
|
|
556
606
|
};
|
|
@@ -615,8 +665,11 @@ ReactionsPlugin.handleAnnounce = async function (context) {
|
|
|
615
665
|
}
|
|
616
666
|
}
|
|
617
667
|
|
|
618
|
-
await ReactionsPlugin.applyEmojiReact(object);
|
|
619
|
-
|
|
668
|
+
const applied = await ReactionsPlugin.applyEmojiReact(object);
|
|
669
|
+
if (applied) {
|
|
670
|
+
return { ...context, claimed: true };
|
|
671
|
+
}
|
|
672
|
+
return context;
|
|
620
673
|
};
|
|
621
674
|
|
|
622
675
|
SocketPlugins.reactions = {
|