diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2020-04-16 14:22:27 +0200 |
---|---|---|
committer | Rigel Kent <par@rigelk.eu> | 2020-05-01 16:41:02 +0200 |
commit | 68d19a0ace01cb7a3550da420d27663e2db1b98d (patch) | |
tree | fcdac5341001b9e6d15ddd0ca8239372ec2b3053 | |
parent | 165ee2929bc76fc7f9985ae81cc33736820c7865 (diff) | |
download | PeerTube-68d19a0ace01cb7a3550da420d27663e2db1b98d.tar.gz PeerTube-68d19a0ace01cb7a3550da420d27663e2db1b98d.tar.zst PeerTube-68d19a0ace01cb7a3550da420d27663e2db1b98d.zip |
Make sure a report doesn't get deleted upon the deletion of its video
15 files changed, 141 insertions, 38 deletions
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.html b/client/src/app/+admin/follows/followers-list/followers-list.component.html index c532b5f32..7455cdf2b 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.html +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.html | |||
@@ -14,10 +14,10 @@ | |||
14 | <ng-template pTemplate="header"> | 14 | <ng-template pTemplate="header"> |
15 | <tr> | 15 | <tr> |
16 | <th i18n>Follower handle</th> | 16 | <th i18n>Follower handle</th> |
17 | <th i18n pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th> | 17 | <th style="width: 100px;" i18n pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th> |
18 | <th i18n pSortableColumn="score">Score <p-sortIcon field="score"></p-sortIcon></th> | 18 | <th style="width: 100px;" i18n pSortableColumn="score">Score <p-sortIcon field="score"></p-sortIcon></th> |
19 | <th i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> | 19 | <th style="width: 200px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> |
20 | <th></th> | 20 | <th style="width: 100px;"></th> |
21 | </tr> | 21 | </tr> |
22 | </ng-template> | 22 | </ng-template> |
23 | 23 | ||
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.html b/client/src/app/+admin/follows/following-list/following-list.component.html index cb62d52dd..f3bb7216b 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.html +++ b/client/src/app/+admin/follows/following-list/following-list.component.html | |||
@@ -20,10 +20,10 @@ | |||
20 | <ng-template pTemplate="header"> | 20 | <ng-template pTemplate="header"> |
21 | <tr> | 21 | <tr> |
22 | <th i18n>Host</th> | 22 | <th i18n>Host</th> |
23 | <th i18n pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th> | 23 | <th style="width: 100px;" i18n pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th> |
24 | <th i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> | 24 | <th style="width: 200px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> |
25 | <th i18n pSortableColumn="redundancyAllowed">Redundancy allowed <p-sortIcon field="redundancyAllowed"></p-sortIcon></th> | 25 | <th style="width: 160px;" i18n pSortableColumn="redundancyAllowed">Redundancy allowed <p-sortIcon field="redundancyAllowed"></p-sortIcon></th> |
26 | <th></th> | 26 | <th style="width: 100px;"></th> |
27 | </tr> | 27 | </tr> |
28 | </ng-template> | 28 | </ng-template> |
29 | 29 | ||
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html index 07362b3b9..a8dcc69d2 100644 --- a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html | |||
@@ -17,11 +17,11 @@ | |||
17 | > | 17 | > |
18 | <ng-template pTemplate="header"> | 18 | <ng-template pTemplate="header"> |
19 | <tr> | 19 | <tr> |
20 | <th style="width: 40px"></th> | 20 | <th style="width: 40px;"></th> |
21 | <th i18n *ngIf="isDisplayingRemoteVideos()">Strategy</th> | 21 | <th style="width: 160px;" i18n *ngIf="isDisplayingRemoteVideos()">Strategy</th> |
22 | <th i18n pSortableColumn="name">Video name <p-sortIcon field="name"></p-sortIcon></th> | 22 | <th i18n pSortableColumn="name">Video name <p-sortIcon field="name"></p-sortIcon></th> |
23 | <th i18n>Video URL</th> | 23 | <th i18n>Video URL</th> |
24 | <th i18n *ngIf="isDisplayingRemoteVideos()">Total size</th> | 24 | <th style="width: 100px;" i18n *ngIf="isDisplayingRemoteVideos()">Total size</th> |
25 | <th style="width: 80px;"></th> | 25 | <th style="width: 80px;"></th> |
26 | </tr> | 26 | </tr> |
27 | </ng-template> | 27 | </ng-template> |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html index 2efdd2bc3..e40c29abf 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html | |||
@@ -8,8 +8,8 @@ | |||
8 | <ng-template pTemplate="header"> | 8 | <ng-template pTemplate="header"> |
9 | <tr> | 9 | <tr> |
10 | <th i18n>Account</th> | 10 | <th i18n>Account</th> |
11 | <th i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> | 11 | <th style="width: 200px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> |
12 | <th></th> <!-- column for action buttons --> | 12 | <th style="width: 100px;"></th> <!-- column for action buttons --> |
13 | </tr> | 13 | </tr> |
14 | </ng-template> | 14 | </ng-template> |
15 | 15 | ||
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html index cec703289..bf5c00918 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html | |||
@@ -16,8 +16,8 @@ | |||
16 | <ng-template pTemplate="header"> | 16 | <ng-template pTemplate="header"> |
17 | <tr> | 17 | <tr> |
18 | <th i18n>Instance</th> | 18 | <th i18n>Instance</th> |
19 | <th i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> | 19 | <th style="width: 200px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> |
20 | <th></th> <!-- column for action buttons --> | 20 | <th style="width: 100px;"></th> <!-- column for action buttons --> |
21 | </tr> | 21 | </tr> |
22 | </ng-template> | 22 | </ng-template> |
23 | 23 | ||
diff --git a/client/src/app/+admin/moderation/moderation.component.scss b/client/src/app/+admin/moderation/moderation.component.scss index 89e9b47d3..9af76d2dd 100644 --- a/client/src/app/+admin/moderation/moderation.component.scss +++ b/client/src/app/+admin/moderation/moderation.component.scss | |||
@@ -1,5 +1,6 @@ | |||
1 | @import 'variables'; | 1 | @import 'variables'; |
2 | @import 'mixins'; | 2 | @import 'mixins'; |
3 | @import 'miniature'; | ||
3 | 4 | ||
4 | .form-sub-title { | 5 | .form-sub-title { |
5 | flex-grow: 0; | 6 | flex-grow: 0; |
@@ -22,12 +23,28 @@ | |||
22 | } | 23 | } |
23 | } | 24 | } |
24 | 25 | ||
26 | .video-abuse-states { | ||
27 | & > :not(:first-child) { | ||
28 | margin-left: .4rem; | ||
29 | } | ||
30 | } | ||
31 | |||
25 | .screenratio { | 32 | .screenratio { |
26 | position: relative; | 33 | position: relative; |
27 | width: 100%; | 34 | width: 100%; |
28 | height: 0; | 35 | height: 0; |
29 | padding-bottom: 56%; | 36 | padding-bottom: 56%; |
30 | 37 | ||
38 | div { | ||
39 | @include miniature-thumbnail; | ||
40 | position: absolute; | ||
41 | height: 100%; | ||
42 | width: 100%; | ||
43 | display: inline-flex; | ||
44 | justify-content: center; | ||
45 | align-items: center; | ||
46 | } | ||
47 | |||
31 | ::ng-deep iframe { | 48 | ::ng-deep iframe { |
32 | position: absolute; | 49 | position: absolute; |
33 | width: 100% !important; | 50 | width: 100% !important; |
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html index 4ecb395f8..3d356dc7c 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html | |||
@@ -48,9 +48,10 @@ | |||
48 | </a> | 48 | </a> |
49 | </td> | 49 | </td> |
50 | 50 | ||
51 | <td class="c-hand" [pRowToggler]="videoAbuse"> | 51 | <td class="c-hand video-abuse-states" [pRowToggler]="videoAbuse"> |
52 | <span *ngIf="isVideoAbuseAccepted(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-ok"></span> | 52 | <span *ngIf="isVideoAbuseAccepted(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-ok"></span> |
53 | <span *ngIf="isVideoAbuseRejected(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-remove"></span> | 53 | <span *ngIf="isVideoAbuseRejected(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-remove"></span> |
54 | <span *ngIf="videoAbuse.moderationComment" [title]="videoAbuse.moderationComment" class="glyphicon glyphicon-comment"></span> | ||
54 | </td> | 55 | </td> |
55 | 56 | ||
56 | <td class="action-cell"> | 57 | <td class="action-cell"> |
@@ -75,7 +76,12 @@ | |||
75 | </div> | 76 | </div> |
76 | 77 | ||
77 | <div class="col-4"> | 78 | <div class="col-4"> |
78 | <div class="screenratio" [innerHTML]="videoAbuse.embedHtml"></div> | 79 | <div class="screenratio"> |
80 | <div *ngIf="videoAbuse.video.deleted"> | ||
81 | <span i18n>The video was {{ videoAbuse.video.deleted ? 'deleted' : 'blacklisted' }}</span> | ||
82 | </div> | ||
83 | <div *ngIf="!videoAbuse.video.deleted" [innerHTML]="videoAbuse.embedHtml"></div> | ||
84 | </div> | ||
79 | </div> | 85 | </div> |
80 | </div> | 86 | </div> |
81 | </td> | 87 | </td> |
diff --git a/server/helpers/middlewares/video-abuses.ts b/server/helpers/middlewares/video-abuses.ts index 8a1d3d618..7553a5eb3 100644 --- a/server/helpers/middlewares/video-abuses.ts +++ b/server/helpers/middlewares/video-abuses.ts | |||
@@ -1,9 +1,17 @@ | |||
1 | import { Response } from 'express' | 1 | import { Response } from 'express' |
2 | import { VideoAbuseModel } from '../../models/video/video-abuse' | 2 | import { VideoAbuseModel } from '../../models/video/video-abuse' |
3 | import { fetchVideo } from '../video' | ||
3 | 4 | ||
4 | async function doesVideoAbuseExist (abuseIdArg: number | string, videoId: number, res: Response) { | 5 | async function doesVideoAbuseExist (abuseIdArg: number | string, videoUUID: string, res: Response) { |
5 | const abuseId = parseInt(abuseIdArg + '', 10) | 6 | const abuseId = parseInt(abuseIdArg + '', 10) |
6 | const videoAbuse = await VideoAbuseModel.loadByIdAndVideoId(abuseId, videoId) | 7 | let videoAbuse = await VideoAbuseModel.loadByIdAndVideoId(abuseId, null, videoUUID) |
8 | |||
9 | if (!videoAbuse) { | ||
10 | const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined | ||
11 | const video = await fetchVideo(videoUUID, 'all', userId) | ||
12 | |||
13 | if (video) videoAbuse = await VideoAbuseModel.loadByIdAndVideoId(abuseId, video.id) | ||
14 | } | ||
7 | 15 | ||
8 | if (videoAbuse === null) { | 16 | if (videoAbuse === null) { |
9 | res.status(404) | 17 | res.status(404) |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index bc6c58b06..c8623a5d4 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -14,7 +14,7 @@ import { CONFIG, registerConfigChangedHandler } from './config' | |||
14 | 14 | ||
15 | // --------------------------------------------------------------------------- | 15 | // --------------------------------------------------------------------------- |
16 | 16 | ||
17 | const LAST_MIGRATION_VERSION = 485 | 17 | const LAST_MIGRATION_VERSION = 490 |
18 | 18 | ||
19 | // --------------------------------------------------------------------------- | 19 | // --------------------------------------------------------------------------- |
20 | 20 | ||
diff --git a/server/initializers/migrations/0490-abuse-video.ts b/server/initializers/migrations/0490-abuse-video.ts new file mode 100644 index 000000000..26333feb5 --- /dev/null +++ b/server/initializers/migrations/0490-abuse-video.ts | |||
@@ -0,0 +1,28 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | async function up (utils: { | ||
4 | transaction: Sequelize.Transaction | ||
5 | queryInterface: Sequelize.QueryInterface | ||
6 | sequelize: Sequelize.Sequelize | ||
7 | }): Promise<void> { | ||
8 | |||
9 | const deletedVideo = { | ||
10 | type: Sequelize.JSONB, | ||
11 | allowNull: true | ||
12 | } | ||
13 | await utils.queryInterface.addColumn('videoAbuse', 'deletedVideo', deletedVideo) | ||
14 | await utils.sequelize.query(`ALTER TABLE "videoAbsue" ALTER COLUMN "videoId" DROP NOT NULL;`) | ||
15 | await utils.sequelize.query(`ALTER TABLE "videoAbuse" DROP CONSTRAINT IF EXISTS "videoAbuse_videoId_fkey";`) | ||
16 | await utils.sequelize.query(`ALTER TABLE "videoAbuse" ADD CONSTRAINT "videoAbuse_videoId_fkey" | ||
17 | FOREIGN KEY ("videoId") REFERENCES video(id) ON UPDATE CASCADE ON DELETE SET NULL;`) | ||
18 | |||
19 | } | ||
20 | |||
21 | function down (options) { | ||
22 | throw new Error('Not implemented.') | ||
23 | } | ||
24 | |||
25 | export { | ||
26 | up, | ||
27 | down | ||
28 | } | ||
diff --git a/server/middlewares/validators/videos/video-abuses.ts b/server/middlewares/validators/videos/video-abuses.ts index a4aef4024..7c316fe13 100644 --- a/server/middlewares/validators/videos/video-abuses.ts +++ b/server/middlewares/validators/videos/video-abuses.ts | |||
@@ -32,8 +32,7 @@ const videoAbuseGetValidator = [ | |||
32 | logger.debug('Checking videoAbuseGetValidator parameters', { parameters: req.body }) | 32 | logger.debug('Checking videoAbuseGetValidator parameters', { parameters: req.body }) |
33 | 33 | ||
34 | if (areValidationErrors(req, res)) return | 34 | if (areValidationErrors(req, res)) return |
35 | if (!await doesVideoExist(req.params.videoId, res)) return | 35 | if (!await doesVideoAbuseExist(req.params.id, req.params.videoId, res)) return |
36 | if (!await doesVideoAbuseExist(req.params.id, res.locals.videoAll.id, res)) return | ||
37 | 36 | ||
38 | return next() | 37 | return next() |
39 | } | 38 | } |
@@ -53,8 +52,7 @@ const videoAbuseUpdateValidator = [ | |||
53 | logger.debug('Checking videoAbuseUpdateValidator parameters', { parameters: req.body }) | 52 | logger.debug('Checking videoAbuseUpdateValidator parameters', { parameters: req.body }) |
54 | 53 | ||
55 | if (areValidationErrors(req, res)) return | 54 | if (areValidationErrors(req, res)) return |
56 | if (!await doesVideoExist(req.params.videoId, res)) return | 55 | if (!await doesVideoAbuseExist(req.params.id, req.params.videoId, res)) return |
57 | if (!await doesVideoAbuseExist(req.params.id, res.locals.videoAll.id, res)) return | ||
58 | 56 | ||
59 | return next() | 57 | return next() |
60 | } | 58 | } |
diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts index da8c1577c..ea9856213 100644 --- a/server/models/video/video-abuse.ts +++ b/server/models/video/video-abuse.ts | |||
@@ -9,7 +9,7 @@ import { | |||
9 | import { AccountModel } from '../account/account' | 9 | import { AccountModel } from '../account/account' |
10 | import { buildBlockedAccountSQL, getSort, throwIfNotValid } from '../utils' | 10 | import { buildBlockedAccountSQL, getSort, throwIfNotValid } from '../utils' |
11 | import { VideoModel } from './video' | 11 | import { VideoModel } from './video' |
12 | import { VideoAbuseState } from '../../../shared' | 12 | import { VideoAbuseState, Video } from '../../../shared' |
13 | import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' | 13 | import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' |
14 | import { MUserAccountId, MVideoAbuse, MVideoAbuseFormattable, MVideoAbuseVideo } from '../../typings/models' | 14 | import { MUserAccountId, MVideoAbuse, MVideoAbuseFormattable, MVideoAbuseVideo } from '../../typings/models' |
15 | import * as Bluebird from 'bluebird' | 15 | import * as Bluebird from 'bluebird' |
@@ -46,6 +46,11 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
46 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_ABUSES.MODERATION_COMMENT.max)) | 46 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_ABUSES.MODERATION_COMMENT.max)) |
47 | moderationComment: string | 47 | moderationComment: string |
48 | 48 | ||
49 | @AllowNull(true) | ||
50 | @Default(null) | ||
51 | @Column(DataType.JSONB) | ||
52 | deletedVideo: Video | ||
53 | |||
49 | @CreatedAt | 54 | @CreatedAt |
50 | createdAt: Date | 55 | createdAt: Date |
51 | 56 | ||
@@ -58,9 +63,9 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
58 | 63 | ||
59 | @BelongsTo(() => AccountModel, { | 64 | @BelongsTo(() => AccountModel, { |
60 | foreignKey: { | 65 | foreignKey: { |
61 | allowNull: false | 66 | allowNull: true |
62 | }, | 67 | }, |
63 | onDelete: 'cascade' | 68 | onDelete: 'set null' |
64 | }) | 69 | }) |
65 | Account: AccountModel | 70 | Account: AccountModel |
66 | 71 | ||
@@ -70,17 +75,21 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
70 | 75 | ||
71 | @BelongsTo(() => VideoModel, { | 76 | @BelongsTo(() => VideoModel, { |
72 | foreignKey: { | 77 | foreignKey: { |
73 | allowNull: false | 78 | allowNull: true |
74 | }, | 79 | }, |
75 | onDelete: 'cascade' | 80 | onDelete: 'set null' |
76 | }) | 81 | }) |
77 | Video: VideoModel | 82 | Video: VideoModel |
78 | 83 | ||
79 | static loadByIdAndVideoId (id: number, videoId: number): Bluebird<MVideoAbuse> { | 84 | static loadByIdAndVideoId (id: number, videoId?: number, uuid?: string): Bluebird<MVideoAbuse> { |
85 | const videoAttributes = {} | ||
86 | if (videoId) videoAttributes['videoId'] = videoId | ||
87 | if (uuid) videoAttributes['deletedVideo'] = { uuid } | ||
88 | |||
80 | const query = { | 89 | const query = { |
81 | where: { | 90 | where: { |
82 | id, | 91 | id, |
83 | videoId | 92 | ...videoAttributes |
84 | } | 93 | } |
85 | } | 94 | } |
86 | return VideoAbuseModel.findOne(query) | 95 | return VideoAbuseModel.findOne(query) |
@@ -112,7 +121,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
112 | }, | 121 | }, |
113 | { | 122 | { |
114 | model: VideoModel, | 123 | model: VideoModel, |
115 | required: true | 124 | required: false |
116 | } | 125 | } |
117 | ] | 126 | ] |
118 | } | 127 | } |
@@ -124,6 +133,10 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
124 | } | 133 | } |
125 | 134 | ||
126 | toFormattedJSON (this: MVideoAbuseFormattable): VideoAbuse { | 135 | toFormattedJSON (this: MVideoAbuseFormattable): VideoAbuse { |
136 | const video = this.Video | ||
137 | ? this.Video | ||
138 | : this.deletedVideo | ||
139 | |||
127 | return { | 140 | return { |
128 | id: this.id, | 141 | id: this.id, |
129 | reason: this.reason, | 142 | reason: this.reason, |
@@ -134,9 +147,11 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
134 | }, | 147 | }, |
135 | moderationComment: this.moderationComment, | 148 | moderationComment: this.moderationComment, |
136 | video: { | 149 | video: { |
137 | id: this.Video.id, | 150 | id: video.id, |
138 | uuid: this.Video.uuid, | 151 | uuid: video.uuid, |
139 | name: this.Video.name | 152 | name: video.name, |
153 | nsfw: video.nsfw, | ||
154 | deleted: !this.Video | ||
140 | }, | 155 | }, |
141 | createdAt: this.createdAt | 156 | createdAt: this.createdAt |
142 | } | 157 | } |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 0e7505af5..2636ebd8e 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -628,9 +628,9 @@ export class VideoModel extends Model<VideoModel> { | |||
628 | @HasMany(() => VideoAbuseModel, { | 628 | @HasMany(() => VideoAbuseModel, { |
629 | foreignKey: { | 629 | foreignKey: { |
630 | name: 'videoId', | 630 | name: 'videoId', |
631 | allowNull: false | 631 | allowNull: true |
632 | }, | 632 | }, |
633 | onDelete: 'cascade' | 633 | onDelete: 'set null' |
634 | }) | 634 | }) |
635 | VideoAbuses: VideoAbuseModel[] | 635 | VideoAbuses: VideoAbuseModel[] |
636 | 636 | ||
@@ -798,6 +798,35 @@ export class VideoModel extends Model<VideoModel> { | |||
798 | ModelCache.Instance.invalidateCache('video', instance.id) | 798 | ModelCache.Instance.invalidateCache('video', instance.id) |
799 | } | 799 | } |
800 | 800 | ||
801 | @BeforeDestroy | ||
802 | static async saveEssentialDataToAbuses (instance: VideoModel, options) { | ||
803 | const tasks: Promise<any>[] = [] | ||
804 | |||
805 | logger.info('Saving video abuses details of video %s.', instance.url) | ||
806 | |||
807 | if (!Array.isArray(instance.VideoAbuses)) { | ||
808 | instance.VideoAbuses = await instance.$get('VideoAbuses') | ||
809 | |||
810 | if (instance.VideoAbuses.length === 0) return undefined | ||
811 | } | ||
812 | |||
813 | const details = instance.toFormattedJSON() | ||
814 | |||
815 | for (const abuse of instance.VideoAbuses) { | ||
816 | tasks.push((_ => { | ||
817 | abuse.deletedVideo = details | ||
818 | return abuse.save({ transaction: options.transaction }) | ||
819 | })()) | ||
820 | } | ||
821 | |||
822 | Promise.all(tasks) | ||
823 | .catch(err => { | ||
824 | logger.error('Some errors when saving details of video %s in its abuses before destroy hook.', instance.uuid, { err }) | ||
825 | }) | ||
826 | |||
827 | return undefined | ||
828 | } | ||
829 | |||
801 | static listLocal (): Bluebird<MVideoWithAllFiles[]> { | 830 | static listLocal (): Bluebird<MVideoWithAllFiles[]> { |
802 | const query = { | 831 | const query = { |
803 | where: { | 832 | where: { |
diff --git a/server/typings/models/video/video-abuse.ts b/server/typings/models/video/video-abuse.ts index 955ec4780..49bd1ff2e 100644 --- a/server/typings/models/video/video-abuse.ts +++ b/server/typings/models/video/video-abuse.ts | |||
@@ -31,4 +31,4 @@ export type MVideoAbuseAccountVideo = | |||
31 | export type MVideoAbuseFormattable = | 31 | export type MVideoAbuseFormattable = |
32 | MVideoAbuse & | 32 | MVideoAbuse & |
33 | Use<'Account', MAccountFormattable> & | 33 | Use<'Account', MAccountFormattable> & |
34 | Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'name'>> | 34 | Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'name' | 'nsfw'>> |
diff --git a/shared/models/videos/abuse/video-abuse.model.ts b/shared/models/videos/abuse/video-abuse.model.ts index 4f668795a..b47ee05a0 100644 --- a/shared/models/videos/abuse/video-abuse.model.ts +++ b/shared/models/videos/abuse/video-abuse.model.ts | |||
@@ -14,6 +14,8 @@ export interface VideoAbuse { | |||
14 | id: number | 14 | id: number |
15 | name: string | 15 | name: string |
16 | uuid: string | 16 | uuid: string |
17 | nsfw: boolean | ||
18 | deleted: boolean | ||
17 | } | 19 | } |
18 | 20 | ||
19 | createdAt: Date | 21 | createdAt: Date |