summaryrefslogtreecommitdiff
path: root/packages/backend/src/server
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2023-09-29 18:11:30 +0900
committerGitHub <noreply@github.com>2023-09-29 18:11:30 +0900
commit7adc8fcaf5e7a57edfd2c197fcccb510425bd82c (patch)
treee60179e48010b0a389f87687e934f71ead92b27f /packages/backend/src/server
parentMerge pull request #11898 from misskey-dev/develop (diff)
parentfix (diff)
downloadmisskey-7adc8fcaf5e7a57edfd2c197fcccb510425bd82c.tar.gz
misskey-7adc8fcaf5e7a57edfd2c197fcccb510425bd82c.tar.bz2
misskey-7adc8fcaf5e7a57edfd2c197fcccb510425bd82c.zip
Merge pull request #11920 from misskey-dev/develop
Release: 2023.9.2
Diffstat (limited to 'packages/backend/src/server')
-rw-r--r--packages/backend/src/server/api/EndpointsModule.ts4
-rw-r--r--packages/backend/src/server/api/endpoints.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/ad/create.ts11
-rw-r--r--packages/backend/src/server/api/endpoints/admin/ad/delete.ts8
-rw-r--r--packages/backend/src/server/api/endpoints/admin/ad/list.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/admin/ad/update.ts11
-rw-r--r--packages/backend/src/server/api/endpoints/admin/invite/create.ts7
-rw-r--r--packages/backend/src/server/api/endpoints/admin/show-user.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/update.ts6
-rw-r--r--packages/backend/src/server/api/endpoints/notes/create.test.ts9
-rw-r--r--packages/backend/src/server/api/endpoints/notes/create.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/global-timeline.ts12
-rw-r--r--packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts11
-rw-r--r--packages/backend/src/server/api/endpoints/notes/local-timeline.ts11
-rw-r--r--packages/backend/src/server/api/endpoints/notes/timeline.ts11
-rw-r--r--packages/backend/src/server/api/endpoints/notes/update.ts89
-rw-r--r--packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts16
-rw-r--r--packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users/lists/pull.ts16
-rw-r--r--packages/backend/src/server/api/endpoints/users/lists/push.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users/notes.ts15
-rw-r--r--packages/backend/src/server/api/stream/Connection.ts6
-rw-r--r--packages/backend/src/server/api/stream/channels/antenna.ts4
-rw-r--r--packages/backend/src/server/api/stream/channels/global-timeline.ts6
-rw-r--r--packages/backend/src/server/api/stream/channels/home-timeline.ts6
-rw-r--r--packages/backend/src/server/api/stream/channels/hybrid-timeline.ts6
-rw-r--r--packages/backend/src/server/api/stream/channels/local-timeline.ts6
-rw-r--r--packages/backend/src/server/api/stream/channels/role-timeline.ts4
-rw-r--r--packages/backend/src/server/api/stream/types.ts255
-rw-r--r--packages/backend/src/server/web/ClientServerService.ts6
-rw-r--r--packages/backend/src/server/web/views/base.pug2
31 files changed, 255 insertions, 297 deletions
diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts
index 41a11bfb19..c883c96ba2 100644
--- a/packages/backend/src/server/api/EndpointsModule.ts
+++ b/packages/backend/src/server/api/EndpointsModule.ts
@@ -258,6 +258,7 @@ import * as ep___notes_clips from './endpoints/notes/clips.js';
import * as ep___notes_conversation from './endpoints/notes/conversation.js';
import * as ep___notes_create from './endpoints/notes/create.js';
import * as ep___notes_delete from './endpoints/notes/delete.js';
+import * as ep___notes_update from './endpoints/notes/update.js';
import * as ep___notes_favorites_create from './endpoints/notes/favorites/create.js';
import * as ep___notes_favorites_delete from './endpoints/notes/favorites/delete.js';
import * as ep___notes_featured from './endpoints/notes/featured.js';
@@ -606,6 +607,7 @@ const $notes_clips: Provider = { provide: 'ep:notes/clips', useClass: ep___notes
const $notes_conversation: Provider = { provide: 'ep:notes/conversation', useClass: ep___notes_conversation.default };
const $notes_create: Provider = { provide: 'ep:notes/create', useClass: ep___notes_create.default };
const $notes_delete: Provider = { provide: 'ep:notes/delete', useClass: ep___notes_delete.default };
+const $notes_update: Provider = { provide: 'ep:notes/update', useClass: ep___notes_update.default };
const $notes_favorites_create: Provider = { provide: 'ep:notes/favorites/create', useClass: ep___notes_favorites_create.default };
const $notes_favorites_delete: Provider = { provide: 'ep:notes/favorites/delete', useClass: ep___notes_favorites_delete.default };
const $notes_featured: Provider = { provide: 'ep:notes/featured', useClass: ep___notes_featured.default };
@@ -958,6 +960,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$notes_conversation,
$notes_create,
$notes_delete,
+ $notes_update,
$notes_favorites_create,
$notes_favorites_delete,
$notes_featured,
@@ -1304,6 +1307,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$notes_conversation,
$notes_create,
$notes_delete,
+ $notes_update,
$notes_favorites_create,
$notes_favorites_delete,
$notes_featured,
diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts
index ab20a708ef..b40d654f9c 100644
--- a/packages/backend/src/server/api/endpoints.ts
+++ b/packages/backend/src/server/api/endpoints.ts
@@ -258,6 +258,7 @@ import * as ep___notes_clips from './endpoints/notes/clips.js';
import * as ep___notes_conversation from './endpoints/notes/conversation.js';
import * as ep___notes_create from './endpoints/notes/create.js';
import * as ep___notes_delete from './endpoints/notes/delete.js';
+import * as ep___notes_update from './endpoints/notes/update.js';
import * as ep___notes_favorites_create from './endpoints/notes/favorites/create.js';
import * as ep___notes_favorites_delete from './endpoints/notes/favorites/delete.js';
import * as ep___notes_featured from './endpoints/notes/featured.js';
@@ -604,6 +605,7 @@ const eps = [
['notes/conversation', ep___notes_conversation],
['notes/create', ep___notes_create],
['notes/delete', ep___notes_delete],
+ ['notes/update', ep___notes_update],
['notes/favorites/create', ep___notes_favorites_create],
['notes/favorites/delete', ep___notes_favorites_delete],
['notes/featured', ep___notes_featured],
diff --git a/packages/backend/src/server/api/endpoints/admin/ad/create.ts b/packages/backend/src/server/api/endpoints/admin/ad/create.ts
index a13d08fd3a..e48dffecf4 100644
--- a/packages/backend/src/server/api/endpoints/admin/ad/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/ad/create.ts
@@ -8,6 +8,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import type { AdsRepository } from '@/models/_.js';
import { IdService } from '@/core/IdService.js';
import { DI } from '@/di-symbols.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
export const meta = {
tags: ['admin'],
@@ -39,9 +40,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private adsRepository: AdsRepository,
private idService: IdService,
+ private moderationLogService: ModerationLogService,
) {
super(meta, paramDef, async (ps, me) => {
- await this.adsRepository.insert({
+ const ad = await this.adsRepository.insert({
id: this.idService.genId(),
createdAt: new Date(),
expiresAt: new Date(ps.expiresAt),
@@ -53,7 +55,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
ratio: ps.ratio,
place: ps.place,
memo: ps.memo,
+ }).then(r => this.adsRepository.findOneByOrFail({ id: r.identifiers[0].id }));
+
+ this.moderationLogService.log(me, 'createAd', {
+ adId: ad.id,
+ ad: ad,
});
+
+ return ad;
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts
index d3c53d4f67..8097133a4c 100644
--- a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts
+++ b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts
@@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { AdsRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
import { ApiError } from '../../../error.js';
export const meta = {
@@ -37,6 +38,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
constructor(
@Inject(DI.adsRepository)
private adsRepository: AdsRepository,
+
+ private moderationLogService: ModerationLogService,
) {
super(meta, paramDef, async (ps, me) => {
const ad = await this.adsRepository.findOneBy({ id: ps.id });
@@ -44,6 +47,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (ad == null) throw new ApiError(meta.errors.noSuchAd);
await this.adsRepository.delete(ad.id);
+
+ this.moderationLogService.log(me, 'deleteAd', {
+ adId: ad.id,
+ ad: ad,
+ });
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/admin/ad/list.ts b/packages/backend/src/server/api/endpoints/admin/ad/list.ts
index adff3ed0ae..29eff89523 100644
--- a/packages/backend/src/server/api/endpoints/admin/ad/list.ts
+++ b/packages/backend/src/server/api/endpoints/admin/ad/list.ts
@@ -22,6 +22,7 @@ export const paramDef = {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
+ publishing: { type: 'boolean', default: false },
},
required: [],
} as const;
@@ -36,6 +37,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId);
+ if (ps.publishing) {
+ query.andWhere('ad.expiresAt > :now', { now: new Date() }).andWhere('ad.startsAt <= :now', { now: new Date() });
+ }
const ads = await query.limit(ps.limit).getMany();
return ads;
diff --git a/packages/backend/src/server/api/endpoints/admin/ad/update.ts b/packages/backend/src/server/api/endpoints/admin/ad/update.ts
index 5b77f67e10..d065f9ec50 100644
--- a/packages/backend/src/server/api/endpoints/admin/ad/update.ts
+++ b/packages/backend/src/server/api/endpoints/admin/ad/update.ts
@@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { AdsRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
import { ApiError } from '../../../error.js';
export const meta = {
@@ -46,6 +47,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
constructor(
@Inject(DI.adsRepository)
private adsRepository: AdsRepository,
+
+ private moderationLogService: ModerationLogService,
) {
super(meta, paramDef, async (ps, me) => {
const ad = await this.adsRepository.findOneBy({ id: ps.id });
@@ -63,6 +66,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
startsAt: new Date(ps.startsAt),
dayOfWeek: ps.dayOfWeek,
});
+
+ const updatedAd = await this.adsRepository.findOneByOrFail({ id: ad.id });
+
+ this.moderationLogService.log(me, 'updateAd', {
+ adId: ad.id,
+ before: ad,
+ after: updatedAd,
+ });
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/admin/invite/create.ts b/packages/backend/src/server/api/endpoints/admin/invite/create.ts
index 7112e06bdc..2cc5ab6e35 100644
--- a/packages/backend/src/server/api/endpoints/admin/invite/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/invite/create.ts
@@ -10,6 +10,7 @@ import { InviteCodeEntityService } from '@/core/entities/InviteCodeEntityService
import { IdService } from '@/core/IdService.js';
import { DI } from '@/di-symbols.js';
import { generateInviteCode } from '@/misc/generate-invite-code.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
import { ApiError } from '../../../error.js';
export const meta = {
@@ -60,6 +61,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private inviteCodeEntityService: InviteCodeEntityService,
private idService: IdService,
+ private moderationLogService: ModerationLogService,
) {
super(meta, paramDef, async (ps, me) => {
if (ps.expiresAt && isNaN(Date.parse(ps.expiresAt))) {
@@ -78,6 +80,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
const tickets = await Promise.all(ticketsPromises);
+
+ this.moderationLogService.log(me, 'createInvitation', {
+ invitations: tickets,
+ });
+
return await this.inviteCodeEntityService.packMany(tickets, me);
});
}
diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts
index e065b99e93..3454597532 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-user.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts
@@ -81,7 +81,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
receiveAnnouncementEmail: profile.receiveAnnouncementEmail,
mutedWords: profile.mutedWords,
mutedInstances: profile.mutedInstances,
- mutingNotificationTypes: profile.mutingNotificationTypes,
+ notificationRecieveConfig: profile.notificationRecieveConfig,
isModerator: isModerator,
isSilenced: isSilenced,
isSuspended: user.isSuspended,
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index b11e091957..431bb4c60a 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -165,9 +165,7 @@ export const paramDef = {
mutedInstances: { type: 'array', items: {
type: 'string',
} },
- mutingNotificationTypes: { type: 'array', items: {
- type: 'string', enum: notificationTypes,
- } },
+ notificationRecieveConfig: { type: 'object' },
emailNotificationTypes: { type: 'array', items: {
type: 'string',
} },
@@ -248,7 +246,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
profileUpdates.enableWordMute = ps.mutedWords.length > 0;
}
if (ps.mutedInstances !== undefined) profileUpdates.mutedInstances = ps.mutedInstances;
- if (ps.mutingNotificationTypes !== undefined) profileUpdates.mutingNotificationTypes = ps.mutingNotificationTypes as typeof notificationTypes[number][];
+ if (ps.notificationRecieveConfig !== undefined) profileUpdates.notificationRecieveConfig = ps.notificationRecieveConfig;
if (typeof ps.isLocked === 'boolean') updates.isLocked = ps.isLocked;
if (typeof ps.isExplorable === 'boolean') updates.isExplorable = ps.isExplorable;
if (typeof ps.hideOnlineStatus === 'boolean') updates.hideOnlineStatus = ps.hideOnlineStatus;
diff --git a/packages/backend/src/server/api/endpoints/notes/create.test.ts b/packages/backend/src/server/api/endpoints/notes/create.test.ts
index 6d34aaccf3..bfb024bcf2 100644
--- a/packages/backend/src/server/api/endpoints/notes/create.test.ts
+++ b/packages/backend/src/server/api/endpoints/notes/create.test.ts
@@ -34,10 +34,11 @@ describe('api:notes/create', () => {
.toBe(VALID);
});
- test('null post', () => {
- expect(v({ text: null }))
- .toBe(INVALID);
- });
+ // TODO
+ //test('null post', () => {
+ // expect(v({ text: null }))
+ // .toBe(INVALID);
+ //});
test('0 characters post', () => {
expect(v({ text: '' }))
diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts
index 2e4d316c47..37a0525e25 100644
--- a/packages/backend/src/server/api/endpoints/notes/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/create.ts
@@ -118,7 +118,7 @@ export const paramDef = {
type: 'string',
minLength: 1,
maxLength: MAX_NOTE_TEXT_LENGTH,
- nullable: false,
+ nullable: true,
},
fileIds: {
type: 'array',
diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts
index 0b3b5c902e..8784e86153 100644
--- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts
@@ -4,6 +4,7 @@
*/
import { Inject, Injectable } from '@nestjs/common';
+import { Brackets } from 'typeorm';
import type { NotesRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { QueryService } from '@/core/QueryService.js';
@@ -40,6 +41,7 @@ export const paramDef = {
properties: {
withFiles: { type: 'boolean', default: false },
withReplies: { type: 'boolean', default: false },
+ withRenotes: { type: 'boolean', default: true },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
@@ -88,6 +90,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (ps.withFiles) {
query.andWhere('note.fileIds != \'{}\'');
}
+
+ if (ps.withRenotes === false) {
+ query.andWhere(new Brackets(qb => {
+ qb.orWhere('note.renoteId IS NULL');
+ qb.orWhere(new Brackets(qb => {
+ qb.orWhere('note.text IS NOT NULL');
+ qb.orWhere('note.fileIds != \'{}\'');
+ }));
+ }));
+ }
//#endregion
const timeline = await query.limit(ps.limit).getMany();
diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts
index e9ae5dc755..9bde5dee21 100644
--- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts
@@ -52,6 +52,7 @@ export const paramDef = {
includeLocalRenotes: { type: 'boolean', default: true },
withFiles: { type: 'boolean', default: false },
withReplies: { type: 'boolean', default: false },
+ withRenotes: { type: 'boolean', default: true },
},
required: [],
} as const;
@@ -137,6 +138,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (ps.withFiles) {
query.andWhere('note.fileIds != \'{}\'');
}
+
+ if (ps.withRenotes === false) {
+ query.andWhere(new Brackets(qb => {
+ qb.orWhere('note.renoteId IS NULL');
+ qb.orWhere(new Brackets(qb => {
+ qb.orWhere('note.text IS NOT NULL');
+ qb.orWhere('note.fileIds != \'{}\'');
+ }));
+ }));
+ }
//#endregion
const timeline = await query.limit(ps.limit).getMany();
diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts
index af1e0398dc..0fefddc51b 100644
--- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts
@@ -42,6 +42,7 @@ export const paramDef = {
properties: {
withFiles: { type: 'boolean', default: false },
withReplies: { type: 'boolean', default: false },
+ withRenotes: { type: 'boolean', default: true },
fileType: { type: 'array', items: {
type: 'string',
} },
@@ -110,6 +111,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
query.andWhere('0 = (SELECT COUNT(*) FROM drive_file df WHERE df.id = ANY(note."fileIds") AND df."isSensitive" = TRUE)');
}
}
+
+ if (ps.withRenotes === false) {
+ query.andWhere(new Brackets(qb => {
+ qb.orWhere('note.renoteId IS NULL');
+ qb.orWhere(new Brackets(qb => {
+ qb.orWhere('note.text IS NOT NULL');
+ qb.orWhere('note.fileIds != \'{}\'');
+ }));
+ }));
+ }
//#endregion
const timeline = await query.limit(ps.limit).getMany();
diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts
index 042115ab84..0d47cc1702 100644
--- a/packages/backend/src/server/api/endpoints/notes/timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts
@@ -42,6 +42,7 @@ export const paramDef = {
includeLocalRenotes: { type: 'boolean', default: true },
withFiles: { type: 'boolean', default: false },
withReplies: { type: 'boolean', default: false },
+ withRenotes: { type: 'boolean', default: true },
},
required: [],
} as const;
@@ -126,6 +127,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (ps.withFiles) {
query.andWhere('note.fileIds != \'{}\'');
}
+
+ if (ps.withRenotes === false) {
+ query.andWhere(new Brackets(qb => {
+ qb.orWhere('note.renoteId IS NULL');
+ qb.orWhere(new Brackets(qb => {
+ qb.orWhere('note.text IS NOT NULL');
+ qb.orWhere('note.fileIds != \'{}\'');
+ }));
+ }));
+ }
//#endregion
const timeline = await query.limit(ps.limit).getMany();
diff --git a/packages/backend/src/server/api/endpoints/notes/update.ts b/packages/backend/src/server/api/endpoints/notes/update.ts
new file mode 100644
index 0000000000..cdf7f085e0
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/notes/update.ts
@@ -0,0 +1,89 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and other misskey contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import ms from 'ms';
+import { Inject, Injectable } from '@nestjs/common';
+import type { UsersRepository, NotesRepository } from '@/models/_.js';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { NoteDeleteService } from '@/core/NoteDeleteService.js';
+import { DI } from '@/di-symbols.js';
+import { GetterService } from '@/server/api/GetterService.js';
+import { GlobalEventService } from '@/core/GlobalEventService.js';
+import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
+import { ApiError } from '../../error.js';
+
+export const meta = {
+ tags: ['notes'],
+
+ requireCredential: true,
+ requireRolePolicy: 'canEditNote',
+
+ kind: 'write:notes',
+
+ limit: {
+ duration: ms('1hour'),
+ max: 10,
+ minInterval: ms('1sec'),
+ },
+
+ errors: {
+ noSuchNote: {
+ message: 'No such note.',
+ code: 'NO_SUCH_NOTE',
+ id: 'a6584e14-6e01-4ad3-b566-851e7bf0d474',
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ noteId: { type: 'string', format: 'misskey:id' },
+ text: {
+ type: 'string',
+ minLength: 1,
+ maxLength: MAX_NOTE_TEXT_LENGTH,
+ nullable: false,
+ },
+ cw: { type: 'string', nullable: true, maxLength: 100 },
+ },
+ required: ['noteId', 'text', 'cw'],
+} as const;
+
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
+ constructor(
+ @Inject(DI.usersRepository)
+ private usersRepository: UsersRepository,
+
+ @Inject(DI.notesRepository)
+ private notesRepository: NotesRepository,
+
+ private getterService: GetterService,
+ private globalEventService: GlobalEventService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const note = await this.getterService.getNote(ps.noteId).catch(err => {
+ if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
+ throw err;
+ });
+
+ if (note.userId !== me.id) {
+ throw new ApiError(meta.errors.noSuchNote);
+ }
+
+ await this.notesRepository.update({ id: note.id }, {
+ updatedAt: new Date(),
+ cw: ps.cw,
+ text: ps.text,
+ });
+
+ this.globalEventService.publishNoteStream(note.id, 'updated', {
+ cw: ps.cw,
+ text: ps.text,
+ });
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts
index 6932073791..c20274b2ba 100644
--- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts
@@ -49,6 +49,8 @@ export const paramDef = {
includeMyRenotes: { type: 'boolean', default: true },
includeRenotedMyNotes: { type: 'boolean', default: true },
includeLocalRenotes: { type: 'boolean', default: true },
+ withReplies: { type: 'boolean', default: false },
+ withRenotes: { type: 'boolean', default: true },
withFiles: {
type: 'boolean',
default: false,
@@ -130,6 +132,20 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}));
}
+ if (!ps.withReplies) {
+ query.andWhere('note.replyId IS NULL');
+ }
+
+ if (ps.withRenotes === false) {
+ query.andWhere(new Brackets(qb => {
+ qb.orWhere('note.renoteId IS NULL');
+ qb.orWhere(new Brackets(qb => {
+ qb.orWhere('note.text IS NOT NULL');
+ qb.orWhere('note.fileIds != \'{}\'');
+ }));
+ }));
+ }
+
if (ps.withFiles) {
query.andWhere('note.fileIds != \'{}\'');
}
diff --git a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts
index fd1bb48a4e..eae55905d3 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts
@@ -144,7 +144,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
try {
- await this.userListService.push(currentUser, userList, me);
+ await this.userListService.addMember(currentUser, userList, me);
} catch (err) {
if (err instanceof UserListService.TooManyUsersError) {
throw new ApiError(meta.errors.tooManyUsers);
diff --git a/packages/backend/src/server/api/endpoints/users/lists/pull.ts b/packages/backend/src/server/api/endpoints/users/lists/pull.ts
index 0b01061740..e90122224c 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/pull.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/pull.ts
@@ -4,12 +4,11 @@
*/
import { Inject, Injectable } from '@nestjs/common';
-import type { UserListsRepository, UserListJoiningsRepository } from '@/models/_.js';
+import type { UserListsRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
-import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { GetterService } from '@/server/api/GetterService.js';
-import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js';
+import { UserListService } from '@/core/UserListService.js';
import { ApiError } from '../../../error.js';
export const meta = {
@@ -53,12 +52,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.userListsRepository)
private userListsRepository: UserListsRepository,
- @Inject(DI.userListJoiningsRepository)
- private userListJoiningsRepository: UserListJoiningsRepository,
-
- private userEntityService: UserEntityService,
+ private userListService: UserListService,
private getterService: GetterService,
- private globalEventService: GlobalEventService,
) {
super(meta, paramDef, async (ps, me) => {
// Fetch the list
@@ -77,10 +72,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw err;
});
- // Pull the user
- await this.userListJoiningsRepository.delete({ userListId: userList.id, userId: user.id });
-
- this.globalEventService.publishUserListStream(userList.id, 'userRemoved', await this.userEntityService.pack(user));
+ await this.userListService.removeMember(user, userList);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/users/lists/push.ts b/packages/backend/src/server/api/endpoints/users/lists/push.ts
index 9bb1a71f58..72a6a7380d 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/push.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/push.ts
@@ -127,7 +127,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
try {
- await this.userListService.push(user, userList, me);
+ await this.userListService.addMember(user, userList, me);
} catch (err) {
if (err instanceof UserListService.TooManyUsersError) {
throw new ApiError(meta.errors.tooManyUsers);
diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts
index 5934baef47..e660a0bb25 100644
--- a/packages/backend/src/server/api/endpoints/users/notes.ts
+++ b/packages/backend/src/server/api/endpoints/users/notes.ts
@@ -41,7 +41,8 @@ export const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
- includeReplies: { type: 'boolean', default: true },
+ withReplies: { type: 'boolean', default: false },
+ withRenotes: { type: 'boolean', default: true },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
@@ -114,10 +115,20 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
}
- if (!ps.includeReplies) {
+ if (!ps.withReplies) {
query.andWhere('note.replyId IS NULL');
}
+ if (ps.withRenotes === false) {
+ query.andWhere(new Brackets(qb => {
+ qb.orWhere('note.renoteId IS NULL');
+ qb.orWhere(new Brackets(qb => {
+ qb.orWhere('note.text IS NOT NULL');
+ qb.orWhere('note.fileIds != \'{}\'');
+ }));
+ }));
+ }
+
if (ps.includeMyRenotes === false) {
query.andWhere(new Brackets(qb => {
qb.orWhere('note.userId != :userId', { userId: user.id });
diff --git a/packages/backend/src/server/api/stream/Connection.ts b/packages/backend/src/server/api/stream/Connection.ts
index fd91681fc1..a73071ea99 100644
--- a/packages/backend/src/server/api/stream/Connection.ts
+++ b/packages/backend/src/server/api/stream/Connection.ts
@@ -12,10 +12,10 @@ import type { NotificationService } from '@/core/NotificationService.js';
import { bindThis } from '@/decorators.js';
import { CacheService } from '@/core/CacheService.js';
import { MiUserProfile } from '@/models/_.js';
+import type { StreamEventEmitter, GlobalEvents } from '@/core/GlobalEventService.js';
import type { ChannelsService } from './ChannelsService.js';
import type { EventEmitter } from 'events';
import type Channel from './channel.js';
-import type { StreamEventEmitter, StreamMessages } from './types.js';
/**
* Main stream connection
@@ -122,7 +122,7 @@ export default class Connection {
}
@bindThis
- private onBroadcastMessage(data: StreamMessages['broadcast']['payload']) {
+ private onBroadcastMessage(data: GlobalEvents['broadcast']['payload']) {
this.sendMessageToWs(data.type, data.body);
}
@@ -196,7 +196,7 @@ export default class Connection {
}
@bindThis
- private async onNoteStreamMessage(data: StreamMessages['note']['payload']) {
+ private async onNoteStreamMessage(data: GlobalEvents['note']['payload']) {
this.sendMessageToWs('noteUpdated', {
id: data.body.id,
type: data.type,
diff --git a/packages/backend/src/server/api/stream/channels/antenna.ts b/packages/backend/src/server/api/stream/channels/antenna.ts
index 87648a3a77..a48e6ba5c6 100644
--- a/packages/backend/src/server/api/stream/channels/antenna.ts
+++ b/packages/backend/src/server/api/stream/channels/antenna.ts
@@ -7,8 +7,8 @@ import { Injectable } from '@nestjs/common';
import { isUserRelated } from '@/misc/is-user-related.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
+import type { GlobalEvents } from '@/core/GlobalEventService.js';
import Channel from '../channel.js';
-import type { StreamMessages } from '../types.js';
class AntennaChannel extends Channel {
public readonly chName = 'antenna';
@@ -35,7 +35,7 @@ class AntennaChannel extends Channel {
}
@bindThis
- private async onEvent(data: StreamMessages['antenna']['payload']) {
+ private async onEvent(data: GlobalEvents['antenna']['payload']) {
if (data.type === 'note') {
const note = await this.noteEntityService.pack(data.body.id, this.user, { detail: true });
diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts
index a33f1a956a..fef52b6856 100644
--- a/packages/backend/src/server/api/stream/channels/global-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts
@@ -19,6 +19,7 @@ class GlobalTimelineChannel extends Channel {
public static shouldShare = true;
public static requireCredential = false;
private withReplies: boolean;
+ private withRenotes: boolean;
constructor(
private metaService: MetaService,
@@ -37,7 +38,8 @@ class GlobalTimelineChannel extends Channel {
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
if (!policies.gtlAvailable) return;
- this.withReplies = params.withReplies as boolean;
+ this.withReplies = params.withReplies ?? false;
+ this.withRenotes = params.withRenotes ?? true;
// Subscribe events
this.subscriber.on('notesStream', this.onNote);
@@ -68,6 +70,8 @@ class GlobalTimelineChannel extends Channel {
if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return;
}
+ if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return;
+
// Ignore notes from instances the user has muted
if (isInstanceMuted(note, new Set<string>(this.userProfile?.mutedInstances ?? []))) return;
diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts
index bd8888f679..198c68e1c2 100644
--- a/packages/backend/src/server/api/stream/channels/home-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts
@@ -17,6 +17,7 @@ class HomeTimelineChannel extends Channel {
public static shouldShare = true;
public static requireCredential = true;
private withReplies: boolean;
+ private withRenotes: boolean;
constructor(
private noteEntityService: NoteEntityService,
@@ -30,7 +31,8 @@ class HomeTimelineChannel extends Channel {
@bindThis
public async init(params: any) {
- this.withReplies = params.withReplies as boolean;
+ this.withReplies = params.withReplies ?? false;
+ this.withRenotes = params.withRenotes ?? true;
this.subscriber.on('notesStream', this.onNote);
}
@@ -77,6 +79,8 @@ class HomeTimelineChannel extends Channel {
if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return;
}
+ if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return;
+
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts
index 760fb8d19f..cde4297478 100644
--- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts
@@ -19,6 +19,7 @@ class HybridTimelineChannel extends Channel {
public static shouldShare = true;
public static requireCredential = true;
private withReplies: boolean;
+ private withRenotes: boolean;
constructor(
private metaService: MetaService,
@@ -37,7 +38,8 @@ class HybridTimelineChannel extends Channel {
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
if (!policies.ltlAvailable) return;
- this.withReplies = params.withReplies as boolean;
+ this.withReplies = params.withReplies ?? false;
+ this.withRenotes = params.withRenotes ?? true;
// Subscribe events
this.subscriber.on('notesStream', this.onNote);
@@ -89,6 +91,8 @@ class HybridTimelineChannel extends Channel {
if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return;
}
+ if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return;
+
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts
index f32f8c5cec..ef708c4fee 100644
--- a/packages/backend/src/server/api/stream/channels/local-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts
@@ -18,6 +18,7 @@ class LocalTimelineChannel extends Channel {
public static shouldShare = true;
public static requireCredential = false;
private withReplies: boolean;
+ private withRenotes: boolean;
constructor(
private metaService: MetaService,
@@ -36,7 +37,8 @@ class LocalTimelineChannel extends Channel {
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
if (!policies.ltlAvailable) return;
- this.withReplies = params.withReplies as boolean;
+ this.withReplies = params.withReplies ?? false;
+ this.withRenotes = params.withRenotes ?? true;
// Subscribe events
this.subscriber.on('notesStream', this.onNote);
@@ -68,6 +70,8 @@ class LocalTimelineChannel extends Channel {
if (reply.userId !== this.user.id && note.userId !== this.user.id && reply.userId !== note.userId) return;
}
+ if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return;
+
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
diff --git a/packages/backend/src/server/api/stream/channels/role-timeline.ts b/packages/backend/src/server/api/stream/channels/role-timeline.ts
index 76b5875343..38d3604cc5 100644
--- a/packages/backend/src/server/api/stream/channels/role-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/role-timeline.ts
@@ -9,8 +9,8 @@ import type { Packed } from '@/misc/json-schema.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
+import type { GlobalEvents } from '@/core/GlobalEventService.js';
import Channel from '../channel.js';
-import { StreamMessages } from '../types.js';
class RoleTimelineChannel extends Channel {
public readonly chName = 'roleTimeline';
@@ -37,7 +37,7 @@ class RoleTimelineChannel extends Channel {
}
@bindThis
- private async onEvent(data: StreamMessages['roleTimeline']['payload']) {
+ private async onEvent(data: GlobalEvents['roleTimeline']['payload']) {
if (data.type === 'note') {
const note = data.body;
diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts
deleted file mode 100644
index 90e0a61f26..0000000000
--- a/packages/backend/src/server/api/stream/types.ts
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and other misskey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import type { MiChannel } from '@/models/Channel.js';
-import type { MiUser } from '@/models/User.js';
-import type { MiUserProfile } from '@/models/UserProfile.js';
-import type { MiNote } from '@/models/Note.js';
-import type { MiAntenna } from '@/models/Antenna.js';
-import type { MiDriveFile } from '@/models/DriveFile.js';
-import type { MiDriveFolder } from '@/models/DriveFolder.js';
-import type { MiUserList } from '@/models/UserList.js';
-import type { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
-import type { MiSignin } from '@/models/Signin.js';
-import type { MiPage } from '@/models/Page.js';
-import type { Packed } from '@/misc/json-schema.js';
-import type { MiWebhook } from '@/models/Webhook.js';
-import type { MiMeta } from '@/models/Meta.js';
-import { MiRole, MiRoleAssignment } from '@/models/_.js';
-import type Emitter from 'strict-event-emitter-types';
-import type { EventEmitter } from 'events';
-
-//#region Stream type-body definitions
-export interface InternalStreamTypes {
- userChangeSuspendedState: { id: MiUser['id']; isSuspended: MiUser['isSuspended']; };
- userTokenRegenerated: { id: MiUser['id']; oldToken: string; newToken: string; };
- remoteUserUpdated: { id: MiUser['id']; };
- follow: { followerId: MiUser['id']; followeeId: MiUser['id']; };
- unfollow: { followerId: MiUser['id']; followeeId: MiUser['id']; };
- blockingCreated: { blockerId: MiUser['id']; blockeeId: MiUser['id']; };
- blockingDeleted: { blockerId: MiUser['id']; blockeeId: MiUser['id']; };
- policiesUpdated: MiRole['policies'];
- roleCreated: MiRole;
- roleDeleted: MiRole;
- roleUpdated: MiRole;
- userRoleAssigned: MiRoleAssignment;
- userRoleUnassigned: MiRoleAssignment;
- webhookCreated: MiWebhook;
- webhookDeleted: MiWebhook;
- webhookUpdated: MiWebhook;
- antennaCreated: MiAntenna;
- antennaDeleted: MiAntenna;
- antennaUpdated: MiAntenna;
- metaUpdated: MiMeta;
- followChannel: { userId: MiUser['id']; channelId: MiChannel['id']; };
- unfollowChannel: { userId: MiUser['id']; channelId: MiChannel['id']; };
- updateUserProfile: MiUserProfile;
- mute: { muterId: MiUser['id']; muteeId: MiUser['id']; };
- unmute: { muterId: MiUser['id']; muteeId: MiUser['id']; };
-}
-
-export interface BroadcastTypes {
- emojiAdded: {
- emoji: Packed<'EmojiDetailed'>;
- };
- emojiUpdated: {
- emojis: Packed<'EmojiDetailed'>[];
- };
- emojiDeleted: {
- emojis: {
- id?: string;
- name: string;
- [other: string]: any;
- }[];
- };
- announcementCreated: {
- announcement: Packed<'Announcement'>;
- };
-}
-
-export interface MainStreamTypes {
- notification: Packed<'Notification'>;
- mention: Packed<'Note'>;
- reply: Packed<'Note'>;
- renote: Packed<'Note'>;
- follow: Packed<'UserDetailedNotMe'>;
- followed: Packed<'User'>;
- unfollow: Packed<'User'>;
- meUpdated: Packed<'User'>;
- pageEvent: {
- pageId: MiPage['id'];
- event: string;
- var: any;
- userId: MiUser['id'];
- user: Packed<'User'>;
- };
- urlUploadFinished: {
- marker?: string | null;
- file: Packed<'DriveFile'>;
- };
- readAllNotifications: undefined;
- unreadNotification: Packed<'Notification'>;
- unreadMention: MiNote['id'];
- readAllUnreadMentions: undefined;
- unreadSpecifiedNote: MiNote['id'];
- readAllUnreadSpecifiedNotes: undefined;
- readAllAntennas: undefined;
- unreadAntenna: MiAntenna;
- readAllAnnouncements: undefined;
- myTokenRegenerated: undefined;
- signin: MiSignin;
- registryUpdated: {
- scope?: string[];
- key: string;
- value: any | null;
- };
- driveFileCreated: Packed<'DriveFile'>;
- readAntenna: MiAntenna;
- receiveFollowRequest: Packed<'User'>;
- announcementCreated: {
- announcement: Packed<'Announcement'>;
- };
-}
-
-export interface DriveStreamTypes {
- fileCreated: Packed<'DriveFile'>;
- fileDeleted: MiDriveFile['id'];
- fileUpdated: Packed<'DriveFile'>;
- folderCreated: Packed<'DriveFolder'>;
- folderDeleted: MiDriveFolder['id'];
- folderUpdated: Packed<'DriveFolder'>;
-}
-
-export interface NoteStreamTypes {
- pollVoted: {
- choice: number;
- userId: MiUser['id'];
- };
- deleted: {
- deletedAt: Date;
- };
- reacted: {
- reaction: string;
- emoji?: {
- name: string;
- url: string;
- } | null;
- userId: MiUser['id'];
- };
- unreacted: {
- reaction: string;
- userId: MiUser['id'];
- };
-}
-type NoteStreamEventTypes = {
- [key in keyof NoteStreamTypes]: {
- id: MiNote['id'];
- body: NoteStreamTypes[key];
- };
-};
-
-export interface UserListStreamTypes {
- userAdded: Packed<'User'>;
- userRemoved: Packed<'User'>;
-}
-
-export interface AntennaStreamTypes {
- note: MiNote;
-}
-
-export interface RoleTimelineStreamTypes {
- note: Packed<'Note'>;
-}
-
-export interface AdminStreamTypes {
- newAbuseUserReport: {
- id: MiAbuseUserReport['id'];
- targetUserId: MiUser['id'],
- reporterId: MiUser['id'],
- comment: string;
- };
-}
-//#endregion
-
-// 辞書(interface or type)から{ type, body }ユニオンを定義
-// https://stackoverflow.com/questions/49311989/can-i-infer-the-type-of-a-value-using-extends-keyof-type
-// VS Codeの展開を防止するためにEvents型を定義
-type Events<T extends object> = { [K in keyof T]: { type: K; body: T[K]; } };
-type EventUnionFromDictionary<
- T extends object,
- U = Events<T>
-> = U[keyof U];
-
-// redis通すとDateのインスタンスはstringに変換されるので
-export type Serialized<T> = {
- [K in keyof T]:
- T[K] extends Date
- ? string
- : T[K] extends (Date | null)
- ? (string | null)
- : T[K] extends Record<string, any>
- ? Serialized<T[K]>
- : T[K];
-};
-
-type SerializedAll<T> = {
- [K in keyof T]: Serialized<T[K]>;
-};
-
-// name/messages(spec) pairs dictionary
-export type StreamMessages = {
- internal: {
- name: 'internal';
- payload: EventUnionFromDictionary<SerializedAll<InternalStreamTypes>>;
- };
- broadcast: {
- name: 'broadcast';
- payload: EventUnionFromDictionary<SerializedAll<BroadcastTypes>>;
- };
- main: {
- name: `mainStream:${MiUser['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<MainStreamTypes>>;
- };
- drive: {
- name: `driveStream:${MiUser['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<DriveStreamTypes>>;
- };
- note: {
- name: `noteStream:${MiNote['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<NoteStreamEventTypes>>;
- };
- userList: {
- name: `userListStream:${MiUserList['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<UserListStreamTypes>>;
- };
- roleTimeline: {
- name: `roleTimelineStream:${MiRole['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<RoleTimelineStreamTypes>>;
- };
- antenna: {
- name: `antennaStream:${MiAntenna['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<AntennaStreamTypes>>;
- };
- admin: {
- name: `adminStream:${MiUser['id']}`;
- payload: EventUnionFromDictionary<SerializedAll<AdminStreamTypes>>;
- };
- notes: {
- name: 'notesStream';
- payload: Serialized<Packed<'Note'>>;
- };
-};
-
-// API event definitions
-// ストリームごとのEmitterの辞書を用意
-type EventEmitterDictionary = { [x in keyof StreamMessages]: Emitter.default<EventEmitter, { [y in StreamMessages[x]['name']]: (e: StreamMessages[x]['payload']) => void }> };
-// 共用体型を交差型にする型 https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection
-type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
-// Emitter辞書から共用体型を作り、UnionToIntersectionで交差型にする
-export type StreamEventEmitter = UnionToIntersection<EventEmitterDictionary[keyof StreamMessages]>;
-// { [y in name]: (e: spec) => void }をまとめてその交差型をEmitterにかけるとts(2590)にひっかかる
-
-// provide stream channels union
-export type StreamChannels = StreamMessages[keyof StreamMessages]['name'];
diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index 1faff24201..5c13c2c870 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -188,7 +188,7 @@ export class ClientServerService {
// Authenticate
fastify.addHook('onRequest', async (request, reply) => {
// %71ueueとかでリクエストされたら困るため
- const url = decodeURI(request.url);
+ const url = decodeURI(request.routerPath);
if (url === bullBoardPath || url.startsWith(bullBoardPath + '/')) {
const token = request.cookies.token;
if (token == null) {
@@ -728,8 +728,8 @@ export class ClientServerService {
fastify.setErrorHandler(async (error, request, reply) => {
const errId = randomUUID();
- this.clientLoggerService.logger.error(`Internal error occurred in ${request.routerPath}: ${error.message}`, {
- path: request.routerPath,
+ this.clientLoggerService.logger.error(`Internal error occurred in ${request.routeOptions.url}: ${error.message}`, {
+ path: request.routeOptions.url,
params: request.params,
query: request.query,
code: error.name,
diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug
index 71bcf9462f..9b6c671cad 100644
--- a/packages/backend/src/server/web/views/base.pug
+++ b/packages/backend/src/server/web/views/base.pug
@@ -35,7 +35,7 @@ html
link(rel='prefetch' href=infoImageUrl)
link(rel='prefetch' href=notFoundImageUrl)
//- https://github.com/misskey-dev/misskey/issues/9842
- link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css?v2.35.0')
+ link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css?v2.37.0')
link(rel='modulepreload' href=`/vite/${clientEntry.file}`)
if !config.clientManifestExists