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