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