]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/models/video/video-share.ts
Fix RSS feed when HLS only is enabled
[github/Chocobozzz/PeerTube.git] / server / models / video / video-share.ts
1 import * as Bluebird from 'bluebird'
2 import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
3 import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
4 import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
5 import { ActorModel } from '../activitypub/actor'
6 import { buildLocalActorIdsIn, throwIfNotValid } from '../utils'
7 import { VideoModel } from './video'
8 import { literal, Op, Transaction } from 'sequelize'
9 import { MVideoShareActor, MVideoShareFull } from '../../types/models/video'
10 import { MActorDefault } from '../../types/models'
11
12 enum ScopeNames {
13 FULL = 'FULL',
14 WITH_ACTOR = 'WITH_ACTOR'
15 }
16
17 @Scopes(() => ({
18 [ScopeNames.FULL]: {
19 include: [
20 {
21 model: ActorModel,
22 required: true
23 },
24 {
25 model: VideoModel,
26 required: true
27 }
28 ]
29 },
30 [ScopeNames.WITH_ACTOR]: {
31 include: [
32 {
33 model: ActorModel,
34 required: true
35 }
36 ]
37 }
38 }))
39 @Table({
40 tableName: 'videoShare',
41 indexes: [
42 {
43 fields: [ 'actorId' ]
44 },
45 {
46 fields: [ 'videoId' ]
47 },
48 {
49 fields: [ 'url' ],
50 unique: true
51 }
52 ]
53 })
54 export class VideoShareModel extends Model<VideoShareModel> {
55
56 @AllowNull(false)
57 @Is('VideoShareUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
58 @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_SHARE.URL.max))
59 url: string
60
61 @CreatedAt
62 createdAt: Date
63
64 @UpdatedAt
65 updatedAt: Date
66
67 @ForeignKey(() => ActorModel)
68 @Column
69 actorId: number
70
71 @BelongsTo(() => ActorModel, {
72 foreignKey: {
73 allowNull: false
74 },
75 onDelete: 'cascade'
76 })
77 Actor: ActorModel
78
79 @ForeignKey(() => VideoModel)
80 @Column
81 videoId: number
82
83 @BelongsTo(() => VideoModel, {
84 foreignKey: {
85 allowNull: false
86 },
87 onDelete: 'cascade'
88 })
89 Video: VideoModel
90
91 static load (actorId: number | string, videoId: number | string, t?: Transaction): Bluebird<MVideoShareActor> {
92 return VideoShareModel.scope(ScopeNames.WITH_ACTOR).findOne({
93 where: {
94 actorId,
95 videoId
96 },
97 transaction: t
98 })
99 }
100
101 static loadByUrl (url: string, t: Transaction): Bluebird<MVideoShareFull> {
102 return VideoShareModel.scope(ScopeNames.FULL).findOne({
103 where: {
104 url
105 },
106 transaction: t
107 })
108 }
109
110 static loadActorsByShare (videoId: number, t: Transaction): Bluebird<MActorDefault[]> {
111 const query = {
112 where: {
113 videoId
114 },
115 include: [
116 {
117 model: ActorModel,
118 required: true
119 }
120 ],
121 transaction: t
122 }
123
124 return VideoShareModel.scope(ScopeNames.FULL).findAll(query)
125 .then((res: MVideoShareFull[]) => res.map(r => r.Actor))
126 }
127
128 static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Transaction): Bluebird<MActorDefault[]> {
129 const safeOwnerId = parseInt(actorOwnerId + '', 10)
130
131 // /!\ On actor model
132 const query = {
133 where: {
134 [Op.and]: [
135 literal(
136 `EXISTS (` +
137 ` SELECT 1 FROM "videoShare" ` +
138 ` INNER JOIN "video" ON "videoShare"."videoId" = "video"."id" ` +
139 ` INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ` +
140 ` INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ` +
141 ` WHERE "videoShare"."actorId" = "ActorModel"."id" AND "account"."actorId" = ${safeOwnerId} ` +
142 ` LIMIT 1` +
143 `)`
144 )
145 ]
146 },
147 transaction: t
148 }
149
150 return ActorModel.findAll(query)
151 }
152
153 static loadActorsByVideoChannel (videoChannelId: number, t: Transaction): Bluebird<MActorDefault[]> {
154 const safeChannelId = parseInt(videoChannelId + '', 10)
155
156 // /!\ On actor model
157 const query = {
158 where: {
159 [Op.and]: [
160 literal(
161 `EXISTS (` +
162 ` SELECT 1 FROM "videoShare" ` +
163 ` INNER JOIN "video" ON "videoShare"."videoId" = "video"."id" ` +
164 ` WHERE "videoShare"."actorId" = "ActorModel"."id" AND "video"."channelId" = ${safeChannelId} ` +
165 ` LIMIT 1` +
166 `)`
167 )
168 ]
169 },
170 transaction: t
171 }
172
173 return ActorModel.findAll(query)
174 }
175
176 static listAndCountByVideoId (videoId: number, start: number, count: number, t?: Transaction) {
177 const query = {
178 offset: start,
179 limit: count,
180 where: {
181 videoId
182 },
183 transaction: t
184 }
185
186 return VideoShareModel.findAndCountAll(query)
187 }
188
189 static cleanOldSharesOf (videoId: number, beforeUpdatedAt: Date) {
190 const query = {
191 where: {
192 updatedAt: {
193 [Op.lt]: beforeUpdatedAt
194 },
195 videoId,
196 actorId: {
197 [Op.notIn]: buildLocalActorIdsIn()
198 }
199 }
200 }
201
202 return VideoShareModel.destroy(query)
203 }
204 }