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