Limit associations fetch when loading token
authorChocobozzz <me@florianbigard.com>
Thu, 20 Sep 2018 08:13:13 +0000 (10:13 +0200)
committerChocobozzz <me@florianbigard.com>
Thu, 20 Sep 2018 09:45:59 +0000 (11:45 +0200)
server/controllers/api/users/index.ts
server/controllers/api/users/me.ts
server/controllers/api/video-channel.ts
server/controllers/api/videos/abuse.ts
server/controllers/api/videos/comment.ts
server/controllers/api/videos/ownership.ts
server/controllers/api/videos/rate.ts
server/lib/activitypub/videos.ts
server/lib/schedulers/youtube-dl-update-scheduler.ts
server/models/account/account.ts
server/models/oauth/oauth-token.ts

index a299167e8de1b75b8d2594bbbdb9a5be356df265..d1163900bd3709a7b6a04846bea75d283813c660 100644 (file)
@@ -267,15 +267,9 @@ async function updateUser (req: express.Request, res: express.Response, next: ex
   const user = await userToUpdate.save()
 
   // Destroy user token to refresh rights
-  if (roleChanged) {
-    await OAuthTokenModel.deleteUserToken(userToUpdate.id)
-  }
+  if (roleChanged) await OAuthTokenModel.deleteUserToken(userToUpdate.id)
 
-  auditLogger.update(
-    getAuditIdFromRes(res),
-    new UserAuditView(user.toFormattedJSON()),
-    oldUserAuditView
-  )
+  auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView)
 
   // Don't need to send this update to followers, these attributes are not propagated
 
@@ -343,9 +337,5 @@ async function changeUserBlock (res: express.Response, user: UserModel, block: b
 
   await Emailer.Instance.addUserBlockJob(user, block, reason)
 
-  auditLogger.update(
-    getAuditIdFromRes(res),
-    new UserAuditView(user.toFormattedJSON()),
-    oldUserAuditView
-  )
+  auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView)
 }
index d4b7e371521de2eafc73f20e3a58145d749df289..eba1e7eddbe5278e852c148835b273b50ffa3536 100644 (file)
@@ -38,6 +38,7 @@ import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
 import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
 import { JobQueue } from '../../../lib/job-queue'
 import { logger } from '../../../helpers/logger'
+import { AccountModel } from '../../../models/account/account'
 
 const auditLogger = auditLoggerFactory('users-me')
 
@@ -329,19 +330,17 @@ async function updateMe (req: express.Request, res: express.Response, next: expr
   if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo
 
   await sequelizeTypescript.transaction(async t => {
+    const userAccount = await AccountModel.load(user.Account.id)
+
     await user.save({ transaction: t })
 
-    if (body.displayName !== undefined) user.Account.name = body.displayName
-    if (body.description !== undefined) user.Account.description = body.description
-    await user.Account.save({ transaction: t })
+    if (body.displayName !== undefined) userAccount.name = body.displayName
+    if (body.description !== undefined) userAccount.description = body.description
+    await userAccount.save({ transaction: t })
 
-    await sendUpdateActor(user.Account, t)
+    await sendUpdateActor(userAccount, t)
 
-    auditLogger.update(
-      getAuditIdFromRes(res),
-      new UserAuditView(user.toFormattedJSON()),
-      oldUserAuditView
-    )
+    auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView)
   })
 
   return res.sendStatus(204)
@@ -351,15 +350,12 @@ async function updateMyAvatar (req: express.Request, res: express.Response, next
   const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ]
   const user: UserModel = res.locals.oauth.token.user
   const oldUserAuditView = new UserAuditView(user.toFormattedJSON())
-  const account = user.Account
 
-  const avatar = await updateActorAvatarFile(avatarPhysicalFile, account.Actor, account)
+  const userAccount = await AccountModel.load(user.Account.id)
 
-  auditLogger.update(
-    getAuditIdFromRes(res),
-    new UserAuditView(user.toFormattedJSON()),
-    oldUserAuditView
-  )
+  const avatar = await updateActorAvatarFile(avatarPhysicalFile, userAccount.Actor, userAccount)
+
+  auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView)
 
   return res.json({ avatar: avatar.toFormattedJSON() })
 }
index 50dc44f7c6fa571edc0e4eeba3c7e72ca83d72fc..8fc34022430bb61dc3aff14ced7164581d71fda2 100644 (file)
@@ -29,6 +29,7 @@ import { updateAvatarValidator } from '../../middlewares/validators/avatar'
 import { updateActorAvatarFile } from '../../lib/avatar'
 import { auditLoggerFactory, getAuditIdFromRes, VideoChannelAuditView } from '../../helpers/audit-logger'
 import { resetSequelizeInstance } from '../../helpers/database-utils'
+import { UserModel } from '../../models/account/user'
 
 const auditLogger = auditLoggerFactory('channels')
 const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR })
@@ -123,19 +124,17 @@ async function updateVideoChannelAvatar (req: express.Request, res: express.Resp
 
 async function addVideoChannel (req: express.Request, res: express.Response) {
   const videoChannelInfo: VideoChannelCreate = req.body
-  const account: AccountModel = res.locals.oauth.token.User.Account
 
   const videoChannelCreated: VideoChannelModel = await sequelizeTypescript.transaction(async t => {
+    const account = await AccountModel.load((res.locals.oauth.token.User as UserModel).Account.id, t)
+
     return createVideoChannel(videoChannelInfo, account, t)
   })
 
   setAsyncActorKeys(videoChannelCreated.Actor)
     .catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.uuid, { err }))
 
-  auditLogger.create(
-    getAuditIdFromRes(res),
-    new VideoChannelAuditView(videoChannelCreated.toFormattedJSON())
-  )
+  auditLogger.create(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelCreated.toFormattedJSON()))
   logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid)
 
   return res.json({
index 08e11b00bd930e5b0e604be68f7d3e73a454f179..d0c81804bfe538036938e69bb4432880704554da 100644 (file)
@@ -21,6 +21,7 @@ import { AccountModel } from '../../../models/account/account'
 import { VideoModel } from '../../../models/video/video'
 import { VideoAbuseModel } from '../../../models/video/video-abuse'
 import { auditLoggerFactory, VideoAbuseAuditView } from '../../../helpers/audit-logger'
+import { UserModel } from '../../../models/account/user'
 
 const auditLogger = auditLoggerFactory('abuse')
 const abuseVideoRouter = express.Router()
@@ -95,17 +96,18 @@ async function deleteVideoAbuse (req: express.Request, res: express.Response) {
 
 async function reportVideoAbuse (req: express.Request, res: express.Response) {
   const videoInstance = res.locals.video as VideoModel
-  const reporterAccount = res.locals.oauth.token.User.Account as AccountModel
   const body: VideoAbuseCreate = req.body
 
-  const abuseToCreate = {
-    reporterAccountId: reporterAccount.id,
-    reason: body.reason,
-    videoId: videoInstance.id,
-    state: VideoAbuseState.PENDING
-  }
-
   const videoAbuse: VideoAbuseModel = await sequelizeTypescript.transaction(async t => {
+    const reporterAccount = await AccountModel.load((res.locals.oauth.token.User as UserModel).Account.id, t)
+
+    const abuseToCreate = {
+      reporterAccountId: reporterAccount.id,
+      reason: body.reason,
+      videoId: videoInstance.id,
+      state: VideoAbuseState.PENDING
+    }
+
     const videoAbuseInstance = await VideoAbuseModel.create(abuseToCreate, { transaction: t })
     videoAbuseInstance.Video = videoInstance
     videoAbuseInstance.Account = reporterAccount
@@ -121,7 +123,6 @@ async function reportVideoAbuse (req: express.Request, res: express.Response) {
   })
 
   logger.info('Abuse report for video %s created.', videoInstance.name)
-  return res.json({
-    videoAbuse: videoAbuse.toFormattedJSON()
-  }).end()
+
+  return res.json({ videoAbuse: videoAbuse.toFormattedJSON() }).end()
 }
index 40ad54d09a09c41411f9e2b71d165e769fcb2a3c..dc25e1e859502b820692bf50e7a138be326f8cd1 100644 (file)
@@ -24,6 +24,8 @@ import {
 import { VideoModel } from '../../../models/video/video'
 import { VideoCommentModel } from '../../../models/video/video-comment'
 import { auditLoggerFactory, CommentAuditView, getAuditIdFromRes } from '../../../helpers/audit-logger'
+import { AccountModel } from '../../../models/account/account'
+import { UserModel } from '../../../models/account/user'
 
 const auditLogger = auditLoggerFactory('comments')
 const videoCommentRouter = express.Router()
@@ -101,11 +103,13 @@ async function addVideoCommentThread (req: express.Request, res: express.Respons
   const videoCommentInfo: VideoCommentCreate = req.body
 
   const comment = await sequelizeTypescript.transaction(async t => {
+    const account = await AccountModel.load((res.locals.oauth.token.User as UserModel).Account.id, t)
+
     return createVideoComment({
       text: videoCommentInfo.text,
       inReplyToComment: null,
       video: res.locals.video,
-      account: res.locals.oauth.token.User.Account
+      account
     }, t)
   })
 
@@ -120,19 +124,19 @@ async function addVideoCommentReply (req: express.Request, res: express.Response
   const videoCommentInfo: VideoCommentCreate = req.body
 
   const comment = await sequelizeTypescript.transaction(async t => {
+    const account = await AccountModel.load((res.locals.oauth.token.User as UserModel).Account.id, t)
+
     return createVideoComment({
       text: videoCommentInfo.text,
       inReplyToComment: res.locals.videoComment,
       video: res.locals.video,
-      account: res.locals.oauth.token.User.Account
+      account
     }, t)
   })
 
   auditLogger.create(getAuditIdFromRes(res), new CommentAuditView(comment.toFormattedJSON()))
 
-  return res.json({
-    comment: comment.toFormattedJSON()
-  }).end()
+  return res.json({ comment: comment.toFormattedJSON() }).end()
 }
 
 async function removeVideoComment (req: express.Request, res: express.Response) {
index d26ed6cfc39adb8385f5e9e0d5504ec86b8a4a32..5ea7d7c6a3d72428be0f968581bfd9ef710eff8c 100644 (file)
@@ -19,6 +19,7 @@ import { VideoChannelModel } from '../../../models/video/video-channel'
 import { getFormattedObjects } from '../../../helpers/utils'
 import { changeVideoChannelShare } from '../../../lib/activitypub'
 import { sendUpdateVideo } from '../../../lib/activitypub/send'
+import { UserModel } from '../../../models/account/user'
 
 const ownershipVideoRouter = express.Router()
 
@@ -58,26 +59,25 @@ export {
 
 async function giveVideoOwnership (req: express.Request, res: express.Response) {
   const videoInstance = res.locals.video as VideoModel
-  const initiatorAccount = res.locals.oauth.token.User.Account as AccountModel
+  const initiatorAccountId = (res.locals.oauth.token.User as UserModel).Account.id
   const nextOwner = res.locals.nextOwner as AccountModel
 
   await sequelizeTypescript.transaction(t => {
     return VideoChangeOwnershipModel.findOrCreate({
       where: {
-        initiatorAccountId: initiatorAccount.id,
+        initiatorAccountId,
         nextOwnerAccountId: nextOwner.id,
         videoId: videoInstance.id,
         status: VideoChangeOwnershipStatus.WAITING
       },
       defaults: {
-        initiatorAccountId: initiatorAccount.id,
+        initiatorAccountId,
         nextOwnerAccountId: nextOwner.id,
         videoId: videoInstance.id,
         status: VideoChangeOwnershipStatus.WAITING
       },
       transaction: t
     })
-
   })
 
   logger.info('Ownership change for video %s created.', videoInstance.name)
@@ -85,9 +85,10 @@ async function giveVideoOwnership (req: express.Request, res: express.Response)
 }
 
 async function listVideoOwnership (req: express.Request, res: express.Response) {
-  const currentAccount = res.locals.oauth.token.User.Account as AccountModel
+  const currentAccountId = (res.locals.oauth.token.User as UserModel).Account.id
+
   const resultList = await VideoChangeOwnershipModel.listForApi(
-    currentAccount.id,
+    currentAccountId,
     req.query.start || 0,
     req.query.count || 10,
     req.query.sort || 'createdAt'
index b1732837d1518c08f7e58a85b2863e5a0e91ffe1..dc322bb0c070c0ad3ac9353cab8232783e4dc066 100644 (file)
@@ -28,10 +28,11 @@ async function rateVideo (req: express.Request, res: express.Response) {
   const body: UserVideoRateUpdate = req.body
   const rateType = body.rating
   const videoInstance: VideoModel = res.locals.video
-  const accountInstance: AccountModel = res.locals.oauth.token.User.Account
 
   await sequelizeTypescript.transaction(async t => {
     const sequelizeOptions = { transaction: t }
+
+    const accountInstance = await AccountModel.load(res.locals.oauth.token.User.Account.id, t)
     const previousRate = await AccountVideoRateModel.load(accountInstance.id, videoInstance.id, t)
 
     let likesToIncrement = 0
@@ -47,10 +48,10 @@ async function rateVideo (req: express.Request, res: express.Response) {
       else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement--
 
       if (rateType === 'none') { // Destroy previous rate
-        await previousRate.destroy({ transaction: t })
+        await previousRate.destroy(sequelizeOptions)
       } else { // Update previous rate
         previousRate.type = rateType
-        await previousRate.save({ transaction: t })
+        await previousRate.save(sequelizeOptions)
       }
     } else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate
       const query = {
@@ -70,9 +71,9 @@ async function rateVideo (req: express.Request, res: express.Response) {
     await videoInstance.increment(incrementQuery, sequelizeOptions)
 
     await sendVideoRateChange(accountInstance, videoInstance, likesToIncrement, dislikesToIncrement, t)
-  })
 
-  logger.info('Account video rate for video %s of account %s updated.', videoInstance.name, accountInstance.name)
+    logger.info('Account video rate for video %s of account %s updated.', videoInstance.name, accountInstance.name)
+  })
 
   return res.type('json').status(204).end()
 }
index 91231a187f386e6a04e7e429ecca2ba4d99340bb..48c0e0a5ca9c7217e19713daeb55b1531125ef0e 100644 (file)
@@ -354,11 +354,11 @@ async function refreshVideoIfNeeded (options: {
   syncParam: SyncParam,
   refreshViews: boolean
 }): Promise<VideoModel> {
+  if (!options.video.isOutdated()) return options.video
+
   // We need more attributes if the argument video was fetched with not enough joints
   const video = options.fetchedType === 'all' ? options.video : await VideoModel.loadByUrlAndPopulateAccount(options.video.url)
 
-  if (!video.isOutdated()) return video
-
   try {
     const { response, videoObject } = await fetchRemoteVideo(video.url)
     if (response.statusCode === 404) {
index 2fc8950fe3031c16fcdd2915339491e91e71644a..461cd045ef1256bc9f83a36c334c6d8774ac1085 100644 (file)
@@ -1,12 +1,5 @@
-
-
 import { AbstractScheduler } from './abstract-scheduler'
 import { SCHEDULER_INTERVALS_MS } from '../../initializers'
-import { logger } from '../../helpers/logger'
-import * as request from 'request'
-import { createWriteStream, ensureDir, writeFile } from 'fs-extra'
-import { join } from 'path'
-import { root } from '../../helpers/core-utils'
 import { updateYoutubeDLBinary } from '../../helpers/youtube-dl'
 
 export class YoutubeDlUpdateScheduler extends AbstractScheduler {
index 6bbfc6f4e8d50f223c8eddb45f2f22ad50de9178..580d920ceddad9cd23db6eeb01740eec26822611 100644 (file)
@@ -134,8 +134,8 @@ export class AccountModel extends Model<AccountModel> {
     return undefined
   }
 
-  static load (id: number) {
-    return AccountModel.findById(id)
+  static load (id: number, transaction?: Sequelize.Transaction) {
+    return AccountModel.findById(id, { transaction })
   }
 
   static loadByUUID (uuid: string) {
index 4c53848dc4aa77220659d436d0b55ad12910b8e4..1dd5e02891ebedd98d3da04f2287cf967d5777f7 100644 (file)
@@ -1,9 +1,10 @@
 import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
 import { logger } from '../../helpers/logger'
-import { AccountModel } from '../account/account'
 import { UserModel } from '../account/user'
 import { OAuthClientModel } from './oauth-client'
 import { Transaction } from 'sequelize'
+import { AccountModel } from '../account/account'
+import { ActorModel } from '../activitypub/actor'
 
 export type OAuthTokenInfo = {
   refreshToken: string
@@ -17,18 +18,27 @@ export type OAuthTokenInfo = {
 }
 
 enum ScopeNames {
-  WITH_ACCOUNT = 'WITH_ACCOUNT'
+  WITH_USER = 'WITH_USER'
 }
 
 @Scopes({
-  [ScopeNames.WITH_ACCOUNT]: {
+  [ScopeNames.WITH_USER]: {
     include: [
       {
-        model: () => UserModel,
+        model: () => UserModel.unscoped(),
+        required: true,
         include: [
           {
-            model: () => AccountModel,
-            required: true
+            attributes: [ 'id' ],
+            model: () => AccountModel.unscoped(),
+            required: true,
+            include: [
+              {
+                attributes: [ 'id' ],
+                model: () => ActorModel.unscoped(),
+                required: true
+              }
+            ]
           }
         ]
       }
@@ -138,7 +148,7 @@ export class OAuthTokenModel extends Model<OAuthTokenModel> {
       }
     }
 
-    return OAuthTokenModel.scope(ScopeNames.WITH_ACCOUNT).findOne(query).then(token => {
+    return OAuthTokenModel.scope(ScopeNames.WITH_USER).findOne(query).then(token => {
       if (token) token['user'] = token.User
 
       return token
@@ -152,7 +162,7 @@ export class OAuthTokenModel extends Model<OAuthTokenModel> {
       }
     }
 
-    return OAuthTokenModel.scope(ScopeNames.WITH_ACCOUNT)
+    return OAuthTokenModel.scope(ScopeNames.WITH_USER)
       .findOne(query)
       .then(token => {
         if (token) {