1 import * as Sequelize from 'sequelize'
17 } from 'sequelize-typescript'
18 import { IFindOptions } from 'sequelize-typescript/lib/interfaces/IFindOptions'
19 import { activityPubCollection } from '../../helpers'
20 import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub'
21 import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels'
22 import { CONSTRAINTS_FIELDS } from '../../initializers'
23 import { getAnnounceActivityPubUrl } from '../../lib/activitypub'
24 import { sendDeleteVideoChannel } from '../../lib/activitypub/send'
25 import { AccountModel } from '../account/account'
26 import { ServerModel } from '../server/server'
27 import { getSort, throwIfNotValid } from '../utils'
28 import { VideoModel } from './video'
29 import { VideoChannelShareModel } from './video-channel-share'
32 WITH_ACCOUNT = 'WITH_ACCOUNT',
33 WITH_VIDEOS = 'WITH_VIDEOS'
37 [ScopeNames.WITH_ACCOUNT]: {
40 model: () => AccountModel,
41 include: [ { model: () => ServerModel, required: false } ]
45 [ScopeNames.WITH_VIDEOS]: {
52 tableName: 'videoChannel',
55 fields: [ 'accountId' ]
59 export class VideoChannelModel extends Model<VideoChannelModel> {
62 @Default(DataType.UUIDV4)
64 @Column(DataType.UUID)
68 @Is('VideoChannelName', value => throwIfNotValid(value, isVideoChannelNameValid, 'name'))
73 @Is('VideoChannelDescription', value => throwIfNotValid(value, isVideoChannelDescriptionValid, 'description'))
82 @Is('VideoChannelUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
83 @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.URL.max))
92 @ForeignKey(() => AccountModel)
96 @BelongsTo(() => AccountModel, {
102 Account: AccountModel
104 @HasMany(() => VideoModel, {
113 @HasMany(() => VideoChannelShareModel, {
120 VideoChannelShares: VideoChannelShareModel[]
123 static sendDeleteIfOwned (instance: VideoChannelModel) {
124 if (instance.isOwned()) {
125 return sendDeleteVideoChannel(instance, undefined)
131 static countByAccount (accountId: number) {
138 return VideoChannelModel.count(query)
141 static listForApi (start: number, count: number, sort: string) {
145 order: [ getSort(sort) ]
148 return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findAndCountAll(query)
149 .then(({ rows, count }) => {
150 return { total: count, data: rows }
154 static listByAccount (accountId: number) {
156 order: [ getSort('createdAt') ],
164 include: [ { model: ServerModel, required: false } ]
169 return VideoChannelModel.findAndCountAll(query)
170 .then(({ rows, count }) => {
171 return { total: count, data: rows }
175 static loadByUrl (url: string, t?: Sequelize.Transaction) {
176 const query: IFindOptions<VideoChannelModel> = {
182 if (t !== undefined) query.transaction = t
184 return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findOne(query)
187 static loadByUUIDOrUrl (uuid: string, url: string, t?: Sequelize.Transaction) {
188 const query: IFindOptions<VideoChannelModel> = {
190 [ Sequelize.Op.or ]: [
197 if (t !== undefined) query.transaction = t
199 return VideoChannelModel.findOne(query)
202 static loadByIdAndAccount (id: number, accountId: number) {
210 return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findOne(options)
213 static loadAndPopulateAccount (id: number) {
214 return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findById(id)
217 static loadByUUIDAndPopulateAccount (uuid: string) {
224 return VideoChannelModel.scope(ScopeNames.WITH_ACCOUNT).findOne(options)
227 static loadAndPopulateAccountAndVideos (id: number) {
234 return VideoChannelModel.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEOS ]).findById(id, options)
238 return this.remote === false
246 description: this.description,
247 isLocal: this.isOwned(),
248 createdAt: this.createdAt,
249 updatedAt: this.updatedAt
252 if (this.Account !== undefined) {
254 name: this.Account.name,
255 uuid: this.Account.uuid
259 if (Array.isArray(this.Videos)) {
260 json[ 'videos' ] = this.Videos.map(v => v.toFormattedJSON())
266 toActivityPubObject () {
268 if (Array.isArray(this.VideoChannelShares)) {
269 const shares: string[] = []
271 for (const videoChannelShare of this.VideoChannelShares) {
272 const shareUrl = getAnnounceActivityPubUrl(this.url, videoChannelShare.Account)
273 shares.push(shareUrl)
276 sharesObject = activityPubCollection(shares)
280 type: 'VideoChannel' as 'VideoChannel',
283 content: this.description,
285 published: this.createdAt.toISOString(),
286 updated: this.updatedAt.toISOString(),