aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2018-09-20 16:24:31 +0200
committerGitHub <noreply@github.com>2018-09-20 16:24:31 +0200
commit0491173a61aed66205c017e0d7e0503ea316c144 (patch)
treece6621597505f9518cfdf0981977d097c63f9fad /server/controllers/api
parent8704acf49efc770d73bf07c10468ed8c74d28a83 (diff)
parent6247b2057b792cea155a1abd9788c363ae7d2cc2 (diff)
downloadPeerTube-0491173a61aed66205c017e0d7e0503ea316c144.tar.gz
PeerTube-0491173a61aed66205c017e0d7e0503ea316c144.tar.zst
PeerTube-0491173a61aed66205c017e0d7e0503ea316c144.zip
Merge branch 'develop' into cli-wrapper
Diffstat (limited to 'server/controllers/api')
-rw-r--r--server/controllers/api/config.ts9
-rw-r--r--server/controllers/api/overviews.ts42
-rw-r--r--server/controllers/api/search.ts7
-rw-r--r--server/controllers/api/server/stats.ts14
-rw-r--r--server/controllers/api/users/index.ts32
-rw-r--r--server/controllers/api/users/me.ts41
-rw-r--r--server/controllers/api/video-channel.ts28
-rw-r--r--server/controllers/api/videos/abuse.ts23
-rw-r--r--server/controllers/api/videos/comment.ts24
-rw-r--r--server/controllers/api/videos/import.ts6
-rw-r--r--server/controllers/api/videos/index.ts12
-rw-r--r--server/controllers/api/videos/ownership.ts13
-rw-r--r--server/controllers/api/videos/rate.ts11
13 files changed, 137 insertions, 125 deletions
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'
8import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares' 8import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares'
9import { customConfigUpdateValidator } from '../../middlewares/validators/config' 9import { customConfigUpdateValidator } from '../../middlewares/validators/config'
10import { ClientHtml } from '../../lib/client-html' 10import { ClientHtml } from '../../lib/client-html'
11import { auditLoggerFactory, CustomConfigAuditView } from '../../helpers/audit-logger' 11import { auditLoggerFactory, CustomConfigAuditView, getAuditIdFromRes } from '../../helpers/audit-logger'
12import { remove, writeJSON } from 'fs-extra' 12import { remove, writeJSON } from 'fs-extra'
13 13
14const packageJSON = require('../../../../package.json') 14const packageJSON = require('../../../../package.json')
@@ -134,10 +134,7 @@ async function getCustomConfig (req: express.Request, res: express.Response, nex
134async function deleteCustomConfig (req: express.Request, res: express.Response, next: express.NextFunction) { 134async 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'
4import { asyncMiddleware } from '../../middlewares' 4import { asyncMiddleware } from '../../middlewares'
5import { TagModel } from '../../models/video/tag' 5import { TagModel } from '../../models/video/tag'
6import { VideosOverview } from '../../../shared/models/overviews' 6import { VideosOverview } from '../../../shared/models/overviews'
7import { OVERVIEWS, ROUTE_CACHE_LIFETIME } from '../../initializers' 7import { MEMOIZE_TTL, OVERVIEWS, ROUTE_CACHE_LIFETIME } from '../../initializers'
8import { cacheRoute } from '../../middlewares/cache' 8import { cacheRoute } from '../../middlewares/cache'
9import * as memoizee from 'memoizee'
9 10
10const overviewsRouter = express.Router() 11const overviewsRouter = express.Router()
11 12
@@ -20,13 +21,30 @@ export { overviewsRouter }
20 21
21// --------------------------------------------------------------------------- 22// ---------------------------------------------------------------------------
22 23
24const 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
24async function getVideosOverview (req: express.Request, res: express.Response) { 35async 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
40async 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
50async function getVideosByTag (tag: string, res: express.Response) { 58async 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'
5import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 5import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
6import { VideoModel } from '../../../models/video/video' 6import { VideoModel } from '../../../models/video/video'
7import { VideoCommentModel } from '../../../models/video/video-comment' 7import { VideoCommentModel } from '../../../models/video/video-comment'
8import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy'
9import { CONFIG, ROUTE_CACHE_LIFETIME } from '../../../initializers/constants'
10import { cacheRoute } from '../../../middlewares/cache'
8 11
9const statsRouter = express.Router() 12const statsRouter = express.Router()
10 13
11statsRouter.get('/stats', 14statsRouter.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'
29import { 29import {
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'
33import { UserModel } from '../../../models/account/user' 36import { UserModel } from '../../../models/account/user'
34import { OAuthTokenModel } from '../../../models/oauth/oauth-token' 37import { OAuthTokenModel } from '../../../models/oauth/oauth-token'
35import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger' 38import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger'
36import { meRouter } from './me' 39import { meRouter } from './me'
40import { deleteUserToken } from '../../../lib/oauth-model'
37 41
38const auditLogger = auditLoggerFactory('users') 42const 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'
5import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../../initializers' 5import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../../initializers'
6import { sendUpdateActor } from '../../../lib/activitypub/send' 6import { sendUpdateActor } from '../../../lib/activitypub/send'
7import { 7import {
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'
19import { 20import {
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'
26import { AccountVideoRateModel } from '../../../models/account/account-video-rate' 27import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
27import { UserModel } from '../../../models/account/user' 28import { UserModel } from '../../../models/account/user'
@@ -31,12 +32,13 @@ import { buildNSFWFilter, createReqFiles } from '../../../helpers/express-utils'
31import { UserVideoQuota } from '../../../../shared/models/users/user-video-quota.model' 32import { UserVideoQuota } from '../../../../shared/models/users/user-video-quota.model'
32import { updateAvatarValidator } from '../../../middlewares/validators/avatar' 33import { updateAvatarValidator } from '../../../middlewares/validators/avatar'
33import { updateActorAvatarFile } from '../../../lib/avatar' 34import { updateActorAvatarFile } from '../../../lib/avatar'
34import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger' 35import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger'
35import { VideoImportModel } from '../../../models/video/video-import' 36import { VideoImportModel } from '../../../models/video/video-import'
36import { VideoFilter } from '../../../../shared/models/videos/video-query.type' 37import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
37import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 38import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
38import { JobQueue } from '../../../lib/job-queue' 39import { JobQueue } from '../../../lib/job-queue'
39import { logger } from '../../../helpers/logger' 40import { logger } from '../../../helpers/logger'
41import { AccountModel } from '../../../models/account/account'
40 42
41const auditLogger = auditLoggerFactory('users-me') 43const auditLogger = auditLoggerFactory('users-me')
42 44
@@ -293,7 +295,7 @@ async function getUserVideoQuotaUsed (req: express.Request, res: express.Respons
293} 295}
294 296
295async function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) { 297async 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'
27import { VideoModel } from '../../models/video/video' 27import { VideoModel } from '../../models/video/video'
28import { updateAvatarValidator } from '../../middlewares/validators/avatar' 28import { updateAvatarValidator } from '../../middlewares/validators/avatar'
29import { updateActorAvatarFile } from '../../lib/avatar' 29import { updateActorAvatarFile } from '../../lib/avatar'
30import { auditLoggerFactory, VideoChannelAuditView } from '../../helpers/audit-logger' 30import { auditLoggerFactory, getAuditIdFromRes, VideoChannelAuditView } from '../../helpers/audit-logger'
31import { resetSequelizeInstance } from '../../helpers/database-utils' 31import { resetSequelizeInstance } from '../../helpers/database-utils'
32import { UserModel } from '../../models/account/user'
32 33
33const auditLogger = auditLoggerFactory('channels') 34const auditLogger = auditLoggerFactory('channels')
34const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR }) 35const 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
61videoChannelRouter.put('/:nameWithHost', 62videoChannelRouter.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
124async function addVideoChannel (req: express.Request, res: express.Response) { 121async 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'
21import { VideoModel } from '../../../models/video/video' 21import { VideoModel } from '../../../models/video/video'
22import { VideoAbuseModel } from '../../../models/video/video-abuse' 22import { VideoAbuseModel } from '../../../models/video/video-abuse'
23import { auditLoggerFactory, VideoAbuseAuditView } from '../../../helpers/audit-logger' 23import { auditLoggerFactory, VideoAbuseAuditView } from '../../../helpers/audit-logger'
24import { UserModel } from '../../../models/account/user'
24 25
25const auditLogger = auditLoggerFactory('abuse') 26const auditLogger = auditLoggerFactory('abuse')
26const abuseVideoRouter = express.Router() 27const abuseVideoRouter = express.Router()
@@ -95,17 +96,18 @@ async function deleteVideoAbuse (req: express.Request, res: express.Response) {
95 96
96async function reportVideoAbuse (req: express.Request, res: express.Response) { 97async 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'
24import { VideoModel } from '../../../models/video/video' 24import { VideoModel } from '../../../models/video/video'
25import { VideoCommentModel } from '../../../models/video/video-comment' 25import { VideoCommentModel } from '../../../models/video/video-comment'
26import { auditLoggerFactory, CommentAuditView } from '../../../helpers/audit-logger' 26import { auditLoggerFactory, CommentAuditView, getAuditIdFromRes } from '../../../helpers/audit-logger'
27import { AccountModel } from '../../../models/account/account'
28import { UserModel } from '../../../models/account/user'
27 29
28const auditLogger = auditLoggerFactory('comments') 30const auditLogger = auditLoggerFactory('comments')
29const videoCommentRouter = express.Router() 31const 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
138async function removeVideoComment (req: express.Request, res: express.Response) { 142async 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 @@
1import * as express from 'express' 1import * as express from 'express'
2import * as magnetUtil from 'magnet-uri' 2import * as magnetUtil from 'magnet-uri'
3import 'multer' 3import 'multer'
4import { auditLoggerFactory, VideoImportAuditView } from '../../../helpers/audit-logger' 4import { auditLoggerFactory, getAuditIdFromRes, VideoImportAuditView } from '../../../helpers/audit-logger'
5import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoImportAddValidator } from '../../../middlewares' 5import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoImportAddValidator } from '../../../middlewares'
6import { 6import {
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 '../../../../
4import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' 4import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils'
5import { processImage } from '../../../helpers/image-utils' 5import { processImage } from '../../../helpers/image-utils'
6import { logger } from '../../../helpers/logger' 6import { logger } from '../../../helpers/logger'
7import { auditLoggerFactory, VideoAuditView } from '../../../helpers/audit-logger' 7import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger'
8import { getFormattedObjects, getServerActor } from '../../../helpers/utils' 8import { getFormattedObjects, getServerActor } from '../../../helpers/utils'
9import { 9import {
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'
19import { getFormattedObjects } from '../../../helpers/utils' 19import { getFormattedObjects } from '../../../helpers/utils'
20import { changeVideoChannelShare } from '../../../lib/activitypub' 20import { changeVideoChannelShare } from '../../../lib/activitypub'
21import { sendUpdateVideo } from '../../../lib/activitypub/send' 21import { sendUpdateVideo } from '../../../lib/activitypub/send'
22import { UserModel } from '../../../models/account/user'
22 23
23const ownershipVideoRouter = express.Router() 24const ownershipVideoRouter = express.Router()
24 25
@@ -58,26 +59,25 @@ export {
58 59
59async function giveVideoOwnership (req: express.Request, res: express.Response) { 60async 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
87async function listVideoOwnership (req: express.Request, res: express.Response) { 87async 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}