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