Basic api documentation #7 (#220)
[oweals/peertube.git] / server / models / video / video-channel.ts
1 import {
2   AllowNull, BeforeDestroy, BelongsTo, Column, CreatedAt, DefaultScope, ForeignKey, HasMany, Is, Model, Scopes, Table,
3   UpdatedAt
4 } from 'sequelize-typescript'
5 import { ActivityPubActor } from '../../../shared/models/activitypub'
6 import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels'
7 import { logger } from '../../helpers/logger'
8 import { sendDeleteActor } from '../../lib/activitypub/send'
9 import { AccountModel } from '../account/account'
10 import { ActorModel } from '../activitypub/actor'
11 import { getSort, throwIfNotValid } from '../utils'
12 import { VideoModel } from './video'
13
14 enum ScopeNames {
15   WITH_ACCOUNT = 'WITH_ACCOUNT',
16   WITH_ACTOR = 'WITH_ACTOR',
17   WITH_VIDEOS = 'WITH_VIDEOS'
18 }
19
20 @DefaultScope({
21   include: [
22     {
23       model: () => ActorModel,
24       required: true
25     }
26   ]
27 })
28 @Scopes({
29   [ScopeNames.WITH_ACCOUNT]: {
30     include: [
31       {
32         model: () => AccountModel,
33         required: true,
34         include: [
35           {
36             model: () => ActorModel,
37             required: true
38           }
39         ]
40       }
41     ]
42   },
43   [ScopeNames.WITH_VIDEOS]: {
44     include: [
45       () => VideoModel
46     ]
47   },
48   [ScopeNames.WITH_ACTOR]: {
49     include: [
50       () => ActorModel
51     ]
52   }
53 })
54 @Table({
55   tableName: 'videoChannel',
56   indexes: [
57     {
58       fields: [ 'accountId' ]
59     }
60   ]
61 })
62 export class VideoChannelModel extends Model<VideoChannelModel> {
63
64   @AllowNull(false)
65   @Is('VideoChannelName', value => throwIfNotValid(value, isVideoChannelNameValid, 'name'))
66   @Column
67   name: string
68
69   @AllowNull(true)
70   @Is('VideoChannelDescription', value => throwIfNotValid(value, isVideoChannelDescriptionValid, 'description'))
71   @Column
72   description: string
73
74   @CreatedAt
75   createdAt: Date
76
77   @UpdatedAt
78   updatedAt: Date
79
80   @ForeignKey(() => ActorModel)
81   @Column
82   actorId: number
83
84   @BelongsTo(() => ActorModel, {
85     foreignKey: {
86       allowNull: false
87     },
88     onDelete: 'cascade'
89   })
90   Actor: ActorModel
91
92   @ForeignKey(() => AccountModel)
93   @Column
94   accountId: number
95
96   @BelongsTo(() => AccountModel, {
97     foreignKey: {
98       allowNull: false
99     },
100     onDelete: 'CASCADE'
101   })
102   Account: AccountModel
103
104   @HasMany(() => VideoModel, {
105     foreignKey: {
106       name: 'channelId',
107       allowNull: false
108     },
109     onDelete: 'CASCADE',
110     hooks: true
111   })
112   Videos: VideoModel[]
113
114   @BeforeDestroy
115   static async sendDeleteIfOwned (instance: VideoChannelModel, options) {
116     if (!instance.Actor) {
117       instance.Actor = await instance.$get('Actor', { transaction: options.transaction }) as ActorModel
118     }
119
120     if (instance.Actor.isOwned()) {
121       logger.debug('Sending delete of actor of video channel %s.', instance.Actor.url)
122
123       return sendDeleteActor(instance.Actor, options.transaction)
124     }
125
126     return undefined
127   }
128
129   static countByAccount (accountId: number) {
130     const query = {
131       where: {
132         accountId
133       }
134     }
135
136     return VideoChannelModel.count(query)
137   }
138
139   static listForApi (start: number, count: number, sort: string) {
140     const query = {
141       offset: start,
142       limit: count,
143       order: [ getSort(sort) ]
144     }
145
146     return VideoChannelModel
147       .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
148       .findAndCountAll(query)
149       .then(({ rows, count }) => {
150         return { total: count, data: rows }
151       })
152   }
153
154   static listByAccount (accountId: number) {
155     const query = {
156       order: [ getSort('createdAt') ],
157       include: [
158         {
159           model: AccountModel,
160           where: {
161             id: accountId
162           },
163           required: true
164         }
165       ]
166     }
167
168     return VideoChannelModel
169       .findAndCountAll(query)
170       .then(({ rows, count }) => {
171         return { total: count, data: rows }
172       })
173   }
174
175   static loadByIdAndAccount (id: number, accountId: number) {
176     const options = {
177       where: {
178         id,
179         accountId
180       }
181     }
182
183     return VideoChannelModel
184       .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
185       .findOne(options)
186   }
187
188   static loadAndPopulateAccount (id: number) {
189     return VideoChannelModel
190       .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
191       .findById(id)
192   }
193
194   static loadByUUIDAndPopulateAccount (uuid: string) {
195     const options = {
196       include: [
197         {
198           model: ActorModel,
199           required: true,
200           where: {
201             uuid
202           }
203         }
204       ]
205     }
206
207     return VideoChannelModel
208       .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
209       .findOne(options)
210   }
211
212   static loadAndPopulateAccountAndVideos (id: number) {
213     const options = {
214       include: [
215         VideoModel
216       ]
217     }
218
219     return VideoChannelModel
220       .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEOS ])
221       .findById(id, options)
222   }
223
224   toFormattedJSON () {
225     const actor = this.Actor.toFormattedJSON()
226     const account = {
227       id: this.id,
228       displayName: this.name,
229       description: this.description,
230       isLocal: this.Actor.isOwned(),
231       createdAt: this.createdAt,
232       updatedAt: this.updatedAt
233     }
234
235     return Object.assign(actor, account)
236   }
237
238   toActivityPubObject (): ActivityPubActor {
239     const obj = this.Actor.toActivityPubObject(this.name, 'VideoChannel')
240
241     return Object.assign(obj, {
242       summary: this.description,
243       attributedTo: [
244         {
245           type: 'Person' as 'Person',
246           id: this.Account.Actor.url
247         }
248       ]
249     })
250   }
251 }