summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/endpoints/notes
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/server/api/endpoints/notes')
-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
8 files changed, 156 insertions, 5 deletions
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 != \'{}\'');
}