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