mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-05-02 01:36:03 +02:00
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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
try {
|
||||
let eyeCatchingImage: MiDriveFile | null | undefined | string = ps.eyeCatchingImageId;
|
||||
if (eyeCatchingImage != null) {
|
||||
eyeCatchingImage = await this.driveFilesRepository.findOneBy({
|
||||
id: eyeCatchingImage,
|
||||
userId: me.id,
|
||||
});
|
||||
|
||||
if (ps.eyeCatchingImageId != null) {
|
||||
const eyeCatchingImage = await this.driveFilesRepository.findOneBy({
|
||||
id: ps.eyeCatchingImageId,
|
||||
userId: me.id,
|
||||
});
|
||||
|
||||
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);
|
||||
if (eyeCatchingImage == null) {
|
||||
throw new ApiError(meta.errors.noSuchFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user