diff options
author | Chocobozzz <me@florianbigard.com> | 2018-09-20 16:24:31 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-09-20 16:24:31 +0200 |
commit | 0491173a61aed66205c017e0d7e0503ea316c144 (patch) | |
tree | ce6621597505f9518cfdf0981977d097c63f9fad /server/controllers | |
parent | 8704acf49efc770d73bf07c10468ed8c74d28a83 (diff) | |
parent | 6247b2057b792cea155a1abd9788c363ae7d2cc2 (diff) | |
download | PeerTube-0491173a61aed66205c017e0d7e0503ea316c144.tar.gz PeerTube-0491173a61aed66205c017e0d7e0503ea316c144.tar.zst PeerTube-0491173a61aed66205c017e0d7e0503ea316c144.zip |
Merge branch 'develop' into cli-wrapper
Diffstat (limited to 'server/controllers')
-rw-r--r-- | server/controllers/activitypub/client.ts | 16 | ||||
-rw-r--r-- | server/controllers/activitypub/inbox.ts | 23 | ||||
-rw-r--r-- | server/controllers/api/config.ts | 9 | ||||
-rw-r--r-- | server/controllers/api/overviews.ts | 42 | ||||
-rw-r--r-- | server/controllers/api/search.ts | 7 | ||||
-rw-r--r-- | server/controllers/api/server/stats.ts | 14 | ||||
-rw-r--r-- | server/controllers/api/users/index.ts | 32 | ||||
-rw-r--r-- | server/controllers/api/users/me.ts | 41 | ||||
-rw-r--r-- | server/controllers/api/video-channel.ts | 28 | ||||
-rw-r--r-- | server/controllers/api/videos/abuse.ts | 23 | ||||
-rw-r--r-- | server/controllers/api/videos/comment.ts | 24 | ||||
-rw-r--r-- | server/controllers/api/videos/import.ts | 6 | ||||
-rw-r--r-- | server/controllers/api/videos/index.ts | 12 | ||||
-rw-r--r-- | server/controllers/api/videos/ownership.ts | 13 | ||||
-rw-r--r-- | server/controllers/api/videos/rate.ts | 11 | ||||
-rw-r--r-- | server/controllers/client.ts | 2 |
16 files changed, 166 insertions, 137 deletions
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts index 2e168ea78..6229c44aa 100644 --- a/server/controllers/activitypub/client.ts +++ b/server/controllers/activitypub/client.ts | |||
@@ -6,7 +6,13 @@ import { CONFIG, ROUTE_CACHE_LIFETIME } from '../../initializers' | |||
6 | import { buildAnnounceWithVideoAudience } from '../../lib/activitypub/send' | 6 | import { buildAnnounceWithVideoAudience } from '../../lib/activitypub/send' |
7 | import { audiencify, getAudience } from '../../lib/activitypub/audience' | 7 | import { audiencify, getAudience } from '../../lib/activitypub/audience' |
8 | import { buildCreateActivity } from '../../lib/activitypub/send/send-create' | 8 | import { buildCreateActivity } from '../../lib/activitypub/send/send-create' |
9 | import { asyncMiddleware, executeIfActivityPub, localAccountValidator, localVideoChannelValidator } from '../../middlewares' | 9 | import { |
10 | asyncMiddleware, | ||
11 | executeIfActivityPub, | ||
12 | localAccountValidator, | ||
13 | localVideoChannelValidator, | ||
14 | videosCustomGetValidator | ||
15 | } from '../../middlewares' | ||
10 | import { videosGetValidator, videosShareValidator } from '../../middlewares/validators' | 16 | import { videosGetValidator, videosShareValidator } from '../../middlewares/validators' |
11 | import { videoCommentGetValidator } from '../../middlewares/validators/video-comments' | 17 | import { videoCommentGetValidator } from '../../middlewares/validators/video-comments' |
12 | import { AccountModel } from '../../models/account/account' | 18 | import { AccountModel } from '../../models/account/account' |
@@ -54,7 +60,7 @@ activityPubClientRouter.get('/videos/watch/:id/activity', | |||
54 | executeIfActivityPub(asyncMiddleware(videoController)) | 60 | executeIfActivityPub(asyncMiddleware(videoController)) |
55 | ) | 61 | ) |
56 | activityPubClientRouter.get('/videos/watch/:id/announces', | 62 | activityPubClientRouter.get('/videos/watch/:id/announces', |
57 | executeIfActivityPub(asyncMiddleware(videosGetValidator)), | 63 | executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video'))), |
58 | executeIfActivityPub(asyncMiddleware(videoAnnouncesController)) | 64 | executeIfActivityPub(asyncMiddleware(videoAnnouncesController)) |
59 | ) | 65 | ) |
60 | activityPubClientRouter.get('/videos/watch/:id/announces/:accountId', | 66 | activityPubClientRouter.get('/videos/watch/:id/announces/:accountId', |
@@ -62,15 +68,15 @@ activityPubClientRouter.get('/videos/watch/:id/announces/:accountId', | |||
62 | executeIfActivityPub(asyncMiddleware(videoAnnounceController)) | 68 | executeIfActivityPub(asyncMiddleware(videoAnnounceController)) |
63 | ) | 69 | ) |
64 | activityPubClientRouter.get('/videos/watch/:id/likes', | 70 | activityPubClientRouter.get('/videos/watch/:id/likes', |
65 | executeIfActivityPub(asyncMiddleware(videosGetValidator)), | 71 | executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video'))), |
66 | executeIfActivityPub(asyncMiddleware(videoLikesController)) | 72 | executeIfActivityPub(asyncMiddleware(videoLikesController)) |
67 | ) | 73 | ) |
68 | activityPubClientRouter.get('/videos/watch/:id/dislikes', | 74 | activityPubClientRouter.get('/videos/watch/:id/dislikes', |
69 | executeIfActivityPub(asyncMiddleware(videosGetValidator)), | 75 | executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video'))), |
70 | executeIfActivityPub(asyncMiddleware(videoDislikesController)) | 76 | executeIfActivityPub(asyncMiddleware(videoDislikesController)) |
71 | ) | 77 | ) |
72 | activityPubClientRouter.get('/videos/watch/:id/comments', | 78 | activityPubClientRouter.get('/videos/watch/:id/comments', |
73 | executeIfActivityPub(asyncMiddleware(videosGetValidator)), | 79 | executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video'))), |
74 | executeIfActivityPub(asyncMiddleware(videoCommentsController)) | 80 | executeIfActivityPub(asyncMiddleware(videoCommentsController)) |
75 | ) | 81 | ) |
76 | activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId', | 82 | activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId', |
diff --git a/server/controllers/activitypub/inbox.ts b/server/controllers/activitypub/inbox.ts index 20bd20ed4..738d155eb 100644 --- a/server/controllers/activitypub/inbox.ts +++ b/server/controllers/activitypub/inbox.ts | |||
@@ -7,6 +7,8 @@ import { asyncMiddleware, checkSignature, localAccountValidator, localVideoChann | |||
7 | import { activityPubValidator } from '../../middlewares/validators/activitypub/activity' | 7 | import { activityPubValidator } from '../../middlewares/validators/activitypub/activity' |
8 | import { VideoChannelModel } from '../../models/video/video-channel' | 8 | import { VideoChannelModel } from '../../models/video/video-channel' |
9 | import { AccountModel } from '../../models/account/account' | 9 | import { AccountModel } from '../../models/account/account' |
10 | import { queue } from 'async' | ||
11 | import { ActorModel } from '../../models/activitypub/actor' | ||
10 | 12 | ||
11 | const inboxRouter = express.Router() | 13 | const inboxRouter = express.Router() |
12 | 14 | ||
@@ -14,7 +16,7 @@ inboxRouter.post('/inbox', | |||
14 | signatureValidator, | 16 | signatureValidator, |
15 | asyncMiddleware(checkSignature), | 17 | asyncMiddleware(checkSignature), |
16 | asyncMiddleware(activityPubValidator), | 18 | asyncMiddleware(activityPubValidator), |
17 | asyncMiddleware(inboxController) | 19 | inboxController |
18 | ) | 20 | ) |
19 | 21 | ||
20 | inboxRouter.post('/accounts/:name/inbox', | 22 | inboxRouter.post('/accounts/:name/inbox', |
@@ -22,14 +24,14 @@ inboxRouter.post('/accounts/:name/inbox', | |||
22 | asyncMiddleware(checkSignature), | 24 | asyncMiddleware(checkSignature), |
23 | asyncMiddleware(localAccountValidator), | 25 | asyncMiddleware(localAccountValidator), |
24 | asyncMiddleware(activityPubValidator), | 26 | asyncMiddleware(activityPubValidator), |
25 | asyncMiddleware(inboxController) | 27 | inboxController |
26 | ) | 28 | ) |
27 | inboxRouter.post('/video-channels/:name/inbox', | 29 | inboxRouter.post('/video-channels/:name/inbox', |
28 | signatureValidator, | 30 | signatureValidator, |
29 | asyncMiddleware(checkSignature), | 31 | asyncMiddleware(checkSignature), |
30 | asyncMiddleware(localVideoChannelValidator), | 32 | asyncMiddleware(localVideoChannelValidator), |
31 | asyncMiddleware(activityPubValidator), | 33 | asyncMiddleware(activityPubValidator), |
32 | asyncMiddleware(inboxController) | 34 | inboxController |
33 | ) | 35 | ) |
34 | 36 | ||
35 | // --------------------------------------------------------------------------- | 37 | // --------------------------------------------------------------------------- |
@@ -40,7 +42,12 @@ export { | |||
40 | 42 | ||
41 | // --------------------------------------------------------------------------- | 43 | // --------------------------------------------------------------------------- |
42 | 44 | ||
43 | async function inboxController (req: express.Request, res: express.Response, next: express.NextFunction) { | 45 | const inboxQueue = queue<{ activities: Activity[], signatureActor?: ActorModel, inboxActor?: ActorModel }, Error>((task, cb) => { |
46 | processActivities(task.activities, task.signatureActor, task.inboxActor) | ||
47 | .then(() => cb()) | ||
48 | }) | ||
49 | |||
50 | function inboxController (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
44 | const rootActivity: RootActivity = req.body | 51 | const rootActivity: RootActivity = req.body |
45 | let activities: Activity[] = [] | 52 | let activities: Activity[] = [] |
46 | 53 | ||
@@ -66,7 +73,11 @@ async function inboxController (req: express.Request, res: express.Response, nex | |||
66 | 73 | ||
67 | logger.info('Receiving inbox requests for %d activities by %s.', activities.length, res.locals.signature.actor.url) | 74 | logger.info('Receiving inbox requests for %d activities by %s.', activities.length, res.locals.signature.actor.url) |
68 | 75 | ||
69 | await processActivities(activities, res.locals.signature.actor, accountOrChannel ? accountOrChannel.Actor : undefined) | 76 | inboxQueue.push({ |
77 | activities, | ||
78 | signatureActor: res.locals.signature.actor, | ||
79 | inboxActor: accountOrChannel ? accountOrChannel.Actor : undefined | ||
80 | }) | ||
70 | 81 | ||
71 | res.status(204).end() | 82 | return res.status(204).end() |
72 | } | 83 | } |
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 6edbe4820..95549b724 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -8,7 +8,7 @@ import { CONFIG, CONSTRAINTS_FIELDS, reloadConfig } from '../../initializers' | |||
8 | import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares' | 8 | import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares' |
9 | import { customConfigUpdateValidator } from '../../middlewares/validators/config' | 9 | import { customConfigUpdateValidator } from '../../middlewares/validators/config' |
10 | import { ClientHtml } from '../../lib/client-html' | 10 | import { ClientHtml } from '../../lib/client-html' |
11 | import { auditLoggerFactory, CustomConfigAuditView } from '../../helpers/audit-logger' | 11 | import { auditLoggerFactory, CustomConfigAuditView, getAuditIdFromRes } from '../../helpers/audit-logger' |
12 | import { remove, writeJSON } from 'fs-extra' | 12 | import { remove, writeJSON } from 'fs-extra' |
13 | 13 | ||
14 | const packageJSON = require('../../../../package.json') | 14 | const packageJSON = require('../../../../package.json') |
@@ -134,10 +134,7 @@ async function getCustomConfig (req: express.Request, res: express.Response, nex | |||
134 | async function deleteCustomConfig (req: express.Request, res: express.Response, next: express.NextFunction) { | 134 | async function deleteCustomConfig (req: express.Request, res: express.Response, next: express.NextFunction) { |
135 | await remove(CONFIG.CUSTOM_FILE) | 135 | await remove(CONFIG.CUSTOM_FILE) |
136 | 136 | ||
137 | auditLogger.delete( | 137 | auditLogger.delete(getAuditIdFromRes(res), new CustomConfigAuditView(customConfig())) |
138 | res.locals.oauth.token.User.Account.Actor.getIdentifier(), | ||
139 | new CustomConfigAuditView(customConfig()) | ||
140 | ) | ||
141 | 138 | ||
142 | reloadConfig() | 139 | reloadConfig() |
143 | ClientHtml.invalidCache() | 140 | ClientHtml.invalidCache() |
@@ -183,7 +180,7 @@ async function updateCustomConfig (req: express.Request, res: express.Response, | |||
183 | const data = customConfig() | 180 | const data = customConfig() |
184 | 181 | ||
185 | auditLogger.update( | 182 | auditLogger.update( |
186 | res.locals.oauth.token.User.Account.Actor.getIdentifier(), | 183 | getAuditIdFromRes(res), |
187 | new CustomConfigAuditView(data), | 184 | new CustomConfigAuditView(data), |
188 | oldCustomConfigAuditKeys | 185 | oldCustomConfigAuditKeys |
189 | ) | 186 | ) |
diff --git a/server/controllers/api/overviews.ts b/server/controllers/api/overviews.ts index da941c0ac..8b6773056 100644 --- a/server/controllers/api/overviews.ts +++ b/server/controllers/api/overviews.ts | |||
@@ -4,8 +4,9 @@ import { VideoModel } from '../../models/video/video' | |||
4 | import { asyncMiddleware } from '../../middlewares' | 4 | import { asyncMiddleware } from '../../middlewares' |
5 | import { TagModel } from '../../models/video/tag' | 5 | import { TagModel } from '../../models/video/tag' |
6 | import { VideosOverview } from '../../../shared/models/overviews' | 6 | import { VideosOverview } from '../../../shared/models/overviews' |
7 | import { OVERVIEWS, ROUTE_CACHE_LIFETIME } from '../../initializers' | 7 | import { MEMOIZE_TTL, OVERVIEWS, ROUTE_CACHE_LIFETIME } from '../../initializers' |
8 | import { cacheRoute } from '../../middlewares/cache' | 8 | import { cacheRoute } from '../../middlewares/cache' |
9 | import * as memoizee from 'memoizee' | ||
9 | 10 | ||
10 | const overviewsRouter = express.Router() | 11 | const overviewsRouter = express.Router() |
11 | 12 | ||
@@ -20,13 +21,30 @@ export { overviewsRouter } | |||
20 | 21 | ||
21 | // --------------------------------------------------------------------------- | 22 | // --------------------------------------------------------------------------- |
22 | 23 | ||
24 | const buildSamples = memoizee(async function () { | ||
25 | const [ categories, channels, tags ] = await Promise.all([ | ||
26 | VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), | ||
27 | VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD ,OVERVIEWS.VIDEOS.SAMPLES_COUNT), | ||
28 | TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT) | ||
29 | ]) | ||
30 | |||
31 | return { categories, channels, tags } | ||
32 | }, { maxAge: MEMOIZE_TTL.OVERVIEWS_SAMPLE }) | ||
33 | |||
23 | // This endpoint could be quite long, but we cache it | 34 | // This endpoint could be quite long, but we cache it |
24 | async function getVideosOverview (req: express.Request, res: express.Response) { | 35 | async function getVideosOverview (req: express.Request, res: express.Response) { |
25 | const attributes = await buildSamples() | 36 | const attributes = await buildSamples() |
37 | |||
38 | const [ categories, channels, tags ] = await Promise.all([ | ||
39 | Promise.all(attributes.categories.map(c => getVideosByCategory(c, res))), | ||
40 | Promise.all(attributes.channels.map(c => getVideosByChannel(c, res))), | ||
41 | Promise.all(attributes.tags.map(t => getVideosByTag(t, res))) | ||
42 | ]) | ||
43 | |||
26 | const result: VideosOverview = { | 44 | const result: VideosOverview = { |
27 | categories: await Promise.all(attributes.categories.map(c => getVideosByCategory(c, res))), | 45 | categories, |
28 | channels: await Promise.all(attributes.channels.map(c => getVideosByChannel(c, res))), | 46 | channels, |
29 | tags: await Promise.all(attributes.tags.map(t => getVideosByTag(t, res))) | 47 | tags |
30 | } | 48 | } |
31 | 49 | ||
32 | // Cleanup our object | 50 | // Cleanup our object |
@@ -37,16 +55,6 @@ async function getVideosOverview (req: express.Request, res: express.Response) { | |||
37 | return res.json(result) | 55 | return res.json(result) |
38 | } | 56 | } |
39 | 57 | ||
40 | async function buildSamples () { | ||
41 | const [ categories, channels, tags ] = await Promise.all([ | ||
42 | VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), | ||
43 | VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD ,OVERVIEWS.VIDEOS.SAMPLES_COUNT), | ||
44 | TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT) | ||
45 | ]) | ||
46 | |||
47 | return { categories, channels, tags } | ||
48 | } | ||
49 | |||
50 | async function getVideosByTag (tag: string, res: express.Response) { | 58 | async function getVideosByTag (tag: string, res: express.Response) { |
51 | const videos = await getVideos(res, { tagsOneOf: [ tag ] }) | 59 | const videos = await getVideos(res, { tagsOneOf: [ tag ] }) |
52 | 60 | ||
@@ -84,14 +92,16 @@ async function getVideos ( | |||
84 | res: express.Response, | 92 | res: express.Response, |
85 | where: { videoChannelId?: number, tagsOneOf?: string[], categoryOneOf?: number[] } | 93 | where: { videoChannelId?: number, tagsOneOf?: string[], categoryOneOf?: number[] } |
86 | ) { | 94 | ) { |
87 | const { data } = await VideoModel.listForApi(Object.assign({ | 95 | const query = Object.assign({ |
88 | start: 0, | 96 | start: 0, |
89 | count: 10, | 97 | count: 10, |
90 | sort: '-createdAt', | 98 | sort: '-createdAt', |
91 | includeLocalVideos: true, | 99 | includeLocalVideos: true, |
92 | nsfw: buildNSFWFilter(res), | 100 | nsfw: buildNSFWFilter(res), |
93 | withFiles: false | 101 | withFiles: false |
94 | }, where)) | 102 | }, where) |
103 | |||
104 | const { data } = await VideoModel.listForApi(query, false) | ||
95 | 105 | ||
96 | return data.map(d => d.toFormattedJSON()) | 106 | return data.map(d => d.toFormattedJSON()) |
97 | } | 107 | } |
diff --git a/server/controllers/api/search.ts b/server/controllers/api/search.ts index 28a7a04ca..fd4db7a54 100644 --- a/server/controllers/api/search.ts +++ b/server/controllers/api/search.ts | |||
@@ -56,6 +56,9 @@ function searchVideoChannels (req: express.Request, res: express.Response) { | |||
56 | const isURISearch = search.startsWith('http://') || search.startsWith('https://') | 56 | const isURISearch = search.startsWith('http://') || search.startsWith('https://') |
57 | 57 | ||
58 | const parts = search.split('@') | 58 | const parts = search.split('@') |
59 | |||
60 | // Handle strings like @toto@example.com | ||
61 | if (parts.length === 3 && parts[0].length === 0) parts.shift() | ||
59 | const isWebfingerSearch = parts.length === 2 && parts.every(p => p.indexOf(' ') === -1) | 62 | const isWebfingerSearch = parts.length === 2 && parts.every(p => p.indexOf(' ') === -1) |
60 | 63 | ||
61 | if (isURISearch || isWebfingerSearch) return searchVideoChannelURI(search, isWebfingerSearch, res) | 64 | if (isURISearch || isWebfingerSearch) return searchVideoChannelURI(search, isWebfingerSearch, res) |
@@ -86,7 +89,7 @@ async function searchVideoChannelURI (search: string, isWebfingerSearch: boolean | |||
86 | 89 | ||
87 | if (isUserAbleToSearchRemoteURI(res)) { | 90 | if (isUserAbleToSearchRemoteURI(res)) { |
88 | try { | 91 | try { |
89 | const actor = await getOrCreateActorAndServerAndModel(uri, true, true) | 92 | const actor = await getOrCreateActorAndServerAndModel(uri, 'all', true, true) |
90 | videoChannel = actor.VideoChannel | 93 | videoChannel = actor.VideoChannel |
91 | } catch (err) { | 94 | } catch (err) { |
92 | logger.info('Cannot search remote video channel %s.', uri, { err }) | 95 | logger.info('Cannot search remote video channel %s.', uri, { err }) |
@@ -136,7 +139,7 @@ async function searchVideoURI (url: string, res: express.Response) { | |||
136 | refreshVideo: false | 139 | refreshVideo: false |
137 | } | 140 | } |
138 | 141 | ||
139 | const result = await getOrCreateVideoAndAccountAndChannel(url, syncParam) | 142 | const result = await getOrCreateVideoAndAccountAndChannel({ videoObject: url, syncParam }) |
140 | video = result ? result.video : undefined | 143 | video = result ? result.video : undefined |
141 | } catch (err) { | 144 | } catch (err) { |
142 | logger.info('Cannot search remote video %s.', url, { err }) | 145 | logger.info('Cannot search remote video %s.', url, { err }) |
diff --git a/server/controllers/api/server/stats.ts b/server/controllers/api/server/stats.ts index 6f4fe938c..85803f69e 100644 --- a/server/controllers/api/server/stats.ts +++ b/server/controllers/api/server/stats.ts | |||
@@ -5,10 +5,14 @@ import { UserModel } from '../../../models/account/user' | |||
5 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 5 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
6 | import { VideoModel } from '../../../models/video/video' | 6 | import { VideoModel } from '../../../models/video/video' |
7 | import { VideoCommentModel } from '../../../models/video/video-comment' | 7 | import { VideoCommentModel } from '../../../models/video/video-comment' |
8 | import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' | ||
9 | import { CONFIG, ROUTE_CACHE_LIFETIME } from '../../../initializers/constants' | ||
10 | import { cacheRoute } from '../../../middlewares/cache' | ||
8 | 11 | ||
9 | const statsRouter = express.Router() | 12 | const statsRouter = express.Router() |
10 | 13 | ||
11 | statsRouter.get('/stats', | 14 | statsRouter.get('/stats', |
15 | asyncMiddleware(cacheRoute(ROUTE_CACHE_LIFETIME.STATS)), | ||
12 | asyncMiddleware(getStats) | 16 | asyncMiddleware(getStats) |
13 | ) | 17 | ) |
14 | 18 | ||
@@ -18,6 +22,13 @@ async function getStats (req: express.Request, res: express.Response, next: expr | |||
18 | const { totalUsers } = await UserModel.getStats() | 22 | const { totalUsers } = await UserModel.getStats() |
19 | const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats() | 23 | const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats() |
20 | 24 | ||
25 | const videosRedundancyStats = await Promise.all( | ||
26 | CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.map(r => { | ||
27 | return VideoRedundancyModel.getStats(r.strategy) | ||
28 | .then(stats => Object.assign(stats, { strategy: r.strategy, totalSize: r.size })) | ||
29 | }) | ||
30 | ) | ||
31 | |||
21 | const data: ServerStats = { | 32 | const data: ServerStats = { |
22 | totalLocalVideos, | 33 | totalLocalVideos, |
23 | totalLocalVideoViews, | 34 | totalLocalVideoViews, |
@@ -26,7 +37,8 @@ async function getStats (req: express.Request, res: express.Response, next: expr | |||
26 | totalVideoComments, | 37 | totalVideoComments, |
27 | totalUsers, | 38 | totalUsers, |
28 | totalInstanceFollowers, | 39 | totalInstanceFollowers, |
29 | totalInstanceFollowing | 40 | totalInstanceFollowing, |
41 | videosRedundancy: videosRedundancyStats | ||
30 | } | 42 | } |
31 | 43 | ||
32 | return res.json(data).end() | 44 | return res.json(data).end() |
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index 07edf3727..8b8ebcd23 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts | |||
@@ -27,13 +27,17 @@ import { | |||
27 | usersUpdateValidator | 27 | usersUpdateValidator |
28 | } from '../../../middlewares' | 28 | } from '../../../middlewares' |
29 | import { | 29 | import { |
30 | usersAskResetPasswordValidator, usersBlockingValidator, usersResetPasswordValidator, | 30 | usersAskResetPasswordValidator, |
31 | usersAskSendVerifyEmailValidator, usersVerifyEmailValidator | 31 | usersAskSendVerifyEmailValidator, |
32 | usersBlockingValidator, | ||
33 | usersResetPasswordValidator, | ||
34 | usersVerifyEmailValidator | ||
32 | } from '../../../middlewares/validators' | 35 | } from '../../../middlewares/validators' |
33 | import { UserModel } from '../../../models/account/user' | 36 | import { UserModel } from '../../../models/account/user' |
34 | import { OAuthTokenModel } from '../../../models/oauth/oauth-token' | 37 | import { OAuthTokenModel } from '../../../models/oauth/oauth-token' |
35 | import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger' | 38 | import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger' |
36 | import { meRouter } from './me' | 39 | import { meRouter } from './me' |
40 | import { deleteUserToken } from '../../../lib/oauth-model' | ||
37 | 41 | ||
38 | const auditLogger = auditLoggerFactory('users') | 42 | const auditLogger = auditLoggerFactory('users') |
39 | 43 | ||
@@ -166,7 +170,7 @@ async function createUser (req: express.Request, res: express.Response) { | |||
166 | 170 | ||
167 | const { user, account } = await createUserAccountAndChannel(userToCreate) | 171 | const { user, account } = await createUserAccountAndChannel(userToCreate) |
168 | 172 | ||
169 | auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new UserAuditView(user.toFormattedJSON())) | 173 | auditLogger.create(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON())) |
170 | logger.info('User %s with its channel and account created.', body.username) | 174 | logger.info('User %s with its channel and account created.', body.username) |
171 | 175 | ||
172 | return res.json({ | 176 | return res.json({ |
@@ -245,7 +249,7 @@ async function removeUser (req: express.Request, res: express.Response, next: ex | |||
245 | 249 | ||
246 | await user.destroy() | 250 | await user.destroy() |
247 | 251 | ||
248 | auditLogger.delete(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new UserAuditView(user.toFormattedJSON())) | 252 | auditLogger.delete(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON())) |
249 | 253 | ||
250 | return res.sendStatus(204) | 254 | return res.sendStatus(204) |
251 | } | 255 | } |
@@ -264,15 +268,9 @@ async function updateUser (req: express.Request, res: express.Response, next: ex | |||
264 | const user = await userToUpdate.save() | 268 | const user = await userToUpdate.save() |
265 | 269 | ||
266 | // Destroy user token to refresh rights | 270 | // Destroy user token to refresh rights |
267 | if (roleChanged) { | 271 | if (roleChanged) await deleteUserToken(userToUpdate.id) |
268 | await OAuthTokenModel.deleteUserToken(userToUpdate.id) | ||
269 | } | ||
270 | 272 | ||
271 | auditLogger.update( | 273 | auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView) |
272 | res.locals.oauth.token.User.Account.Actor.getIdentifier(), | ||
273 | new UserAuditView(user.toFormattedJSON()), | ||
274 | oldUserAuditView | ||
275 | ) | ||
276 | 274 | ||
277 | // Don't need to send this update to followers, these attributes are not propagated | 275 | // Don't need to send this update to followers, these attributes are not propagated |
278 | 276 | ||
@@ -333,16 +331,12 @@ async function changeUserBlock (res: express.Response, user: UserModel, block: b | |||
333 | user.blockedReason = reason || null | 331 | user.blockedReason = reason || null |
334 | 332 | ||
335 | await sequelizeTypescript.transaction(async t => { | 333 | await sequelizeTypescript.transaction(async t => { |
336 | await OAuthTokenModel.deleteUserToken(user.id, t) | 334 | await deleteUserToken(user.id, t) |
337 | 335 | ||
338 | await user.save({ transaction: t }) | 336 | await user.save({ transaction: t }) |
339 | }) | 337 | }) |
340 | 338 | ||
341 | await Emailer.Instance.addUserBlockJob(user, block, reason) | 339 | await Emailer.Instance.addUserBlockJob(user, block, reason) |
342 | 340 | ||
343 | auditLogger.update( | 341 | auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView) |
344 | res.locals.oauth.token.User.Account.Actor.getIdentifier(), | ||
345 | new UserAuditView(user.toFormattedJSON()), | ||
346 | oldUserAuditView | ||
347 | ) | ||
348 | } | 342 | } |
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index e886d4b2a..ff3a87b7f 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts | |||
@@ -5,7 +5,8 @@ import { getFormattedObjects } from '../../../helpers/utils' | |||
5 | import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../../initializers' | 5 | import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../../initializers' |
6 | import { sendUpdateActor } from '../../../lib/activitypub/send' | 6 | import { sendUpdateActor } from '../../../lib/activitypub/send' |
7 | import { | 7 | import { |
8 | asyncMiddleware, asyncRetryTransactionMiddleware, | 8 | asyncMiddleware, |
9 | asyncRetryTransactionMiddleware, | ||
9 | authenticate, | 10 | authenticate, |
10 | commonVideosFiltersValidator, | 11 | commonVideosFiltersValidator, |
11 | paginationValidator, | 12 | paginationValidator, |
@@ -17,11 +18,11 @@ import { | |||
17 | usersVideoRatingValidator | 18 | usersVideoRatingValidator |
18 | } from '../../../middlewares' | 19 | } from '../../../middlewares' |
19 | import { | 20 | import { |
21 | areSubscriptionsExistValidator, | ||
20 | deleteMeValidator, | 22 | deleteMeValidator, |
21 | userSubscriptionsSortValidator, | 23 | userSubscriptionsSortValidator, |
22 | videoImportsSortValidator, | 24 | videoImportsSortValidator, |
23 | videosSortValidator, | 25 | videosSortValidator |
24 | areSubscriptionsExistValidator | ||
25 | } from '../../../middlewares/validators' | 26 | } from '../../../middlewares/validators' |
26 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' | 27 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' |
27 | import { UserModel } from '../../../models/account/user' | 28 | import { UserModel } from '../../../models/account/user' |
@@ -31,12 +32,13 @@ import { buildNSFWFilter, createReqFiles } from '../../../helpers/express-utils' | |||
31 | import { UserVideoQuota } from '../../../../shared/models/users/user-video-quota.model' | 32 | import { UserVideoQuota } from '../../../../shared/models/users/user-video-quota.model' |
32 | import { updateAvatarValidator } from '../../../middlewares/validators/avatar' | 33 | import { updateAvatarValidator } from '../../../middlewares/validators/avatar' |
33 | import { updateActorAvatarFile } from '../../../lib/avatar' | 34 | import { updateActorAvatarFile } from '../../../lib/avatar' |
34 | import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger' | 35 | import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger' |
35 | import { VideoImportModel } from '../../../models/video/video-import' | 36 | import { VideoImportModel } from '../../../models/video/video-import' |
36 | import { VideoFilter } from '../../../../shared/models/videos/video-query.type' | 37 | import { VideoFilter } from '../../../../shared/models/videos/video-query.type' |
37 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 38 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
38 | import { JobQueue } from '../../../lib/job-queue' | 39 | import { JobQueue } from '../../../lib/job-queue' |
39 | import { logger } from '../../../helpers/logger' | 40 | import { logger } from '../../../helpers/logger' |
41 | import { AccountModel } from '../../../models/account/account' | ||
40 | 42 | ||
41 | const auditLogger = auditLoggerFactory('users-me') | 43 | const auditLogger = auditLoggerFactory('users-me') |
42 | 44 | ||
@@ -293,7 +295,7 @@ async function getUserVideoQuotaUsed (req: express.Request, res: express.Respons | |||
293 | } | 295 | } |
294 | 296 | ||
295 | async function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) { | 297 | async function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) { |
296 | const videoId = +req.params.videoId | 298 | const videoId = res.locals.video.id |
297 | const accountId = +res.locals.oauth.token.User.Account.id | 299 | const accountId = +res.locals.oauth.token.User.Account.id |
298 | 300 | ||
299 | const ratingObj = await AccountVideoRateModel.load(accountId, videoId, null) | 301 | const ratingObj = await AccountVideoRateModel.load(accountId, videoId, null) |
@@ -311,7 +313,7 @@ async function deleteMe (req: express.Request, res: express.Response) { | |||
311 | 313 | ||
312 | await user.destroy() | 314 | await user.destroy() |
313 | 315 | ||
314 | auditLogger.delete(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new UserAuditView(user.toFormattedJSON())) | 316 | auditLogger.delete(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON())) |
315 | 317 | ||
316 | return res.sendStatus(204) | 318 | return res.sendStatus(204) |
317 | } | 319 | } |
@@ -328,19 +330,17 @@ async function updateMe (req: express.Request, res: express.Response, next: expr | |||
328 | if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo | 330 | if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo |
329 | 331 | ||
330 | await sequelizeTypescript.transaction(async t => { | 332 | await sequelizeTypescript.transaction(async t => { |
333 | const userAccount = await AccountModel.load(user.Account.id) | ||
334 | |||
331 | await user.save({ transaction: t }) | 335 | await user.save({ transaction: t }) |
332 | 336 | ||
333 | if (body.displayName !== undefined) user.Account.name = body.displayName | 337 | if (body.displayName !== undefined) userAccount.name = body.displayName |
334 | if (body.description !== undefined) user.Account.description = body.description | 338 | if (body.description !== undefined) userAccount.description = body.description |
335 | await user.Account.save({ transaction: t }) | 339 | await userAccount.save({ transaction: t }) |
336 | 340 | ||
337 | await sendUpdateActor(user.Account, t) | 341 | await sendUpdateActor(userAccount, t) |
338 | 342 | ||
339 | auditLogger.update( | 343 | auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView) |
340 | res.locals.oauth.token.User.Account.Actor.getIdentifier(), | ||
341 | new UserAuditView(user.toFormattedJSON()), | ||
342 | oldUserAuditView | ||
343 | ) | ||
344 | }) | 344 | }) |
345 | 345 | ||
346 | return res.sendStatus(204) | 346 | return res.sendStatus(204) |
@@ -350,15 +350,12 @@ async function updateMyAvatar (req: express.Request, res: express.Response, next | |||
350 | const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ] | 350 | const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ] |
351 | const user: UserModel = res.locals.oauth.token.user | 351 | const user: UserModel = res.locals.oauth.token.user |
352 | const oldUserAuditView = new UserAuditView(user.toFormattedJSON()) | 352 | const oldUserAuditView = new UserAuditView(user.toFormattedJSON()) |
353 | const account = user.Account | ||
354 | 353 | ||
355 | const avatar = await updateActorAvatarFile(avatarPhysicalFile, account.Actor, account) | 354 | const userAccount = await AccountModel.load(user.Account.id) |
356 | 355 | ||
357 | auditLogger.update( | 356 | const avatar = await updateActorAvatarFile(avatarPhysicalFile, userAccount) |
358 | res.locals.oauth.token.User.Account.Actor.getIdentifier(), | 357 | |
359 | new UserAuditView(user.toFormattedJSON()), | 358 | auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView) |
360 | oldUserAuditView | ||
361 | ) | ||
362 | 359 | ||
363 | return res.json({ avatar: avatar.toFormattedJSON() }) | 360 | return res.json({ avatar: avatar.toFormattedJSON() }) |
364 | } | 361 | } |
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index a7a36080b..ff6bbe44c 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts | |||
@@ -27,8 +27,9 @@ import { logger } from '../../helpers/logger' | |||
27 | import { VideoModel } from '../../models/video/video' | 27 | import { VideoModel } from '../../models/video/video' |
28 | import { updateAvatarValidator } from '../../middlewares/validators/avatar' | 28 | import { updateAvatarValidator } from '../../middlewares/validators/avatar' |
29 | import { updateActorAvatarFile } from '../../lib/avatar' | 29 | import { updateActorAvatarFile } from '../../lib/avatar' |
30 | import { auditLoggerFactory, VideoChannelAuditView } from '../../helpers/audit-logger' | 30 | import { auditLoggerFactory, getAuditIdFromRes, VideoChannelAuditView } from '../../helpers/audit-logger' |
31 | import { resetSequelizeInstance } from '../../helpers/database-utils' | 31 | import { resetSequelizeInstance } from '../../helpers/database-utils' |
32 | import { UserModel } from '../../models/account/user' | ||
32 | 33 | ||
33 | const auditLogger = auditLoggerFactory('channels') | 34 | const auditLogger = auditLoggerFactory('channels') |
34 | const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR }) | 35 | const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR }) |
@@ -55,7 +56,7 @@ videoChannelRouter.post('/:nameWithHost/avatar/pick', | |||
55 | // Check the rights | 56 | // Check the rights |
56 | asyncMiddleware(videoChannelsUpdateValidator), | 57 | asyncMiddleware(videoChannelsUpdateValidator), |
57 | updateAvatarValidator, | 58 | updateAvatarValidator, |
58 | asyncMiddleware(updateVideoChannelAvatar) | 59 | asyncRetryTransactionMiddleware(updateVideoChannelAvatar) |
59 | ) | 60 | ) |
60 | 61 | ||
61 | videoChannelRouter.put('/:nameWithHost', | 62 | videoChannelRouter.put('/:nameWithHost', |
@@ -106,13 +107,9 @@ async function updateVideoChannelAvatar (req: express.Request, res: express.Resp | |||
106 | const videoChannel = res.locals.videoChannel as VideoChannelModel | 107 | const videoChannel = res.locals.videoChannel as VideoChannelModel |
107 | const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON()) | 108 | const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON()) |
108 | 109 | ||
109 | const avatar = await updateActorAvatarFile(avatarPhysicalFile, videoChannel.Actor, videoChannel) | 110 | const avatar = await updateActorAvatarFile(avatarPhysicalFile, videoChannel) |
110 | 111 | ||
111 | auditLogger.update( | 112 | auditLogger.update(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannel.toFormattedJSON()), oldVideoChannelAuditKeys) |
112 | res.locals.oauth.token.User.Account.Actor.getIdentifier(), | ||
113 | new VideoChannelAuditView(videoChannel.toFormattedJSON()), | ||
114 | oldVideoChannelAuditKeys | ||
115 | ) | ||
116 | 113 | ||
117 | return res | 114 | return res |
118 | .json({ | 115 | .json({ |
@@ -123,19 +120,17 @@ async function updateVideoChannelAvatar (req: express.Request, res: express.Resp | |||
123 | 120 | ||
124 | async function addVideoChannel (req: express.Request, res: express.Response) { | 121 | async function addVideoChannel (req: express.Request, res: express.Response) { |
125 | const videoChannelInfo: VideoChannelCreate = req.body | 122 | const videoChannelInfo: VideoChannelCreate = req.body |
126 | const account: AccountModel = res.locals.oauth.token.User.Account | ||
127 | 123 | ||
128 | const videoChannelCreated: VideoChannelModel = await sequelizeTypescript.transaction(async t => { | 124 | const videoChannelCreated: VideoChannelModel = await sequelizeTypescript.transaction(async t => { |
125 | const account = await AccountModel.load((res.locals.oauth.token.User as UserModel).Account.id, t) | ||
126 | |||
129 | return createVideoChannel(videoChannelInfo, account, t) | 127 | return createVideoChannel(videoChannelInfo, account, t) |
130 | }) | 128 | }) |
131 | 129 | ||
132 | setAsyncActorKeys(videoChannelCreated.Actor) | 130 | setAsyncActorKeys(videoChannelCreated.Actor) |
133 | .catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.uuid, { err })) | 131 | .catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.uuid, { err })) |
134 | 132 | ||
135 | auditLogger.create( | 133 | auditLogger.create(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelCreated.toFormattedJSON())) |
136 | res.locals.oauth.token.User.Account.Actor.getIdentifier(), | ||
137 | new VideoChannelAuditView(videoChannelCreated.toFormattedJSON()) | ||
138 | ) | ||
139 | logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid) | 134 | logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid) |
140 | 135 | ||
141 | return res.json({ | 136 | return res.json({ |
@@ -166,7 +161,7 @@ async function updateVideoChannel (req: express.Request, res: express.Response) | |||
166 | await sendUpdateActor(videoChannelInstanceUpdated, t) | 161 | await sendUpdateActor(videoChannelInstanceUpdated, t) |
167 | 162 | ||
168 | auditLogger.update( | 163 | auditLogger.update( |
169 | res.locals.oauth.token.User.Account.Actor.getIdentifier(), | 164 | getAuditIdFromRes(res), |
170 | new VideoChannelAuditView(videoChannelInstanceUpdated.toFormattedJSON()), | 165 | new VideoChannelAuditView(videoChannelInstanceUpdated.toFormattedJSON()), |
171 | oldVideoChannelAuditKeys | 166 | oldVideoChannelAuditKeys |
172 | ) | 167 | ) |
@@ -192,10 +187,7 @@ async function removeVideoChannel (req: express.Request, res: express.Response) | |||
192 | await sequelizeTypescript.transaction(async t => { | 187 | await sequelizeTypescript.transaction(async t => { |
193 | await videoChannelInstance.destroy({ transaction: t }) | 188 | await videoChannelInstance.destroy({ transaction: t }) |
194 | 189 | ||
195 | auditLogger.delete( | 190 | auditLogger.delete(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelInstance.toFormattedJSON())) |
196 | res.locals.oauth.token.User.Account.Actor.getIdentifier(), | ||
197 | new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()) | ||
198 | ) | ||
199 | logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.Actor.uuid) | 191 | logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.Actor.uuid) |
200 | }) | 192 | }) |
201 | 193 | ||
diff --git a/server/controllers/api/videos/abuse.ts b/server/controllers/api/videos/abuse.ts index 08e11b00b..d0c81804b 100644 --- a/server/controllers/api/videos/abuse.ts +++ b/server/controllers/api/videos/abuse.ts | |||
@@ -21,6 +21,7 @@ import { AccountModel } from '../../../models/account/account' | |||
21 | import { VideoModel } from '../../../models/video/video' | 21 | import { VideoModel } from '../../../models/video/video' |
22 | import { VideoAbuseModel } from '../../../models/video/video-abuse' | 22 | import { VideoAbuseModel } from '../../../models/video/video-abuse' |
23 | import { auditLoggerFactory, VideoAbuseAuditView } from '../../../helpers/audit-logger' | 23 | import { auditLoggerFactory, VideoAbuseAuditView } from '../../../helpers/audit-logger' |
24 | import { UserModel } from '../../../models/account/user' | ||
24 | 25 | ||
25 | const auditLogger = auditLoggerFactory('abuse') | 26 | const auditLogger = auditLoggerFactory('abuse') |
26 | const abuseVideoRouter = express.Router() | 27 | const abuseVideoRouter = express.Router() |
@@ -95,17 +96,18 @@ async function deleteVideoAbuse (req: express.Request, res: express.Response) { | |||
95 | 96 | ||
96 | async function reportVideoAbuse (req: express.Request, res: express.Response) { | 97 | async function reportVideoAbuse (req: express.Request, res: express.Response) { |
97 | const videoInstance = res.locals.video as VideoModel | 98 | const videoInstance = res.locals.video as VideoModel |
98 | const reporterAccount = res.locals.oauth.token.User.Account as AccountModel | ||
99 | const body: VideoAbuseCreate = req.body | 99 | const body: VideoAbuseCreate = req.body |
100 | 100 | ||
101 | const abuseToCreate = { | ||
102 | reporterAccountId: reporterAccount.id, | ||
103 | reason: body.reason, | ||
104 | videoId: videoInstance.id, | ||
105 | state: VideoAbuseState.PENDING | ||
106 | } | ||
107 | |||
108 | const videoAbuse: VideoAbuseModel = await sequelizeTypescript.transaction(async t => { | 101 | const videoAbuse: VideoAbuseModel = await sequelizeTypescript.transaction(async t => { |
102 | const reporterAccount = await AccountModel.load((res.locals.oauth.token.User as UserModel).Account.id, t) | ||
103 | |||
104 | const abuseToCreate = { | ||
105 | reporterAccountId: reporterAccount.id, | ||
106 | reason: body.reason, | ||
107 | videoId: videoInstance.id, | ||
108 | state: VideoAbuseState.PENDING | ||
109 | } | ||
110 | |||
109 | const videoAbuseInstance = await VideoAbuseModel.create(abuseToCreate, { transaction: t }) | 111 | const videoAbuseInstance = await VideoAbuseModel.create(abuseToCreate, { transaction: t }) |
110 | videoAbuseInstance.Video = videoInstance | 112 | videoAbuseInstance.Video = videoInstance |
111 | videoAbuseInstance.Account = reporterAccount | 113 | videoAbuseInstance.Account = reporterAccount |
@@ -121,7 +123,6 @@ async function reportVideoAbuse (req: express.Request, res: express.Response) { | |||
121 | }) | 123 | }) |
122 | 124 | ||
123 | logger.info('Abuse report for video %s created.', videoInstance.name) | 125 | logger.info('Abuse report for video %s created.', videoInstance.name) |
124 | return res.json({ | 126 | |
125 | videoAbuse: videoAbuse.toFormattedJSON() | 127 | return res.json({ videoAbuse: videoAbuse.toFormattedJSON() }).end() |
126 | }).end() | ||
127 | } | 128 | } |
diff --git a/server/controllers/api/videos/comment.ts b/server/controllers/api/videos/comment.ts index e35247829..dc25e1e85 100644 --- a/server/controllers/api/videos/comment.ts +++ b/server/controllers/api/videos/comment.ts | |||
@@ -23,7 +23,9 @@ import { | |||
23 | } from '../../../middlewares/validators/video-comments' | 23 | } from '../../../middlewares/validators/video-comments' |
24 | import { VideoModel } from '../../../models/video/video' | 24 | import { VideoModel } from '../../../models/video/video' |
25 | import { VideoCommentModel } from '../../../models/video/video-comment' | 25 | import { VideoCommentModel } from '../../../models/video/video-comment' |
26 | import { auditLoggerFactory, CommentAuditView } from '../../../helpers/audit-logger' | 26 | import { auditLoggerFactory, CommentAuditView, getAuditIdFromRes } from '../../../helpers/audit-logger' |
27 | import { AccountModel } from '../../../models/account/account' | ||
28 | import { UserModel } from '../../../models/account/user' | ||
27 | 29 | ||
28 | const auditLogger = auditLoggerFactory('comments') | 30 | const auditLogger = auditLoggerFactory('comments') |
29 | const videoCommentRouter = express.Router() | 31 | const videoCommentRouter = express.Router() |
@@ -86,7 +88,7 @@ async function listVideoThreadComments (req: express.Request, res: express.Respo | |||
86 | let resultList: ResultList<VideoCommentModel> | 88 | let resultList: ResultList<VideoCommentModel> |
87 | 89 | ||
88 | if (video.commentsEnabled === true) { | 90 | if (video.commentsEnabled === true) { |
89 | resultList = await VideoCommentModel.listThreadCommentsForApi(res.locals.video.id, res.locals.videoCommentThread.id) | 91 | resultList = await VideoCommentModel.listThreadCommentsForApi(video.id, res.locals.videoCommentThread.id) |
90 | } else { | 92 | } else { |
91 | resultList = { | 93 | resultList = { |
92 | total: 0, | 94 | total: 0, |
@@ -101,15 +103,17 @@ async function addVideoCommentThread (req: express.Request, res: express.Respons | |||
101 | const videoCommentInfo: VideoCommentCreate = req.body | 103 | const videoCommentInfo: VideoCommentCreate = req.body |
102 | 104 | ||
103 | const comment = await sequelizeTypescript.transaction(async t => { | 105 | const comment = await sequelizeTypescript.transaction(async t => { |
106 | const account = await AccountModel.load((res.locals.oauth.token.User as UserModel).Account.id, t) | ||
107 | |||
104 | return createVideoComment({ | 108 | return createVideoComment({ |
105 | text: videoCommentInfo.text, | 109 | text: videoCommentInfo.text, |
106 | inReplyToComment: null, | 110 | inReplyToComment: null, |
107 | video: res.locals.video, | 111 | video: res.locals.video, |
108 | account: res.locals.oauth.token.User.Account | 112 | account |
109 | }, t) | 113 | }, t) |
110 | }) | 114 | }) |
111 | 115 | ||
112 | auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new CommentAuditView(comment.toFormattedJSON())) | 116 | auditLogger.create(getAuditIdFromRes(res), new CommentAuditView(comment.toFormattedJSON())) |
113 | 117 | ||
114 | return res.json({ | 118 | return res.json({ |
115 | comment: comment.toFormattedJSON() | 119 | comment: comment.toFormattedJSON() |
@@ -120,19 +124,19 @@ async function addVideoCommentReply (req: express.Request, res: express.Response | |||
120 | const videoCommentInfo: VideoCommentCreate = req.body | 124 | const videoCommentInfo: VideoCommentCreate = req.body |
121 | 125 | ||
122 | const comment = await sequelizeTypescript.transaction(async t => { | 126 | const comment = await sequelizeTypescript.transaction(async t => { |
127 | const account = await AccountModel.load((res.locals.oauth.token.User as UserModel).Account.id, t) | ||
128 | |||
123 | return createVideoComment({ | 129 | return createVideoComment({ |
124 | text: videoCommentInfo.text, | 130 | text: videoCommentInfo.text, |
125 | inReplyToComment: res.locals.videoComment, | 131 | inReplyToComment: res.locals.videoComment, |
126 | video: res.locals.video, | 132 | video: res.locals.video, |
127 | account: res.locals.oauth.token.User.Account | 133 | account |
128 | }, t) | 134 | }, t) |
129 | }) | 135 | }) |
130 | 136 | ||
131 | auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new CommentAuditView(comment.toFormattedJSON())) | 137 | auditLogger.create(getAuditIdFromRes(res), new CommentAuditView(comment.toFormattedJSON())) |
132 | 138 | ||
133 | return res.json({ | 139 | return res.json({ comment: comment.toFormattedJSON() }).end() |
134 | comment: comment.toFormattedJSON() | ||
135 | }).end() | ||
136 | } | 140 | } |
137 | 141 | ||
138 | async function removeVideoComment (req: express.Request, res: express.Response) { | 142 | async function removeVideoComment (req: express.Request, res: express.Response) { |
@@ -143,7 +147,7 @@ async function removeVideoComment (req: express.Request, res: express.Response) | |||
143 | }) | 147 | }) |
144 | 148 | ||
145 | auditLogger.delete( | 149 | auditLogger.delete( |
146 | res.locals.oauth.token.User.Account.Actor.getIdentifier(), | 150 | getAuditIdFromRes(res), |
147 | new CommentAuditView(videoCommentInstance.toFormattedJSON()) | 151 | new CommentAuditView(videoCommentInstance.toFormattedJSON()) |
148 | ) | 152 | ) |
149 | logger.info('Video comment %d deleted.', videoCommentInstance.id) | 153 | logger.info('Video comment %d deleted.', videoCommentInstance.id) |
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index 44f15ef74..398fd5a7f 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import * as magnetUtil from 'magnet-uri' | 2 | import * as magnetUtil from 'magnet-uri' |
3 | import 'multer' | 3 | import 'multer' |
4 | import { auditLoggerFactory, VideoImportAuditView } from '../../../helpers/audit-logger' | 4 | import { auditLoggerFactory, getAuditIdFromRes, VideoImportAuditView } from '../../../helpers/audit-logger' |
5 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoImportAddValidator } from '../../../middlewares' | 5 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoImportAddValidator } from '../../../middlewares' |
6 | import { | 6 | import { |
7 | CONFIG, | 7 | CONFIG, |
@@ -114,7 +114,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to | |||
114 | } | 114 | } |
115 | await JobQueue.Instance.createJob({ type: 'video-import', payload }) | 115 | await JobQueue.Instance.createJob({ type: 'video-import', payload }) |
116 | 116 | ||
117 | auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new VideoImportAuditView(videoImport.toFormattedJSON())) | 117 | auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) |
118 | 118 | ||
119 | return res.json(videoImport.toFormattedJSON()).end() | 119 | return res.json(videoImport.toFormattedJSON()).end() |
120 | } | 120 | } |
@@ -158,7 +158,7 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response) | |||
158 | } | 158 | } |
159 | await JobQueue.Instance.createJob({ type: 'video-import', payload }) | 159 | await JobQueue.Instance.createJob({ type: 'video-import', payload }) |
160 | 160 | ||
161 | auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new VideoImportAuditView(videoImport.toFormattedJSON())) | 161 | auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) |
162 | 162 | ||
163 | return res.json(videoImport.toFormattedJSON()).end() | 163 | return res.json(videoImport.toFormattedJSON()).end() |
164 | } | 164 | } |
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 0c9e6c2d1..581046782 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts | |||
@@ -4,7 +4,7 @@ import { VideoCreate, VideoPrivacy, VideoState, VideoUpdate } from '../../../../ | |||
4 | import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' | 4 | import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' |
5 | import { processImage } from '../../../helpers/image-utils' | 5 | import { processImage } from '../../../helpers/image-utils' |
6 | import { logger } from '../../../helpers/logger' | 6 | import { logger } from '../../../helpers/logger' |
7 | import { auditLoggerFactory, VideoAuditView } from '../../../helpers/audit-logger' | 7 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' |
8 | import { getFormattedObjects, getServerActor } from '../../../helpers/utils' | 8 | import { getFormattedObjects, getServerActor } from '../../../helpers/utils' |
9 | import { | 9 | import { |
10 | CONFIG, | 10 | CONFIG, |
@@ -253,7 +253,7 @@ async function addVideo (req: express.Request, res: express.Response) { | |||
253 | 253 | ||
254 | await federateVideoIfNeeded(video, true, t) | 254 | await federateVideoIfNeeded(video, true, t) |
255 | 255 | ||
256 | auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new VideoAuditView(videoCreated.toFormattedDetailsJSON())) | 256 | auditLogger.create(getAuditIdFromRes(res), new VideoAuditView(videoCreated.toFormattedDetailsJSON())) |
257 | logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoCreated.uuid) | 257 | logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoCreated.uuid) |
258 | 258 | ||
259 | return videoCreated | 259 | return videoCreated |
@@ -354,7 +354,7 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
354 | await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t) | 354 | await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t) |
355 | 355 | ||
356 | auditLogger.update( | 356 | auditLogger.update( |
357 | res.locals.oauth.token.User.Account.Actor.getIdentifier(), | 357 | getAuditIdFromRes(res), |
358 | new VideoAuditView(videoInstanceUpdated.toFormattedDetailsJSON()), | 358 | new VideoAuditView(videoInstanceUpdated.toFormattedDetailsJSON()), |
359 | oldVideoAuditView | 359 | oldVideoAuditView |
360 | ) | 360 | ) |
@@ -393,9 +393,9 @@ async function viewVideo (req: express.Request, res: express.Response) { | |||
393 | Redis.Instance.setIPVideoView(ip, videoInstance.uuid) | 393 | Redis.Instance.setIPVideoView(ip, videoInstance.uuid) |
394 | ]) | 394 | ]) |
395 | 395 | ||
396 | const serverAccount = await getServerActor() | 396 | const serverActor = await getServerActor() |
397 | 397 | ||
398 | await sendCreateView(serverAccount, videoInstance, undefined) | 398 | await sendCreateView(serverActor, videoInstance, undefined) |
399 | 399 | ||
400 | return res.status(204).end() | 400 | return res.status(204).end() |
401 | } | 401 | } |
@@ -439,7 +439,7 @@ async function removeVideo (req: express.Request, res: express.Response) { | |||
439 | await videoInstance.destroy({ transaction: t }) | 439 | await videoInstance.destroy({ transaction: t }) |
440 | }) | 440 | }) |
441 | 441 | ||
442 | auditLogger.delete(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new VideoAuditView(videoInstance.toFormattedDetailsJSON())) | 442 | auditLogger.delete(getAuditIdFromRes(res), new VideoAuditView(videoInstance.toFormattedDetailsJSON())) |
443 | logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid) | 443 | logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid) |
444 | 444 | ||
445 | return res.type('json').status(204).end() | 445 | return res.type('json').status(204).end() |
diff --git a/server/controllers/api/videos/ownership.ts b/server/controllers/api/videos/ownership.ts index d26ed6cfc..5ea7d7c6a 100644 --- a/server/controllers/api/videos/ownership.ts +++ b/server/controllers/api/videos/ownership.ts | |||
@@ -19,6 +19,7 @@ import { VideoChannelModel } from '../../../models/video/video-channel' | |||
19 | import { getFormattedObjects } from '../../../helpers/utils' | 19 | import { getFormattedObjects } from '../../../helpers/utils' |
20 | import { changeVideoChannelShare } from '../../../lib/activitypub' | 20 | import { changeVideoChannelShare } from '../../../lib/activitypub' |
21 | import { sendUpdateVideo } from '../../../lib/activitypub/send' | 21 | import { sendUpdateVideo } from '../../../lib/activitypub/send' |
22 | import { UserModel } from '../../../models/account/user' | ||
22 | 23 | ||
23 | const ownershipVideoRouter = express.Router() | 24 | const ownershipVideoRouter = express.Router() |
24 | 25 | ||
@@ -58,26 +59,25 @@ export { | |||
58 | 59 | ||
59 | async function giveVideoOwnership (req: express.Request, res: express.Response) { | 60 | async function giveVideoOwnership (req: express.Request, res: express.Response) { |
60 | const videoInstance = res.locals.video as VideoModel | 61 | const videoInstance = res.locals.video as VideoModel |
61 | const initiatorAccount = res.locals.oauth.token.User.Account as AccountModel | 62 | const initiatorAccountId = (res.locals.oauth.token.User as UserModel).Account.id |
62 | const nextOwner = res.locals.nextOwner as AccountModel | 63 | const nextOwner = res.locals.nextOwner as AccountModel |
63 | 64 | ||
64 | await sequelizeTypescript.transaction(t => { | 65 | await sequelizeTypescript.transaction(t => { |
65 | return VideoChangeOwnershipModel.findOrCreate({ | 66 | return VideoChangeOwnershipModel.findOrCreate({ |
66 | where: { | 67 | where: { |
67 | initiatorAccountId: initiatorAccount.id, | 68 | initiatorAccountId, |
68 | nextOwnerAccountId: nextOwner.id, | 69 | nextOwnerAccountId: nextOwner.id, |
69 | videoId: videoInstance.id, | 70 | videoId: videoInstance.id, |
70 | status: VideoChangeOwnershipStatus.WAITING | 71 | status: VideoChangeOwnershipStatus.WAITING |
71 | }, | 72 | }, |
72 | defaults: { | 73 | defaults: { |
73 | initiatorAccountId: initiatorAccount.id, | 74 | initiatorAccountId, |
74 | nextOwnerAccountId: nextOwner.id, | 75 | nextOwnerAccountId: nextOwner.id, |
75 | videoId: videoInstance.id, | 76 | videoId: videoInstance.id, |
76 | status: VideoChangeOwnershipStatus.WAITING | 77 | status: VideoChangeOwnershipStatus.WAITING |
77 | }, | 78 | }, |
78 | transaction: t | 79 | transaction: t |
79 | }) | 80 | }) |
80 | |||
81 | }) | 81 | }) |
82 | 82 | ||
83 | logger.info('Ownership change for video %s created.', videoInstance.name) | 83 | logger.info('Ownership change for video %s created.', videoInstance.name) |
@@ -85,9 +85,10 @@ async function giveVideoOwnership (req: express.Request, res: express.Response) | |||
85 | } | 85 | } |
86 | 86 | ||
87 | async function listVideoOwnership (req: express.Request, res: express.Response) { | 87 | async function listVideoOwnership (req: express.Request, res: express.Response) { |
88 | const currentAccount = res.locals.oauth.token.User.Account as AccountModel | 88 | const currentAccountId = (res.locals.oauth.token.User as UserModel).Account.id |
89 | |||
89 | const resultList = await VideoChangeOwnershipModel.listForApi( | 90 | const resultList = await VideoChangeOwnershipModel.listForApi( |
90 | currentAccount.id, | 91 | currentAccountId, |
91 | req.query.start || 0, | 92 | req.query.start || 0, |
92 | req.query.count || 10, | 93 | req.query.count || 10, |
93 | req.query.sort || 'createdAt' | 94 | req.query.sort || 'createdAt' |
diff --git a/server/controllers/api/videos/rate.ts b/server/controllers/api/videos/rate.ts index b1732837d..dc322bb0c 100644 --- a/server/controllers/api/videos/rate.ts +++ b/server/controllers/api/videos/rate.ts | |||
@@ -28,10 +28,11 @@ async function rateVideo (req: express.Request, res: express.Response) { | |||
28 | const body: UserVideoRateUpdate = req.body | 28 | const body: UserVideoRateUpdate = req.body |
29 | const rateType = body.rating | 29 | const rateType = body.rating |
30 | const videoInstance: VideoModel = res.locals.video | 30 | const videoInstance: VideoModel = res.locals.video |
31 | const accountInstance: AccountModel = res.locals.oauth.token.User.Account | ||
32 | 31 | ||
33 | await sequelizeTypescript.transaction(async t => { | 32 | await sequelizeTypescript.transaction(async t => { |
34 | const sequelizeOptions = { transaction: t } | 33 | const sequelizeOptions = { transaction: t } |
34 | |||
35 | const accountInstance = await AccountModel.load(res.locals.oauth.token.User.Account.id, t) | ||
35 | const previousRate = await AccountVideoRateModel.load(accountInstance.id, videoInstance.id, t) | 36 | const previousRate = await AccountVideoRateModel.load(accountInstance.id, videoInstance.id, t) |
36 | 37 | ||
37 | let likesToIncrement = 0 | 38 | let likesToIncrement = 0 |
@@ -47,10 +48,10 @@ async function rateVideo (req: express.Request, res: express.Response) { | |||
47 | else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement-- | 48 | else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement-- |
48 | 49 | ||
49 | if (rateType === 'none') { // Destroy previous rate | 50 | if (rateType === 'none') { // Destroy previous rate |
50 | await previousRate.destroy({ transaction: t }) | 51 | await previousRate.destroy(sequelizeOptions) |
51 | } else { // Update previous rate | 52 | } else { // Update previous rate |
52 | previousRate.type = rateType | 53 | previousRate.type = rateType |
53 | await previousRate.save({ transaction: t }) | 54 | await previousRate.save(sequelizeOptions) |
54 | } | 55 | } |
55 | } else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate | 56 | } else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate |
56 | const query = { | 57 | const query = { |
@@ -70,9 +71,9 @@ async function rateVideo (req: express.Request, res: express.Response) { | |||
70 | await videoInstance.increment(incrementQuery, sequelizeOptions) | 71 | await videoInstance.increment(incrementQuery, sequelizeOptions) |
71 | 72 | ||
72 | await sendVideoRateChange(accountInstance, videoInstance, likesToIncrement, dislikesToIncrement, t) | 73 | await sendVideoRateChange(accountInstance, videoInstance, likesToIncrement, dislikesToIncrement, t) |
73 | }) | ||
74 | 74 | ||
75 | logger.info('Account video rate for video %s of account %s updated.', videoInstance.name, accountInstance.name) | 75 | logger.info('Account video rate for video %s of account %s updated.', videoInstance.name, accountInstance.name) |
76 | }) | ||
76 | 77 | ||
77 | return res.type('json').status(204).end() | 78 | return res.type('json').status(204).end() |
78 | } | 79 | } |
diff --git a/server/controllers/client.ts b/server/controllers/client.ts index c33061289..73b40cf65 100644 --- a/server/controllers/client.ts +++ b/server/controllers/client.ts | |||
@@ -35,7 +35,7 @@ clientsRouter.use('' + | |||
35 | // Static HTML/CSS/JS client files | 35 | // Static HTML/CSS/JS client files |
36 | 36 | ||
37 | const staticClientFiles = [ | 37 | const staticClientFiles = [ |
38 | 'manifest.json', | 38 | 'manifest.webmanifest', |
39 | 'ngsw-worker.js', | 39 | 'ngsw-worker.js', |
40 | 'ngsw.json' | 40 | 'ngsw.json' |
41 | ] | 41 | ] |