Fix createdAt/updatedAt issues
[oweals/peertube.git] / server / models / video / video-share.ts
1 import * as Sequelize from 'sequelize'
2 import * as Bluebird from 'bluebird'
3 import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
4 import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
5 import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
6 import { AccountModel } from '../account/account'
7 import { ActorModel } from '../activitypub/actor'
8 import { throwIfNotValid } from '../utils'
9 import { VideoModel } from './video'
10 import { VideoChannelModel } from './video-channel'
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, videoId: number, t?: Sequelize.Transaction) {
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: Sequelize.Transaction) {
102     return VideoShareModel.scope(ScopeNames.FULL).findOne({
103       where: {
104         url
105       },
106       transaction: t
107     })
108   }
109
110   static loadActorsByShare (videoId: number, t: Sequelize.Transaction) {
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 => res.map(r => r.Actor))
126   }
127
128   static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Sequelize.Transaction): Bluebird<ActorModel[]> {
129     const query = {
130       attributes: [],
131       include: [
132         {
133           model: ActorModel,
134           required: true
135         },
136         {
137           attributes: [],
138           model: VideoModel,
139           required: true,
140           include: [
141             {
142               attributes: [],
143               model: VideoChannelModel.unscoped(),
144               required: true,
145               include: [
146                 {
147                   attributes: [],
148                   model: AccountModel.unscoped(),
149                   required: true,
150                   where: {
151                     actorId: actorOwnerId
152                   }
153                 }
154               ]
155             }
156           ]
157         }
158       ],
159       transaction: t
160     }
161
162     return VideoShareModel.scope(ScopeNames.FULL).findAll(query)
163       .then(res => res.map(r => r.Actor))
164   }
165
166   static loadActorsByVideoChannel (videoChannelId: number, t: Sequelize.Transaction): Bluebird<ActorModel[]> {
167     const query = {
168       attributes: [],
169       include: [
170         {
171           model: ActorModel,
172           required: true
173         },
174         {
175           attributes: [],
176           model: VideoModel,
177           required: true,
178           where: {
179             channelId: videoChannelId
180           }
181         }
182       ],
183       transaction: t
184     }
185
186     return VideoShareModel.scope(ScopeNames.FULL)
187       .findAll(query)
188       .then(res => res.map(r => r.Actor))
189   }
190
191   static listAndCountByVideoId (videoId: number, start: number, count: number, t?: Sequelize.Transaction) {
192     const query = {
193       offset: start,
194       limit: count,
195       where: {
196         videoId
197       },
198       transaction: t
199     }
200
201     return VideoShareModel.findAndCountAll(query)
202   }
203
204   static cleanOldSharesOf (videoId: number, beforeUpdatedAt: Date) {
205     const query = {
206       where: {
207         updatedAt: {
208           [Sequelize.Op.lt]: beforeUpdatedAt
209         },
210         videoId
211       }
212     }
213
214     return VideoShareModel.destroy(query)
215   }
216 }