Merge remote-tracking branch 'misskey-dev/develop' into io
This commit is contained in:
commit
0f70bf57f3
71 changed files with 4144 additions and 2532 deletions
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class ChannelIdDenormalizedForMiPoll1716129964060 {
|
||||
name = 'ChannelIdDenormalizedForMiPoll1716129964060'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "poll" ADD "channelId" character varying(32)`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "poll"."channelId" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_c1240fcc9675946ea5d6c2860e" ON "poll" ("channelId") `);
|
||||
await queryRunner.query(`UPDATE "poll" SET "channelId" = "note"."channelId" FROM "note" WHERE "poll"."noteId" = "note"."id"`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_c1240fcc9675946ea5d6c2860e"`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "poll"."channelId" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`ALTER TABLE "poll" DROP COLUMN "channelId"`);
|
||||
}
|
||||
}
|
|
@ -35,17 +35,17 @@
|
|||
},
|
||||
"optionalDependencies": {
|
||||
"@swc/core-android-arm64": "1.3.11",
|
||||
"@swc/core-darwin-arm64": "1.5.5",
|
||||
"@swc/core-darwin-x64": "1.5.5",
|
||||
"@swc/core-darwin-arm64": "1.5.7",
|
||||
"@swc/core-darwin-x64": "1.5.7",
|
||||
"@swc/core-freebsd-x64": "1.3.11",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.5.5",
|
||||
"@swc/core-linux-arm64-gnu": "1.5.5",
|
||||
"@swc/core-linux-arm64-musl": "1.5.5",
|
||||
"@swc/core-linux-x64-gnu": "1.5.5",
|
||||
"@swc/core-linux-x64-musl": "1.5.5",
|
||||
"@swc/core-win32-arm64-msvc": "1.5.5",
|
||||
"@swc/core-win32-ia32-msvc": "1.5.5",
|
||||
"@swc/core-win32-x64-msvc": "1.5.5",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.5.7",
|
||||
"@swc/core-linux-arm64-gnu": "1.5.7",
|
||||
"@swc/core-linux-arm64-musl": "1.5.7",
|
||||
"@swc/core-linux-x64-gnu": "1.5.7",
|
||||
"@swc/core-linux-x64-musl": "1.5.7",
|
||||
"@swc/core-win32-arm64-msvc": "1.5.7",
|
||||
"@swc/core-win32-ia32-msvc": "1.5.7",
|
||||
"@swc/core-win32-x64-msvc": "1.5.7",
|
||||
"@tensorflow/tfjs": "4.19.0",
|
||||
"@tensorflow/tfjs-node": "4.19.0",
|
||||
"bufferutil": "4.0.8",
|
||||
|
@ -62,15 +62,15 @@
|
|||
"slacc-linux-x64-musl": "0.0.10",
|
||||
"slacc-win32-arm64-msvc": "0.0.10",
|
||||
"slacc-win32-x64-msvc": "0.0.10",
|
||||
"utf-8-validate": "6.0.3"
|
||||
"utf-8-validate": "6.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@authenio/samlify-node-xmllint": "2.0.0",
|
||||
"@aws-sdk/client-s3": "3.569.0",
|
||||
"@aws-sdk/lib-storage": "3.569.0",
|
||||
"@bull-board/api": "5.17.1",
|
||||
"@bull-board/fastify": "5.17.1",
|
||||
"@bull-board/ui": "5.17.1",
|
||||
"@aws-sdk/client-s3": "3.577.0",
|
||||
"@aws-sdk/lib-storage": "3.578.0",
|
||||
"@bull-board/api": "5.18.1",
|
||||
"@bull-board/fastify": "5.18.1",
|
||||
"@bull-board/ui": "5.18.1",
|
||||
"@discordapp/twemoji": "15.0.3",
|
||||
"@fastify/accepts": "4.3.0",
|
||||
"@fastify/cookie": "9.3.1",
|
||||
|
@ -90,9 +90,9 @@
|
|||
"@peertube/http-signature": "1.7.0",
|
||||
"@simplewebauthn/server": "10.0.0",
|
||||
"@sinonjs/fake-timers": "11.2.2",
|
||||
"@smithy/node-http-handler": "2.5.0",
|
||||
"@smithy/node-http-handler": "3.0.0",
|
||||
"@swc/cli": "0.3.12",
|
||||
"@swc/core": "1.5.5",
|
||||
"@swc/core": "1.5.7",
|
||||
"@twemoji/parser": "15.1.1",
|
||||
"accepts": "1.3.8",
|
||||
"ajv": "8.13.0",
|
||||
|
@ -101,7 +101,7 @@
|
|||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "2.0.5",
|
||||
"body-parser": "1.20.2",
|
||||
"bullmq": "5.7.8",
|
||||
"bullmq": "5.7.10",
|
||||
"cacheable-lookup": "7.0.0",
|
||||
"cbor": "9.0.2",
|
||||
"chalk": "5.3.0",
|
||||
|
@ -117,24 +117,24 @@
|
|||
"fastify-raw-body": "4.3.0",
|
||||
"feed": "4.2.2",
|
||||
"file-type": "19.0.0",
|
||||
"fluent-ffmpeg": "2.1.2",
|
||||
"fluent-ffmpeg": "2.1.3",
|
||||
"form-data": "4.0.0",
|
||||
"got": "14.2.1",
|
||||
"happy-dom": "14.10.1",
|
||||
"got": "14.3.0",
|
||||
"happy-dom": "14.11.0",
|
||||
"hpagent": "1.2.0",
|
||||
"htmlescape": "1.1.1",
|
||||
"http-link-header": "1.1.3",
|
||||
"ioredis": "5.4.1",
|
||||
"ip-cidr": "3.1.0",
|
||||
"ipaddr.js": "2.2.0",
|
||||
"is-svg": "5.0.0",
|
||||
"jose": "5.2.4",
|
||||
"is-svg": "5.0.1",
|
||||
"jose": "5.3.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"jsdom": "24.0.0",
|
||||
"json5": "2.2.3",
|
||||
"jsonld": "8.3.2",
|
||||
"jsrsasign": "11.1.0",
|
||||
"meilisearch": "0.39.0",
|
||||
"meilisearch": "0.40.0",
|
||||
"mfm-js": "0.24.0",
|
||||
"microformats-parser": "2.0.2",
|
||||
"mime-types": "2.1.35",
|
||||
|
@ -154,7 +154,7 @@
|
|||
"otpauth": "9.2.4",
|
||||
"parse5": "7.1.2",
|
||||
"pg": "8.11.5",
|
||||
"pino": "9.0.0",
|
||||
"pino": "9.1.0",
|
||||
"pino-pretty": "11.0.0",
|
||||
"pkce-challenge": "4.1.0",
|
||||
"probe-image-size": "7.2.3",
|
||||
|
@ -173,14 +173,14 @@
|
|||
"samlify": "2.8.11",
|
||||
"sanitize-html": "2.13.0",
|
||||
"secure-json-parse": "2.7.0",
|
||||
"sharp": "0.33.3",
|
||||
"sharp": "0.33.4",
|
||||
"slacc": "0.0.10",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"stringz": "2.1.0",
|
||||
"systeminformation": "5.22.8",
|
||||
"systeminformation": "5.22.9",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tmp": "0.2.3",
|
||||
"tsc-alias": "1.8.8",
|
||||
"tsc-alias": "1.8.10",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typeorm": "0.3.20",
|
||||
"typescript": "5.4.5",
|
||||
|
@ -213,7 +213,7 @@
|
|||
"@types/jsrsasign": "10.5.14",
|
||||
"@types/mime-types": "2.1.4",
|
||||
"@types/ms": "0.7.34",
|
||||
"@types/node": "20.12.11",
|
||||
"@types/node": "20.12.12",
|
||||
"@types/node-forge": "1.3.11",
|
||||
"@types/nodemailer": "6.4.15",
|
||||
"@types/oauth": "0.9.4",
|
||||
|
@ -235,13 +235,13 @@
|
|||
"@types/vary": "1.1.3",
|
||||
"@types/web-push": "3.6.3",
|
||||
"@types/ws": "8.5.10",
|
||||
"@typescript-eslint/eslint-plugin": "7.8.0",
|
||||
"@typescript-eslint/parser": "7.8.0",
|
||||
"@typescript-eslint/eslint-plugin": "7.10.0",
|
||||
"@typescript-eslint/parser": "7.10.0",
|
||||
"aws-sdk-client-mock": "4.0.0",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"execa": "8.0.1",
|
||||
"execa": "9.1.0",
|
||||
"fkill": "^9.0.0",
|
||||
"jest": "29.7.0",
|
||||
"jest-mock": "29.7.0",
|
||||
|
|
|
@ -61,8 +61,8 @@ export class FanoutTimelineEndpointService {
|
|||
// 呼び出し元と以下の処理をシンプルにするためにdbFallbackを置き換える
|
||||
if (!ps.useDbFallback) ps.dbFallback = () => Promise.resolve([]);
|
||||
|
||||
const shouldPrepend = ps.sinceId && !ps.untilId;
|
||||
const idCompare: (a: string, b: string) => number = shouldPrepend ? (a, b) => a < b ? -1 : 1 : (a, b) => a > b ? -1 : 1;
|
||||
const ascending = ps.sinceId && !ps.untilId;
|
||||
const idCompare: (a: string, b: string) => number = ascending ? (a, b) => a < b ? -1 : 1 : (a, b) => a > b ? -1 : 1;
|
||||
|
||||
const redisResult = await this.fanoutTimelineService.getMulti(ps.redisTimelines, ps.untilId, ps.sinceId);
|
||||
|
||||
|
@ -142,9 +142,7 @@ export class FanoutTimelineEndpointService {
|
|||
|
||||
if (ps.allowPartial ? redisTimeline.length !== 0 : redisTimeline.length >= ps.limit) {
|
||||
// 十分Redisからとれた
|
||||
const result = redisTimeline.slice(0, ps.limit);
|
||||
if (shouldPrepend) result.reverse();
|
||||
return result;
|
||||
return redisTimeline.slice(0, ps.limit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,8 +150,7 @@ export class FanoutTimelineEndpointService {
|
|||
const remainingToRead = ps.limit - redisTimeline.length;
|
||||
let dbUntil: string | null;
|
||||
let dbSince: string | null;
|
||||
if (shouldPrepend) {
|
||||
redisTimeline.reverse();
|
||||
if (ascending) {
|
||||
dbUntil = ps.untilId;
|
||||
dbSince = noteIds[noteIds.length - 1];
|
||||
} else {
|
||||
|
@ -161,7 +158,7 @@ export class FanoutTimelineEndpointService {
|
|||
dbSince = ps.sinceId;
|
||||
}
|
||||
const gotFromDb = await ps.dbFallback(dbUntil, dbSince, remainingToRead);
|
||||
return shouldPrepend ? [...gotFromDb, ...redisTimeline] : [...redisTimeline, ...gotFromDb];
|
||||
return [...redisTimeline, ...gotFromDb];
|
||||
}
|
||||
|
||||
return await ps.dbFallback(ps.untilId, ps.sinceId, ps.limit);
|
||||
|
|
|
@ -502,6 +502,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
noteVisibility: insert.visibility,
|
||||
userId: user.id,
|
||||
userHost: user.host,
|
||||
channelId: insert.channelId,
|
||||
});
|
||||
|
||||
await transactionalEntityManager.insert(MiPoll, poll);
|
||||
|
|
|
@ -238,7 +238,7 @@ export type SchemaTypeDef<p extends Schema> =
|
|||
p['items']['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<NonNullable<p['items']['allOf']>>>[] :
|
||||
never
|
||||
) :
|
||||
p['items'] extends NonNullable<Schema> ? SchemaTypeDef<p['items']>[] :
|
||||
p['items'] extends NonNullable<Schema> ? SchemaType<p['items']>[] :
|
||||
any[]
|
||||
) :
|
||||
p['anyOf'] extends ReadonlyArray<Schema> ? UnionSchemaType<p['anyOf']> & PartialIntersection<UnionSchemaType<p['anyOf']>> :
|
||||
|
|
|
@ -8,6 +8,7 @@ import { noteVisibilities } from '@/types.js';
|
|||
import { id } from './util/id.js';
|
||||
import { MiNote } from './Note.js';
|
||||
import type { MiUser } from './User.js';
|
||||
import type { MiChannel } from "@/models/Channel.js";
|
||||
|
||||
@Entity('poll')
|
||||
export class MiPoll {
|
||||
|
@ -58,6 +59,14 @@ export class MiPoll {
|
|||
comment: '[Denormalized]',
|
||||
})
|
||||
public userHost: string | null;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
nullable: true,
|
||||
comment: '[Denormalized]',
|
||||
})
|
||||
public channelId: MiChannel['id'] | null;
|
||||
//#endregion
|
||||
|
||||
constructor(data: Partial<MiPoll>) {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { In } from 'typeorm';
|
|||
import * as Redis from 'ioredis';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import type { NotesRepository } from '@/models/_.js';
|
||||
import { obsoleteNotificationTypes, notificationTypes, FilterUnionByProperty } from '@/types.js';
|
||||
import { FilterUnionByProperty, notificationTypes, obsoleteNotificationTypes } from '@/types.js';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { NoteReadService } from '@/core/NoteReadService.js';
|
||||
import { NotificationEntityService } from '@/core/entities/NotificationEntityService.js';
|
||||
|
@ -84,27 +84,51 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
const includeTypes = ps.includeTypes && ps.includeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][];
|
||||
const excludeTypes = ps.excludeTypes && ps.excludeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][];
|
||||
|
||||
const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1
|
||||
const notificationsRes = await this.redisClient.xrevrange(
|
||||
`notificationTimeline:${me.id}`,
|
||||
ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : '+',
|
||||
ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : '-',
|
||||
'COUNT', limit);
|
||||
let sinceTime = ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime().toString() : null;
|
||||
let untilTime = ps.untilId ? this.idService.parse(ps.untilId).date.getTime().toString() : null;
|
||||
|
||||
if (notificationsRes.length === 0) {
|
||||
return [];
|
||||
}
|
||||
let notifications: MiNotification[];
|
||||
for (;;) {
|
||||
let notificationsRes: [id: string, fields: string[]][];
|
||||
|
||||
let notifications = notificationsRes.map(x => JSON.parse(x[1][1])).filter(x => x.id !== ps.untilId && x !== ps.sinceId) as MiNotification[];
|
||||
// sinceidのみの場合は古い順、そうでない場合は新しい順。 QueryService.makePaginationQueryも参照
|
||||
if (sinceTime && !untilTime) {
|
||||
notificationsRes = await this.redisClient.xrange(
|
||||
`notificationTimeline:${me.id}`,
|
||||
'(' + sinceTime,
|
||||
'+',
|
||||
'COUNT', ps.limit);
|
||||
} else {
|
||||
notificationsRes = await this.redisClient.xrevrange(
|
||||
`notificationTimeline:${me.id}`,
|
||||
untilTime ? '(' + untilTime : '+',
|
||||
sinceTime ? '(' + sinceTime : '-',
|
||||
'COUNT', ps.limit);
|
||||
}
|
||||
|
||||
if (includeTypes && includeTypes.length > 0) {
|
||||
notifications = notifications.filter(notification => includeTypes.includes(notification.type));
|
||||
} else if (excludeTypes && excludeTypes.length > 0) {
|
||||
notifications = notifications.filter(notification => !excludeTypes.includes(notification.type));
|
||||
}
|
||||
if (notificationsRes.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (notifications.length === 0) {
|
||||
return [];
|
||||
notifications = notificationsRes.map(x => JSON.parse(x[1][1])) as MiNotification[];
|
||||
|
||||
if (includeTypes && includeTypes.length > 0) {
|
||||
notifications = notifications.filter(notification => includeTypes.includes(notification.type));
|
||||
} else if (excludeTypes && excludeTypes.length > 0) {
|
||||
notifications = notifications.filter(notification => !excludeTypes.includes(notification.type));
|
||||
}
|
||||
|
||||
if (notifications.length !== 0) {
|
||||
// 通知が1件以上ある場合は返す
|
||||
break;
|
||||
}
|
||||
|
||||
// フィルタしたことで通知が0件になった場合、次のページを取得する
|
||||
if (ps.sinceId && !ps.untilId) {
|
||||
sinceTime = notificationsRes[notificationsRes.length - 1][0];
|
||||
} else {
|
||||
untilTime = notificationsRes[notificationsRes.length - 1][0];
|
||||
}
|
||||
}
|
||||
|
||||
// Mark all as read
|
||||
|
|
|
@ -32,6 +32,7 @@ export const paramDef = {
|
|||
properties: {
|
||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||
offset: { type: 'integer', default: 0 },
|
||||
excludeChannels: { type: 'boolean', default: false },
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
@ -86,6 +87,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
query.setParameters(mutingQuery.getParameters());
|
||||
//#endregion
|
||||
|
||||
//#region exclude channels
|
||||
if (ps.excludeChannels) {
|
||||
query.andWhere('poll.channelId IS NULL');
|
||||
}
|
||||
//#endregion
|
||||
|
||||
const polls = await query
|
||||
.orderBy('poll.noteId', 'DESC')
|
||||
.limit(ps.limit)
|
||||
|
|
|
@ -122,6 +122,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
});
|
||||
|
||||
// リクエストされた通りに並べ替え
|
||||
// 順番は保持されるけど数は減ってる可能性がある
|
||||
const _users: MiUser[] = [];
|
||||
for (const id of ps.userIds) {
|
||||
const user = users.find((u) => u.id === id);
|
||||
|
|
|
@ -439,7 +439,7 @@ export class ClientServerService {
|
|||
|
||||
//#endregion
|
||||
|
||||
const renderBase = async (reply: FastifyReply) => {
|
||||
const renderBase = async (reply: FastifyReply, data: { [key: string]: any } = {}) => {
|
||||
const meta = await this.metaService.fetch();
|
||||
reply.header('Cache-Control', 'public, max-age=30');
|
||||
return await reply.view('base', {
|
||||
|
@ -448,6 +448,7 @@ export class ClientServerService {
|
|||
title: meta.name ?? 'Misskey',
|
||||
desc: meta.description,
|
||||
...await this.generateCommonPugData(meta),
|
||||
...data,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -780,6 +781,18 @@ export class ClientServerService {
|
|||
});
|
||||
//#endregion
|
||||
|
||||
//region noindex pages
|
||||
// Tags
|
||||
fastify.get<{ Params: { clip: string; } }>('/tags/:tag', async (request, reply) => {
|
||||
return await renderBase(reply, { noindex: true });
|
||||
});
|
||||
|
||||
// User with Tags
|
||||
fastify.get<{ Params: { clip: string; } }>('/user-tags/:tag', async (request, reply) => {
|
||||
return await renderBase(reply, { noindex: true });
|
||||
});
|
||||
//endregion
|
||||
|
||||
fastify.get('/_info_card_', async (request, reply) => {
|
||||
const meta = await this.metaService.fetch(true);
|
||||
|
||||
|
|
|
@ -50,6 +50,9 @@ html
|
|||
block title
|
||||
= title || 'Misskey'
|
||||
|
||||
if noindex
|
||||
meta(name='robots' content='noindex')
|
||||
|
||||
block desc
|
||||
meta(name='description' content= desc || '✨🌎✨ A interplanetary communication platform ✨🚀✨')
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue