Fix missing transactions
This commit is contained in:
parent
51f636ad0f
commit
eae0365b5c
|
@ -176,7 +176,7 @@ async function removeOrRejectFollower (req: express.Request, res: express.Respon
|
|||
async function acceptFollower (req: express.Request, res: express.Response) {
|
||||
const follow = res.locals.follow
|
||||
|
||||
await sendAccept(follow)
|
||||
sendAccept(follow)
|
||||
|
||||
follow.state = 'accepted'
|
||||
await follow.save()
|
||||
|
|
|
@ -105,9 +105,9 @@ function acceptOwnership (req: express.Request, res: express.Response) {
|
|||
const channel = res.locals.videoChannel
|
||||
|
||||
// We need more attributes for federation
|
||||
const targetVideo = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoChangeOwnership.Video.id)
|
||||
const targetVideo = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoChangeOwnership.Video.id, t)
|
||||
|
||||
const oldVideoChannel = await VideoChannelModel.loadAndPopulateAccount(targetVideo.channelId)
|
||||
const oldVideoChannel = await VideoChannelModel.loadAndPopulateAccount(targetVideo.channelId, t)
|
||||
|
||||
targetVideo.channelId = channel.id
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import { MActorFollowActors } from '../../types/models'
|
||||
import { Transaction } from 'sequelize'
|
||||
import { getServerActor } from '@server/models/application/application'
|
||||
import { logger } from '../../helpers/logger'
|
||||
import { CONFIG } from '../../initializers/config'
|
||||
import { SERVER_ACTOR_NAME } from '../../initializers/constants'
|
||||
import { JobQueue } from '../job-queue'
|
||||
import { logger } from '../../helpers/logger'
|
||||
import { ServerModel } from '../../models/server/server'
|
||||
import { getServerActor } from '@server/models/application/application'
|
||||
import { MActorFollowActors } from '../../types/models'
|
||||
import { JobQueue } from '../job-queue'
|
||||
|
||||
async function autoFollowBackIfNeeded (actorFollow: MActorFollowActors) {
|
||||
async function autoFollowBackIfNeeded (actorFollow: MActorFollowActors, transaction?: Transaction) {
|
||||
if (!CONFIG.FOLLOWINGS.INSTANCE.AUTO_FOLLOW_BACK.ENABLED) return
|
||||
|
||||
const follower = actorFollow.ActorFollower
|
||||
|
@ -16,7 +17,7 @@ async function autoFollowBackIfNeeded (actorFollow: MActorFollowActors) {
|
|||
|
||||
const me = await getServerActor()
|
||||
|
||||
const server = await ServerModel.load(follower.serverId)
|
||||
const server = await ServerModel.load(follower.serverId, transaction)
|
||||
const host = server.host
|
||||
|
||||
const payload = {
|
||||
|
|
|
@ -16,7 +16,6 @@ import {
|
|||
MChannelActor,
|
||||
MCommentOwnerVideo
|
||||
} from '../../../types/models'
|
||||
import { markCommentAsDeleted } from '../../video-comment'
|
||||
import { forwardVideoRelatedActivity } from '../send/utils'
|
||||
|
||||
async function processDeleteActivity (options: APProcessorOptions<ActivityDelete>) {
|
||||
|
@ -139,11 +138,9 @@ function processDeleteVideoComment (byActor: MActorSignature, videoComment: MCom
|
|||
throw new Error(`Account ${byActor.url} does not own video comment ${videoComment.url} or video ${videoComment.Video.url}`)
|
||||
}
|
||||
|
||||
await sequelizeTypescript.transaction(async t => {
|
||||
markCommentAsDeleted(videoComment)
|
||||
videoComment.markAsDeleted()
|
||||
|
||||
await videoComment.save()
|
||||
})
|
||||
await videoComment.save({ transaction: t })
|
||||
|
||||
if (videoComment.Video.isOwned()) {
|
||||
// Don't resend the activity to the sender
|
||||
|
|
|
@ -43,7 +43,7 @@ async function processFollow (byActor: MActorSignature, activityId: string, targ
|
|||
if (isFollowingInstance && CONFIG.FOLLOWERS.INSTANCE.ENABLED === false) {
|
||||
logger.info('Rejecting %s because instance followers are disabled.', targetActor.url)
|
||||
|
||||
await sendReject(activityId, byActor, targetActor)
|
||||
sendReject(activityId, byActor, targetActor)
|
||||
|
||||
return { actorFollow: undefined as MActorFollowActors }
|
||||
}
|
||||
|
@ -84,8 +84,9 @@ async function processFollow (byActor: MActorSignature, activityId: string, targ
|
|||
|
||||
// Target sends to actor he accepted the follow request
|
||||
if (actorFollow.state === 'accepted') {
|
||||
await sendAccept(actorFollow)
|
||||
await autoFollowBackIfNeeded(actorFollow)
|
||||
sendAccept(actorFollow)
|
||||
|
||||
await autoFollowBackIfNeeded(actorFollow, t)
|
||||
}
|
||||
|
||||
return { actorFollow, created, isFollowingInstance, targetActor }
|
||||
|
|
|
@ -106,7 +106,7 @@ async function processUndoCacheFile (byActor: MActorSignature, activity: Activit
|
|||
const { video } = await getOrCreateAPVideo({ videoObject: cacheFileObject.object })
|
||||
|
||||
return sequelizeTypescript.transaction(async t => {
|
||||
const cacheFile = await VideoRedundancyModel.loadByUrl(cacheFileObject.id)
|
||||
const cacheFile = await VideoRedundancyModel.loadByUrl(cacheFileObject.id, t)
|
||||
if (!cacheFile) {
|
||||
logger.debug('Cannot undo unknown video cache %s.', cacheFileObject.id)
|
||||
return
|
||||
|
@ -114,7 +114,7 @@ async function processUndoCacheFile (byActor: MActorSignature, activity: Activit
|
|||
|
||||
if (cacheFile.actorId !== byActor.id) throw new Error('Cannot delete redundancy ' + cacheFile.url + ' of another actor.')
|
||||
|
||||
await cacheFile.destroy()
|
||||
await cacheFile.destroy({ transaction: t })
|
||||
|
||||
if (video.isOwned()) {
|
||||
// Don't resend the activity to the sender
|
||||
|
|
|
@ -151,35 +151,31 @@ async function onVideoFileOptimizer (
|
|||
// Outside the transaction (IO on disk)
|
||||
const { videoFileResolution, isPortraitMode } = await videoArg.getMaxQualityResolution()
|
||||
|
||||
const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => {
|
||||
// Maybe the video changed in database, refresh it
|
||||
const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid, t)
|
||||
// Video does not exist anymore
|
||||
if (!videoDatabase) return undefined
|
||||
// Maybe the video changed in database, refresh it
|
||||
const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid)
|
||||
// Video does not exist anymore
|
||||
if (!videoDatabase) return undefined
|
||||
|
||||
let videoPublished = false
|
||||
let videoPublished = false
|
||||
|
||||
// Generate HLS version of the original file
|
||||
const originalFileHLSPayload = Object.assign({}, payload, {
|
||||
isPortraitMode,
|
||||
resolution: videoDatabase.getMaxQualityFile().resolution,
|
||||
// If we quick transcoded original file, force transcoding for HLS to avoid some weird playback issues
|
||||
copyCodecs: transcodeType !== 'quick-transcode',
|
||||
isMaxQuality: true
|
||||
})
|
||||
const hasHls = await createHlsJobIfEnabled(user, originalFileHLSPayload)
|
||||
|
||||
const hasNewResolutions = await createLowerResolutionsJobs(videoDatabase, user, videoFileResolution, isPortraitMode, 'webtorrent')
|
||||
|
||||
if (!hasHls && !hasNewResolutions) {
|
||||
// No transcoding to do, it's now published
|
||||
videoPublished = await videoDatabase.publishIfNeededAndSave(t)
|
||||
}
|
||||
|
||||
await federateVideoIfNeeded(videoDatabase, payload.isNewVideo, t)
|
||||
|
||||
return { videoDatabase, videoPublished }
|
||||
// Generate HLS version of the original file
|
||||
const originalFileHLSPayload = Object.assign({}, payload, {
|
||||
isPortraitMode,
|
||||
resolution: videoDatabase.getMaxQualityFile().resolution,
|
||||
// If we quick transcoded original file, force transcoding for HLS to avoid some weird playback issues
|
||||
copyCodecs: transcodeType !== 'quick-transcode',
|
||||
isMaxQuality: true
|
||||
})
|
||||
const hasHls = await createHlsJobIfEnabled(user, originalFileHLSPayload)
|
||||
|
||||
const hasNewResolutions = await createLowerResolutionsJobs(videoDatabase, user, videoFileResolution, isPortraitMode, 'webtorrent')
|
||||
|
||||
if (!hasHls && !hasNewResolutions) {
|
||||
// No transcoding to do, it's now published
|
||||
videoPublished = await videoDatabase.publishIfNeededAndSave(undefined)
|
||||
}
|
||||
|
||||
await federateVideoIfNeeded(videoDatabase, payload.isNewVideo)
|
||||
|
||||
if (payload.isNewVideo) Notifier.Instance.notifyOnNewVideoIfNeeded(videoDatabase)
|
||||
if (videoPublished) Notifier.Instance.notifyOnVideoPublishedAfterTranscoding(videoDatabase)
|
||||
|
|
|
@ -221,7 +221,7 @@ async function createAbuse (options: {
|
|||
const { isOwned } = await associateFun(abuseInstance)
|
||||
|
||||
if (isOwned === false) {
|
||||
await sendAbuse(reporterAccount.Actor, abuseInstance, abuseInstance.FlaggedAccount, transaction)
|
||||
sendAbuse(reporterAccount.Actor, abuseInstance, abuseInstance.FlaggedAccount, transaction)
|
||||
}
|
||||
|
||||
const abuseJSON = abuseInstance.toFormattedAdminJSON()
|
||||
|
|
|
@ -44,11 +44,11 @@ async function createUserAccountAndChannelAndPlaylist (parameters: {
|
|||
displayName: userDisplayName,
|
||||
userId: userCreated.id,
|
||||
applicationId: null,
|
||||
t: t
|
||||
t
|
||||
})
|
||||
userCreated.Account = accountCreated
|
||||
|
||||
const channelAttributes = await buildChannelAttributes(userCreated, channelNames)
|
||||
const channelAttributes = await buildChannelAttributes(userCreated, t, channelNames)
|
||||
const videoChannel = await createLocalVideoChannel(channelAttributes, accountCreated, t)
|
||||
|
||||
const videoPlaylist = await createWatchLaterPlaylist(accountCreated, t)
|
||||
|
@ -203,13 +203,13 @@ function createDefaultUserNotificationSettings (user: MUserId, t: Transaction |
|
|||
return UserNotificationSettingModel.create(values, { transaction: t })
|
||||
}
|
||||
|
||||
async function buildChannelAttributes (user: MUser, channelNames?: ChannelNames) {
|
||||
async function buildChannelAttributes (user: MUser, transaction?: Transaction, channelNames?: ChannelNames) {
|
||||
if (channelNames) return channelNames
|
||||
|
||||
let channelName = user.username + '_channel'
|
||||
|
||||
// Conflict, generate uuid instead
|
||||
const actor = await ActorModel.loadLocalByName(channelName)
|
||||
const actor = await ActorModel.loadLocalByName(channelName, transaction)
|
||||
if (actor) channelName = uuidv4()
|
||||
|
||||
const videoChannelDisplayName = `Main ${user.username} channel`
|
||||
|
|
|
@ -18,9 +18,9 @@ async function removeComment (videoCommentInstance: MCommentOwnerVideo) {
|
|||
await sendDeleteVideoComment(videoCommentInstance, t)
|
||||
}
|
||||
|
||||
markCommentAsDeleted(videoCommentInstance)
|
||||
videoCommentInstance.markAsDeleted()
|
||||
|
||||
await videoCommentInstance.save()
|
||||
await videoCommentInstance.save({ transaction: t })
|
||||
})
|
||||
|
||||
logger.info('Video comment %d deleted.', videoCommentInstance.id)
|
||||
|
@ -95,17 +95,10 @@ function buildFormattedCommentTree (resultList: ResultList<VideoCommentModel>):
|
|||
return thread
|
||||
}
|
||||
|
||||
function markCommentAsDeleted (comment: MComment): void {
|
||||
comment.text = ''
|
||||
comment.deletedAt = new Date()
|
||||
comment.accountId = null
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
removeComment,
|
||||
createVideoComment,
|
||||
buildFormattedCommentTree,
|
||||
markCommentAsDeleted
|
||||
buildFormattedCommentTree
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { Transaction } from 'sequelize'
|
||||
import { AllowNull, Column, CreatedAt, Default, HasMany, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
|
||||
import { MServer, MServerFormattable } from '@server/types/models/server'
|
||||
import { AttributesOnly } from '@shared/core-utils'
|
||||
|
@ -51,11 +52,12 @@ export class ServerModel extends Model<Partial<AttributesOnly<ServerModel>>> {
|
|||
})
|
||||
BlockedByAccounts: ServerBlocklistModel[]
|
||||
|
||||
static load (id: number): Promise<MServer> {
|
||||
static load (id: number, transaction?: Transaction): Promise<MServer> {
|
||||
const query = {
|
||||
where: {
|
||||
id
|
||||
}
|
||||
},
|
||||
transaction
|
||||
}
|
||||
|
||||
return ServerModel.findOne(query)
|
||||
|
|
|
@ -91,9 +91,9 @@ export class VideoCaptionModel extends Model<Partial<AttributesOnly<VideoCaption
|
|||
Video: VideoModel
|
||||
|
||||
@BeforeDestroy
|
||||
static async removeFiles (instance: VideoCaptionModel) {
|
||||
static async removeFiles (instance: VideoCaptionModel, options) {
|
||||
if (!instance.Video) {
|
||||
instance.Video = await instance.$get('Video')
|
||||
instance.Video = await instance.$get('Video', { transaction: options.transaction })
|
||||
}
|
||||
|
||||
if (instance.isOwned()) {
|
||||
|
@ -113,8 +113,7 @@ export class VideoCaptionModel extends Model<Partial<AttributesOnly<VideoCaption
|
|||
const videoInclude = {
|
||||
model: VideoModel.unscoped(),
|
||||
attributes: [ 'id', 'remote', 'uuid' ],
|
||||
where: buildWhereIdOrUUID(videoId),
|
||||
transaction
|
||||
where: buildWhereIdOrUUID(videoId)
|
||||
}
|
||||
|
||||
const query = {
|
||||
|
@ -123,7 +122,8 @@ export class VideoCaptionModel extends Model<Partial<AttributesOnly<VideoCaption
|
|||
},
|
||||
include: [
|
||||
videoInclude
|
||||
]
|
||||
],
|
||||
transaction
|
||||
}
|
||||
|
||||
return VideoCaptionModel.findOne(query)
|
||||
|
|
|
@ -522,10 +522,10 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
|
|||
})
|
||||
}
|
||||
|
||||
static loadAndPopulateAccount (id: number): Promise<MChannelBannerAccountDefault> {
|
||||
static loadAndPopulateAccount (id: number, transaction?: Transaction): Promise<MChannelBannerAccountDefault> {
|
||||
return VideoChannelModel.unscoped()
|
||||
.scope([ ScopeNames.WITH_ACTOR_BANNER, ScopeNames.WITH_ACCOUNT ])
|
||||
.findByPk(id)
|
||||
.findByPk(id, { transaction })
|
||||
}
|
||||
|
||||
static loadByUrlAndPopulateAccount (url: string): Promise<MChannelBannerAccountDefault> {
|
||||
|
|
|
@ -739,6 +739,12 @@ export class VideoCommentModel extends Model<Partial<AttributesOnly<VideoComment
|
|||
return this.Account.isOwned()
|
||||
}
|
||||
|
||||
markAsDeleted () {
|
||||
this.text = ''
|
||||
this.deletedAt = new Date()
|
||||
this.accountId = null
|
||||
}
|
||||
|
||||
isDeleted () {
|
||||
return this.deletedAt !== null
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue