Skip to content

Commit

Permalink
Enhance: 高度な検索でフォロー中/フォロー外を検索条件にできるように (#503)
Browse files Browse the repository at this point in the history
  • Loading branch information
penginn-net authored Oct 17, 2024
1 parent 2d9ccd3 commit 8b0fd6f
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG_YOJO.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Cherrypick 4.11.1
- Enhance: ノートにつけられたリアクションを対象にした検索ができるように
- Opensearchのみ対応
- Opensearchの設定で` reactionSearchLocalOnly: true`にすることでリモートのカスタム絵文字リアクションをインデックス対象外にできます
- Enhance: 高度な検索でフォロー中/フォロー外を検索条件にできるように
- Fix: 照会かリモートユーザーの投稿取得で作成されたノートの場合通知を発行しないように
- Enhance(Opensearch): 表記ゆれがヒットしないようにするオプションを追加

Expand Down
18 changes: 18 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11891,6 +11891,24 @@ export interface Locale extends ILocale {
*/
"endDate": string;
};
"_followingFilter": {
/**
* フォローフィルター
*/
"title": string;
/**
* フィルタしない
*/
"combined": string;
/**
* フォロー中
*/
"following": string;
/**
* フォロー外
*/
"notFollowing": string;
};
"_description": {
/**
* その他の設定
Expand Down
5 changes: 5 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3169,6 +3169,11 @@ _advancedSearch:
_specifyDate:
startDate: "から"
endDate: "まで"
_followingFilter:
title: "フォローフィルター"
combined: "フィルタしない"
following: "フォロー中"
notFollowing: "フォロー外"
_description:
other: "その他の設定"
_fileNsfwOption:
Expand Down
18 changes: 14 additions & 4 deletions packages/backend/src/core/AdvancedSearchService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,7 @@ export class AdvancedSearchService {
excludeReply?: boolean;
excludeQuote?: boolean;
sensitiveFilter?: string | null;
followingFilter?: string | null;
offset?: number | null;
useStrictSearch?: boolean | null;
}, pagination: {
Expand Down Expand Up @@ -955,7 +956,7 @@ export class AdvancedSearchService {
});
}

const Result = await this.search(Option, pagination.untilId ? 1 : 0, me ? me.id : undefined);
const Result = await this.search(Option, pagination.untilId ? 1 : 0, opts.followingFilter ?? 'combined', me ? me.id : undefined);
if (Result.length === 0) {
return [];
}
Expand Down Expand Up @@ -1032,7 +1033,11 @@ export class AdvancedSearchService {
}
}

this.queryService.generateVisibilityQuery(query, me);
if (opts.followingFilter) {
this.queryService.generateVisibilityQuery(query, me, opts.followingFilter);
} else {
this.queryService.generateVisibilityQuery(query, me);
}
this.queryService.generateSearchableQuery(query, me);
if (me) this.queryService.generateMutedUserQuery(query, me);
if (me) this.queryService.generateBlockedUserQuery(query, me);
Expand All @@ -1045,6 +1050,7 @@ export class AdvancedSearchService {
private async search(
OpenSearchOption: any,
untilAvail: number,
followingFilter: string,
meUserId?: string,
): Promise<any[]> {
if (!this.opensearch) throw new Error();
Expand All @@ -1065,7 +1071,7 @@ export class AdvancedSearchService {
notes = res.body.hits.hits as OpenSearchHit[];
if (notes.length === 0) break;//これ以上探してもない

const resultPromises = notes.map(x => this.filter(x, Filter, Followings, meUserId));
const resultPromises = notes.map(x => this.filter(x, Filter, Followings, followingFilter, meUserId));
const Results = (await Promise.all(resultPromises)).filter( (x) => x !== null);

if (Results.length > 0) {
Expand Down Expand Up @@ -1095,12 +1101,16 @@ export class AdvancedSearchService {
Note: OpenSearchHit,
Filter: string[],
Followings: string[],
meUserId?: string): Promise<OpenSearchHit| null> {
followingFilter: string,
meUserId?: string ): Promise<OpenSearchHit| null> {
if (meUserId) {//ミュートしているか、ブロックされている
if (Filter.includes(Note._source.userId) ) return null;
if (Note._source.referenceUserId) {
if (Filter.includes(Note._source.referenceUserId)) return null;
}
if (followingFilter === 'following' && !Followings.includes(Note._source.userId)) return null;
if (followingFilter === 'notFollowing' && Followings.includes(Note._source.userId)) return null;

if (Note._source.userId === meUserId) {//自分のノート
return Note;
}
Expand Down
7 changes: 6 additions & 1 deletion packages/backend/src/core/QueryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export class QueryService {
}

@bindThis
public generateVisibilityQuery(q: SelectQueryBuilder<any>, me?: { id: MiUser['id'] } | null): void {
public generateVisibilityQuery(q: SelectQueryBuilder<any>, me?: { id: MiUser['id'] } | null, followingFilter?: string): void {
// This code must always be synchronized with the checks in Notes.isVisibleForMe.
if (me == null) {
q.andWhere(new Brackets(qb => {
Expand All @@ -201,6 +201,11 @@ export class QueryService {
.select('following.followeeId')
.where('following.followerId = :meId');

if (followingFilter) {
if (followingFilter === 'following') q.andWhere(`note.userId IN (${ followingQuery.getQuery() })`);
if (followingFilter === 'notFollowing') q.andWhere(`note.userId NOT IN (${ followingQuery.getQuery() })`);
}

q.andWhere(new Brackets(qb => {
qb
// 公開投稿である
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ export const paramDef = {
default: 'combined',
description: '添付ファイルのセンシティブ状態',
},
followingFilter: {
type: 'string',
enum: ['following', 'notFollowing', 'combined'],
default: 'combined',
description: 'ユーザーのフォロー状態',
},
offset: {
type: 'integer',
default: 0,
Expand Down Expand Up @@ -163,6 +169,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
origin: ps.origin,
fileOption: ps.fileOption,
sensitiveFilter: ps.sensitiveFilter,
followingFilter: ps.followingFilter,
excludeCW: ps.excludeCW,
excludeReply: ps.excludeReply,
excludeQuote: ps.excludeQuote,
Expand Down
6 changes: 6 additions & 0 deletions packages/cherrypick-js/src/autogen/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23621,6 +23621,12 @@ export type operations = {
* @enum {string}
*/
sensitiveFilter?: 'includeSensitive' | 'withOutSensitive' | 'sensitiveOnly' | 'combined';
/**
* @description ユーザーのフォロー状態
* @default combined
* @enum {string}
*/
followingFilter?: 'following' | 'notFollowing' | 'combined';
/**
* @description 指定された件数の以降のノートを返します
* @default 0
Expand Down
12 changes: 12 additions & 0 deletions packages/frontend/src/pages/search.anote.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
</FormSection>
<FormSection>
<template #label>{{ i18n.ts._advancedSearch._followingFilter.title }}</template>
<div style="text-align: center;" class="_gaps_m">
<MkRadios v-model="followingFilter" @update:modelValue="search()">
<option value="combined">{{ i18n.ts._advancedSearch._followingFilter.combined }}</option>
<option value="following">{{ i18n.ts._advancedSearch._followingFilter.following }}</option>
<option value="notFollowing">{{ i18n.ts._advancedSearch._followingFilter.notFollowing }}</option>
</MkRadios>
</div>
</FormSection>
<FormSection>
<template #label>{{ i18n.ts.other }}</template>
<template #caption>{{ i18n.ts._advancedSearch._description.other }}</template>
Expand Down Expand Up @@ -125,6 +135,7 @@ const excludeCW = ref(false);
const excludeReply = ref(false);
const excludeQuote = ref(false);
const sensitiveFilter = ref('combined');
const followingFilter = ref('combined');
const hostInput = ref('');
const emojiSearchQuery = ref('');
const emojiExcludeSearchQuery = ref('');
Expand Down Expand Up @@ -228,6 +239,7 @@ async function search() {
excludeReply: excludeReply.value,
excludeQuote: excludeQuote.value,
sensitiveFilter: sensitiveFilter.value,
followingFilter: followingFilter.value,
useStrictSearch: strictSearch.value,
},
};
Expand Down

0 comments on commit 8b0fd6f

Please sign in to comment.