diff options
Diffstat (limited to 'server/models/video/video-channel.ts')
-rw-r--r-- | server/models/video/video-channel.ts | 164 |
1 files changed, 69 insertions, 95 deletions
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index fe44d3d53..acc2486b3 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -1,42 +1,52 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | import { | 1 | import { |
3 | AfterDestroy, | 2 | AfterDestroy, |
4 | AllowNull, | 3 | AllowNull, |
5 | BelongsTo, | 4 | BelongsTo, |
6 | Column, | 5 | Column, |
7 | CreatedAt, | 6 | CreatedAt, |
8 | DataType, | 7 | DefaultScope, |
9 | Default, | ||
10 | ForeignKey, | 8 | ForeignKey, |
11 | HasMany, | 9 | HasMany, |
12 | Is, | 10 | Is, |
13 | IsUUID, | ||
14 | Model, | 11 | Model, |
15 | Scopes, | 12 | Scopes, |
16 | Table, | 13 | Table, |
17 | UpdatedAt | 14 | UpdatedAt |
18 | } from 'sequelize-typescript' | 15 | } from 'sequelize-typescript' |
19 | import { IFindOptions } from 'sequelize-typescript/lib/interfaces/IFindOptions' | 16 | import { ActivityPubActor } from '../../../shared/models/activitypub' |
20 | import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels' | 17 | import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels' |
21 | import { sendDeleteVideoChannel } from '../../lib/activitypub/send' | 18 | import { sendDeleteActor } from '../../lib/activitypub/send' |
22 | import { AccountModel } from '../account/account' | 19 | import { AccountModel } from '../account/account' |
23 | import { ActorModel } from '../activitypub/actor' | 20 | import { ActorModel } from '../activitypub/actor' |
24 | import { ServerModel } from '../server/server' | ||
25 | import { getSort, throwIfNotValid } from '../utils' | 21 | import { getSort, throwIfNotValid } from '../utils' |
26 | import { VideoModel } from './video' | 22 | import { VideoModel } from './video' |
27 | import { VideoChannelShareModel } from './video-channel-share' | ||
28 | 23 | ||
29 | enum ScopeNames { | 24 | enum ScopeNames { |
30 | WITH_ACCOUNT = 'WITH_ACCOUNT', | 25 | WITH_ACCOUNT = 'WITH_ACCOUNT', |
26 | WITH_ACTOR = 'WITH_ACTOR', | ||
31 | WITH_VIDEOS = 'WITH_VIDEOS' | 27 | WITH_VIDEOS = 'WITH_VIDEOS' |
32 | } | 28 | } |
33 | 29 | ||
30 | @DefaultScope({ | ||
31 | include: [ | ||
32 | { | ||
33 | model: () => ActorModel, | ||
34 | required: true | ||
35 | } | ||
36 | ] | ||
37 | }) | ||
34 | @Scopes({ | 38 | @Scopes({ |
35 | [ScopeNames.WITH_ACCOUNT]: { | 39 | [ScopeNames.WITH_ACCOUNT]: { |
36 | include: [ | 40 | include: [ |
37 | { | 41 | { |
38 | model: () => AccountModel, | 42 | model: () => AccountModel, |
39 | include: [ { model: () => ServerModel, required: false } ] | 43 | required: true, |
44 | include: [ | ||
45 | { | ||
46 | model: () => ActorModel, | ||
47 | required: true | ||
48 | } | ||
49 | ] | ||
40 | } | 50 | } |
41 | ] | 51 | ] |
42 | }, | 52 | }, |
@@ -44,6 +54,11 @@ enum ScopeNames { | |||
44 | include: [ | 54 | include: [ |
45 | () => VideoModel | 55 | () => VideoModel |
46 | ] | 56 | ] |
57 | }, | ||
58 | [ScopeNames.WITH_ACTOR]: { | ||
59 | include: [ | ||
60 | () => ActorModel | ||
61 | ] | ||
47 | } | 62 | } |
48 | }) | 63 | }) |
49 | @Table({ | 64 | @Table({ |
@@ -57,12 +72,6 @@ enum ScopeNames { | |||
57 | export class VideoChannelModel extends Model<VideoChannelModel> { | 72 | export class VideoChannelModel extends Model<VideoChannelModel> { |
58 | 73 | ||
59 | @AllowNull(false) | 74 | @AllowNull(false) |
60 | @Default(DataType.UUIDV4) | ||
61 | @IsUUID(4) | ||
62 | @Column(DataType.UUID) | ||
63 | uuid: string | ||
64 | |||
65 | @AllowNull(false) | ||
66 | @Is('VideoChannelName', value => throwIfNotValid(value, isVideoChannelNameValid, 'name')) | 75 | @Is('VideoChannelName', value => throwIfNotValid(value, isVideoChannelNameValid, 'name')) |
67 | @Column | 76 | @Column |
68 | name: string | 77 | name: string |
@@ -72,10 +81,6 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
72 | @Column | 81 | @Column |
73 | description: string | 82 | description: string |
74 | 83 | ||
75 | @AllowNull(false) | ||
76 | @Column | ||
77 | remote: boolean | ||
78 | |||
79 | @CreatedAt | 84 | @CreatedAt |
80 | createdAt: Date | 85 | createdAt: Date |
81 | 86 | ||
@@ -115,19 +120,10 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
115 | }) | 120 | }) |
116 | Videos: VideoModel[] | 121 | Videos: VideoModel[] |
117 | 122 | ||
118 | @HasMany(() => VideoChannelShareModel, { | ||
119 | foreignKey: { | ||
120 | name: 'channelId', | ||
121 | allowNull: false | ||
122 | }, | ||
123 | onDelete: 'CASCADE' | ||
124 | }) | ||
125 | VideoChannelShares: VideoChannelShareModel[] | ||
126 | |||
127 | @AfterDestroy | 123 | @AfterDestroy |
128 | static sendDeleteIfOwned (instance: VideoChannelModel) { | 124 | static sendDeleteIfOwned (instance: VideoChannelModel) { |
129 | if (instance.isOwned()) { | 125 | if (instance.Actor.isOwned()) { |
130 | return sendDeleteVideoChannel(instance, undefined) | 126 | return sendDeleteActor(instance.Actor, undefined) |
131 | } | 127 | } |
132 | 128 | ||
133 | return undefined | 129 | return undefined |
@@ -150,7 +146,9 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
150 | order: [ getSort(sort) ] | 146 | order: [ getSort(sort) ] |
151 | } | 147 | } |
152 | 148 | ||
153 | return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findAndCountAll(query) | 149 | return VideoChannelModel |
150 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) | ||
151 | .findAndCountAll(query) | ||
154 | .then(({ rows, count }) => { | 152 | .then(({ rows, count }) => { |
155 | return { total: count, data: rows } | 153 | return { total: count, data: rows } |
156 | }) | 154 | }) |
@@ -165,51 +163,18 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
165 | where: { | 163 | where: { |
166 | id: accountId | 164 | id: accountId |
167 | }, | 165 | }, |
168 | required: true, | 166 | required: true |
169 | include: [ { model: ServerModel, required: false } ] | ||
170 | } | 167 | } |
171 | ] | 168 | ] |
172 | } | 169 | } |
173 | 170 | ||
174 | return VideoChannelModel.findAndCountAll(query) | 171 | return VideoChannelModel |
172 | .findAndCountAll(query) | ||
175 | .then(({ rows, count }) => { | 173 | .then(({ rows, count }) => { |
176 | return { total: count, data: rows } | 174 | return { total: count, data: rows } |
177 | }) | 175 | }) |
178 | } | 176 | } |
179 | 177 | ||
180 | static loadByUrl (url: string, t?: Sequelize.Transaction) { | ||
181 | const query: IFindOptions<VideoChannelModel> = { | ||
182 | include: [ | ||
183 | { | ||
184 | model: ActorModel, | ||
185 | required: true, | ||
186 | where: { | ||
187 | url | ||
188 | } | ||
189 | } | ||
190 | ] | ||
191 | } | ||
192 | |||
193 | if (t !== undefined) query.transaction = t | ||
194 | |||
195 | return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findOne(query) | ||
196 | } | ||
197 | |||
198 | static loadByUUIDOrUrl (uuid: string, url: string, t?: Sequelize.Transaction) { | ||
199 | const query: IFindOptions<VideoChannelModel> = { | ||
200 | where: { | ||
201 | [ Sequelize.Op.or ]: [ | ||
202 | { uuid }, | ||
203 | { url } | ||
204 | ] | ||
205 | } | ||
206 | } | ||
207 | |||
208 | if (t !== undefined) query.transaction = t | ||
209 | |||
210 | return VideoChannelModel.findOne(query) | ||
211 | } | ||
212 | |||
213 | static loadByIdAndAccount (id: number, accountId: number) { | 178 | static loadByIdAndAccount (id: number, accountId: number) { |
214 | const options = { | 179 | const options = { |
215 | where: { | 180 | where: { |
@@ -218,21 +183,33 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
218 | } | 183 | } |
219 | } | 184 | } |
220 | 185 | ||
221 | return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findOne(options) | 186 | return VideoChannelModel |
187 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) | ||
188 | .findOne(options) | ||
222 | } | 189 | } |
223 | 190 | ||
224 | static loadAndPopulateAccount (id: number) { | 191 | static loadAndPopulateAccount (id: number) { |
225 | return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findById(id) | 192 | return VideoChannelModel |
193 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) | ||
194 | .findById(id) | ||
226 | } | 195 | } |
227 | 196 | ||
228 | static loadByUUIDAndPopulateAccount (uuid: string) { | 197 | static loadByUUIDAndPopulateAccount (uuid: string) { |
229 | const options = { | 198 | const options = { |
230 | where: { | 199 | include: [ |
231 | uuid | 200 | { |
232 | } | 201 | model: ActorModel, |
202 | required: true, | ||
203 | where: { | ||
204 | uuid | ||
205 | } | ||
206 | } | ||
207 | ] | ||
233 | } | 208 | } |
234 | 209 | ||
235 | return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findOne(options) | 210 | return VideoChannelModel |
211 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) | ||
212 | .findOne(options) | ||
236 | } | 213 | } |
237 | 214 | ||
238 | static loadAndPopulateAccountAndVideos (id: number) { | 215 | static loadAndPopulateAccountAndVideos (id: number) { |
@@ -242,39 +219,36 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
242 | ] | 219 | ] |
243 | } | 220 | } |
244 | 221 | ||
245 | return VideoChannelModel.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEOS ]).findById(id, options) | 222 | return VideoChannelModel |
246 | } | 223 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEOS ]) |
247 | 224 | .findById(id, options) | |
248 | isOwned () { | ||
249 | return this.remote === false | ||
250 | } | 225 | } |
251 | 226 | ||
252 | toFormattedJSON () { | 227 | toFormattedJSON () { |
253 | const json = { | 228 | const actor = this.Actor.toFormattedJSON() |
229 | const account = { | ||
254 | id: this.id, | 230 | id: this.id, |
255 | uuid: this.uuid, | ||
256 | name: this.name, | 231 | name: this.name, |
257 | description: this.description, | 232 | description: this.description, |
258 | isLocal: this.isOwned(), | 233 | isLocal: this.Actor.isOwned(), |
259 | createdAt: this.createdAt, | 234 | createdAt: this.createdAt, |
260 | updatedAt: this.updatedAt | 235 | updatedAt: this.updatedAt |
261 | } | 236 | } |
262 | 237 | ||
263 | if (this.Account !== undefined) { | 238 | return Object.assign(actor, account) |
264 | json[ 'owner' ] = { | ||
265 | name: this.Account.name, | ||
266 | uuid: this.Account.uuid | ||
267 | } | ||
268 | } | ||
269 | |||
270 | if (Array.isArray(this.Videos)) { | ||
271 | json[ 'videos' ] = this.Videos.map(v => v.toFormattedJSON()) | ||
272 | } | ||
273 | |||
274 | return json | ||
275 | } | 239 | } |
276 | 240 | ||
277 | toActivityPubObject () { | 241 | toActivityPubObject (): ActivityPubActor { |
278 | return this.Actor.toActivityPubObject(this.name, this.uuid, 'VideoChannel') | 242 | const obj = this.Actor.toActivityPubObject(this.name, 'VideoChannel') |
243 | |||
244 | return Object.assign(obj, { | ||
245 | summary: this.description, | ||
246 | attributedTo: [ | ||
247 | { | ||
248 | type: 'Person' as 'Person', | ||
249 | id: this.Account.Actor.url | ||
250 | } | ||
251 | ] | ||
252 | }) | ||
279 | } | 253 | } |
280 | } | 254 | } |