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