]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/models/video/video-channel.ts
Fix video upload and videos list
[github/Chocobozzz/PeerTube.git] / server / models / video / video-channel.ts
1 import * as Sequelize from 'sequelize'
2
3 import { isVideoChannelNameValid, isVideoChannelDescriptionValid } from '../../helpers'
4
5 import { addMethodsToModel, getSort } from '../utils'
6 import {
7 VideoChannelInstance,
8 VideoChannelAttributes,
9
10 VideoChannelMethods
11 } from './video-channel-interface'
12 import { sendDeleteVideoChannel } from '../../lib/activitypub/send-request'
13 import { isVideoChannelUrlValid } from '../../helpers/custom-validators/video-channels'
14 import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
15
16 let VideoChannel: Sequelize.Model<VideoChannelInstance, VideoChannelAttributes>
17 let toFormattedJSON: VideoChannelMethods.ToFormattedJSON
18 let toActivityPubObject: VideoChannelMethods.ToActivityPubObject
19 let isOwned: VideoChannelMethods.IsOwned
20 let countByAccount: VideoChannelMethods.CountByAccount
21 let listOwned: VideoChannelMethods.ListOwned
22 let listForApi: VideoChannelMethods.ListForApi
23 let listByAccount: VideoChannelMethods.ListByAccount
24 let loadByIdAndAccount: VideoChannelMethods.LoadByIdAndAccount
25 let loadByUUID: VideoChannelMethods.LoadByUUID
26 let loadAndPopulateAccount: VideoChannelMethods.LoadAndPopulateAccount
27 let loadByUUIDAndPopulateAccount: VideoChannelMethods.LoadByUUIDAndPopulateAccount
28 let loadByHostAndUUID: VideoChannelMethods.LoadByHostAndUUID
29 let loadAndPopulateAccountAndVideos: VideoChannelMethods.LoadAndPopulateAccountAndVideos
30 let loadByUrl: VideoChannelMethods.LoadByUrl
31 let loadByUUIDOrUrl: VideoChannelMethods.LoadByUUIDOrUrl
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
68 },
69 url: {
70 type: DataTypes.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.URL.max),
71 allowNull: false,
72 validate: {
73 urlValid: value => {
74 const res = isVideoChannelUrlValid(value)
75 if (res === false) throw new Error('Video channel URL is not valid.')
76 }
77 }
78 }
79 },
80 {
81 indexes: [
82 {
83 fields: [ 'accountId' ]
84 }
85 ],
86 hooks: {
87 afterDestroy
88 }
89 }
90 )
91
92 const classMethods = [
93 associate,
94
95 listForApi,
96 listByAccount,
97 listOwned,
98 loadByIdAndAccount,
99 loadAndPopulateAccount,
100 loadByUUIDAndPopulateAccount,
101 loadByUUID,
102 loadByHostAndUUID,
103 loadAndPopulateAccountAndVideos,
104 countByAccount,
105 loadByUrl,
106 loadByUUIDOrUrl
107 ]
108 const instanceMethods = [
109 isOwned,
110 toFormattedJSON,
111 toActivityPubObject
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
135 if (this.Account !== undefined) {
136 json['owner'] = {
137 name: this.Account.name,
138 uuid: this.Account.uuid
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
149 toActivityPubObject = function (this: VideoChannelInstance) {
150 const json = {
151 type: 'VideoChannel' as 'VideoChannel',
152 id: this.url,
153 uuid: this.uuid,
154 content: this.description,
155 name: this.name,
156 published: this.createdAt,
157 updated: this.updatedAt
158 }
159
160 return json
161 }
162
163 // ------------------------------ STATICS ------------------------------
164
165 function associate (models) {
166 VideoChannel.belongsTo(models.Account, {
167 foreignKey: {
168 name: 'accountId',
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
183 function afterDestroy (videoChannel: VideoChannelInstance) {
184 if (videoChannel.isOwned()) {
185 return sendDeleteVideoChannel(videoChannel, undefined)
186 }
187
188 return undefined
189 }
190
191 countByAccount = function (accountId: number) {
192 const query = {
193 where: {
194 accountId
195 }
196 }
197
198 return VideoChannel.count(query)
199 }
200
201 listOwned = function () {
202 const query = {
203 where: {
204 remote: false
205 },
206 include: [ VideoChannel['sequelize'].models.Account ]
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 {
219 model: VideoChannel['sequelize'].models.Account,
220 required: true,
221 include: [ { model: VideoChannel['sequelize'].models.Server, required: false } ]
222 }
223 ]
224 }
225
226 return VideoChannel.findAndCountAll(query).then(({ rows, count }) => {
227 return { total: count, data: rows }
228 })
229 }
230
231 listByAccount = function (accountId: number) {
232 const query = {
233 order: [ getSort('createdAt') ],
234 include: [
235 {
236 model: VideoChannel['sequelize'].models.Account,
237 where: {
238 id: accountId
239 },
240 required: true,
241 include: [ { model: VideoChannel['sequelize'].models.Server, required: false } ]
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
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 ]
282 }
283 }
284
285 if (t !== undefined) query.transaction = t
286
287 return VideoChannel.findOne(query)
288 }
289
290 loadByHostAndUUID = function (fromHost: string, uuid: string, t?: Sequelize.Transaction) {
291 const query: Sequelize.FindOptions<VideoChannelAttributes> = {
292 where: {
293 uuid
294 },
295 include: [
296 {
297 model: VideoChannel['sequelize'].models.Account,
298 include: [
299 {
300 model: VideoChannel['sequelize'].models.Server,
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
316 loadByIdAndAccount = function (id: number, accountId: number) {
317 const options = {
318 where: {
319 id,
320 accountId
321 },
322 include: [
323 {
324 model: VideoChannel['sequelize'].models.Account,
325 include: [ { model: VideoChannel['sequelize'].models.Server, required: false } ]
326 }
327 ]
328 }
329
330 return VideoChannel.findOne(options)
331 }
332
333 loadAndPopulateAccount = function (id: number) {
334 const options = {
335 include: [
336 {
337 model: VideoChannel['sequelize'].models.Account,
338 include: [ { model: VideoChannel['sequelize'].models.Server, required: false } ]
339 }
340 ]
341 }
342
343 return VideoChannel.findById(id, options)
344 }
345
346 loadByUUIDAndPopulateAccount = function (uuid: string) {
347 const options = {
348 where: {
349 uuid
350 },
351 include: [
352 {
353 model: VideoChannel['sequelize'].models.Account,
354 include: [ { model: VideoChannel['sequelize'].models.Server, required: false } ]
355 }
356 ]
357 }
358
359 return VideoChannel.findOne(options)
360 }
361
362 loadAndPopulateAccountAndVideos = function (id: number) {
363 const options = {
364 include: [
365 {
366 model: VideoChannel['sequelize'].models.Account,
367 include: [ { model: VideoChannel['sequelize'].models.Server, required: false } ]
368 },
369 VideoChannel['sequelize'].models.Video
370 ]
371 }
372
373 return VideoChannel.findById(id, options)
374 }