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