diff options
-rw-r--r-- | client/angular.json | 15 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-dislike.ts | 21 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-like.ts | 24 | ||||
-rw-r--r-- | server/lib/activitypub/video-comments.ts | 2 | ||||
-rw-r--r-- | server/lib/video-comment.ts | 6 | ||||
-rw-r--r-- | server/models/account/account-video-rate.ts | 36 | ||||
-rw-r--r-- | server/models/video/video-comment.ts | 19 | ||||
-rw-r--r-- | server/models/video/video-share.ts | 29 | ||||
-rw-r--r-- | shared/extra-utils/videos/videos.ts | 3 |
9 files changed, 119 insertions, 36 deletions
diff --git a/client/angular.json b/client/angular.json index 8a709e269..cce930b82 100644 --- a/client/angular.json +++ b/client/angular.json | |||
@@ -44,6 +44,21 @@ | |||
44 | "buildOptimizer": true, | 44 | "buildOptimizer": true, |
45 | "serviceWorker": true, | 45 | "serviceWorker": true, |
46 | "ngswConfigPath": "src/ngsw-config.json", | 46 | "ngswConfigPath": "src/ngsw-config.json", |
47 | "budgets": [ | ||
48 | { | ||
49 | "type": "initial", | ||
50 | "type": "initial", | ||
51 | "maximumWarning": "2mb", | ||
52 | "maximumWarning": "2mb", | ||
53 | "maximumError": "5mb" | ||
54 | "maximumError": "5mb" | ||
55 | }, | ||
56 | { | ||
57 | "type": "anyComponentStyle", | ||
58 | "maximumWarning": "6kb", | ||
59 | "maximumError": "10kb" | ||
60 | } | ||
61 | ], | ||
47 | "fileReplacements": [ | 62 | "fileReplacements": [ |
48 | { | 63 | { |
49 | "replace": "src/environments/environment.ts", | 64 | "replace": "src/environments/environment.ts", |
diff --git a/server/lib/activitypub/process/process-dislike.ts b/server/lib/activitypub/process/process-dislike.ts index bfd69e07a..ed8afd3d2 100644 --- a/server/lib/activitypub/process/process-dislike.ts +++ b/server/lib/activitypub/process/process-dislike.ts | |||
@@ -29,20 +29,21 @@ async function processDislike (activity: ActivityCreate | ActivityDislike, byAct | |||
29 | const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: dislikeObject }) | 29 | const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: dislikeObject }) |
30 | 30 | ||
31 | return sequelizeTypescript.transaction(async t => { | 31 | return sequelizeTypescript.transaction(async t => { |
32 | const rate = { | 32 | const url = getVideoDislikeActivityPubUrl(byActor, video) |
33 | |||
34 | const existingRate = await AccountVideoRateModel.loadByAccountAndVideoOrUrl(byAccount.id, video.id, url) | ||
35 | if (existingRate && existingRate.type === 'dislike') return | ||
36 | |||
37 | await AccountVideoRateModel.create({ | ||
33 | type: 'dislike' as 'dislike', | 38 | type: 'dislike' as 'dislike', |
34 | videoId: video.id, | 39 | videoId: video.id, |
35 | accountId: byAccount.id | 40 | accountId: byAccount.id, |
36 | } | 41 | url |
42 | }, { transaction: t }) | ||
37 | 43 | ||
38 | const [ , created ] = await AccountVideoRateModel.findOrCreate({ | 44 | await video.increment('dislikes', { transaction: t }) |
39 | where: rate, | ||
40 | defaults: Object.assign({}, rate, { url: getVideoDislikeActivityPubUrl(byActor, video) }), | ||
41 | transaction: t | ||
42 | }) | ||
43 | if (created === true) await video.increment('dislikes', { transaction: t }) | ||
44 | 45 | ||
45 | if (video.isOwned() && created === true) { | 46 | if (video.isOwned()) { |
46 | // Don't resend the activity to the sender | 47 | // Don't resend the activity to the sender |
47 | const exceptions = [ byActor ] | 48 | const exceptions = [ byActor ] |
48 | 49 | ||
diff --git a/server/lib/activitypub/process/process-like.ts b/server/lib/activitypub/process/process-like.ts index 2a04167d7..8b97aae55 100644 --- a/server/lib/activitypub/process/process-like.ts +++ b/server/lib/activitypub/process/process-like.ts | |||
@@ -29,19 +29,21 @@ async function processLikeVideo (byActor: ActorModel, activity: ActivityLike) { | |||
29 | const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoUrl }) | 29 | const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoUrl }) |
30 | 30 | ||
31 | return sequelizeTypescript.transaction(async t => { | 31 | return sequelizeTypescript.transaction(async t => { |
32 | const rate = { | 32 | const url = getVideoLikeActivityPubUrl(byActor, video) |
33 | |||
34 | const existingRate = await AccountVideoRateModel.loadByAccountAndVideoOrUrl(byAccount.id, video.id, url) | ||
35 | if (existingRate && existingRate.type === 'like') return | ||
36 | |||
37 | await AccountVideoRateModel.create({ | ||
33 | type: 'like' as 'like', | 38 | type: 'like' as 'like', |
34 | videoId: video.id, | 39 | videoId: video.id, |
35 | accountId: byAccount.id | 40 | accountId: byAccount.id, |
36 | } | 41 | url |
37 | const [ , created ] = await AccountVideoRateModel.findOrCreate({ | 42 | }, { transaction: t }) |
38 | where: rate, | 43 | |
39 | defaults: Object.assign({}, rate, { url: getVideoLikeActivityPubUrl(byActor, video) }), | 44 | await video.increment('likes', { transaction: t }) |
40 | transaction: t | 45 | |
41 | }) | 46 | if (video.isOwned()) { |
42 | if (created === true) await video.increment('likes', { transaction: t }) | ||
43 | |||
44 | if (video.isOwned() && created === true) { | ||
45 | // Don't resend the activity to the sender | 47 | // Don't resend the activity to the sender |
46 | const exceptions = [ byActor ] | 48 | const exceptions = [ byActor ] |
47 | 49 | ||
diff --git a/server/lib/activitypub/video-comments.ts b/server/lib/activitypub/video-comments.ts index 2f26ddefd..921abdb8d 100644 --- a/server/lib/activitypub/video-comments.ts +++ b/server/lib/activitypub/video-comments.ts | |||
@@ -54,7 +54,7 @@ async function addVideoComment (videoInstance: VideoModel, commentUrl: string) { | |||
54 | }) | 54 | }) |
55 | 55 | ||
56 | if (sanitizeAndCheckVideoCommentObject(body) === false) { | 56 | if (sanitizeAndCheckVideoCommentObject(body) === false) { |
57 | logger.debug('Remote video comment JSON is not valid.', { body }) | 57 | logger.debug('Remote video comment JSON %s is not valid.', commentUrl, { body }) |
58 | return { created: false } | 58 | return { created: false } |
59 | } | 59 | } |
60 | 60 | ||
diff --git a/server/lib/video-comment.ts b/server/lib/video-comment.ts index bfe22d225..449aa74cb 100644 --- a/server/lib/video-comment.ts +++ b/server/lib/video-comment.ts | |||
@@ -27,10 +27,10 @@ async function createVideoComment (obj: { | |||
27 | inReplyToCommentId, | 27 | inReplyToCommentId, |
28 | videoId: obj.video.id, | 28 | videoId: obj.video.id, |
29 | accountId: obj.account.id, | 29 | accountId: obj.account.id, |
30 | url: 'fake url' | 30 | url: new Date().toISOString() |
31 | }, { transaction: t, validate: false } as any) // FIXME: sequelize typings | 31 | }, { transaction: t, validate: false }) |
32 | 32 | ||
33 | comment.set('url', getVideoCommentActivityPubUrl(obj.video, comment)) | 33 | comment.url = getVideoCommentActivityPubUrl(obj.video, comment) |
34 | 34 | ||
35 | const savedComment = await comment.save({ transaction: t }) | 35 | const savedComment = await comment.save({ transaction: t }) |
36 | savedComment.InReplyToVideoComment = obj.inReplyToComment | 36 | savedComment.InReplyToVideoComment = obj.inReplyToComment |
diff --git a/server/models/account/account-video-rate.ts b/server/models/account/account-video-rate.ts index 85af9e378..d5c214ecb 100644 --- a/server/models/account/account-video-rate.ts +++ b/server/models/account/account-video-rate.ts | |||
@@ -89,6 +89,25 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> { | |||
89 | return AccountVideoRateModel.findOne(options) | 89 | return AccountVideoRateModel.findOne(options) |
90 | } | 90 | } |
91 | 91 | ||
92 | static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, transaction?: Transaction) { | ||
93 | const options: FindOptions = { | ||
94 | where: { | ||
95 | [ Op.or]: [ | ||
96 | { | ||
97 | accountId, | ||
98 | videoId | ||
99 | }, | ||
100 | { | ||
101 | url | ||
102 | } | ||
103 | ] | ||
104 | } | ||
105 | } | ||
106 | if (transaction) options.transaction = transaction | ||
107 | |||
108 | return AccountVideoRateModel.findOne(options) | ||
109 | } | ||
110 | |||
92 | static listByAccountForApi (options: { | 111 | static listByAccountForApi (options: { |
93 | start: number, | 112 | start: number, |
94 | count: number, | 113 | count: number, |
@@ -202,6 +221,23 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> { | |||
202 | videoId, | 221 | videoId, |
203 | type | 222 | type |
204 | }, | 223 | }, |
224 | include: [ | ||
225 | { | ||
226 | model: AccountModel.unscoped(), | ||
227 | required: true, | ||
228 | include: [ | ||
229 | { | ||
230 | model: ActorModel.unscoped(), | ||
231 | required: true, | ||
232 | where: { | ||
233 | serverId: { | ||
234 | [Op.ne]: null | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | ] | ||
239 | } | ||
240 | ], | ||
205 | transaction: t | 241 | transaction: t |
206 | } | 242 | } |
207 | 243 | ||
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index 536b6cb3e..28e5818cd 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts | |||
@@ -472,7 +472,24 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
472 | [Op.lt]: beforeUpdatedAt | 472 | [Op.lt]: beforeUpdatedAt |
473 | }, | 473 | }, |
474 | videoId | 474 | videoId |
475 | } | 475 | }, |
476 | include: [ | ||
477 | { | ||
478 | required: true, | ||
479 | model: AccountModel.unscoped(), | ||
480 | include: [ | ||
481 | { | ||
482 | required: true, | ||
483 | model: ActorModel.unscoped(), | ||
484 | where: { | ||
485 | serverId: { | ||
486 | [Op.ne]: null | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | ] | ||
491 | } | ||
492 | ] | ||
476 | } | 493 | } |
477 | 494 | ||
478 | return VideoCommentModel.destroy(query) | 495 | return VideoCommentModel.destroy(query) |
diff --git a/server/models/video/video-share.ts b/server/models/video/video-share.ts index fda2d7cea..3bab3c027 100644 --- a/server/models/video/video-share.ts +++ b/server/models/video/video-share.ts | |||
@@ -1,4 +1,3 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
3 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' |
4 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 3 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
@@ -8,6 +7,7 @@ import { ActorModel } from '../activitypub/actor' | |||
8 | import { throwIfNotValid } from '../utils' | 7 | import { throwIfNotValid } from '../utils' |
9 | import { VideoModel } from './video' | 8 | import { VideoModel } from './video' |
10 | import { VideoChannelModel } from './video-channel' | 9 | import { VideoChannelModel } from './video-channel' |
10 | import { Op, Transaction } from 'sequelize' | ||
11 | 11 | ||
12 | enum ScopeNames { | 12 | enum ScopeNames { |
13 | FULL = 'FULL', | 13 | FULL = 'FULL', |
@@ -88,7 +88,7 @@ export class VideoShareModel extends Model<VideoShareModel> { | |||
88 | }) | 88 | }) |
89 | Video: VideoModel | 89 | Video: VideoModel |
90 | 90 | ||
91 | static load (actorId: number, videoId: number, t?: Sequelize.Transaction) { | 91 | static load (actorId: number, videoId: number, t?: Transaction) { |
92 | return VideoShareModel.scope(ScopeNames.WITH_ACTOR).findOne({ | 92 | return VideoShareModel.scope(ScopeNames.WITH_ACTOR).findOne({ |
93 | where: { | 93 | where: { |
94 | actorId, | 94 | actorId, |
@@ -98,7 +98,7 @@ export class VideoShareModel extends Model<VideoShareModel> { | |||
98 | }) | 98 | }) |
99 | } | 99 | } |
100 | 100 | ||
101 | static loadByUrl (url: string, t: Sequelize.Transaction) { | 101 | static loadByUrl (url: string, t: Transaction) { |
102 | return VideoShareModel.scope(ScopeNames.FULL).findOne({ | 102 | return VideoShareModel.scope(ScopeNames.FULL).findOne({ |
103 | where: { | 103 | where: { |
104 | url | 104 | url |
@@ -107,7 +107,7 @@ export class VideoShareModel extends Model<VideoShareModel> { | |||
107 | }) | 107 | }) |
108 | } | 108 | } |
109 | 109 | ||
110 | static loadActorsByShare (videoId: number, t: Sequelize.Transaction) { | 110 | static loadActorsByShare (videoId: number, t: Transaction) { |
111 | const query = { | 111 | const query = { |
112 | where: { | 112 | where: { |
113 | videoId | 113 | videoId |
@@ -125,7 +125,7 @@ export class VideoShareModel extends Model<VideoShareModel> { | |||
125 | .then(res => res.map(r => r.Actor)) | 125 | .then(res => res.map(r => r.Actor)) |
126 | } | 126 | } |
127 | 127 | ||
128 | static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Sequelize.Transaction): Bluebird<ActorModel[]> { | 128 | static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Transaction): Bluebird<ActorModel[]> { |
129 | const query = { | 129 | const query = { |
130 | attributes: [], | 130 | attributes: [], |
131 | include: [ | 131 | include: [ |
@@ -163,7 +163,7 @@ export class VideoShareModel extends Model<VideoShareModel> { | |||
163 | .then(res => res.map(r => r.Actor)) | 163 | .then(res => res.map(r => r.Actor)) |
164 | } | 164 | } |
165 | 165 | ||
166 | static loadActorsByVideoChannel (videoChannelId: number, t: Sequelize.Transaction): Bluebird<ActorModel[]> { | 166 | static loadActorsByVideoChannel (videoChannelId: number, t: Transaction): Bluebird<ActorModel[]> { |
167 | const query = { | 167 | const query = { |
168 | attributes: [], | 168 | attributes: [], |
169 | include: [ | 169 | include: [ |
@@ -188,7 +188,7 @@ export class VideoShareModel extends Model<VideoShareModel> { | |||
188 | .then(res => res.map(r => r.Actor)) | 188 | .then(res => res.map(r => r.Actor)) |
189 | } | 189 | } |
190 | 190 | ||
191 | static listAndCountByVideoId (videoId: number, start: number, count: number, t?: Sequelize.Transaction) { | 191 | static listAndCountByVideoId (videoId: number, start: number, count: number, t?: Transaction) { |
192 | const query = { | 192 | const query = { |
193 | offset: start, | 193 | offset: start, |
194 | limit: count, | 194 | limit: count, |
@@ -205,10 +205,21 @@ export class VideoShareModel extends Model<VideoShareModel> { | |||
205 | const query = { | 205 | const query = { |
206 | where: { | 206 | where: { |
207 | updatedAt: { | 207 | updatedAt: { |
208 | [Sequelize.Op.lt]: beforeUpdatedAt | 208 | [Op.lt]: beforeUpdatedAt |
209 | }, | 209 | }, |
210 | videoId | 210 | videoId |
211 | } | 211 | }, |
212 | include: [ | ||
213 | { | ||
214 | model: ActorModel.unscoped(), | ||
215 | required: true, | ||
216 | where: { | ||
217 | serverId: { | ||
218 | [ Op.ne ]: null | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | ] | ||
212 | } | 223 | } |
213 | 224 | ||
214 | return VideoShareModel.destroy(query) | 225 | return VideoShareModel.destroy(query) |
diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index c78563232..1533f37ab 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts | |||
@@ -379,7 +379,8 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg | |||
379 | req.field('licence', attributes.licence.toString()) | 379 | req.field('licence', attributes.licence.toString()) |
380 | } | 380 | } |
381 | 381 | ||
382 | for (let i = 0; i < attributes.tags.length; i++) { | 382 | const tags = attributes.tags || [] |
383 | for (let i = 0; i < tags.length; i++) { | ||
383 | req.field('tags[' + i + ']', attributes.tags[i]) | 384 | req.field('tags[' + i + ']', attributes.tags[i]) |
384 | } | 385 | } |
385 | 386 | ||