diff options
Diffstat (limited to 'server/models/video')
-rw-r--r-- | server/models/video/video-channel.ts | 41 | ||||
-rw-r--r-- | server/models/video/video.ts | 31 |
2 files changed, 56 insertions, 16 deletions
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index d0dba18d5..0273fab13 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -1,14 +1,27 @@ | |||
1 | import { | 1 | import { |
2 | AllowNull, BeforeDestroy, BelongsTo, Column, CreatedAt, DefaultScope, ForeignKey, HasMany, Is, Model, Scopes, Table, | 2 | AllowNull, |
3 | UpdatedAt, Default, DataType | 3 | BeforeDestroy, |
4 | BelongsTo, | ||
5 | Column, | ||
6 | CreatedAt, | ||
7 | DataType, | ||
8 | Default, | ||
9 | DefaultScope, | ||
10 | ForeignKey, | ||
11 | HasMany, | ||
12 | Is, | ||
13 | Model, | ||
14 | Scopes, | ||
15 | Table, | ||
16 | UpdatedAt | ||
4 | } from 'sequelize-typescript' | 17 | } from 'sequelize-typescript' |
5 | import { ActivityPubActor } from '../../../shared/models/activitypub' | 18 | import { ActivityPubActor } from '../../../shared/models/activitypub' |
6 | import { VideoChannel } from '../../../shared/models/videos' | 19 | import { VideoChannel } from '../../../shared/models/videos' |
7 | import { | 20 | import { |
8 | isVideoChannelDescriptionValid, isVideoChannelNameValid, | 21 | isVideoChannelDescriptionValid, |
22 | isVideoChannelNameValid, | ||
9 | isVideoChannelSupportValid | 23 | isVideoChannelSupportValid |
10 | } from '../../helpers/custom-validators/video-channels' | 24 | } from '../../helpers/custom-validators/video-channels' |
11 | import { logger } from '../../helpers/logger' | ||
12 | import { sendDeleteActor } from '../../lib/activitypub/send' | 25 | import { sendDeleteActor } from '../../lib/activitypub/send' |
13 | import { AccountModel } from '../account/account' | 26 | import { AccountModel } from '../account/account' |
14 | import { ActorModel } from '../activitypub/actor' | 27 | import { ActorModel } from '../activitypub/actor' |
@@ -241,6 +254,23 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
241 | .findById(id, options) | 254 | .findById(id, options) |
242 | } | 255 | } |
243 | 256 | ||
257 | static loadLocalByName (name: string) { | ||
258 | const query = { | ||
259 | include: [ | ||
260 | { | ||
261 | model: ActorModel, | ||
262 | required: true, | ||
263 | where: { | ||
264 | preferredUsername: name, | ||
265 | serverId: null | ||
266 | } | ||
267 | } | ||
268 | ] | ||
269 | } | ||
270 | |||
271 | return VideoChannelModel.findOne(query) | ||
272 | } | ||
273 | |||
244 | toFormattedJSON (): VideoChannel { | 274 | toFormattedJSON (): VideoChannel { |
245 | const actor = this.Actor.toFormattedJSON() | 275 | const actor = this.Actor.toFormattedJSON() |
246 | const videoChannel = { | 276 | const videoChannel = { |
@@ -251,8 +281,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
251 | isLocal: this.Actor.isOwned(), | 281 | isLocal: this.Actor.isOwned(), |
252 | createdAt: this.createdAt, | 282 | createdAt: this.createdAt, |
253 | updatedAt: this.updatedAt, | 283 | updatedAt: this.updatedAt, |
254 | ownerAccount: undefined, | 284 | ownerAccount: undefined |
255 | videos: undefined | ||
256 | } | 285 | } |
257 | 286 | ||
258 | if (this.Account) videoChannel.ownerAccount = this.Account.toFormattedJSON() | 287 | if (this.Account) videoChannel.ownerAccount = this.Account.toFormattedJSON() |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index b13dee403..5db718061 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -133,6 +133,7 @@ export enum ScopeNames { | |||
133 | 133 | ||
134 | type AvailableForListOptions = { | 134 | type AvailableForListOptions = { |
135 | actorId: number, | 135 | actorId: number, |
136 | includeLocalVideos: boolean, | ||
136 | filter?: VideoFilter, | 137 | filter?: VideoFilter, |
137 | categoryOneOf?: number[], | 138 | categoryOneOf?: number[], |
138 | nsfw?: boolean, | 139 | nsfw?: boolean, |
@@ -201,6 +202,15 @@ type AvailableForListOptions = { | |||
201 | 202 | ||
202 | // Force actorId to be a number to avoid SQL injections | 203 | // Force actorId to be a number to avoid SQL injections |
203 | const actorIdNumber = parseInt(options.actorId.toString(), 10) | 204 | const actorIdNumber = parseInt(options.actorId.toString(), 10) |
205 | let localVideosReq = '' | ||
206 | if (options.includeLocalVideos === true) { | ||
207 | localVideosReq = ' UNION ALL ' + | ||
208 | 'SELECT "video"."id" AS "id" FROM "video" ' + | ||
209 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | ||
210 | 'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' + | ||
211 | 'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' + | ||
212 | 'WHERE "actor"."serverId" IS NULL' | ||
213 | } | ||
204 | 214 | ||
205 | // FIXME: It would be more efficient to use a CTE so we join AFTER the filters, but sequelize does not support it... | 215 | // FIXME: It would be more efficient to use a CTE so we join AFTER the filters, but sequelize does not support it... |
206 | const query: IFindOptions<VideoModel> = { | 216 | const query: IFindOptions<VideoModel> = { |
@@ -214,12 +224,6 @@ type AvailableForListOptions = { | |||
214 | 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + | 224 | 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + |
215 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + | 225 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + |
216 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + | 226 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + |
217 | ' UNION ' + | ||
218 | 'SELECT "video"."id" AS "id" FROM "video" ' + | ||
219 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | ||
220 | 'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' + | ||
221 | 'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' + | ||
222 | 'WHERE "actor"."serverId" IS NULL ' + | ||
223 | ' UNION ALL ' + | 227 | ' UNION ALL ' + |
224 | 'SELECT "video"."id" AS "id" FROM "video" ' + | 228 | 'SELECT "video"."id" AS "id" FROM "video" ' + |
225 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | 229 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + |
@@ -227,6 +231,7 @@ type AvailableForListOptions = { | |||
227 | 'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' + | 231 | 'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' + |
228 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "actor"."id" ' + | 232 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "actor"."id" ' + |
229 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + | 233 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + |
234 | localVideosReq + | ||
230 | ')' | 235 | ')' |
231 | ) | 236 | ) |
232 | }, | 237 | }, |
@@ -825,6 +830,7 @@ export class VideoModel extends Model<VideoModel> { | |||
825 | count: number, | 830 | count: number, |
826 | sort: string, | 831 | sort: string, |
827 | nsfw: boolean, | 832 | nsfw: boolean, |
833 | includeLocalVideos: boolean, | ||
828 | withFiles: boolean, | 834 | withFiles: boolean, |
829 | categoryOneOf?: number[], | 835 | categoryOneOf?: number[], |
830 | licenceOneOf?: number[], | 836 | licenceOneOf?: number[], |
@@ -833,7 +839,8 @@ export class VideoModel extends Model<VideoModel> { | |||
833 | tagsAllOf?: string[], | 839 | tagsAllOf?: string[], |
834 | filter?: VideoFilter, | 840 | filter?: VideoFilter, |
835 | accountId?: number, | 841 | accountId?: number, |
836 | videoChannelId?: number | 842 | videoChannelId?: number, |
843 | actorId?: number | ||
837 | }) { | 844 | }) { |
838 | const query = { | 845 | const query = { |
839 | offset: options.start, | 846 | offset: options.start, |
@@ -841,11 +848,12 @@ export class VideoModel extends Model<VideoModel> { | |||
841 | order: getSort(options.sort) | 848 | order: getSort(options.sort) |
842 | } | 849 | } |
843 | 850 | ||
844 | const serverActor = await getServerActor() | 851 | const actorId = options.actorId || (await getServerActor()).id |
852 | |||
845 | const scopes = { | 853 | const scopes = { |
846 | method: [ | 854 | method: [ |
847 | ScopeNames.AVAILABLE_FOR_LIST, { | 855 | ScopeNames.AVAILABLE_FOR_LIST, { |
848 | actorId: serverActor.id, | 856 | actorId, |
849 | nsfw: options.nsfw, | 857 | nsfw: options.nsfw, |
850 | categoryOneOf: options.categoryOneOf, | 858 | categoryOneOf: options.categoryOneOf, |
851 | licenceOneOf: options.licenceOneOf, | 859 | licenceOneOf: options.licenceOneOf, |
@@ -855,7 +863,8 @@ export class VideoModel extends Model<VideoModel> { | |||
855 | filter: options.filter, | 863 | filter: options.filter, |
856 | withFiles: options.withFiles, | 864 | withFiles: options.withFiles, |
857 | accountId: options.accountId, | 865 | accountId: options.accountId, |
858 | videoChannelId: options.videoChannelId | 866 | videoChannelId: options.videoChannelId, |
867 | includeLocalVideos: options.includeLocalVideos | ||
859 | } as AvailableForListOptions | 868 | } as AvailableForListOptions |
860 | ] | 869 | ] |
861 | } | 870 | } |
@@ -871,6 +880,7 @@ export class VideoModel extends Model<VideoModel> { | |||
871 | } | 880 | } |
872 | 881 | ||
873 | static async searchAndPopulateAccountAndServer (options: { | 882 | static async searchAndPopulateAccountAndServer (options: { |
883 | includeLocalVideos: boolean | ||
874 | search?: string | 884 | search?: string |
875 | start?: number | 885 | start?: number |
876 | count?: number | 886 | count?: number |
@@ -955,6 +965,7 @@ export class VideoModel extends Model<VideoModel> { | |||
955 | method: [ | 965 | method: [ |
956 | ScopeNames.AVAILABLE_FOR_LIST, { | 966 | ScopeNames.AVAILABLE_FOR_LIST, { |
957 | actorId: serverActor.id, | 967 | actorId: serverActor.id, |
968 | includeLocalVideos: options.includeLocalVideos, | ||
958 | nsfw: options.nsfw, | 969 | nsfw: options.nsfw, |
959 | categoryOneOf: options.categoryOneOf, | 970 | categoryOneOf: options.categoryOneOf, |
960 | licenceOneOf: options.licenceOneOf, | 971 | licenceOneOf: options.licenceOneOf, |