aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2018-08-16 15:25:20 +0200
committerChocobozzz <me@florianbigard.com>2018-08-27 09:41:54 +0200
commit06a05d5f4784a7cbb27aa1188385b5679845dad8 (patch)
treeac197f3ed0768529456225ad76c912f22bc55e29 /server/models/video
parent4bda2e47bbc937c401ddcf14c1be53c70481a294 (diff)
downloadPeerTube-06a05d5f4784a7cbb27aa1188385b5679845dad8.tar.gz
PeerTube-06a05d5f4784a7cbb27aa1188385b5679845dad8.tar.zst
PeerTube-06a05d5f4784a7cbb27aa1188385b5679845dad8.zip
Add subscriptions endpoints to REST API
Diffstat (limited to 'server/models/video')
-rw-r--r--server/models/video/video-channel.ts41
-rw-r--r--server/models/video/video.ts31
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 @@
1import { 1import {
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'
5import { ActivityPubActor } from '../../../shared/models/activitypub' 18import { ActivityPubActor } from '../../../shared/models/activitypub'
6import { VideoChannel } from '../../../shared/models/videos' 19import { VideoChannel } from '../../../shared/models/videos'
7import { 20import {
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'
11import { logger } from '../../helpers/logger'
12import { sendDeleteActor } from '../../lib/activitypub/send' 25import { sendDeleteActor } from '../../lib/activitypub/send'
13import { AccountModel } from '../account/account' 26import { AccountModel } from '../account/account'
14import { ActorModel } from '../activitypub/actor' 27import { 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
134type AvailableForListOptions = { 134type 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,