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