aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video/video-channel.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/video/video-channel.ts')
-rw-r--r--server/models/video/video-channel.ts164
1 files changed, 69 insertions, 95 deletions
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts
index fe44d3d53..acc2486b3 100644
--- a/server/models/video/video-channel.ts
+++ b/server/models/video/video-channel.ts
@@ -1,42 +1,52 @@
1import * as Sequelize from 'sequelize'
2import { 1import {
3 AfterDestroy, 2 AfterDestroy,
4 AllowNull, 3 AllowNull,
5 BelongsTo, 4 BelongsTo,
6 Column, 5 Column,
7 CreatedAt, 6 CreatedAt,
8 DataType, 7 DefaultScope,
9 Default,
10 ForeignKey, 8 ForeignKey,
11 HasMany, 9 HasMany,
12 Is, 10 Is,
13 IsUUID,
14 Model, 11 Model,
15 Scopes, 12 Scopes,
16 Table, 13 Table,
17 UpdatedAt 14 UpdatedAt
18} from 'sequelize-typescript' 15} from 'sequelize-typescript'
19import { IFindOptions } from 'sequelize-typescript/lib/interfaces/IFindOptions' 16import { ActivityPubActor } from '../../../shared/models/activitypub'
20import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels' 17import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels'
21import { sendDeleteVideoChannel } from '../../lib/activitypub/send' 18import { sendDeleteActor } from '../../lib/activitypub/send'
22import { AccountModel } from '../account/account' 19import { AccountModel } from '../account/account'
23import { ActorModel } from '../activitypub/actor' 20import { ActorModel } from '../activitypub/actor'
24import { ServerModel } from '../server/server'
25import { getSort, throwIfNotValid } from '../utils' 21import { getSort, throwIfNotValid } from '../utils'
26import { VideoModel } from './video' 22import { VideoModel } from './video'
27import { VideoChannelShareModel } from './video-channel-share'
28 23
29enum ScopeNames { 24enum ScopeNames {
30 WITH_ACCOUNT = 'WITH_ACCOUNT', 25 WITH_ACCOUNT = 'WITH_ACCOUNT',
26 WITH_ACTOR = 'WITH_ACTOR',
31 WITH_VIDEOS = 'WITH_VIDEOS' 27 WITH_VIDEOS = 'WITH_VIDEOS'
32} 28}
33 29
30@DefaultScope({
31 include: [
32 {
33 model: () => ActorModel,
34 required: true
35 }
36 ]
37})
34@Scopes({ 38@Scopes({
35 [ScopeNames.WITH_ACCOUNT]: { 39 [ScopeNames.WITH_ACCOUNT]: {
36 include: [ 40 include: [
37 { 41 {
38 model: () => AccountModel, 42 model: () => AccountModel,
39 include: [ { model: () => ServerModel, required: false } ] 43 required: true,
44 include: [
45 {
46 model: () => ActorModel,
47 required: true
48 }
49 ]
40 } 50 }
41 ] 51 ]
42 }, 52 },
@@ -44,6 +54,11 @@ enum ScopeNames {
44 include: [ 54 include: [
45 () => VideoModel 55 () => VideoModel
46 ] 56 ]
57 },
58 [ScopeNames.WITH_ACTOR]: {
59 include: [
60 () => ActorModel
61 ]
47 } 62 }
48}) 63})
49@Table({ 64@Table({
@@ -57,12 +72,6 @@ enum ScopeNames {
57export class VideoChannelModel extends Model<VideoChannelModel> { 72export class VideoChannelModel extends Model<VideoChannelModel> {
58 73
59 @AllowNull(false) 74 @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')) 75 @Is('VideoChannelName', value => throwIfNotValid(value, isVideoChannelNameValid, 'name'))
67 @Column 76 @Column
68 name: string 77 name: string
@@ -72,10 +81,6 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
72 @Column 81 @Column
73 description: string 82 description: string
74 83
75 @AllowNull(false)
76 @Column
77 remote: boolean
78
79 @CreatedAt 84 @CreatedAt
80 createdAt: Date 85 createdAt: Date
81 86
@@ -115,19 +120,10 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
115 }) 120 })
116 Videos: VideoModel[] 121 Videos: VideoModel[]
117 122
118 @HasMany(() => VideoChannelShareModel, {
119 foreignKey: {
120 name: 'channelId',
121 allowNull: false
122 },
123 onDelete: 'CASCADE'
124 })
125 VideoChannelShares: VideoChannelShareModel[]
126
127 @AfterDestroy 123 @AfterDestroy
128 static sendDeleteIfOwned (instance: VideoChannelModel) { 124 static sendDeleteIfOwned (instance: VideoChannelModel) {
129 if (instance.isOwned()) { 125 if (instance.Actor.isOwned()) {
130 return sendDeleteVideoChannel(instance, undefined) 126 return sendDeleteActor(instance.Actor, undefined)
131 } 127 }
132 128
133 return undefined 129 return undefined
@@ -150,7 +146,9 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
150 order: [ getSort(sort) ] 146 order: [ getSort(sort) ]
151 } 147 }
152 148
153 return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findAndCountAll(query) 149 return VideoChannelModel
150 .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
151 .findAndCountAll(query)
154 .then(({ rows, count }) => { 152 .then(({ rows, count }) => {
155 return { total: count, data: rows } 153 return { total: count, data: rows }
156 }) 154 })
@@ -165,51 +163,18 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
165 where: { 163 where: {
166 id: accountId 164 id: accountId
167 }, 165 },
168 required: true, 166 required: true
169 include: [ { model: ServerModel, required: false } ]
170 } 167 }
171 ] 168 ]
172 } 169 }
173 170
174 return VideoChannelModel.findAndCountAll(query) 171 return VideoChannelModel
172 .findAndCountAll(query)
175 .then(({ rows, count }) => { 173 .then(({ rows, count }) => {
176 return { total: count, data: rows } 174 return { total: count, data: rows }
177 }) 175 })
178 } 176 }
179 177
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) { 178 static loadByIdAndAccount (id: number, accountId: number) {
214 const options = { 179 const options = {
215 where: { 180 where: {
@@ -218,21 +183,33 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
218 } 183 }
219 } 184 }
220 185
221 return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findOne(options) 186 return VideoChannelModel
187 .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
188 .findOne(options)
222 } 189 }
223 190
224 static loadAndPopulateAccount (id: number) { 191 static loadAndPopulateAccount (id: number) {
225 return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findById(id) 192 return VideoChannelModel
193 .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
194 .findById(id)
226 } 195 }
227 196
228 static loadByUUIDAndPopulateAccount (uuid: string) { 197 static loadByUUIDAndPopulateAccount (uuid: string) {
229 const options = { 198 const options = {
230 where: { 199 include: [
231 uuid 200 {
232 } 201 model: ActorModel,
202 required: true,
203 where: {
204 uuid
205 }
206 }
207 ]
233 } 208 }
234 209
235 return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findOne(options) 210 return VideoChannelModel
211 .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
212 .findOne(options)
236 } 213 }
237 214
238 static loadAndPopulateAccountAndVideos (id: number) { 215 static loadAndPopulateAccountAndVideos (id: number) {
@@ -242,39 +219,36 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
242 ] 219 ]
243 } 220 }
244 221
245 return VideoChannelModel.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEOS ]).findById(id, options) 222 return VideoChannelModel
246 } 223 .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEOS ])
247 224 .findById(id, options)
248 isOwned () {
249 return this.remote === false
250 } 225 }
251 226
252 toFormattedJSON () { 227 toFormattedJSON () {
253 const json = { 228 const actor = this.Actor.toFormattedJSON()
229 const account = {
254 id: this.id, 230 id: this.id,
255 uuid: this.uuid,
256 name: this.name, 231 name: this.name,
257 description: this.description, 232 description: this.description,
258 isLocal: this.isOwned(), 233 isLocal: this.Actor.isOwned(),
259 createdAt: this.createdAt, 234 createdAt: this.createdAt,
260 updatedAt: this.updatedAt 235 updatedAt: this.updatedAt
261 } 236 }
262 237
263 if (this.Account !== undefined) { 238 return Object.assign(actor, account)
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 } 239 }
276 240
277 toActivityPubObject () { 241 toActivityPubObject (): ActivityPubActor {
278 return this.Actor.toActivityPubObject(this.name, this.uuid, 'VideoChannel') 242 const obj = this.Actor.toActivityPubObject(this.name, 'VideoChannel')
243
244 return Object.assign(obj, {
245 summary: this.description,
246 attributedTo: [
247 {
248 type: 'Person' as 'Person',
249 id: this.Account.Actor.url
250 }
251 ]
252 })
279 } 253 }
280} 254}