diff options
Diffstat (limited to 'server/models/video/video-channel.ts')
-rw-r--r-- | server/models/video/video-channel.ts | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts new file mode 100644 index 000000000..e469383e9 --- /dev/null +++ b/server/models/video/video-channel.ts | |||
@@ -0,0 +1,349 @@ | |||
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, options: { transaction: Sequelize.Transaction }) { | ||
182 | if (videoChannel.isOwned()) { | ||
183 | const removeVideoChannelToFriendsParams = { | ||
184 | uuid: videoChannel.uuid | ||
185 | } | ||
186 | |||
187 | return removeVideoChannelToFriends(removeVideoChannelToFriendsParams, options.transaction) | ||
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 | } | ||