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