]>
Commit | Line | Data |
---|---|---|
72c7248b C |
1 | import * as Sequelize from 'sequelize' |
2 | ||
3 | import { isVideoChannelNameValid, isVideoChannelDescriptionValid } from '../../helpers' | |
72c7248b C |
4 | |
5 | import { addMethodsToModel, getSort } from '../utils' | |
6 | import { | |
7 | VideoChannelInstance, | |
8 | VideoChannelAttributes, | |
9 | ||
10 | VideoChannelMethods | |
11 | } from './video-channel-interface' | |
7a7724e6 | 12 | import { sendDeleteVideoChannel } from '../../lib/activitypub/send-request' |
e34c85e5 C |
13 | import { isVideoChannelUrlValid } from '../../helpers/custom-validators/video-channels' |
14 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | |
72c7248b C |
15 | |
16 | let VideoChannel: Sequelize.Model<VideoChannelInstance, VideoChannelAttributes> | |
17 | let toFormattedJSON: VideoChannelMethods.ToFormattedJSON | |
e4f97bab | 18 | let toActivityPubObject: VideoChannelMethods.ToActivityPubObject |
72c7248b | 19 | let isOwned: VideoChannelMethods.IsOwned |
e4f97bab | 20 | let countByAccount: VideoChannelMethods.CountByAccount |
72c7248b C |
21 | let listOwned: VideoChannelMethods.ListOwned |
22 | let listForApi: VideoChannelMethods.ListForApi | |
e4f97bab C |
23 | let listByAccount: VideoChannelMethods.ListByAccount |
24 | let loadByIdAndAccount: VideoChannelMethods.LoadByIdAndAccount | |
72c7248b | 25 | let loadByUUID: VideoChannelMethods.LoadByUUID |
e4f97bab C |
26 | let loadAndPopulateAccount: VideoChannelMethods.LoadAndPopulateAccount |
27 | let loadByUUIDAndPopulateAccount: VideoChannelMethods.LoadByUUIDAndPopulateAccount | |
72c7248b | 28 | let loadByHostAndUUID: VideoChannelMethods.LoadByHostAndUUID |
e4f97bab | 29 | let loadAndPopulateAccountAndVideos: VideoChannelMethods.LoadAndPopulateAccountAndVideos |
0d0e8dd0 C |
30 | let loadByUrl: VideoChannelMethods.LoadByUrl |
31 | let loadByUUIDOrUrl: VideoChannelMethods.LoadByUUIDOrUrl | |
72c7248b C |
32 | |
33 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | |
34 | VideoChannel = sequelize.define<VideoChannelInstance, VideoChannelAttributes>('VideoChannel', | |
35 | { | |
36 | uuid: { | |
37 | type: DataTypes.UUID, | |
38 | defaultValue: DataTypes.UUIDV4, | |
39 | allowNull: false, | |
40 | validate: { | |
41 | isUUID: 4 | |
42 | } | |
43 | }, | |
44 | name: { | |
45 | type: DataTypes.STRING, | |
46 | allowNull: false, | |
47 | validate: { | |
48 | nameValid: value => { | |
49 | const res = isVideoChannelNameValid(value) | |
50 | if (res === false) throw new Error('Video channel name is not valid.') | |
51 | } | |
52 | } | |
53 | }, | |
54 | description: { | |
55 | type: DataTypes.STRING, | |
56 | allowNull: true, | |
57 | validate: { | |
58 | descriptionValid: value => { | |
59 | const res = isVideoChannelDescriptionValid(value) | |
60 | if (res === false) throw new Error('Video channel description is not valid.') | |
61 | } | |
62 | } | |
63 | }, | |
64 | remote: { | |
65 | type: DataTypes.BOOLEAN, | |
66 | allowNull: false, | |
67 | defaultValue: false | |
e4f97bab C |
68 | }, |
69 | url: { | |
e34c85e5 | 70 | type: DataTypes.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.URL.max), |
e4f97bab C |
71 | allowNull: false, |
72 | validate: { | |
e34c85e5 C |
73 | urlValid: value => { |
74 | const res = isVideoChannelUrlValid(value) | |
75 | if (res === false) throw new Error('Video channel URL is not valid.') | |
76 | } | |
e4f97bab | 77 | } |
72c7248b C |
78 | } |
79 | }, | |
80 | { | |
81 | indexes: [ | |
82 | { | |
e4f97bab | 83 | fields: [ 'accountId' ] |
72c7248b C |
84 | } |
85 | ], | |
86 | hooks: { | |
87 | afterDestroy | |
88 | } | |
89 | } | |
90 | ) | |
91 | ||
92 | const classMethods = [ | |
93 | associate, | |
94 | ||
95 | listForApi, | |
e4f97bab | 96 | listByAccount, |
72c7248b | 97 | listOwned, |
e4f97bab C |
98 | loadByIdAndAccount, |
99 | loadAndPopulateAccount, | |
100 | loadByUUIDAndPopulateAccount, | |
72c7248b C |
101 | loadByUUID, |
102 | loadByHostAndUUID, | |
e4f97bab | 103 | loadAndPopulateAccountAndVideos, |
0d0e8dd0 C |
104 | countByAccount, |
105 | loadByUrl, | |
106 | loadByUUIDOrUrl | |
72c7248b C |
107 | ] |
108 | const instanceMethods = [ | |
109 | isOwned, | |
110 | toFormattedJSON, | |
0d0e8dd0 | 111 | toActivityPubObject |
72c7248b C |
112 | ] |
113 | addMethodsToModel(VideoChannel, classMethods, instanceMethods) | |
114 | ||
115 | return VideoChannel | |
116 | } | |
117 | ||
118 | // ------------------------------ METHODS ------------------------------ | |
119 | ||
120 | isOwned = function (this: VideoChannelInstance) { | |
121 | return this.remote === false | |
122 | } | |
123 | ||
124 | toFormattedJSON = function (this: VideoChannelInstance) { | |
125 | const json = { | |
126 | id: this.id, | |
127 | uuid: this.uuid, | |
128 | name: this.name, | |
129 | description: this.description, | |
130 | isLocal: this.isOwned(), | |
131 | createdAt: this.createdAt, | |
132 | updatedAt: this.updatedAt | |
133 | } | |
134 | ||
e4f97bab | 135 | if (this.Account !== undefined) { |
72c7248b | 136 | json['owner'] = { |
e4f97bab C |
137 | name: this.Account.name, |
138 | uuid: this.Account.uuid | |
72c7248b C |
139 | } |
140 | } | |
141 | ||
142 | if (Array.isArray(this.Videos)) { | |
143 | json['videos'] = this.Videos.map(v => v.toFormattedJSON()) | |
144 | } | |
145 | ||
146 | return json | |
147 | } | |
148 | ||
e4f97bab | 149 | toActivityPubObject = function (this: VideoChannelInstance) { |
72c7248b | 150 | const json = { |
571389d4 C |
151 | type: 'VideoChannel' as 'VideoChannel', |
152 | id: this.url, | |
72c7248b | 153 | uuid: this.uuid, |
571389d4 | 154 | content: this.description, |
72c7248b | 155 | name: this.name, |
efc32059 C |
156 | published: this.createdAt.toISOString(), |
157 | updated: this.updatedAt.toISOString() | |
72c7248b C |
158 | } |
159 | ||
160 | return json | |
161 | } | |
162 | ||
163 | // ------------------------------ STATICS ------------------------------ | |
164 | ||
165 | function associate (models) { | |
e4f97bab | 166 | VideoChannel.belongsTo(models.Account, { |
72c7248b | 167 | foreignKey: { |
e4f97bab | 168 | name: 'accountId', |
72c7248b C |
169 | allowNull: false |
170 | }, | |
171 | onDelete: 'CASCADE' | |
172 | }) | |
173 | ||
174 | VideoChannel.hasMany(models.Video, { | |
175 | foreignKey: { | |
176 | name: 'channelId', | |
177 | allowNull: false | |
178 | }, | |
179 | onDelete: 'CASCADE' | |
180 | }) | |
181 | } | |
182 | ||
911238e3 | 183 | function afterDestroy (videoChannel: VideoChannelInstance) { |
72c7248b | 184 | if (videoChannel.isOwned()) { |
7a7724e6 | 185 | return sendDeleteVideoChannel(videoChannel, undefined) |
72c7248b C |
186 | } |
187 | ||
188 | return undefined | |
189 | } | |
190 | ||
e4f97bab | 191 | countByAccount = function (accountId: number) { |
72c7248b C |
192 | const query = { |
193 | where: { | |
e4f97bab | 194 | accountId |
72c7248b C |
195 | } |
196 | } | |
197 | ||
198 | return VideoChannel.count(query) | |
199 | } | |
200 | ||
201 | listOwned = function () { | |
202 | const query = { | |
203 | where: { | |
204 | remote: false | |
205 | }, | |
e4f97bab | 206 | include: [ VideoChannel['sequelize'].models.Account ] |
72c7248b C |
207 | } |
208 | ||
209 | return VideoChannel.findAll(query) | |
210 | } | |
211 | ||
212 | listForApi = function (start: number, count: number, sort: string) { | |
213 | const query = { | |
214 | offset: start, | |
215 | limit: count, | |
216 | order: [ getSort(sort) ], | |
217 | include: [ | |
218 | { | |
e4f97bab | 219 | model: VideoChannel['sequelize'].models.Account, |
72c7248b | 220 | required: true, |
60862425 | 221 | include: [ { model: VideoChannel['sequelize'].models.Server, required: false } ] |
72c7248b C |
222 | } |
223 | ] | |
224 | } | |
225 | ||
226 | return VideoChannel.findAndCountAll(query).then(({ rows, count }) => { | |
227 | return { total: count, data: rows } | |
228 | }) | |
229 | } | |
230 | ||
e4f97bab | 231 | listByAccount = function (accountId: number) { |
72c7248b C |
232 | const query = { |
233 | order: [ getSort('createdAt') ], | |
234 | include: [ | |
235 | { | |
e4f97bab | 236 | model: VideoChannel['sequelize'].models.Account, |
72c7248b | 237 | where: { |
e4f97bab | 238 | id: accountId |
72c7248b C |
239 | }, |
240 | required: true, | |
60862425 | 241 | include: [ { model: VideoChannel['sequelize'].models.Server, required: false } ] |
72c7248b C |
242 | } |
243 | ] | |
244 | } | |
245 | ||
246 | return VideoChannel.findAndCountAll(query).then(({ rows, count }) => { | |
247 | return { total: count, data: rows } | |
248 | }) | |
249 | } | |
250 | ||
251 | loadByUUID = function (uuid: string, t?: Sequelize.Transaction) { | |
252 | const query: Sequelize.FindOptions<VideoChannelAttributes> = { | |
253 | where: { | |
254 | uuid | |
255 | } | |
256 | } | |
257 | ||
258 | if (t !== undefined) query.transaction = t | |
259 | ||
260 | return VideoChannel.findOne(query) | |
261 | } | |
262 | ||
0d0e8dd0 C |
263 | loadByUrl = function (url: string, t?: Sequelize.Transaction) { |
264 | const query: Sequelize.FindOptions<VideoChannelAttributes> = { | |
265 | where: { | |
266 | url | |
267 | } | |
268 | } | |
269 | ||
270 | if (t !== undefined) query.transaction = t | |
271 | ||
272 | return VideoChannel.findOne(query) | |
273 | } | |
274 | ||
275 | loadByUUIDOrUrl = function (uuid: string, url: string, t?: Sequelize.Transaction) { | |
276 | const query: Sequelize.FindOptions<VideoChannelAttributes> = { | |
277 | where: { | |
278 | [Sequelize.Op.or]: [ | |
279 | { uuid }, | |
280 | { url } | |
281 | ] | |
571389d4 | 282 | } |
0d0e8dd0 C |
283 | } |
284 | ||
285 | if (t !== undefined) query.transaction = t | |
286 | ||
287 | return VideoChannel.findOne(query) | |
288 | } | |
289 | ||
72c7248b C |
290 | loadByHostAndUUID = function (fromHost: string, uuid: string, t?: Sequelize.Transaction) { |
291 | const query: Sequelize.FindOptions<VideoChannelAttributes> = { | |
292 | where: { | |
293 | uuid | |
294 | }, | |
295 | include: [ | |
296 | { | |
e4f97bab | 297 | model: VideoChannel['sequelize'].models.Account, |
72c7248b C |
298 | include: [ |
299 | { | |
60862425 | 300 | model: VideoChannel['sequelize'].models.Server, |
72c7248b C |
301 | required: true, |
302 | where: { | |
303 | host: fromHost | |
304 | } | |
305 | } | |
306 | ] | |
307 | } | |
308 | ] | |
309 | } | |
310 | ||
311 | if (t !== undefined) query.transaction = t | |
312 | ||
313 | return VideoChannel.findOne(query) | |
314 | } | |
315 | ||
e4f97bab | 316 | loadByIdAndAccount = function (id: number, accountId: number) { |
72c7248b C |
317 | const options = { |
318 | where: { | |
319 | id, | |
e4f97bab | 320 | accountId |
72c7248b C |
321 | }, |
322 | include: [ | |
323 | { | |
e4f97bab | 324 | model: VideoChannel['sequelize'].models.Account, |
60862425 | 325 | include: [ { model: VideoChannel['sequelize'].models.Server, required: false } ] |
72c7248b C |
326 | } |
327 | ] | |
328 | } | |
329 | ||
330 | return VideoChannel.findOne(options) | |
331 | } | |
332 | ||
e4f97bab | 333 | loadAndPopulateAccount = function (id: number) { |
72c7248b C |
334 | const options = { |
335 | include: [ | |
336 | { | |
e4f97bab | 337 | model: VideoChannel['sequelize'].models.Account, |
60862425 | 338 | include: [ { model: VideoChannel['sequelize'].models.Server, required: false } ] |
72c7248b C |
339 | } |
340 | ] | |
341 | } | |
342 | ||
343 | return VideoChannel.findById(id, options) | |
344 | } | |
345 | ||
e4f97bab | 346 | loadByUUIDAndPopulateAccount = function (uuid: string) { |
72c7248b C |
347 | const options = { |
348 | where: { | |
349 | uuid | |
350 | }, | |
351 | include: [ | |
352 | { | |
e4f97bab | 353 | model: VideoChannel['sequelize'].models.Account, |
60862425 | 354 | include: [ { model: VideoChannel['sequelize'].models.Server, required: false } ] |
72c7248b C |
355 | } |
356 | ] | |
357 | } | |
358 | ||
359 | return VideoChannel.findOne(options) | |
360 | } | |
361 | ||
e4f97bab | 362 | loadAndPopulateAccountAndVideos = function (id: number) { |
72c7248b C |
363 | const options = { |
364 | include: [ | |
365 | { | |
e4f97bab | 366 | model: VideoChannel['sequelize'].models.Account, |
60862425 | 367 | include: [ { model: VideoChannel['sequelize'].models.Server, required: false } ] |
72c7248b C |
368 | }, |
369 | VideoChannel['sequelize'].models.Video | |
370 | ] | |
371 | } | |
372 | ||
373 | return VideoChannel.findById(id, options) | |
374 | } |