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