From 03cd2de8ec286f1c5059550a5b2e1a075985cb99 Mon Sep 17 00:00:00 2001
From: PrivateGER <privateger@privateger.me>
Date: Thu, 25 May 2023 14:15:13 +0200
Subject: [PATCH] Add basic advanced search + attachment metadata hints

---
 packages/backend/src/db/meilisearch.ts | 46 ++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/packages/backend/src/db/meilisearch.ts b/packages/backend/src/db/meilisearch.ts
index f3561b807..407565036 100644
--- a/packages/backend/src/db/meilisearch.ts
+++ b/packages/backend/src/db/meilisearch.ts
@@ -3,7 +3,6 @@ import { dbLogger } from "./logger.js";
 
 import config from "@/config/index.js";
 import {Note} from "@/models/entities/note";
-import {normalizeForSearch} from "@/misc/normalize-for-search";
 
 const logger = dbLogger.createSubLogger("meilisearch", "gray", false);
 
@@ -16,7 +15,7 @@ const host = hasConfig ? config.meilisearch.host ?? "localhost" : "";
 const port = hasConfig ? config.meilisearch.port ?? 7700 : 0;
 const auth = hasConfig ? config.meilisearch.apiKey ?? "" : "";
 
-const client : MeiliSearch = new MeiliSearch({
+const client: MeiliSearch = new MeiliSearch({
 	host: `http://${host}:${port}`,
 	apiKey: auth,
 })
@@ -25,6 +24,8 @@ const posts = client.index('posts');
 
 posts.updateSearchableAttributes(['text']);
 
+posts.updateFilterableAttributes(["userId", "userHost", "mediaAttachment"])
+
 logger.info("Connected to MeiliSearch");
 
 
@@ -34,6 +35,7 @@ export type MeilisearchNote = {
 	userId: string;
 	userHost: string;
 	channelId: string;
+	mediaAttachment: string;
 }
 
 export default hasConfig ? {
@@ -42,14 +44,53 @@ export default hasConfig ? {
 		logger.info(`Limit: ${limit}`);
 		logger.info(`Offset: ${offset}`);
 
+		/// Advanced search syntax
+		/// from:user => filter by user + optional domain
+		/// has:image/video/audio/text/file => filter by attachment types
+		/// domain:domain.com => filter by domain
+
+		let constructedFilters: string[] = [];
+
+		let splitSearch = query.split(" ");
+		splitSearch.forEach(term => {
+			if (term.startsWith("has:")) {
+				let fileType = term.slice(4);
+				constructedFilters.push(`mediaAttachment = "${fileType}"`)
+			}
+			if (term.startsWith("from:")) {
+				let user = term.slice(5);
+				constructedFilters.push(`userId = ${user}`)
+			}
+			if (term.startsWith("domain:")) {
+				let domain = term.slice(7);
+				constructedFilters.push(`userHost = ${domain}`)
+			}
+		})
+
 		return posts.search(query, {
 			limit: limit,
 			offset: offset,
+			filter: constructedFilters
 		});
 	},
 	ingestNote: (note : Note) => {
 		logger.info("Indexing note in MeiliSearch: " + note.id);
 
+		let attachmentType = "";
+		if (note.attachedFileTypes.length > 0) {
+			attachmentType = note.attachedFileTypes[0].split("/")[0];
+			switch (attachmentType) {
+				case "image":
+				case "video":
+				case "audio":
+				case "text":
+					break;
+				default:
+					attachmentType = "file"
+					break
+			}
+		}
+
 		return posts.addDocuments([
 			{
 				id: note.id.toString(),
@@ -57,6 +98,7 @@ export default hasConfig ? {
 				userId: note.userId,
 				userHost: note.userHost,
 				channelId: note.channelId,
+				mediaAttachment: attachmentType
 			}
 		]);
 	},