enhance(sensitive-flag):センシティブフラグの機能の強化 (MisskeyIO#936)
This commit is contained in:
parent
7a94724098
commit
abdaa18666
18 changed files with 197 additions and 20 deletions
13
packages/backend/migration/1739335129758-sensitiveFlag.js
Normal file
13
packages/backend/migration/1739335129758-sensitiveFlag.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
export class SensitiveFlag1739335129758 {
|
||||
name = 'SensitiveFlag1739335129758'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "drive_file" ADD "isSensitiveByModerator" boolean NOT NULL DEFAULT false`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e779d1afdfa44dc3d64213cd2e" ON "drive_file" ("isSensitiveByModerator") `);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_e779d1afdfa44dc3d64213cd2e"`);
|
||||
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "isSensitiveByModerator"`);
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@ import { correctFilename } from '@/misc/correct-filename.js';
|
|||
import { isMimeImage } from '@/misc/is-mime-image.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
import { NotificationService } from '@/core/NotificationService.js';
|
||||
|
||||
type AddFileArgs = {
|
||||
/** User who wish to add file */
|
||||
|
@ -129,6 +130,7 @@ export class DriveService {
|
|||
private driveChart: DriveChart,
|
||||
private perUserDriveChart: PerUserDriveChart,
|
||||
private instanceChart: InstanceChart,
|
||||
private notificationService: NotificationService,
|
||||
) {
|
||||
const logger = this.loggerService.getLogger('drive', 'blue');
|
||||
this.registerLogger = logger.createSubLogger('register', 'yellow');
|
||||
|
@ -664,13 +666,15 @@ export class DriveService {
|
|||
@bindThis
|
||||
public async updateFile(file: MiDriveFile, values: Partial<MiDriveFile>, updater: MiUser) {
|
||||
const alwaysMarkNsfw = (await this.roleService.getUserPolicies(file.userId)).alwaysMarkNsfw;
|
||||
const isModerator = await this.roleService.isModerator(updater);
|
||||
|
||||
if (values.name != null && !this.driveFileEntityService.validateFileName(values.name)) {
|
||||
throw new DriveService.InvalidFileNameError();
|
||||
}
|
||||
|
||||
if (values.isSensitive !== undefined && values.isSensitive !== file.isSensitive && alwaysMarkNsfw && !values.isSensitive) {
|
||||
throw new DriveService.CannotUnmarkSensitiveError();
|
||||
if (values.isSensitive !== undefined && values.isSensitive !== file.isSensitive && !values.isSensitive) {
|
||||
if (alwaysMarkNsfw) throw new DriveService.CannotUnmarkSensitiveError();
|
||||
if (file.isSensitiveByModerator && (file.userId === updater.id)) throw new DriveService.CannotUnmarkSensitiveError();
|
||||
}
|
||||
|
||||
if (values.folderId != null) {
|
||||
|
@ -684,6 +688,10 @@ export class DriveService {
|
|||
}
|
||||
}
|
||||
|
||||
if (isModerator && file.userId !== updater.id) {
|
||||
values.isSensitiveByModerator = values.isSensitive;
|
||||
}
|
||||
|
||||
await this.driveFilesRepository.update(file.id, values);
|
||||
|
||||
const fileObj = await this.driveFileEntityService.pack(file.id, updater, { self: true });
|
||||
|
@ -693,7 +701,7 @@ export class DriveService {
|
|||
this.globalEventService.publishDriveStream(file.userId, 'fileUpdated', fileObj);
|
||||
}
|
||||
|
||||
if (await this.roleService.isModerator(updater) && (file.userId !== updater.id)) {
|
||||
if (isModerator && (file.userId !== updater.id)) {
|
||||
if (values.isSensitive !== undefined && values.isSensitive !== file.isSensitive) {
|
||||
const user = file.userId ? await this.usersRepository.findOneByOrFail({ id: file.userId }) : null;
|
||||
if (values.isSensitive) {
|
||||
|
@ -703,6 +711,11 @@ export class DriveService {
|
|||
fileUserUsername: user?.username ?? null,
|
||||
fileUserHost: user?.host ?? null,
|
||||
});
|
||||
if (file.userId) {
|
||||
this.notificationService.createNotification(file.userId, 'sensitiveFlagAssigned', {
|
||||
fileId: file.id,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.moderationLogService.log(updater, 'unmarkSensitiveDriveFile', {
|
||||
fileId: file.id,
|
||||
|
|
|
@ -210,6 +210,9 @@ export class DriveFileEntityService {
|
|||
md5: file.md5,
|
||||
size: file.size,
|
||||
isSensitive: file.isSensitive,
|
||||
...(opts.detail ? {
|
||||
isSensitiveByModerator: file.isSensitiveByModerator,
|
||||
} : {}),
|
||||
blurhash: file.blurhash,
|
||||
properties: opts.self ? file.properties : this.getPublicProperties(file),
|
||||
url: opts.self ? file.url : this.getPublicUrl(file),
|
||||
|
@ -246,6 +249,9 @@ export class DriveFileEntityService {
|
|||
md5: file.md5,
|
||||
size: file.size,
|
||||
isSensitive: file.isSensitive,
|
||||
...(opts.detail ? {
|
||||
isSensitiveByModerator: file.isSensitiveByModerator,
|
||||
} : {}),
|
||||
blurhash: file.blurhash,
|
||||
properties: opts.self ? file.properties : this.getPublicProperties(file),
|
||||
url: opts.self ? file.url : this.getPublicUrl(file),
|
||||
|
|
|
@ -183,6 +183,9 @@ export class NotificationEntityService implements OnModuleInit {
|
|||
header: notification.customHeader,
|
||||
icon: notification.customIcon,
|
||||
} : {}),
|
||||
...(notification.type === 'sensitiveFlagAssigned' ? {
|
||||
fileId: notification.fileId,
|
||||
} : {}),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -162,6 +162,12 @@ export class MiDriveFile {
|
|||
})
|
||||
public isSensitive: boolean;
|
||||
|
||||
@Index()
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public isSensitiveByModerator: boolean;
|
||||
|
||||
@Index()
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
|
|
|
@ -93,6 +93,11 @@ export type MiNotification = {
|
|||
id: string;
|
||||
createdAt: string;
|
||||
draftId: MiScheduledNote['id'];
|
||||
} | {
|
||||
type: 'sensitiveFlagAssigned'
|
||||
id: string;
|
||||
fileId: string;
|
||||
createdAt: string;
|
||||
} | {
|
||||
type: 'app';
|
||||
id: string;
|
||||
|
|
|
@ -42,6 +42,10 @@ export const packedDriveFileSchema = {
|
|||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
isSensitiveByModerator: {
|
||||
type: 'boolean',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
blurhash: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
|
|
|
@ -309,8 +309,8 @@ export const packedNotificationSchema = {
|
|||
type: 'object',
|
||||
ref: 'NoteDraft',
|
||||
optional: false, nullable: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
@ -324,8 +324,8 @@ export const packedNotificationSchema = {
|
|||
type: 'object',
|
||||
ref: 'Note',
|
||||
optional: false, nullable: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
@ -339,8 +339,21 @@ export const packedNotificationSchema = {
|
|||
type: 'object',
|
||||
ref: 'NoteDraft',
|
||||
optional: false, nullable: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['sensitiveFlagAssigned'],
|
||||
},
|
||||
fileId: {
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
|
|
@ -51,6 +51,12 @@ export const meta = {
|
|||
code: 'RESTRICTED_BY_ROLE',
|
||||
id: '7f59dccb-f465-75ab-5cf4-3ce44e3282f7',
|
||||
},
|
||||
|
||||
restrictedByModerator: {
|
||||
message: 'The isSensitive specified by the administrator cannot be changed.',
|
||||
code: 'RESTRICTED_BY_ADMINISTRATOR',
|
||||
id: '20e6c501-e579-400d-97e4-1c7efc286f35',
|
||||
},
|
||||
},
|
||||
res: {
|
||||
type: 'object',
|
||||
|
@ -105,7 +111,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
} else if (e instanceof DriveService.NoSuchFolderError) {
|
||||
throw new ApiError(meta.errors.noSuchFolder);
|
||||
} else if (e instanceof DriveService.CannotUnmarkSensitiveError) {
|
||||
throw new ApiError(meta.errors.restrictedByRole);
|
||||
if (file.isSensitiveByModerator) {
|
||||
throw new ApiError(meta.errors.restrictedByModerator);
|
||||
} else {
|
||||
throw new ApiError(meta.errors.restrictedByRole);
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import type { MiNote } from '@/models/Note.js';
|
|||
* noteScheduled - 予約投稿が予約された
|
||||
* scheduledNotePosted - 予約投稿が投稿された
|
||||
* scheduledNoteError - 予約投稿がエラーになった
|
||||
* sensitiveFlagAssigned - センシティブフラグが付与された
|
||||
* app - アプリ通知
|
||||
* test - テスト通知(サーバー側)
|
||||
*/
|
||||
|
@ -45,6 +46,7 @@ export const notificationTypes = [
|
|||
'noteScheduled',
|
||||
'scheduledNotePosted',
|
||||
'scheduledNoteError',
|
||||
'sensitiveFlagAssigned',
|
||||
'app',
|
||||
'test',
|
||||
] as const;
|
||||
|
|
|
@ -95,6 +95,7 @@ describe('NoteCreateService', () => {
|
|||
folderId: null,
|
||||
folder: null,
|
||||
isSensitive: false,
|
||||
isSensitiveByModerator: false,
|
||||
maybeSensitive: false,
|
||||
maybePorn: false,
|
||||
isLink: false,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue