feat: 投稿日時の範囲を条件に加えてノート検索出来るようにする
This commit is contained in:
parent
4c77f3e597
commit
4131be525b
|
@ -38,6 +38,8 @@ export type SearchOpts = {
|
||||||
userId?: MiNote['userId'] | null;
|
userId?: MiNote['userId'] | null;
|
||||||
channelId?: MiNote['channelId'] | null;
|
channelId?: MiNote['channelId'] | null;
|
||||||
host?: string | null;
|
host?: string | null;
|
||||||
|
rangeStartAt?: number | null;
|
||||||
|
rangeEndAt?: number | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SearchPagination = {
|
export type SearchPagination = {
|
||||||
|
@ -233,6 +235,16 @@ export class SearchService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opts.rangeStartAt) {
|
||||||
|
const date = this.idService.gen(opts.rangeStartAt);
|
||||||
|
query.andWhere('note.id >= :rangeStartAt', { rangeStartAt: date });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.rangeEndAt) {
|
||||||
|
const date = this.idService.gen(opts.rangeEndAt);
|
||||||
|
query.andWhere('note.id <= :rangeEndAt', { rangeEndAt: date });
|
||||||
|
}
|
||||||
|
|
||||||
this.queryService.generateVisibilityQuery(query, me);
|
this.queryService.generateVisibilityQuery(query, me);
|
||||||
this.queryService.generateBaseNoteFilteringQuery(query, me);
|
this.queryService.generateBaseNoteFilteringQuery(query, me);
|
||||||
|
|
||||||
|
@ -254,16 +266,50 @@ export class SearchService {
|
||||||
op: 'and',
|
op: 'and',
|
||||||
qs: [],
|
qs: [],
|
||||||
};
|
};
|
||||||
if (pagination.untilId) filter.qs.push({
|
if (pagination.untilId || opts.rangeEndAt) {
|
||||||
op: '<',
|
let time: number;
|
||||||
k: 'createdAt',
|
|
||||||
v: this.idService.parse(pagination.untilId).date.getTime(),
|
if (pagination.untilId && opts.rangeEndAt) {
|
||||||
});
|
time = Math.min(
|
||||||
if (pagination.sinceId) filter.qs.push({
|
this.idService.parse(pagination.untilId).date.getTime(),
|
||||||
op: '>',
|
opts.rangeEndAt,
|
||||||
k: 'createdAt',
|
);
|
||||||
v: this.idService.parse(pagination.sinceId).date.getTime(),
|
} else if (pagination.untilId) {
|
||||||
});
|
time = this.idService.parse(pagination.untilId).date.getTime();
|
||||||
|
} else if (opts.rangeEndAt) {
|
||||||
|
time = opts.rangeEndAt;
|
||||||
|
} else {
|
||||||
|
throw new Error('Either pagination.untilId or opts.rangeEndAt must be provided');
|
||||||
|
}
|
||||||
|
|
||||||
|
filter.qs.push({
|
||||||
|
op: '<',
|
||||||
|
k: 'createdAt',
|
||||||
|
v: time,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (pagination.sinceId || opts.rangeStartAt) {
|
||||||
|
let time: number;
|
||||||
|
|
||||||
|
if (pagination.sinceId && opts.rangeStartAt) {
|
||||||
|
time = Math.max(
|
||||||
|
this.idService.parse(pagination.sinceId).date.getTime(),
|
||||||
|
opts.rangeStartAt,
|
||||||
|
);
|
||||||
|
} else if (pagination.sinceId) {
|
||||||
|
time = this.idService.parse(pagination.sinceId).date.getTime();
|
||||||
|
} else if (opts.rangeStartAt) {
|
||||||
|
time = opts.rangeStartAt;
|
||||||
|
} else {
|
||||||
|
throw new Error('Either pagination.sinceId or opts.rangeStartAt must be provided');
|
||||||
|
}
|
||||||
|
|
||||||
|
filter.qs.push({
|
||||||
|
op: '>',
|
||||||
|
k: 'createdAt',
|
||||||
|
v: time,
|
||||||
|
});
|
||||||
|
}
|
||||||
if (opts.userId) filter.qs.push({ op: '=', k: 'userId', v: opts.userId });
|
if (opts.userId) filter.qs.push({ op: '=', k: 'userId', v: opts.userId });
|
||||||
if (opts.channelId) filter.qs.push({ op: '=', k: 'channelId', v: opts.channelId });
|
if (opts.channelId) filter.qs.push({ op: '=', k: 'channelId', v: opts.channelId });
|
||||||
if (opts.host) {
|
if (opts.host) {
|
||||||
|
|
|
@ -38,6 +38,8 @@ export const paramDef = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
query: { type: 'string' },
|
query: { type: 'string' },
|
||||||
|
rangeStartAt: { type: 'integer', nullable: true },
|
||||||
|
rangeEndAt: { type: 'integer', nullable: true },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
|
@ -71,6 +73,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
userId: ps.userId,
|
userId: ps.userId,
|
||||||
channelId: ps.channelId,
|
channelId: ps.channelId,
|
||||||
host: ps.host,
|
host: ps.host,
|
||||||
|
rangeStartAt: ps.rangeStartAt,
|
||||||
|
rangeEndAt: ps.rangeEndAt,
|
||||||
}, {
|
}, {
|
||||||
untilId: ps.untilId,
|
untilId: ps.untilId,
|
||||||
sinceId: ps.sinceId,
|
sinceId: ps.sinceId,
|
||||||
|
|
|
@ -19,6 +19,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #header>{{ i18n.ts.options }}</template>
|
<template #header>{{ i18n.ts.options }}</template>
|
||||||
|
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
|
<div style="display: flex; gap: 8px;">
|
||||||
|
<MkInput v-model="rangeStartAt" type="datetime-local"/>
|
||||||
|
<MkInput v-model="rangeEndAt" type="datetime-local"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<MkRadios v-model="searchScope">
|
<MkRadios v-model="searchScope">
|
||||||
<option v-if="instance.federation !== 'none' && noteSearchableScope === 'global'" value="all">{{ i18n.ts._search.searchScopeAll }}</option>
|
<option v-if="instance.federation !== 'none' && noteSearchableScope === 'global'" value="all">{{ i18n.ts._search.searchScopeAll }}</option>
|
||||||
<option value="local">{{ instance.federation === 'none' ? i18n.ts._search.searchScopeAll : i18n.ts._search.searchScopeLocal }}</option>
|
<option value="local">{{ instance.federation === 'none' ? i18n.ts._search.searchScopeAll : i18n.ts._search.searchScopeLocal }}</option>
|
||||||
|
@ -112,10 +117,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, shallowRef, toRef } from 'vue';
|
import { computed, ref, shallowRef, toRef } from 'vue';
|
||||||
|
import { host as localHost } from '@@/js/config.js';
|
||||||
import type * as Misskey from 'misskey-js';
|
import type * as Misskey from 'misskey-js';
|
||||||
import type { PagingCtx } from '@/composables/use-pagination.js';
|
import type { PagingCtx } from '@/composables/use-pagination.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
import { host as localHost } from '@@/js/config.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
@ -148,6 +153,8 @@ const notePagination = ref<PagingCtx<'notes/search'>>();
|
||||||
|
|
||||||
const searchQuery = ref(toRef(props, 'query').value);
|
const searchQuery = ref(toRef(props, 'query').value);
|
||||||
const hostInput = ref(toRef(props, 'host').value);
|
const hostInput = ref(toRef(props, 'host').value);
|
||||||
|
const rangeStartAt = ref<string | null>(null);
|
||||||
|
const rangeEndAt = ref<string | null>(null);
|
||||||
|
|
||||||
const user = shallowRef<Misskey.entities.UserDetailed | null>(null);
|
const user = shallowRef<Misskey.entities.UserDetailed | null>(null);
|
||||||
|
|
||||||
|
@ -188,6 +195,8 @@ type SearchParams = {
|
||||||
readonly query: string;
|
readonly query: string;
|
||||||
readonly host?: string;
|
readonly host?: string;
|
||||||
readonly userId?: string;
|
readonly userId?: string;
|
||||||
|
readonly rangeStartAt?: number | null;
|
||||||
|
readonly rangeEndAt?: number | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const fixHostIfLocal = (target: string | null | undefined) => {
|
const fixHostIfLocal = (target: string | null | undefined) => {
|
||||||
|
@ -195,6 +204,13 @@ const fixHostIfLocal = (target: string | null | undefined) => {
|
||||||
return target;
|
return target;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const searchRange = () => {
|
||||||
|
return {
|
||||||
|
rangeStartAt: rangeStartAt.value ? new Date(rangeStartAt.value).getTime() : null,
|
||||||
|
rangeEndAt: rangeEndAt.value ? new Date(rangeEndAt.value).getTime() : null,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const searchParams = computed<SearchParams | null>(() => {
|
const searchParams = computed<SearchParams | null>(() => {
|
||||||
const trimmedQuery = searchQuery.value.trim();
|
const trimmedQuery = searchQuery.value.trim();
|
||||||
if (!trimmedQuery) return null;
|
if (!trimmedQuery) return null;
|
||||||
|
@ -205,6 +221,7 @@ const searchParams = computed<SearchParams | null>(() => {
|
||||||
query: trimmedQuery,
|
query: trimmedQuery,
|
||||||
host: fixHostIfLocal(user.value.host),
|
host: fixHostIfLocal(user.value.host),
|
||||||
userId: user.value.id,
|
userId: user.value.id,
|
||||||
|
...searchRange(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,6 +236,7 @@ const searchParams = computed<SearchParams | null>(() => {
|
||||||
return {
|
return {
|
||||||
query: trimmedQuery,
|
query: trimmedQuery,
|
||||||
host: fixHostIfLocal(trimmedHost),
|
host: fixHostIfLocal(trimmedHost),
|
||||||
|
...searchRange(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,11 +244,13 @@ const searchParams = computed<SearchParams | null>(() => {
|
||||||
return {
|
return {
|
||||||
query: trimmedQuery,
|
query: trimmedQuery,
|
||||||
host: '.',
|
host: '.',
|
||||||
|
...searchRange(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
query: trimmedQuery,
|
query: trimmedQuery,
|
||||||
|
...searchRange(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -265,7 +285,7 @@ async function search() {
|
||||||
|
|
||||||
if (res.type === 'User') {
|
if (res.type === 'User') {
|
||||||
router.push(`/@${res.object.username}@${res.object.host}`);
|
router.push(`/@${res.object.username}@${res.object.host}`);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
} else if (res.type === 'Note') {
|
} else if (res.type === 'Note') {
|
||||||
router.push(`/notes/${res.object.id}`);
|
router.push(`/notes/${res.object.id}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25720,6 +25720,8 @@ export type operations = {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
query: string;
|
query: string;
|
||||||
|
rangeStartAt?: number | null;
|
||||||
|
rangeEndAt?: number | null;
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
sinceId?: string;
|
sinceId?: string;
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
|
|
Loading…
Reference in New Issue