summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/endpoints
diff options
context:
space:
mode:
authoranatawa12 <anatawa12@icloud.com>2025-08-15 22:39:55 +0900
committerGitHub <noreply@github.com>2025-08-15 22:39:55 +0900
commit60f7278aff27b9a0e03c1f1a2a77663cfb0e0ddb (patch)
tree76d9f4e99144879566c5d39da7de7bd7f11a7668 /packages/backend/src/server/api/endpoints
parentenhance(frontend): improve enableInfiniteScroll stability (diff)
downloadmisskey-60f7278aff27b9a0e03c1f1a2a77663cfb0e0ddb.tar.gz
misskey-60f7278aff27b9a0e03c1f1a2a77663cfb0e0ddb.tar.bz2
misskey-60f7278aff27b9a0e03c1f1a2a77663cfb0e0ddb.zip
fix: Remote Note Cleaning will delete notes embedded in a page (#16408)
* feat: preserve number of pages referencing the note * chore: delete pages on account delete * fix: notes on the pages are removed by CleanRemoteNotes * test: add the simplest test for page embedded notes * fix: section block is not considered * fix: section block is not considered in migration * chore: remove comments from columns * revert unnecessary change * add pageCount to webhook test * fix type error on backend
Diffstat (limited to 'packages/backend/src/server/api/endpoints')
-rw-r--r--packages/backend/src/server/api/endpoints/pages/create.ts41
-rw-r--r--packages/backend/src/server/api/endpoints/pages/delete.ts41
-rw-r--r--packages/backend/src/server/api/endpoints/pages/update.ts69
3 files changed, 56 insertions, 95 deletions
diff --git a/packages/backend/src/server/api/endpoints/pages/create.ts b/packages/backend/src/server/api/endpoints/pages/create.ts
index 6de5fe3d44..96bc2a953a 100644
--- a/packages/backend/src/server/api/endpoints/pages/create.ts
+++ b/packages/backend/src/server/api/endpoints/pages/create.ts
@@ -5,12 +5,13 @@
import ms from 'ms';
import { Inject, Injectable } from '@nestjs/common';
-import type { DriveFilesRepository, PagesRepository } from '@/models/_.js';
-import { IdService } from '@/core/IdService.js';
-import { MiPage, pageNameSchema } from '@/models/Page.js';
+import type { DriveFilesRepository, MiDriveFile, PagesRepository } from '@/models/_.js';
+import { pageNameSchema } from '@/models/Page.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { PageEntityService } from '@/core/entities/PageEntityService.js';
import { DI } from '@/di-symbols.js';
+import { PageService } from '@/core/PageService.js';
+import { IdentifiableError } from '@/misc/identifiable-error.js';
import { ApiError } from '../../error.js';
export const meta = {
@@ -77,11 +78,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
+ private pageService: PageService,
private pageEntityService: PageEntityService,
- private idService: IdService,
) {
super(meta, paramDef, async (ps, me) => {
- let eyeCatchingImage = null;
+ let eyeCatchingImage: MiDriveFile | null = null;
if (ps.eyeCatchingImageId != null) {
eyeCatchingImage = await this.driveFilesRepository.findOneBy({
id: ps.eyeCatchingImageId,
@@ -102,24 +103,20 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
});
- const page = await this.pagesRepository.insertOne(new MiPage({
- id: this.idService.gen(),
- updatedAt: new Date(),
- title: ps.title,
- name: ps.name,
- summary: ps.summary,
- content: ps.content,
- variables: ps.variables,
- script: ps.script,
- eyeCatchingImageId: eyeCatchingImage ? eyeCatchingImage.id : null,
- userId: me.id,
- visibility: 'public',
- alignCenter: ps.alignCenter,
- hideTitleWhenPinned: ps.hideTitleWhenPinned,
- font: ps.font,
- }));
+ try {
+ const page = await this.pageService.create(me, {
+ ...ps,
+ eyeCatchingImage,
+ summary: ps.summary ?? null,
+ });
- return await this.pageEntityService.pack(page);
+ return await this.pageEntityService.pack(page);
+ } catch (err) {
+ if (err instanceof IdentifiableError && err.id === '1a79e38e-3d83-4423-845b-a9d83ff93b61') {
+ throw new ApiError(meta.errors.nameAlreadyExists);
+ }
+ throw err;
+ }
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/pages/delete.ts b/packages/backend/src/server/api/endpoints/pages/delete.ts
index f2bc946788..a33868552d 100644
--- a/packages/backend/src/server/api/endpoints/pages/delete.ts
+++ b/packages/backend/src/server/api/endpoints/pages/delete.ts
@@ -4,12 +4,14 @@
*/
import { Inject, Injectable } from '@nestjs/common';
-import type { PagesRepository, UsersRepository } from '@/models/_.js';
+import type { MiDriveFile, PagesRepository, UsersRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../error.js';
+import { IdentifiableError } from '@/misc/identifiable-error.js';
+import { PageService } from '@/core/PageService.js';
export const meta = {
tags: ['pages'],
@@ -44,36 +46,17 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
- @Inject(DI.pagesRepository)
- private pagesRepository: PagesRepository,
-
- @Inject(DI.usersRepository)
- private usersRepository: UsersRepository,
-
- private moderationLogService: ModerationLogService,
- private roleService: RoleService,
+ private pageService: PageService,
) {
super(meta, paramDef, async (ps, me) => {
- const page = await this.pagesRepository.findOneBy({ id: ps.pageId });
-
- if (page == null) {
- throw new ApiError(meta.errors.noSuchPage);
- }
-
- if (!await this.roleService.isModerator(me) && page.userId !== me.id) {
- throw new ApiError(meta.errors.accessDenied);
- }
-
- await this.pagesRepository.delete(page.id);
-
- if (page.userId !== me.id) {
- const user = await this.usersRepository.findOneByOrFail({ id: page.userId });
- this.moderationLogService.log(me, 'deletePage', {
- pageId: page.id,
- pageUserId: page.userId,
- pageUserUsername: user.username,
- page,
- });
+ try {
+ await this.pageService.delete(me, ps.pageId);
+ } catch (err) {
+ if (err instanceof IdentifiableError) {
+ if (err.id === '66aefd3c-fdb2-4a71-85ae-cc18bea85d3f') throw new ApiError(meta.errors.noSuchPage);
+ if (err.id === 'd0017699-8256-46f1-aed4-bc03bed73616') throw new ApiError(meta.errors.accessDenied);
+ }
+ throw err;
}
});
}
diff --git a/packages/backend/src/server/api/endpoints/pages/update.ts b/packages/backend/src/server/api/endpoints/pages/update.ts
index a6aeb6002e..6fa5c1d75c 100644
--- a/packages/backend/src/server/api/endpoints/pages/update.ts
+++ b/packages/backend/src/server/api/endpoints/pages/update.ts
@@ -4,13 +4,14 @@
*/
import ms from 'ms';
-import { Not } from 'typeorm';
import { Inject, Injectable } from '@nestjs/common';
-import type { PagesRepository, DriveFilesRepository } from '@/models/_.js';
+import type { DriveFilesRepository, MiDriveFile } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { pageNameSchema } from '@/models/Page.js';
+import { IdentifiableError } from '@/misc/identifiable-error.js';
+import { PageService } from '@/core/PageService.js';
export const meta = {
tags: ['pages'],
@@ -75,57 +76,37 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
- @Inject(DI.pagesRepository)
- private pagesRepository: PagesRepository,
-
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
+
+ private pageService: PageService,
) {
super(meta, paramDef, async (ps, me) => {
- const page = await this.pagesRepository.findOneBy({ id: ps.pageId });
- if (page == null) {
- throw new ApiError(meta.errors.noSuchPage);
- }
- if (page.userId !== me.id) {
- throw new ApiError(meta.errors.accessDenied);
- }
-
- if (ps.eyeCatchingImageId != null) {
- const eyeCatchingImage = await this.driveFilesRepository.findOneBy({
- id: ps.eyeCatchingImageId,
- userId: me.id,
- });
+ try {
+ let eyeCatchingImage: MiDriveFile | null | undefined | string = ps.eyeCatchingImageId;
+ if (eyeCatchingImage != null) {
+ eyeCatchingImage = await this.driveFilesRepository.findOneBy({
+ id: eyeCatchingImage,
+ userId: me.id,
+ });
- if (eyeCatchingImage == null) {
- throw new ApiError(meta.errors.noSuchFile);
+ if (eyeCatchingImage == null) {
+ throw new ApiError(meta.errors.noSuchFile);
+ }
}
- }
- if (ps.name != null) {
- await this.pagesRepository.findBy({
- id: Not(ps.pageId),
- userId: me.id,
- name: ps.name,
- }).then(result => {
- if (result.length > 0) {
- throw new ApiError(meta.errors.nameAlreadyExists);
- }
+ await this.pageService.update(me, ps.pageId, {
+ ...ps,
+ eyeCatchingImage,
});
+ } catch (err) {
+ if (err instanceof IdentifiableError) {
+ if (err.id === '66aefd3c-fdb2-4a71-85ae-cc18bea85d3f') throw new ApiError(meta.errors.noSuchPage);
+ if (err.id === 'd0017699-8256-46f1-aed4-bc03bed73616') throw new ApiError(meta.errors.accessDenied);
+ if (err.id === 'd05bfe24-24b6-4ea2-a3ec-87cc9bf4daa4') throw new ApiError(meta.errors.nameAlreadyExists);
+ }
+ throw err;
}
-
- await this.pagesRepository.update(page.id, {
- updatedAt: new Date(),
- title: ps.title,
- name: ps.name,
- summary: ps.summary === undefined ? page.summary : ps.summary,
- content: ps.content,
- variables: ps.variables,
- script: ps.script,
- alignCenter: ps.alignCenter,
- hideTitleWhenPinned: ps.hideTitleWhenPinned,
- font: ps.font,
- eyeCatchingImageId: ps.eyeCatchingImageId,
- });
});
}
}