diff --git a/lib/account.js b/lib/account.js
index 3a4c6f5..1e4b526 100644
--- a/lib/account.js
+++ b/lib/account.js
@@ -30,7 +30,8 @@ import {
import {
getActivity,
createActivity,
- deleteActivity
+ deleteActivity,
+ getHashtagsFromNote
} from './notes.js';
import debug from 'debug';
@@ -484,8 +485,24 @@ export const createNote = async (body, cw, inReplyTo, toUser, editOf) => {
}
}
+ // if it contains hashtags, add them
+ let hashtags = body.match(/#[a-z]+/gi)
+ if (hashtags) {
+ hashtags.forEach((tag) => {
+ tags.push({
+ "type": "Hashtag",
+ "href": `https://${ DOMAIN }/tags/${tag}`,
+ "name": tag
+ });
+ });
+ }
+
+ const mdContent = md.render(processedContent);
+
+ // rewrite links to tags in content
+ let content = mdContent.replace(/#([a-z]+)/gi, '#$1');
- const content = md.render(processedContent);
+ content = '' + content + '';
const activityId = `https://${ DOMAIN }/m/${guid}`;
const url = `https://${ DOMAIN }/notes/${guid}`;
@@ -538,6 +555,7 @@ export const createNote = async (body, cw, inReplyTo, toUser, editOf) => {
actor: object.attributedTo,
published: new Date(object.published).getTime(),
inReplyTo: object.inReplyTo,
+ hashtags: getHashtagsFromNote(object),
});
}
}
diff --git a/lib/notes.js b/lib/notes.js
index c422fe0..1a00261 100644
--- a/lib/notes.js
+++ b/lib/notes.js
@@ -287,3 +287,7 @@ export const getActivitySince = async (since, excludeSelf = false) => {
activitystream: res,
}
}
+
+export const getHashtagsFromNote = (note) => {
+ return (note.tag && note.tag.length > 0) ? note.tag.filter((t) => t.type === 'Hashtag').map((t) => t.name) : [];
+}
diff --git a/lib/storage.js b/lib/storage.js
index 60113ef..29d204b 100644
--- a/lib/storage.js
+++ b/lib/storage.js
@@ -5,6 +5,7 @@ import debug from 'debug';
const logger = debug('ono:storage');
import md5 from 'md5';
import dotenv from 'dotenv';
+import { getHashtagsFromNote } from './notes.js';
dotenv.config();
export const dataDir = path.resolve('./', '.data/');
@@ -64,6 +65,7 @@ export const addActivityToIndex = (note, type = 'activity') => {
actor: note.attributedTo || note.actor,
published: new Date(note.published).getTime(),
inReplyTo: note.inReplyTo,
+ hashtags: getHashtagsFromNote(note)
});
}
export const deleteActivityFromIndex = (id) => {
diff --git a/routes/public.js b/routes/public.js
index 24e8922..32689a0 100644
--- a/routes/public.js
+++ b/routes/public.js
@@ -195,4 +195,23 @@ router.get('/notes/:guid', async (req, res) => {
});
}
}
-});
\ No newline at end of file
+});
+
+router.get('/tags/:tag', async (req, res) => {
+ // all posts referencing tag by the owner user
+ const noteIds = INDEX.filter((i) => (i.actor === ActivityPub.actor.id) && i.hashtags.includes('#' + req.params.tag));
+ // get full posts
+ const posts = await Promise.all(noteIds.map(async (p) => {
+ return await getNote(p.id);
+ }));
+
+ res.render('public/tag', {
+ tag: req.params.tag,
+ layout: 'public',
+ me: ActivityPub.actor,
+ actor: ActivityPub.actor,
+ domain: DOMAIN,
+ user: USERNAME,
+ notes: posts
+ });
+});