From 50d6de9c286abcb34ff4234d56d9cbb803db7665 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 14 Dec 2017 17:38:41 +0100 Subject: Begin moving video channel to actor --- server/controllers/api/server/follows.ts | 114 ++++++++++++------------------- server/controllers/api/users.ts | 2 +- server/controllers/api/videos/abuse.ts | 20 +++--- server/controllers/api/videos/channel.ts | 28 ++++---- server/controllers/api/videos/index.ts | 13 ++-- 5 files changed, 76 insertions(+), 101 deletions(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts index 497edb8eb..e7d81f7c3 100644 --- a/server/controllers/api/server/follows.ts +++ b/server/controllers/api/server/follows.ts @@ -1,10 +1,9 @@ import * as express from 'express' import { UserRight } from '../../../../shared/models/users' -import { getAccountFromWebfinger, getFormattedObjects, getServerAccount, logger, retryTransactionWrapper } from '../../../helpers' -import { sequelizeTypescript, SERVER_ACCOUNT_NAME } from '../../../initializers' -import { saveAccountAndServerIfNotExist } from '../../../lib/activitypub' -import { sendUndoFollow } from '../../../lib/activitypub/send' -import { sendFollow } from '../../../lib/index' +import { getFormattedObjects, getServerActor, loadActorUrlOrGetFromWebfinger, logger, retryTransactionWrapper } from '../../../helpers' +import { sequelizeTypescript, SERVER_ACTOR_NAME } from '../../../initializers' +import { getOrCreateActorAndServerAndModel } from '../../../lib/activitypub' +import { sendFollow, sendUndoFollow } from '../../../lib/activitypub/send' import { asyncMiddleware, authenticate, @@ -17,8 +16,8 @@ import { setPagination } from '../../../middlewares' import { followersSortValidator, followingSortValidator, followValidator } from '../../../middlewares/validators' -import { AccountModel } from '../../../models/account/account' -import { AccountFollowModel } from '../../../models/account/account-follow' +import { ActorModel } from '../../../models/activitypub/actor' +import { ActorFollowModel } from '../../../models/activitypub/actor-follow' const serverFollowsRouter = express.Router() @@ -38,7 +37,7 @@ serverFollowsRouter.post('/following', asyncMiddleware(followRetry) ) -serverFollowsRouter.delete('/following/:accountId', +serverFollowsRouter.delete('/following/:host', authenticate, ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW), asyncMiddleware(removeFollowingValidator), @@ -62,43 +61,41 @@ export { // --------------------------------------------------------------------------- async function listFollowing (req: express.Request, res: express.Response, next: express.NextFunction) { - const serverAccount = await getServerAccount() - const resultList = await AccountFollowModel.listFollowingForApi(serverAccount.id, req.query.start, req.query.count, req.query.sort) + const serverActor = await getServerActor() + const resultList = await ActorFollowModel.listFollowingForApi(serverActor.id, req.query.start, req.query.count, req.query.sort) return res.json(getFormattedObjects(resultList.data, resultList.total)) } async function listFollowers (req: express.Request, res: express.Response, next: express.NextFunction) { - const serverAccount = await getServerAccount() - const resultList = await AccountFollowModel.listFollowersForApi(serverAccount.id, req.query.start, req.query.count, req.query.sort) + const serverActor = await getServerActor() + const resultList = await ActorFollowModel.listFollowersForApi(serverActor.id, req.query.start, req.query.count, req.query.sort) return res.json(getFormattedObjects(resultList.data, resultList.total)) } async function followRetry (req: express.Request, res: express.Response, next: express.NextFunction) { const hosts = req.body.hosts as string[] - const fromAccount = await getServerAccount() + const fromActor = await getServerActor() const tasks: Promise[] = [] - const accountName = SERVER_ACCOUNT_NAME + const actorName = SERVER_ACTOR_NAME for (const host of hosts) { - // We process each host in a specific transaction // First, we add the follow request in the database - // Then we send the follow request to other account - const p = loadLocalOrGetAccountFromWebfinger(accountName, host) - .then(accountResult => { - let targetAccount = accountResult.account - + // Then we send the follow request to other actor + const p = loadActorUrlOrGetFromWebfinger(actorName, host) + .then(actorUrl => getOrCreateActorAndServerAndModel(actorUrl)) + .then(targetActor => { const options = { - arguments: [ fromAccount, targetAccount, accountResult.loadedFromDB ], + arguments: [ fromActor, targetActor ], errorMessage: 'Cannot follow with many retries.' } return retryTransactionWrapper(follow, options) }) - .catch(err => logger.warn('Cannot follow server %s.', `${accountName}@${host}`, err)) + .catch(err => logger.warn('Cannot follow server %s.', host, err)) tasks.push(p) } @@ -110,42 +107,32 @@ async function followRetry (req: express.Request, res: express.Response, next: e return res.status(204).end() } -async function follow (fromAccount: AccountModel, targetAccount: AccountModel, targetAlreadyInDB: boolean) { - try { - await sequelizeTypescript.transaction(async t => { - if (targetAlreadyInDB === false) { - await saveAccountAndServerIfNotExist(targetAccount, t) - } - - const [ accountFollow ] = await AccountFollowModel.findOrCreate({ - where: { - accountId: fromAccount.id, - targetAccountId: targetAccount.id - }, - defaults: { - state: 'pending', - accountId: fromAccount.id, - targetAccountId: targetAccount.id - }, - transaction: t - }) - accountFollow.AccountFollowing = targetAccount - accountFollow.AccountFollower = fromAccount - - // Send a notification to remote server - if (accountFollow.state === 'pending') { - await sendFollow(accountFollow, t) - } +function follow (fromActor: ActorModel, targetActor: ActorModel) { + return sequelizeTypescript.transaction(async t => { + const [ actorFollow ] = await ActorFollowModel.findOrCreate({ + where: { + actorId: fromActor.id, + targetActorId: targetActor.id + }, + defaults: { + state: 'pending', + actorId: fromActor.id, + targetActorId: targetActor.id + }, + transaction: t }) - } catch (err) { - // Reset target account - targetAccount.isNewRecord = !targetAlreadyInDB - throw err - } + actorFollow.ActorFollowing = targetActor + actorFollow.ActorFollower = fromActor + + // Send a notification to remote server + if (actorFollow.state === 'pending') { + await sendFollow(actorFollow, t) + } + }) } async function removeFollow (req: express.Request, res: express.Response, next: express.NextFunction) { - const follow: AccountFollowModel = res.locals.follow + const follow: ActorFollowModel = res.locals.follow await sequelizeTypescript.transaction(async t => { if (follow.state === 'accepted') await sendUndoFollow(follow, t) @@ -153,24 +140,11 @@ async function removeFollow (req: express.Request, res: express.Response, next: await follow.destroy({ transaction: t }) }) - // Destroy the account that will destroy video channels, videos and video files too + // Destroy the actor that will destroy video channels, videos and video files too // This could be long so don't wait this task - const following = follow.AccountFollowing + const following = follow.ActorFollowing following.destroy() - .catch(err => logger.error('Cannot destroy account that we do not follow anymore %s.', following.Actor.url, err)) + .catch(err => logger.error('Cannot destroy actor that we do not follow anymore %s.', following.url, err)) return res.status(204).end() } - -async function loadLocalOrGetAccountFromWebfinger (name: string, host: string) { - let loadedFromDB = true - let account = await AccountModel.loadByNameAndHost(name, host) - - if (!account) { - const nameWithDomain = name + '@' + host - account = await getAccountFromWebfinger(nameWithDomain) - loadedFromDB = false - } - - return { account, loadedFromDB } -} diff --git a/server/controllers/api/users.ts b/server/controllers/api/users.ts index 995542604..3106df9b9 100644 --- a/server/controllers/api/users.ts +++ b/server/controllers/api/users.ts @@ -2,7 +2,7 @@ import * as express from 'express' import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared' import { getFormattedObjects, logger, retryTransactionWrapper } from '../../helpers' import { CONFIG } from '../../initializers' -import { createUserAccountAndChannel } from '../../lib' +import { createUserAccountAndChannel } from '../../lib/user' import { asyncMiddleware, authenticate, diff --git a/server/controllers/api/videos/abuse.ts b/server/controllers/api/videos/abuse.ts index 08cc4d0b4..fecdaf5a3 100644 --- a/server/controllers/api/videos/abuse.ts +++ b/server/controllers/api/videos/abuse.ts @@ -1,22 +1,18 @@ import * as express from 'express' -import { - logger, - getFormattedObjects, - retryTransactionWrapper -} from '../../../helpers' +import { UserRight, VideoAbuseCreate } from '../../../../shared' +import { getFormattedObjects, logger, retryTransactionWrapper } from '../../../helpers' import { sequelizeTypescript } from '../../../initializers' +import { sendVideoAbuse } from '../../../lib/activitypub/send' import { + asyncMiddleware, authenticate, ensureUserHasRight, paginationValidator, - videoAbuseReportValidator, - videoAbusesSortValidator, - setVideoAbusesSort, setPagination, - asyncMiddleware + setVideoAbusesSort, + videoAbuseReportValidator, + videoAbusesSortValidator } from '../../../middlewares' -import { VideoAbuseCreate, UserRight } from '../../../../shared' -import { sendVideoAbuse } from '../../../lib/index' import { AccountModel } from '../../../models/account/account' import { VideoModel } from '../../../models/video/video' import { VideoAbuseModel } from '../../../models/video/video-abuse' @@ -80,7 +76,7 @@ async function reportVideoAbuse (req: express.Request, res: express.Response) { // We send the video abuse to the origin server if (videoInstance.isOwned() === false) { - await sendVideoAbuse(reporterAccount, videoAbuseInstance, videoInstance, t) + await sendVideoAbuse(reporterAccount.Actor, videoAbuseInstance, videoInstance, t) } }) diff --git a/server/controllers/api/videos/channel.ts b/server/controllers/api/videos/channel.ts index 315469115..cc00d9f8d 100644 --- a/server/controllers/api/videos/channel.ts +++ b/server/controllers/api/videos/channel.ts @@ -2,8 +2,8 @@ import * as express from 'express' import { VideoChannelCreate, VideoChannelUpdate } from '../../../../shared' import { getFormattedObjects, logger, resetSequelizeInstance, retryTransactionWrapper } from '../../../helpers' import { sequelizeTypescript } from '../../../initializers' -import { createVideoChannel } from '../../../lib' -import { sendUpdateVideoChannel } from '../../../lib/activitypub/send/send-update' +import { setAsyncActorKeys } from '../../../lib/activitypub' +import { createVideoChannel } from '../../../lib/video-channel' import { asyncMiddleware, authenticate, @@ -92,15 +92,17 @@ async function addVideoChannelRetryWrapper (req: express.Request, res: express.R return res.type('json').status(204).end() } -function addVideoChannel (req: express.Request, res: express.Response) { +async function addVideoChannel (req: express.Request, res: express.Response) { const videoChannelInfo: VideoChannelCreate = req.body const account: AccountModel = res.locals.oauth.token.User.Account - return sequelizeTypescript.transaction(async t => { - const videoChannelCreated = await createVideoChannel(videoChannelInfo, account, t) - - logger.info('Video channel with uuid %s created.', videoChannelCreated.uuid) + const videoChannelCreated = await sequelizeTypescript.transaction(async t => { + return createVideoChannel(videoChannelInfo, account, t) }) + + setAsyncActorKeys(videoChannelCreated.Actor) + + logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid) } async function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { @@ -128,12 +130,13 @@ async function updateVideoChannel (req: express.Request, res: express.Response) if (videoChannelInfoToUpdate.name !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.name) if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description) - const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions) + await videoChannelInstance.save(sequelizeOptions) - await sendUpdateVideoChannel(videoChannelInstanceUpdated, t) + // TODO + // await sendUpdateVideoChannel(videoChannelInstanceUpdated, t) }) - logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.uuid) + logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.Actor.uuid) } catch (err) { logger.debug('Cannot update the video channel.', err) @@ -160,11 +163,12 @@ async function removeVideoChannelRetryWrapper (req: express.Request, res: expres async function removeVideoChannel (req: express.Request, res: express.Response) { const videoChannelInstance: VideoChannelModel = res.locals.videoChannel - await sequelizeTypescript.transaction(async t => { + return sequelizeTypescript.transaction(async t => { await videoChannelInstance.destroy({ transaction: t }) + + logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.Actor.uuid) }) - logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.uuid) } async function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) { diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 91ab8c66a..d6934748f 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -11,7 +11,7 @@ import { resetSequelizeInstance, retryTransactionWrapper } from '../../../helpers' -import { getServerAccount } from '../../../helpers/utils' +import { getServerActor } from '../../../helpers/utils' import { CONFIG, sequelizeTypescript, @@ -22,8 +22,7 @@ import { VIDEO_PRIVACIES } from '../../../initializers' import { fetchRemoteVideoDescription, getVideoActivityPubUrl, shareVideoByServer } from '../../../lib/activitypub' -import { sendAddVideo, sendCreateViewToOrigin, sendUpdateVideo } from '../../../lib/activitypub/send' -import { sendCreateViewToVideoFollowers } from '../../../lib/index' +import { sendCreateVideo, sendCreateViewToOrigin, sendCreateViewToVideoFollowers, sendUpdateVideo } from '../../../lib/activitypub/send' import { transcodingJobScheduler } from '../../../lib/jobs/transcoding-job-scheduler' import { asyncMiddleware, @@ -248,7 +247,8 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi // Don't send video to remote servers, it is private if (video.privacy === VideoPrivacy.PRIVATE) return videoCreated - await sendAddVideo(video, t) + await sendCreateVideo(video, t) + // TODO: share by video channel await shareVideoByServer(video, t) logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoCreated.uuid) @@ -304,7 +304,8 @@ async function updateVideo (req: express.Request, res: express.Response) { // Video is not private anymore, send a create action to remote servers if (wasPrivateVideo === true && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE) { - await sendAddVideo(videoInstanceUpdated, t) + await sendCreateVideo(videoInstanceUpdated, t) + // TODO: Send by video channel await shareVideoByServer(videoInstanceUpdated, t) } }) @@ -330,7 +331,7 @@ async function viewVideo (req: express.Request, res: express.Response) { const videoInstance = res.locals.video await videoInstance.increment('views') - const serverAccount = await getServerAccount() + const serverAccount = await getServerActor() if (videoInstance.isOwned()) { await sendCreateViewToVideoFollowers(serverAccount, videoInstance, undefined) -- cgit v1.2.3