diff options
author | Wicklow <123956049+wickloww@users.noreply.github.com> | 2023-03-31 07:12:21 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-31 09:12:21 +0200 |
commit | 05a60d85997c108d39bcfb14f1ffd4c74f8b1e93 (patch) | |
tree | 5041a95ef945620a17f25ba934064b41f6bb00b7 /server/models | |
parent | ebd61437c1ec92bea9772924c7051cb00d71f778 (diff) | |
download | PeerTube-05a60d85997c108d39bcfb14f1ffd4c74f8b1e93.tar.gz PeerTube-05a60d85997c108d39bcfb14f1ffd4c74f8b1e93.tar.zst PeerTube-05a60d85997c108d39bcfb14f1ffd4c74f8b1e93.zip |
Feature/Add replay privacy (#5692)
* Add replay settings feature
* Fix replay settings behaviour
* Fix tests
* Fix tests
* Fix tests
* Update openapi doc and fix tests
* Add tests and fix code
* Models correction
* Add migration and update controller and middleware
* Add check params tests
* Fix video live middleware
* Updated code based on review comments
Diffstat (limited to 'server/models')
-rw-r--r-- | server/models/video/sql/video/shared/video-table-attributes.ts | 1 | ||||
-rw-r--r-- | server/models/video/video-live-replay-setting.ts | 42 | ||||
-rw-r--r-- | server/models/video/video-live-session.ts | 49 | ||||
-rw-r--r-- | server/models/video/video-live.ts | 57 | ||||
-rw-r--r-- | server/models/video/video.ts | 1 |
5 files changed, 146 insertions, 4 deletions
diff --git a/server/models/video/sql/video/shared/video-table-attributes.ts b/server/models/video/sql/video/shared/video-table-attributes.ts index e2c1c0f6d..34967cd20 100644 --- a/server/models/video/sql/video/shared/video-table-attributes.ts +++ b/server/models/video/sql/video/shared/video-table-attributes.ts | |||
@@ -160,6 +160,7 @@ export class VideoTableAttributes { | |||
160 | 'permanentLive', | 160 | 'permanentLive', |
161 | 'latencyMode', | 161 | 'latencyMode', |
162 | 'videoId', | 162 | 'videoId', |
163 | 'replaySettingId', | ||
163 | 'createdAt', | 164 | 'createdAt', |
164 | 'updatedAt' | 165 | 'updatedAt' |
165 | ] | 166 | ] |
diff --git a/server/models/video/video-live-replay-setting.ts b/server/models/video/video-live-replay-setting.ts new file mode 100644 index 000000000..1c824dfa2 --- /dev/null +++ b/server/models/video/video-live-replay-setting.ts | |||
@@ -0,0 +1,42 @@ | |||
1 | import { isVideoPrivacyValid } from '@server/helpers/custom-validators/videos' | ||
2 | import { MLiveReplaySetting } from '@server/types/models/video/video-live-replay-setting' | ||
3 | import { VideoPrivacy } from '@shared/models/videos/video-privacy.enum' | ||
4 | import { Transaction } from 'sequelize' | ||
5 | import { AllowNull, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | ||
6 | import { throwIfNotValid } from '../shared/sequelize-helpers' | ||
7 | |||
8 | @Table({ | ||
9 | tableName: 'videoLiveReplaySetting' | ||
10 | }) | ||
11 | export class VideoLiveReplaySettingModel extends Model<VideoLiveReplaySettingModel> { | ||
12 | |||
13 | @CreatedAt | ||
14 | createdAt: Date | ||
15 | |||
16 | @UpdatedAt | ||
17 | updatedAt: Date | ||
18 | |||
19 | @AllowNull(false) | ||
20 | @Is('VideoPrivacy', value => throwIfNotValid(value, isVideoPrivacyValid, 'privacy')) | ||
21 | @Column | ||
22 | privacy: VideoPrivacy | ||
23 | |||
24 | static load (id: number, transaction?: Transaction): Promise<MLiveReplaySetting> { | ||
25 | return VideoLiveReplaySettingModel.findOne({ | ||
26 | where: { id }, | ||
27 | transaction | ||
28 | }) | ||
29 | } | ||
30 | |||
31 | static removeSettings (id: number) { | ||
32 | return VideoLiveReplaySettingModel.destroy({ | ||
33 | where: { id } | ||
34 | }) | ||
35 | } | ||
36 | |||
37 | toFormattedJSON () { | ||
38 | return { | ||
39 | privacy: this.privacy | ||
40 | } | ||
41 | } | ||
42 | } | ||
diff --git a/server/models/video/video-live-session.ts b/server/models/video/video-live-session.ts index ed386052b..dcded7872 100644 --- a/server/models/video/video-live-session.ts +++ b/server/models/video/video-live-session.ts | |||
@@ -1,10 +1,23 @@ | |||
1 | import { FindOptions } from 'sequelize' | 1 | import { FindOptions } from 'sequelize' |
2 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { |
3 | AllowNull, | ||
4 | BeforeDestroy, | ||
5 | BelongsTo, | ||
6 | Column, | ||
7 | CreatedAt, | ||
8 | DataType, | ||
9 | ForeignKey, | ||
10 | Model, | ||
11 | Scopes, | ||
12 | Table, | ||
13 | UpdatedAt | ||
14 | } from 'sequelize-typescript' | ||
3 | import { MVideoLiveSession, MVideoLiveSessionReplay } from '@server/types/models' | 15 | import { MVideoLiveSession, MVideoLiveSessionReplay } from '@server/types/models' |
4 | import { uuidToShort } from '@shared/extra-utils' | 16 | import { uuidToShort } from '@shared/extra-utils' |
5 | import { LiveVideoError, LiveVideoSession } from '@shared/models' | 17 | import { LiveVideoError, LiveVideoSession } from '@shared/models' |
6 | import { AttributesOnly } from '@shared/typescript-utils' | 18 | import { AttributesOnly } from '@shared/typescript-utils' |
7 | import { VideoModel } from './video' | 19 | import { VideoModel } from './video' |
20 | import { VideoLiveReplaySettingModel } from './video-live-replay-setting' | ||
8 | 21 | ||
9 | export enum ScopeNames { | 22 | export enum ScopeNames { |
10 | WITH_REPLAY = 'WITH_REPLAY' | 23 | WITH_REPLAY = 'WITH_REPLAY' |
@@ -17,6 +30,10 @@ export enum ScopeNames { | |||
17 | model: VideoModel.unscoped(), | 30 | model: VideoModel.unscoped(), |
18 | as: 'ReplayVideo', | 31 | as: 'ReplayVideo', |
19 | required: false | 32 | required: false |
33 | }, | ||
34 | { | ||
35 | model: VideoLiveReplaySettingModel, | ||
36 | required: false | ||
20 | } | 37 | } |
21 | ] | 38 | ] |
22 | } | 39 | } |
@@ -30,6 +47,10 @@ export enum ScopeNames { | |||
30 | }, | 47 | }, |
31 | { | 48 | { |
32 | fields: [ 'liveVideoId' ] | 49 | fields: [ 'liveVideoId' ] |
50 | }, | ||
51 | { | ||
52 | fields: [ 'replaySettingId' ], | ||
53 | unique: true | ||
33 | } | 54 | } |
34 | ] | 55 | ] |
35 | }) | 56 | }) |
@@ -89,6 +110,27 @@ export class VideoLiveSessionModel extends Model<Partial<AttributesOnly<VideoLiv | |||
89 | }) | 110 | }) |
90 | LiveVideo: VideoModel | 111 | LiveVideo: VideoModel |
91 | 112 | ||
113 | @ForeignKey(() => VideoLiveReplaySettingModel) | ||
114 | @Column | ||
115 | replaySettingId: number | ||
116 | |||
117 | @BelongsTo(() => VideoLiveReplaySettingModel, { | ||
118 | foreignKey: { | ||
119 | allowNull: true | ||
120 | }, | ||
121 | onDelete: 'set null' | ||
122 | }) | ||
123 | ReplaySetting: VideoLiveReplaySettingModel | ||
124 | |||
125 | @BeforeDestroy | ||
126 | static deleteReplaySetting (instance: VideoLiveSessionModel) { | ||
127 | return VideoLiveReplaySettingModel.destroy({ | ||
128 | where: { | ||
129 | id: instance.replaySettingId | ||
130 | } | ||
131 | }) | ||
132 | } | ||
133 | |||
92 | static load (id: number): Promise<MVideoLiveSession> { | 134 | static load (id: number): Promise<MVideoLiveSession> { |
93 | return VideoLiveSessionModel.findOne({ | 135 | return VideoLiveSessionModel.findOne({ |
94 | where: { id } | 136 | where: { id } |
@@ -146,6 +188,10 @@ export class VideoLiveSessionModel extends Model<Partial<AttributesOnly<VideoLiv | |||
146 | } | 188 | } |
147 | : undefined | 189 | : undefined |
148 | 190 | ||
191 | const replaySettings = this.replaySettingId | ||
192 | ? this.ReplaySetting.toFormattedJSON() | ||
193 | : undefined | ||
194 | |||
149 | return { | 195 | return { |
150 | id: this.id, | 196 | id: this.id, |
151 | startDate: this.startDate.toISOString(), | 197 | startDate: this.startDate.toISOString(), |
@@ -154,6 +200,7 @@ export class VideoLiveSessionModel extends Model<Partial<AttributesOnly<VideoLiv | |||
154 | : null, | 200 | : null, |
155 | endingProcessed: this.endingProcessed, | 201 | endingProcessed: this.endingProcessed, |
156 | saveReplay: this.saveReplay, | 202 | saveReplay: this.saveReplay, |
203 | replaySettings, | ||
157 | replayVideo, | 204 | replayVideo, |
158 | error: this.error | 205 | error: this.error |
159 | } | 206 | } |
diff --git a/server/models/video/video-live.ts b/server/models/video/video-live.ts index d2788ef4f..290e1dda7 100644 --- a/server/models/video/video-live.ts +++ b/server/models/video/video-live.ts | |||
@@ -1,11 +1,24 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, DefaultScope, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { |
2 | BeforeDestroy, | ||
3 | AllowNull, | ||
4 | BelongsTo, | ||
5 | Column, | ||
6 | CreatedAt, | ||
7 | DataType, | ||
8 | DefaultScope, | ||
9 | ForeignKey, | ||
10 | Model, | ||
11 | Table, | ||
12 | UpdatedAt | ||
13 | } from 'sequelize-typescript' | ||
2 | import { CONFIG } from '@server/initializers/config' | 14 | import { CONFIG } from '@server/initializers/config' |
3 | import { WEBSERVER } from '@server/initializers/constants' | 15 | import { WEBSERVER } from '@server/initializers/constants' |
4 | import { MVideoLive, MVideoLiveVideo } from '@server/types/models' | 16 | import { MVideoLive, MVideoLiveVideoWithSetting } from '@server/types/models' |
5 | import { LiveVideo, LiveVideoLatencyMode, VideoState } from '@shared/models' | 17 | import { LiveVideo, LiveVideoLatencyMode, VideoState } from '@shared/models' |
6 | import { AttributesOnly } from '@shared/typescript-utils' | 18 | import { AttributesOnly } from '@shared/typescript-utils' |
7 | import { VideoModel } from './video' | 19 | import { VideoModel } from './video' |
8 | import { VideoBlacklistModel } from './video-blacklist' | 20 | import { VideoBlacklistModel } from './video-blacklist' |
21 | import { VideoLiveReplaySettingModel } from './video-live-replay-setting' | ||
9 | 22 | ||
10 | @DefaultScope(() => ({ | 23 | @DefaultScope(() => ({ |
11 | include: [ | 24 | include: [ |
@@ -18,6 +31,10 @@ import { VideoBlacklistModel } from './video-blacklist' | |||
18 | required: false | 31 | required: false |
19 | } | 32 | } |
20 | ] | 33 | ] |
34 | }, | ||
35 | { | ||
36 | model: VideoLiveReplaySettingModel, | ||
37 | required: false | ||
21 | } | 38 | } |
22 | ] | 39 | ] |
23 | })) | 40 | })) |
@@ -27,6 +44,10 @@ import { VideoBlacklistModel } from './video-blacklist' | |||
27 | { | 44 | { |
28 | fields: [ 'videoId' ], | 45 | fields: [ 'videoId' ], |
29 | unique: true | 46 | unique: true |
47 | }, | ||
48 | { | ||
49 | fields: [ 'replaySettingId' ], | ||
50 | unique: true | ||
30 | } | 51 | } |
31 | ] | 52 | ] |
32 | }) | 53 | }) |
@@ -66,6 +87,27 @@ export class VideoLiveModel extends Model<Partial<AttributesOnly<VideoLiveModel> | |||
66 | }) | 87 | }) |
67 | Video: VideoModel | 88 | Video: VideoModel |
68 | 89 | ||
90 | @ForeignKey(() => VideoLiveReplaySettingModel) | ||
91 | @Column | ||
92 | replaySettingId: number | ||
93 | |||
94 | @BelongsTo(() => VideoLiveReplaySettingModel, { | ||
95 | foreignKey: { | ||
96 | allowNull: true | ||
97 | }, | ||
98 | onDelete: 'set null' | ||
99 | }) | ||
100 | ReplaySetting: VideoLiveReplaySettingModel | ||
101 | |||
102 | @BeforeDestroy | ||
103 | static deleteReplaySetting (instance: VideoLiveModel) { | ||
104 | return VideoLiveReplaySettingModel.destroy({ | ||
105 | where: { | ||
106 | id: instance.replaySettingId | ||
107 | } | ||
108 | }) | ||
109 | } | ||
110 | |||
69 | static loadByStreamKey (streamKey: string) { | 111 | static loadByStreamKey (streamKey: string) { |
70 | const query = { | 112 | const query = { |
71 | where: { | 113 | where: { |
@@ -84,11 +126,15 @@ export class VideoLiveModel extends Model<Partial<AttributesOnly<VideoLiveModel> | |||
84 | required: false | 126 | required: false |
85 | } | 127 | } |
86 | ] | 128 | ] |
129 | }, | ||
130 | { | ||
131 | model: VideoLiveReplaySettingModel.unscoped(), | ||
132 | required: false | ||
87 | } | 133 | } |
88 | ] | 134 | ] |
89 | } | 135 | } |
90 | 136 | ||
91 | return VideoLiveModel.findOne<MVideoLiveVideo>(query) | 137 | return VideoLiveModel.findOne<MVideoLiveVideoWithSetting>(query) |
92 | } | 138 | } |
93 | 139 | ||
94 | static loadByVideoId (videoId: number) { | 140 | static loadByVideoId (videoId: number) { |
@@ -120,11 +166,16 @@ export class VideoLiveModel extends Model<Partial<AttributesOnly<VideoLiveModel> | |||
120 | } | 166 | } |
121 | } | 167 | } |
122 | 168 | ||
169 | const replaySettings = this.replaySettingId | ||
170 | ? this.ReplaySetting.toFormattedJSON() | ||
171 | : undefined | ||
172 | |||
123 | return { | 173 | return { |
124 | ...privateInformation, | 174 | ...privateInformation, |
125 | 175 | ||
126 | permanentLive: this.permanentLive, | 176 | permanentLive: this.permanentLive, |
127 | saveReplay: this.saveReplay, | 177 | saveReplay: this.saveReplay, |
178 | replaySettings, | ||
128 | latencyMode: this.latencyMode | 179 | latencyMode: this.latencyMode |
129 | } | 180 | } |
130 | } | 181 | } |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index aa9c62e36..0c5ed64ec 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -706,6 +706,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
706 | name: 'videoId', | 706 | name: 'videoId', |
707 | allowNull: false | 707 | allowNull: false |
708 | }, | 708 | }, |
709 | hooks: true, | ||
709 | onDelete: 'cascade' | 710 | onDelete: 'cascade' |
710 | }) | 711 | }) |
711 | VideoLive: VideoLiveModel | 712 | VideoLive: VideoLiveModel |