]>
Commit | Line | Data |
---|---|---|
72c7248b C |
1 | import * as Sequelize from 'sequelize' |
2 | ||
3 | import { isVideoChannelNameValid, isVideoChannelDescriptionValid } from '../../helpers' | |
72c7248b C |
4 | |
5 | import { addMethodsToModel, getSort } from '../utils' | |
6 | import { | |
7 | VideoChannelInstance, | |
8 | VideoChannelAttributes, | |
9 | ||
10 | VideoChannelMethods | |
11 | } from './video-channel-interface' | |
7a7724e6 | 12 | import { sendDeleteVideoChannel } from '../../lib/activitypub/send-request' |
72c7248b C |
13 | |
14 | let VideoChannel: Sequelize.Model<VideoChannelInstance, VideoChannelAttributes> | |
15 | let toFormattedJSON: VideoChannelMethods.ToFormattedJSON | |
e4f97bab | 16 | let toActivityPubObject: VideoChannelMethods.ToActivityPubObject |
72c7248b | 17 | let isOwned: VideoChannelMethods.IsOwned |
e4f97bab | 18 | let countByAccount: VideoChannelMethods.CountByAccount |
72c7248b C |
19 | let listOwned: VideoChannelMethods.ListOwned |
20 | let listForApi: VideoChannelMethods.ListForApi | |
e4f97bab C |
21 | let listByAccount: VideoChannelMethods.ListByAccount |
22 | let loadByIdAndAccount: VideoChannelMethods.LoadByIdAndAccount | |
72c7248b | 23 | let loadByUUID: VideoChannelMethods.LoadByUUID |
e4f97bab C |
24 | let loadAndPopulateAccount: VideoChannelMethods.LoadAndPopulateAccount |
25 | let loadByUUIDAndPopulateAccount: VideoChannelMethods.LoadByUUIDAndPopulateAccount | |
72c7248b | 26 | let loadByHostAndUUID: VideoChannelMethods.LoadByHostAndUUID |
e4f97bab | 27 | let loadAndPopulateAccountAndVideos: VideoChannelMethods.LoadAndPopulateAccountAndVideos |
0d0e8dd0 C |
28 | let loadByUrl: VideoChannelMethods.LoadByUrl |
29 | let loadByUUIDOrUrl: VideoChannelMethods.LoadByUUIDOrUrl | |
72c7248b C |
30 | |
31 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | |
32 | VideoChannel = sequelize.define<VideoChannelInstance, VideoChannelAttributes>('VideoChannel', | |
33 | { | |
34 | uuid: { | |
35 | type: DataTypes.UUID, | |
36 | defaultValue: DataTypes.UUIDV4, | |
37 | allowNull: false, | |
38 | validate: { | |
39 | isUUID: 4 | |
40 | } | |
41 | }, | |
42 | name: { | |
43 | type: DataTypes.STRING, | |
44 | allowNull: false, | |
45 | validate: { | |
46 | nameValid: value => { | |
47 | const res = isVideoChannelNameValid(value) | |
48 | if (res === false) throw new Error('Video channel name is not valid.') | |
49 | } | |
50 | } | |
51 | }, | |
52 | description: { | |
53 | type: DataTypes.STRING, | |
54 | allowNull: true, | |
55 | validate: { | |
56 | descriptionValid: value => { | |
57 | const res = isVideoChannelDescriptionValid(value) | |
58 | if (res === false) throw new Error('Video channel description is not valid.') | |
59 | } | |
60 | } | |
61 | }, | |
62 | remote: { | |
63 | type: DataTypes.BOOLEAN, | |
64 | allowNull: false, | |
65 | defaultValue: false | |
e4f97bab C |
66 | }, |
67 | url: { | |
68 | type: DataTypes.STRING, | |
69 | allowNull: false, | |
70 | validate: { | |
71 | isUrl: true | |
72 | } | |
72c7248b C |
73 | } |
74 | }, | |
75 | { | |
76 | indexes: [ | |
77 | { | |
e4f97bab | 78 | fields: [ 'accountId' ] |
72c7248b C |
79 | } |
80 | ], | |
81 | hooks: { | |
82 | afterDestroy | |
83 | } | |
84 | } | |
85 | ) | |
86 | ||
87 | const classMethods = [ | |
88 | associate, | |
89 | ||
90 | listForApi, | |
e4f97bab | 91 | listByAccount, |
72c7248b | 92 | listOwned, |
e4f97bab C |
93 | loadByIdAndAccount, |
94 | loadAndPopulateAccount, | |
95 | loadByUUIDAndPopulateAccount, | |
72c7248b C |
96 | loadByUUID, |
97 | loadByHostAndUUID, | |
e4f97bab | 98 | loadAndPopulateAccountAndVideos, |
0d0e8dd0 C |
99 | countByAccount, |
100 | loadByUrl, | |
101 | loadByUUIDOrUrl | |
72c7248b C |
102 | ] |
103 | const instanceMethods = [ | |
104 | isOwned, | |
105 | toFormattedJSON, | |
0d0e8dd0 | 106 | toActivityPubObject |
72c7248b C |
107 | ] |
108 | addMethodsToModel(VideoChannel, classMethods, instanceMethods) | |
109 | ||
110 | return VideoChannel | |
111 | } | |
112 | ||
113 | // ------------------------------ METHODS ------------------------------ | |
114 | ||
115 | isOwned = function (this: VideoChannelInstance) { | |
116 | return this.remote === false | |
117 | } | |
118 | ||
119 | toFormattedJSON = function (this: VideoChannelInstance) { | |
120 | const json = { | |
121 | id: this.id, | |
122 | uuid: this.uuid, | |
123 | name: this.name, | |
124 | description: this.description, | |
125 | isLocal: this.isOwned(), | |
126 | createdAt: this.createdAt, | |
127 | updatedAt: this.updatedAt | |
128 | } | |
129 | ||
e4f97bab | 130 | if (this.Account !== undefined) { |
72c7248b | 131 | json['owner'] = { |
e4f97bab C |
132 | name: this.Account.name, |
133 | uuid: this.Account.uuid | |
72c7248b C |
134 | } |
135 | } | |
136 | ||
137 | if (Array.isArray(this.Videos)) { | |
138 | json['videos'] = this.Videos.map(v => v.toFormattedJSON()) | |
139 | } | |
140 | ||
141 | return json | |
142 | } | |
143 | ||
e4f97bab | 144 | toActivityPubObject = function (this: VideoChannelInstance) { |
72c7248b | 145 | const json = { |
571389d4 C |
146 | type: 'VideoChannel' as 'VideoChannel', |
147 | id: this.url, | |
72c7248b | 148 | uuid: this.uuid, |
571389d4 | 149 | content: this.description, |
72c7248b | 150 | name: this.name, |
571389d4 C |
151 | published: this.createdAt, |
152 | updated: this.updatedAt | |
72c7248b C |
153 | } |
154 | ||
155 | return json | |
156 | } | |
157 | ||
158 | // ------------------------------ STATICS ------------------------------ | |
159 | ||
160 | function associate (models) { | |
e4f97bab | 161 | VideoChannel.belongsTo(models.Account, { |
72c7248b | 162 | foreignKey: { |
e4f97bab | 163 | name: 'accountId', |
72c7248b C |
164 | allowNull: false |
165 | }, | |
166 | onDelete: 'CASCADE' | |
167 | }) | |
168 | ||
169 | VideoChannel.hasMany(models.Video, { | |
170 | foreignKey: { | |
171 | name: 'channelId', | |
172 | allowNull: false | |
173 | }, | |
174 | onDelete: 'CASCADE' | |
175 | }) | |
176 | } | |
177 | ||
911238e3 | 178 | function afterDestroy (videoChannel: VideoChannelInstance) { |
72c7248b | 179 | if (videoChannel.isOwned()) { |
7a7724e6 | 180 | return sendDeleteVideoChannel(videoChannel, undefined) |
72c7248b C |
181 | } |
182 | ||
183 | return undefined | |
184 | } | |
185 | ||
e4f97bab | 186 | countByAccount = function (accountId: number) { |
72c7248b C |
187 | const query = { |
188 | where: { | |
e4f97bab | 189 | accountId |
72c7248b C |
190 | } |
191 | } | |
192 | ||
193 | return VideoChannel.count(query) | |
194 | } | |
195 | ||
196 | listOwned = function () { | |
197 | const query = { | |
198 | where: { | |
199 | remote: false | |
200 | }, | |
e4f97bab | 201 | include: [ VideoChannel['sequelize'].models.Account ] |
72c7248b C |
202 | } |
203 | ||
204 | return VideoChannel.findAll(query) | |
205 | } | |
206 | ||
207 | listForApi = function (start: number, count: number, sort: string) { | |
208 | const query = { | |
209 | offset: start, | |
210 | limit: count, | |
211 | order: [ getSort(sort) ], | |
212 | include: [ | |
213 | { | |
e4f97bab | 214 | model: VideoChannel['sequelize'].models.Account, |
72c7248b C |
215 | required: true, |
216 | include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] | |
217 | } | |
218 | ] | |
219 | } | |
220 | ||
221 | return VideoChannel.findAndCountAll(query).then(({ rows, count }) => { | |
222 | return { total: count, data: rows } | |
223 | }) | |
224 | } | |
225 | ||
e4f97bab | 226 | listByAccount = function (accountId: number) { |
72c7248b C |
227 | const query = { |
228 | order: [ getSort('createdAt') ], | |
229 | include: [ | |
230 | { | |
e4f97bab | 231 | model: VideoChannel['sequelize'].models.Account, |
72c7248b | 232 | where: { |
e4f97bab | 233 | id: accountId |
72c7248b C |
234 | }, |
235 | required: true, | |
236 | include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] | |
237 | } | |
238 | ] | |
239 | } | |
240 | ||
241 | return VideoChannel.findAndCountAll(query).then(({ rows, count }) => { | |
242 | return { total: count, data: rows } | |
243 | }) | |
244 | } | |
245 | ||
246 | loadByUUID = function (uuid: string, t?: Sequelize.Transaction) { | |
247 | const query: Sequelize.FindOptions<VideoChannelAttributes> = { | |
248 | where: { | |
249 | uuid | |
250 | } | |
251 | } | |
252 | ||
253 | if (t !== undefined) query.transaction = t | |
254 | ||
255 | return VideoChannel.findOne(query) | |
256 | } | |
257 | ||
0d0e8dd0 C |
258 | loadByUrl = function (url: string, t?: Sequelize.Transaction) { |
259 | const query: Sequelize.FindOptions<VideoChannelAttributes> = { | |
260 | where: { | |
261 | url | |
262 | } | |
263 | } | |
264 | ||
265 | if (t !== undefined) query.transaction = t | |
266 | ||
267 | return VideoChannel.findOne(query) | |
268 | } | |
269 | ||
270 | loadByUUIDOrUrl = function (uuid: string, url: string, t?: Sequelize.Transaction) { | |
271 | const query: Sequelize.FindOptions<VideoChannelAttributes> = { | |
272 | where: { | |
273 | [Sequelize.Op.or]: [ | |
274 | { uuid }, | |
275 | { url } | |
276 | ] | |
571389d4 | 277 | } |
0d0e8dd0 C |
278 | } |
279 | ||
280 | if (t !== undefined) query.transaction = t | |
281 | ||
282 | return VideoChannel.findOne(query) | |
283 | } | |
284 | ||
72c7248b C |
285 | loadByHostAndUUID = function (fromHost: string, uuid: string, t?: Sequelize.Transaction) { |
286 | const query: Sequelize.FindOptions<VideoChannelAttributes> = { | |
287 | where: { | |
288 | uuid | |
289 | }, | |
290 | include: [ | |
291 | { | |
e4f97bab | 292 | model: VideoChannel['sequelize'].models.Account, |
72c7248b C |
293 | include: [ |
294 | { | |
295 | model: VideoChannel['sequelize'].models.Pod, | |
296 | required: true, | |
297 | where: { | |
298 | host: fromHost | |
299 | } | |
300 | } | |
301 | ] | |
302 | } | |
303 | ] | |
304 | } | |
305 | ||
306 | if (t !== undefined) query.transaction = t | |
307 | ||
308 | return VideoChannel.findOne(query) | |
309 | } | |
310 | ||
e4f97bab | 311 | loadByIdAndAccount = function (id: number, accountId: number) { |
72c7248b C |
312 | const options = { |
313 | where: { | |
314 | id, | |
e4f97bab | 315 | accountId |
72c7248b C |
316 | }, |
317 | include: [ | |
318 | { | |
e4f97bab | 319 | model: VideoChannel['sequelize'].models.Account, |
72c7248b C |
320 | include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] |
321 | } | |
322 | ] | |
323 | } | |
324 | ||
325 | return VideoChannel.findOne(options) | |
326 | } | |
327 | ||
e4f97bab | 328 | loadAndPopulateAccount = function (id: number) { |
72c7248b C |
329 | const options = { |
330 | include: [ | |
331 | { | |
e4f97bab | 332 | model: VideoChannel['sequelize'].models.Account, |
72c7248b C |
333 | include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] |
334 | } | |
335 | ] | |
336 | } | |
337 | ||
338 | return VideoChannel.findById(id, options) | |
339 | } | |
340 | ||
e4f97bab | 341 | loadByUUIDAndPopulateAccount = function (uuid: string) { |
72c7248b C |
342 | const options = { |
343 | where: { | |
344 | uuid | |
345 | }, | |
346 | include: [ | |
347 | { | |
e4f97bab | 348 | model: VideoChannel['sequelize'].models.Account, |
72c7248b C |
349 | include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] |
350 | } | |
351 | ] | |
352 | } | |
353 | ||
354 | return VideoChannel.findOne(options) | |
355 | } | |
356 | ||
e4f97bab | 357 | loadAndPopulateAccountAndVideos = function (id: number) { |
72c7248b C |
358 | const options = { |
359 | include: [ | |
360 | { | |
e4f97bab | 361 | model: VideoChannel['sequelize'].models.Account, |
72c7248b C |
362 | include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] |
363 | }, | |
364 | VideoChannel['sequelize'].models.Video | |
365 | ] | |
366 | } | |
367 | ||
368 | return VideoChannel.findById(id, options) | |
369 | } |