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