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