diff options
Diffstat (limited to 'server/models/video/video-channel.ts')
-rw-r--r-- | server/models/video/video-channel.ts | 78 |
1 files changed, 65 insertions, 13 deletions
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index 2426b3de6..112abf8cf 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -8,7 +8,7 @@ import { | |||
8 | Default, | 8 | Default, |
9 | DefaultScope, | 9 | DefaultScope, |
10 | ForeignKey, | 10 | ForeignKey, |
11 | HasMany, | 11 | HasMany, IFindOptions, |
12 | Is, | 12 | Is, |
13 | Model, | 13 | Model, |
14 | Scopes, | 14 | Scopes, |
@@ -17,20 +17,22 @@ import { | |||
17 | UpdatedAt | 17 | UpdatedAt |
18 | } from 'sequelize-typescript' | 18 | } from 'sequelize-typescript' |
19 | import { ActivityPubActor } from '../../../shared/models/activitypub' | 19 | import { ActivityPubActor } from '../../../shared/models/activitypub' |
20 | import { VideoChannel } from '../../../shared/models/videos' | 20 | import { VideoChannel, VideoChannelSummary } from '../../../shared/models/videos' |
21 | import { | 21 | import { |
22 | isVideoChannelDescriptionValid, | 22 | isVideoChannelDescriptionValid, |
23 | isVideoChannelNameValid, | 23 | isVideoChannelNameValid, |
24 | isVideoChannelSupportValid | 24 | isVideoChannelSupportValid |
25 | } from '../../helpers/custom-validators/video-channels' | 25 | } from '../../helpers/custom-validators/video-channels' |
26 | import { sendDeleteActor } from '../../lib/activitypub/send' | 26 | import { sendDeleteActor } from '../../lib/activitypub/send' |
27 | import { AccountModel } from '../account/account' | 27 | import { AccountModel, ScopeNames as AccountModelScopeNames } from '../account/account' |
28 | import { ActorModel, unusedActorAttributesForAPI } from '../activitypub/actor' | 28 | import { ActorModel, unusedActorAttributesForAPI } from '../activitypub/actor' |
29 | import { buildTrigramSearchIndex, createSimilarityAttribute, getSort, throwIfNotValid } from '../utils' | 29 | import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttribute, getSort, throwIfNotValid } from '../utils' |
30 | import { VideoModel } from './video' | 30 | import { VideoModel } from './video' |
31 | import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers' | 31 | import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers' |
32 | import { ServerModel } from '../server/server' | 32 | import { ServerModel } from '../server/server' |
33 | import { DefineIndexesOptions } from 'sequelize' | 33 | import { DefineIndexesOptions } from 'sequelize' |
34 | import { AvatarModel } from '../avatar/avatar' | ||
35 | import { VideoPlaylistModel } from './video-playlist' | ||
34 | 36 | ||
35 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | 37 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation |
36 | const indexes: DefineIndexesOptions[] = [ | 38 | const indexes: DefineIndexesOptions[] = [ |
@@ -44,11 +46,12 @@ const indexes: DefineIndexesOptions[] = [ | |||
44 | } | 46 | } |
45 | ] | 47 | ] |
46 | 48 | ||
47 | enum ScopeNames { | 49 | export enum ScopeNames { |
48 | AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', | 50 | AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', |
49 | WITH_ACCOUNT = 'WITH_ACCOUNT', | 51 | WITH_ACCOUNT = 'WITH_ACCOUNT', |
50 | WITH_ACTOR = 'WITH_ACTOR', | 52 | WITH_ACTOR = 'WITH_ACTOR', |
51 | WITH_VIDEOS = 'WITH_VIDEOS' | 53 | WITH_VIDEOS = 'WITH_VIDEOS', |
54 | SUMMARY = 'SUMMARY' | ||
52 | } | 55 | } |
53 | 56 | ||
54 | type AvailableForListOptions = { | 57 | type AvailableForListOptions = { |
@@ -64,15 +67,41 @@ type AvailableForListOptions = { | |||
64 | ] | 67 | ] |
65 | }) | 68 | }) |
66 | @Scopes({ | 69 | @Scopes({ |
67 | [ScopeNames.AVAILABLE_FOR_LIST]: (options: AvailableForListOptions) => { | 70 | [ScopeNames.SUMMARY]: (required: boolean, withAccount: boolean) => { |
68 | const actorIdNumber = parseInt(options.actorId + '', 10) | 71 | const base: IFindOptions<VideoChannelModel> = { |
72 | attributes: [ 'name', 'description', 'id' ], | ||
73 | include: [ | ||
74 | { | ||
75 | attributes: [ 'uuid', 'preferredUsername', 'url', 'serverId', 'avatarId' ], | ||
76 | model: ActorModel.unscoped(), | ||
77 | required: true, | ||
78 | include: [ | ||
79 | { | ||
80 | attributes: [ 'host' ], | ||
81 | model: ServerModel.unscoped(), | ||
82 | required: false | ||
83 | }, | ||
84 | { | ||
85 | model: AvatarModel.unscoped(), | ||
86 | required: false | ||
87 | } | ||
88 | ] | ||
89 | } | ||
90 | ] | ||
91 | } | ||
92 | |||
93 | if (withAccount === true) { | ||
94 | base.include.push({ | ||
95 | model: AccountModel.scope(AccountModelScopeNames.SUMMARY), | ||
96 | required: true | ||
97 | }) | ||
98 | } | ||
69 | 99 | ||
100 | return base | ||
101 | }, | ||
102 | [ScopeNames.AVAILABLE_FOR_LIST]: (options: AvailableForListOptions) => { | ||
70 | // Only list local channels OR channels that are on an instance followed by actorId | 103 | // Only list local channels OR channels that are on an instance followed by actorId |
71 | const inQueryInstanceFollow = '(' + | 104 | const inQueryInstanceFollow = buildServerIdsFollowedBy(options.actorId) |
72 | 'SELECT "actor"."serverId" FROM "actorFollow" ' + | ||
73 | 'INNER JOIN "actor" ON actor.id= "actorFollow"."targetActorId" ' + | ||
74 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + | ||
75 | ')' | ||
76 | 105 | ||
77 | return { | 106 | return { |
78 | include: [ | 107 | include: [ |
@@ -192,6 +221,15 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
192 | }) | 221 | }) |
193 | Videos: VideoModel[] | 222 | Videos: VideoModel[] |
194 | 223 | ||
224 | @HasMany(() => VideoPlaylistModel, { | ||
225 | foreignKey: { | ||
226 | allowNull: false | ||
227 | }, | ||
228 | onDelete: 'cascade', | ||
229 | hooks: true | ||
230 | }) | ||
231 | VideoPlaylists: VideoPlaylistModel[] | ||
232 | |||
195 | @BeforeDestroy | 233 | @BeforeDestroy |
196 | static async sendDeleteIfOwned (instance: VideoChannelModel, options) { | 234 | static async sendDeleteIfOwned (instance: VideoChannelModel, options) { |
197 | if (!instance.Actor) { | 235 | if (!instance.Actor) { |
@@ -460,6 +498,20 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
460 | return Object.assign(actor, videoChannel) | 498 | return Object.assign(actor, videoChannel) |
461 | } | 499 | } |
462 | 500 | ||
501 | toFormattedSummaryJSON (): VideoChannelSummary { | ||
502 | const actor = this.Actor.toFormattedJSON() | ||
503 | |||
504 | return { | ||
505 | id: this.id, | ||
506 | uuid: actor.uuid, | ||
507 | name: actor.name, | ||
508 | displayName: this.getDisplayName(), | ||
509 | url: actor.url, | ||
510 | host: actor.host, | ||
511 | avatar: actor.avatar | ||
512 | } | ||
513 | } | ||
514 | |||
463 | toActivityPubObject (): ActivityPubActor { | 515 | toActivityPubObject (): ActivityPubActor { |
464 | const obj = this.Actor.toActivityPubObject(this.name, 'VideoChannel') | 516 | const obj = this.Actor.toActivityPubObject(this.name, 'VideoChannel') |
465 | 517 | ||