diff --git a/README.md b/README.md index 2b040c20..6beab640 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,13 @@ ## 主要な変更点 +- 検索フィルターを強化中 + - `from: me` を検索ワードの末尾につけると自分の投稿のみを検索できるように変更 + - 検索クエリの例: `予定 from:me` + - ホーム・フォロワー限定・ダイレクト・秘密の投稿を含む自分の全ての投稿から検索します - 全文検索のエンジンを [PGroonga](https://pgroonga.github.io/) に変更 - PGroonga のインストールが必要になります!詳しくは[この投稿](https://post.naskya.net/notes/9ldi29amfanomef5)をご覧ください - - Meilisearch, Elasticsearch, Sonic は非推奨となります + - Meilisearch, Elasticsearch, Sonic は使えません - 「秘密」という公開範囲を追加 - 宛先無しのダイレクト投稿を言い換えているだけです - 既存の投稿を削除せずに後から秘密にすることもできます diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts index c6712519..7f971978 100644 --- a/packages/backend/src/server/api/endpoints/notes/search.ts +++ b/packages/backend/src/server/api/endpoints/notes/search.ts @@ -1,10 +1,10 @@ -import { FindManyOptions, In } from "typeorm"; +// import { FindManyOptions, In } from "typeorm"; import { Notes } from "@/models/index.js"; import { Note } from "@/models/entities/note.js"; -import config from "@/config/index.js"; -import es from "@/db/elasticsearch.js"; -import sonic from "@/db/sonic.js"; -import meilisearch, { MeilisearchNote } from "@/db/meilisearch.js"; +// import config from "@/config/index.js"; +// import es from "@/db/elasticsearch.js"; +// import sonic from "@/db/sonic.js"; +// import meilisearch, { MeilisearchNote } from "@/db/meilisearch.js"; import define from "@/server/api/define.js"; import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; import { generateVisibilityQuery } from "@/server/api/common/generate-visibility-query.js"; @@ -73,47 +73,55 @@ export default define(meta, paramDef, async (ps, me) => { // disable the post search if no credentials are provided if (me == null) return []; - if (es == null && sonic == null && meilisearch == null) { - const query = makePaginationQuery( - Notes.createQueryBuilder("note"), - ps.sinceId, - ps.untilId, - ); + /* if (es == null && sonic == null && meilisearch == null) { */ + const query = makePaginationQuery( + Notes.createQueryBuilder("note"), + ps.sinceId, + ps.untilId, + ); - if (ps.userId != null) { - query.andWhere("note.userId = :userId", { userId: ps.userId }); - } + if (ps.channelId != null) { + query.andWhere("note.channelId = :channelId", { + channelId: ps.channelId, + }); + } - if (ps.channelId != null) { - query.andWhere("note.channelId = :channelId", { - channelId: ps.channelId, - }); - } + query + .andWhere("note.text &@~ :q", { q: `${sqlLikeEscape(ps.query)}` }) + .innerJoinAndSelect("note.user", "user"); + // "from: me": search all (public, home, followers, specified) my posts + // otherwise: search public indexable posts only + if (ps.userId == null || ps.userId !== me.id) { query - .andWhere("note.text &@~ :q", { q: `${sqlLikeEscape(ps.query)}` }) .andWhere("note.visibility = 'public'") - .innerJoinAndSelect("note.user", "user") - .andWhere("user.isIndexable = TRUE") - .leftJoinAndSelect("user.avatar", "avatar") - .leftJoinAndSelect("user.banner", "banner") - .leftJoinAndSelect("note.reply", "reply") - .leftJoinAndSelect("note.renote", "renote") - .leftJoinAndSelect("reply.user", "replyUser") - .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") - .leftJoinAndSelect("replyUser.banner", "replyUserBanner") - .leftJoinAndSelect("renote.user", "renoteUser") - .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") - .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); + .andWhere("user.isIndexable = TRUE"); + } - generateVisibilityQuery(query, me); - if (me) generateMutedUserQuery(query, me); - if (me) generateBlockedUserQuery(query, me); + if (ps.userId != null) { + query.andWhere("note.userId = :userId", { userId: ps.userId }); + } - const notes: Note[] = await query.take(ps.limit).getMany(); + query + .leftJoinAndSelect("user.avatar", "avatar") + .leftJoinAndSelect("user.banner", "banner") + .leftJoinAndSelect("note.reply", "reply") + .leftJoinAndSelect("note.renote", "renote") + .leftJoinAndSelect("reply.user", "replyUser") + .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") + .leftJoinAndSelect("replyUser.banner", "replyUserBanner") + .leftJoinAndSelect("renote.user", "renoteUser") + .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") + .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); - return await Notes.packMany(notes, me); - } else if (sonic) { + generateVisibilityQuery(query, me); + if (me) generateMutedUserQuery(query, me); + if (me) generateBlockedUserQuery(query, me); + + const notes: Note[] = await query.take(ps.limit).getMany(); + + return await Notes.packMany(notes, me); + /* } else if (sonic) { let start = 0; const chunkSize = 100; @@ -270,7 +278,7 @@ export default define(meta, paramDef, async (ps, me) => { } return found; - } else { + } else { // Elasticsearch const userQuery = ps.userId != null ? [ @@ -350,5 +358,5 @@ export default define(meta, paramDef, async (ps, me) => { }); return await Notes.packMany(notes, me); - } + } */ }); diff --git a/packages/client/src/pages/search.vue b/packages/client/src/pages/search.vue index 61f211bc..c86734cd 100644 --- a/packages/client/src/pages/search.vue +++ b/packages/client/src/pages/search.vue @@ -50,6 +50,7 @@ import { definePageMetadata } from "@/scripts/page-metadata"; import { defaultStore } from "@/store"; import { deviceKind } from "@/scripts/device-kind"; import icon from "@/scripts/icon"; +import { $i } from "@/reactiveAccount"; import "swiper/scss"; import "swiper/scss/virtual"; @@ -62,7 +63,10 @@ const notesPagination = { endpoint: "notes/search" as const, limit: 10, params: computed(() => ({ - query: props.query, + query: props.query.endsWith("from:me") + ? props.query.slice(0, -7).trim() + : props.query, + userId: props.query.endsWith("from:me") ? $i.id : null, channelId: props.channel, })), };