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