diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/activitypub/inbox.ts | 2 | ||||
-rw-r--r-- | server/helpers/activitypub.ts | 9 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-add.ts | 51 | ||||
-rw-r--r-- | server/lib/activitypub/process/process.ts | 6 | ||||
-rw-r--r-- | server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-fetcher-handler.ts | 2 | ||||
-rw-r--r-- | server/models/account/account-video-rate-interface.ts | 3 | ||||
-rw-r--r-- | server/models/video/video-interface.ts | 3 | ||||
-rw-r--r-- | server/models/video/video.ts | 48 |
8 files changed, 115 insertions, 9 deletions
diff --git a/server/controllers/activitypub/inbox.ts b/server/controllers/activitypub/inbox.ts index 30e7f706b..243ae7381 100644 --- a/server/controllers/activitypub/inbox.ts +++ b/server/controllers/activitypub/inbox.ts | |||
@@ -38,7 +38,7 @@ async function inboxController (req: express.Request, res: express.Response, nex | |||
38 | if ([ 'Collection', 'CollectionPage' ].indexOf(rootActivity.type) !== -1) { | 38 | if ([ 'Collection', 'CollectionPage' ].indexOf(rootActivity.type) !== -1) { |
39 | activities = (rootActivity as ActivityPubCollection).items | 39 | activities = (rootActivity as ActivityPubCollection).items |
40 | } else if ([ 'OrderedCollection', 'OrderedCollectionPage' ].indexOf(rootActivity.type) !== -1) { | 40 | } else if ([ 'OrderedCollection', 'OrderedCollectionPage' ].indexOf(rootActivity.type) !== -1) { |
41 | activities = (rootActivity as ActivityPubOrderedCollection).orderedItems | 41 | activities = (rootActivity as ActivityPubOrderedCollection<Activity>).orderedItems |
42 | } else { | 42 | } else { |
43 | activities = [ rootActivity as Activity ] | 43 | activities = [ rootActivity as Activity ] |
44 | } | 44 | } |
diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts index 54c460200..1ea6422ca 100644 --- a/server/helpers/activitypub.ts +++ b/server/helpers/activitypub.ts | |||
@@ -24,6 +24,14 @@ function activityPubContextify <T> (data: T) { | |||
24 | }) | 24 | }) |
25 | } | 25 | } |
26 | 26 | ||
27 | function activityPubCollection (results: any[]) { | ||
28 | return { | ||
29 | type: 'OrderedCollection', | ||
30 | totalItems: results.length, | ||
31 | orderedItems: results | ||
32 | } | ||
33 | } | ||
34 | |||
27 | function activityPubCollectionPagination (url: string, page: any, result: ResultList<any>) { | 35 | function activityPubCollectionPagination (url: string, page: any, result: ResultList<any>) { |
28 | let next: string | 36 | let next: string |
29 | let prev: string | 37 | let prev: string |
@@ -74,5 +82,6 @@ function buildSignedActivity (byAccount: AccountInstance, data: Object) { | |||
74 | export { | 82 | export { |
75 | activityPubContextify, | 83 | activityPubContextify, |
76 | activityPubCollectionPagination, | 84 | activityPubCollectionPagination, |
85 | activityPubCollection, | ||
77 | buildSignedActivity | 86 | buildSignedActivity |
78 | } | 87 | } |
diff --git a/server/lib/activitypub/process/process-add.ts b/server/lib/activitypub/process/process-add.ts index 332c18cc0..433e68eb6 100644 --- a/server/lib/activitypub/process/process-add.ts +++ b/server/lib/activitypub/process/process-add.ts | |||
@@ -1,11 +1,13 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { VideoTorrentObject } from '../../../../shared' | 2 | import { VideoTorrentObject } from '../../../../shared' |
3 | import { ActivityAdd } from '../../../../shared/models/activitypub/activity' | 3 | import { ActivityAdd } from '../../../../shared/models/activitypub/activity' |
4 | import { VideoRateType } from '../../../../shared/models/videos/video-rate.type' | ||
4 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 5 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
5 | import { logger } from '../../../helpers/logger' | 6 | import { logger } from '../../../helpers/logger' |
6 | import { database as db } from '../../../initializers' | 7 | import { database as db } from '../../../initializers' |
7 | import { AccountInstance } from '../../../models/account/account-interface' | 8 | import { AccountInstance } from '../../../models/account/account-interface' |
8 | import { VideoChannelInstance } from '../../../models/video/video-channel-interface' | 9 | import { VideoChannelInstance } from '../../../models/video/video-channel-interface' |
10 | import { VideoInstance } from '../../../models/video/video-interface' | ||
9 | import { getOrCreateAccountAndServer } from '../account' | 11 | import { getOrCreateAccountAndServer } from '../account' |
10 | import { getOrCreateVideoChannel } from '../video-channels' | 12 | import { getOrCreateVideoChannel } from '../video-channels' |
11 | import { generateThumbnailFromUrl } from '../videos' | 13 | import { generateThumbnailFromUrl } from '../videos' |
@@ -35,13 +37,29 @@ export { | |||
35 | 37 | ||
36 | // --------------------------------------------------------------------------- | 38 | // --------------------------------------------------------------------------- |
37 | 39 | ||
38 | function processAddVideo (account: AccountInstance, activity: ActivityAdd, videoChannel: VideoChannelInstance, video: VideoTorrentObject) { | 40 | async function processAddVideo ( |
41 | account: AccountInstance, | ||
42 | activity: ActivityAdd, | ||
43 | videoChannel: VideoChannelInstance, | ||
44 | videoToCreateData: VideoTorrentObject | ||
45 | ) { | ||
39 | const options = { | 46 | const options = { |
40 | arguments: [ account, activity, videoChannel, video ], | 47 | arguments: [ account, activity, videoChannel, videoToCreateData ], |
41 | errorMessage: 'Cannot insert the remote video with many retries.' | 48 | errorMessage: 'Cannot insert the remote video with many retries.' |
42 | } | 49 | } |
43 | 50 | ||
44 | return retryTransactionWrapper(addRemoteVideo, options) | 51 | const video = await retryTransactionWrapper(addRemoteVideo, options) |
52 | |||
53 | // Process outside the transaction because we could fetch remote data | ||
54 | if (videoToCreateData.likes && Array.isArray(videoToCreateData.likes.orderedItems)) { | ||
55 | await createRates(videoToCreateData.likes.orderedItems, video, 'like') | ||
56 | } | ||
57 | |||
58 | if (videoToCreateData.dislikes && Array.isArray(videoToCreateData.dislikes.orderedItems)) { | ||
59 | await createRates(videoToCreateData.dislikes.orderedItems, video, 'dislike') | ||
60 | } | ||
61 | |||
62 | return video | ||
45 | } | 63 | } |
46 | 64 | ||
47 | function addRemoteVideo (account: AccountInstance, | 65 | function addRemoteVideo (account: AccountInstance, |
@@ -86,3 +104,30 @@ function addRemoteVideo (account: AccountInstance, | |||
86 | return videoCreated | 104 | return videoCreated |
87 | }) | 105 | }) |
88 | } | 106 | } |
107 | |||
108 | async function createRates (accountUrls: string[], video: VideoInstance, rate: VideoRateType) { | ||
109 | let rateCounts = 0 | ||
110 | const tasks: Bluebird<any>[] = [] | ||
111 | |||
112 | for (const accountUrl of accountUrls) { | ||
113 | const account = await getOrCreateAccountAndServer(accountUrl) | ||
114 | const p = db.AccountVideoRate | ||
115 | .create({ | ||
116 | videoId: video.id, | ||
117 | accountId: account.id, | ||
118 | type: rate | ||
119 | }) | ||
120 | .then(() => rateCounts += 1) | ||
121 | |||
122 | tasks.push(p) | ||
123 | } | ||
124 | |||
125 | await Promise.all(tasks) | ||
126 | |||
127 | logger.info('Adding %d %s to video %s.', rateCounts, rate, video.uuid) | ||
128 | |||
129 | // This is "likes" and "dislikes" | ||
130 | await video.increment(rate + 's', { by: rateCounts }) | ||
131 | |||
132 | return | ||
133 | } | ||
diff --git a/server/lib/activitypub/process/process.ts b/server/lib/activitypub/process/process.ts index 942bce0e6..40f19c701 100644 --- a/server/lib/activitypub/process/process.ts +++ b/server/lib/activitypub/process/process.ts | |||
@@ -31,7 +31,11 @@ async function processActivities (activities: Activity[], inboxAccount?: Account | |||
31 | continue | 31 | continue |
32 | } | 32 | } |
33 | 33 | ||
34 | await activityProcessor(activity, inboxAccount) | 34 | try { |
35 | await activityProcessor(activity, inboxAccount) | ||
36 | } catch (err) { | ||
37 | logger.warn('Cannot process activity %s.', activity.type, err) | ||
38 | } | ||
35 | } | 39 | } |
36 | } | 40 | } |
37 | 41 | ||
diff --git a/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-fetcher-handler.ts b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-fetcher-handler.ts index bda319592..9adceab84 100644 --- a/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-fetcher-handler.ts +++ b/server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-fetcher-handler.ts | |||
@@ -49,7 +49,7 @@ async function process (payload: ActivityPubHttpPayload, jobId: number) { | |||
49 | } | 49 | } |
50 | 50 | ||
51 | function onError (err: Error, jobId: number) { | 51 | function onError (err: Error, jobId: number) { |
52 | logger.error('Error when broadcasting ActivityPub request in job %d.', jobId, err) | 52 | logger.error('Error when fetcher ActivityPub request in job %d.', jobId, err) |
53 | return Promise.resolve() | 53 | return Promise.resolve() |
54 | } | 54 | } |
55 | 55 | ||
diff --git a/server/models/account/account-video-rate-interface.ts b/server/models/account/account-video-rate-interface.ts index 316056246..1f395bc45 100644 --- a/server/models/account/account-video-rate-interface.ts +++ b/server/models/account/account-video-rate-interface.ts | |||
@@ -2,6 +2,7 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | import { VideoRateType } from '../../../shared/models/videos/video-rate.type' | 4 | import { VideoRateType } from '../../../shared/models/videos/video-rate.type' |
5 | import { AccountInstance } from './account-interface' | ||
5 | 6 | ||
6 | export namespace AccountVideoRateMethods { | 7 | export namespace AccountVideoRateMethods { |
7 | export type Load = (accountId: number, videoId: number, transaction: Sequelize.Transaction) => Promise<AccountVideoRateInstance> | 8 | export type Load = (accountId: number, videoId: number, transaction: Sequelize.Transaction) => Promise<AccountVideoRateInstance> |
@@ -15,6 +16,8 @@ export interface AccountVideoRateAttributes { | |||
15 | type: VideoRateType | 16 | type: VideoRateType |
16 | accountId: number | 17 | accountId: number |
17 | videoId: number | 18 | videoId: number |
19 | |||
20 | Account?: AccountInstance | ||
18 | } | 21 | } |
19 | 22 | ||
20 | export interface AccountVideoRateInstance | 23 | export interface AccountVideoRateInstance |
diff --git a/server/models/video/video-interface.ts b/server/models/video/video-interface.ts index b97f163ab..89e528acf 100644 --- a/server/models/video/video-interface.ts +++ b/server/models/video/video-interface.ts | |||
@@ -8,6 +8,8 @@ import { TagAttributes, TagInstance } from './tag-interface' | |||
8 | import { VideoChannelInstance } from './video-channel-interface' | 8 | import { VideoChannelInstance } from './video-channel-interface' |
9 | import { VideoFileAttributes, VideoFileInstance } from './video-file-interface' | 9 | import { VideoFileAttributes, VideoFileInstance } from './video-file-interface' |
10 | import { VideoShareInstance } from './video-share-interface' | 10 | import { VideoShareInstance } from './video-share-interface' |
11 | import { UserVideoRate } from '../../../shared/models/videos/user-video-rate.model' | ||
12 | import { AccountVideoRateInstance } from '../account/account-video-rate-interface' | ||
11 | 13 | ||
12 | export namespace VideoMethods { | 14 | export namespace VideoMethods { |
13 | export type GetThumbnailName = (this: VideoInstance) => string | 15 | export type GetThumbnailName = (this: VideoInstance) => string |
@@ -123,6 +125,7 @@ export interface VideoAttributes { | |||
123 | Tags?: TagInstance[] | 125 | Tags?: TagInstance[] |
124 | VideoFiles?: VideoFileInstance[] | 126 | VideoFiles?: VideoFileInstance[] |
125 | VideoShares?: VideoShareInstance[] | 127 | VideoShares?: VideoShareInstance[] |
128 | AccountVideoRates?: AccountVideoRateInstance[] | ||
126 | } | 129 | } |
127 | 130 | ||
128 | export interface VideoInstance extends VideoClass, VideoAttributes, Sequelize.Instance<VideoAttributes> { | 131 | export interface VideoInstance extends VideoClass, VideoAttributes, Sequelize.Instance<VideoAttributes> { |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 052fc0ae8..592fc2d59 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -47,6 +47,7 @@ import { VideoFileInstance, VideoFileModel } from './video-file-interface' | |||
47 | import { VideoAttributes, VideoInstance, VideoMethods } from './video-interface' | 47 | import { VideoAttributes, VideoInstance, VideoMethods } from './video-interface' |
48 | import { sendDeleteVideo } from '../../lib/index' | 48 | import { sendDeleteVideo } from '../../lib/index' |
49 | import * as Bluebird from 'bluebird' | 49 | import * as Bluebird from 'bluebird' |
50 | import { activityPubCollection } from '../../helpers/activitypub' | ||
50 | 51 | ||
51 | const Buffer = safeBuffer.Buffer | 52 | const Buffer = safeBuffer.Buffer |
52 | 53 | ||
@@ -359,6 +360,14 @@ function associate (models) { | |||
359 | }, | 360 | }, |
360 | onDelete: 'cascade' | 361 | onDelete: 'cascade' |
361 | }) | 362 | }) |
363 | |||
364 | Video.hasMany(models.AccountVideoRate, { | ||
365 | foreignKey: { | ||
366 | name: 'videoId', | ||
367 | allowNull: false | ||
368 | }, | ||
369 | onDelete: 'cascade' | ||
370 | }) | ||
362 | } | 371 | } |
363 | 372 | ||
364 | function afterDestroy (video: VideoInstance) { | 373 | function afterDestroy (video: VideoInstance) { |
@@ -575,6 +584,25 @@ toActivityPubObject = function (this: VideoInstance) { | |||
575 | } | 584 | } |
576 | } | 585 | } |
577 | 586 | ||
587 | let likesObject | ||
588 | let dislikesObject | ||
589 | |||
590 | if (Array.isArray(this.AccountVideoRates)) { | ||
591 | const likes: string[] = [] | ||
592 | const dislikes: string[] = [] | ||
593 | |||
594 | for (const rate of this.AccountVideoRates) { | ||
595 | if (rate.type === 'like') { | ||
596 | likes.push(rate.Account.url) | ||
597 | } else if (rate.type === 'dislike') { | ||
598 | dislikes.push(rate.Account.url) | ||
599 | } | ||
600 | } | ||
601 | |||
602 | likesObject = activityPubCollection(likes) | ||
603 | dislikesObject = activityPubCollection(dislikes) | ||
604 | } | ||
605 | |||
578 | const url = [] | 606 | const url = [] |
579 | for (const file of this.VideoFiles) { | 607 | for (const file of this.VideoFiles) { |
580 | url.push({ | 608 | url.push({ |
@@ -630,7 +658,9 @@ toActivityPubObject = function (this: VideoInstance) { | |||
630 | width: THUMBNAILS_SIZE.width, | 658 | width: THUMBNAILS_SIZE.width, |
631 | height: THUMBNAILS_SIZE.height | 659 | height: THUMBNAILS_SIZE.height |
632 | }, | 660 | }, |
633 | url // FIXME: needed? | 661 | url, |
662 | likes: likesObject, | ||
663 | dislikes: dislikesObject | ||
634 | } | 664 | } |
635 | 665 | ||
636 | return videoObject | 666 | return videoObject |
@@ -845,8 +875,12 @@ listAllAndSharedByAccountForOutbox = function (accountId: number, start: number, | |||
845 | } | 875 | } |
846 | ] | 876 | ] |
847 | }, | 877 | }, |
848 | Video['sequelize'].models.Tag, | 878 | { |
849 | Video['sequelize'].models.VideoFile | 879 | model: Video['sequelize'].models.AccountVideoRate, |
880 | include: [ Video['sequelize'].models.Account ] | ||
881 | }, | ||
882 | Video['sequelize'].models.VideoFile, | ||
883 | Video['sequelize'].models.Tag | ||
850 | ] | 884 | ] |
851 | } | 885 | } |
852 | 886 | ||
@@ -1106,6 +1140,10 @@ loadAndPopulateAccountAndServerAndTags = function (id: number) { | |||
1106 | } | 1140 | } |
1107 | ] | 1141 | ] |
1108 | }, | 1142 | }, |
1143 | { | ||
1144 | model: Video['sequelize'].models.AccountVideoRate, | ||
1145 | include: [ Video['sequelize'].models.Account ] | ||
1146 | }, | ||
1109 | Video['sequelize'].models.Tag, | 1147 | Video['sequelize'].models.Tag, |
1110 | Video['sequelize'].models.VideoFile | 1148 | Video['sequelize'].models.VideoFile |
1111 | ] | 1149 | ] |
@@ -1129,6 +1167,10 @@ loadByUUIDAndPopulateAccountAndServerAndTags = function (uuid: string) { | |||
1129 | } | 1167 | } |
1130 | ] | 1168 | ] |
1131 | }, | 1169 | }, |
1170 | { | ||
1171 | model: Video['sequelize'].models.AccountVideoRate, | ||
1172 | include: [ Video['sequelize'].models.Account ] | ||
1173 | }, | ||
1132 | Video['sequelize'].models.Tag, | 1174 | Video['sequelize'].models.Tag, |
1133 | Video['sequelize'].models.VideoFile | 1175 | Video['sequelize'].models.VideoFile |
1134 | ] | 1176 | ] |