aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2017-12-14 17:38:41 +0100
committerChocobozzz <me@florianbigard.com>2017-12-19 10:53:16 +0100
commit50d6de9c286abcb34ff4234d56d9cbb803db7665 (patch)
treef1732b27edcd05c7877a8358b8312f1e38c287ed /server/controllers/api
parentfadf619ad61a016c1c7fc53de5a8f398a4f77519 (diff)
downloadPeerTube-50d6de9c286abcb34ff4234d56d9cbb803db7665.tar.gz
PeerTube-50d6de9c286abcb34ff4234d56d9cbb803db7665.tar.zst
PeerTube-50d6de9c286abcb34ff4234d56d9cbb803db7665.zip
Begin moving video channel to actor
Diffstat (limited to 'server/controllers/api')
-rw-r--r--server/controllers/api/server/follows.ts114
-rw-r--r--server/controllers/api/users.ts2
-rw-r--r--server/controllers/api/videos/abuse.ts20
-rw-r--r--server/controllers/api/videos/channel.ts28
-rw-r--r--server/controllers/api/videos/index.ts13
5 files changed, 76 insertions, 101 deletions
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 @@
1import * as express from 'express' 1import * as express from 'express'
2import { UserRight } from '../../../../shared/models/users' 2import { UserRight } from '../../../../shared/models/users'
3import { getAccountFromWebfinger, getFormattedObjects, getServerAccount, logger, retryTransactionWrapper } from '../../../helpers' 3import { getFormattedObjects, getServerActor, loadActorUrlOrGetFromWebfinger, logger, retryTransactionWrapper } from '../../../helpers'
4import { sequelizeTypescript, SERVER_ACCOUNT_NAME } from '../../../initializers' 4import { sequelizeTypescript, SERVER_ACTOR_NAME } from '../../../initializers'
5import { saveAccountAndServerIfNotExist } from '../../../lib/activitypub' 5import { getOrCreateActorAndServerAndModel } from '../../../lib/activitypub'
6import { sendUndoFollow } from '../../../lib/activitypub/send' 6import { sendFollow, sendUndoFollow } from '../../../lib/activitypub/send'
7import { sendFollow } from '../../../lib/index'
8import { 7import {
9 asyncMiddleware, 8 asyncMiddleware,
10 authenticate, 9 authenticate,
@@ -17,8 +16,8 @@ import {
17 setPagination 16 setPagination
18} from '../../../middlewares' 17} from '../../../middlewares'
19import { followersSortValidator, followingSortValidator, followValidator } from '../../../middlewares/validators' 18import { followersSortValidator, followingSortValidator, followValidator } from '../../../middlewares/validators'
20import { AccountModel } from '../../../models/account/account' 19import { ActorModel } from '../../../models/activitypub/actor'
21import { AccountFollowModel } from '../../../models/account/account-follow' 20import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
22 21
23const serverFollowsRouter = express.Router() 22const serverFollowsRouter = express.Router()
24 23
@@ -38,7 +37,7 @@ serverFollowsRouter.post('/following',
38 asyncMiddleware(followRetry) 37 asyncMiddleware(followRetry)
39) 38)
40 39
41serverFollowsRouter.delete('/following/:accountId', 40serverFollowsRouter.delete('/following/:host',
42 authenticate, 41 authenticate,
43 ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW), 42 ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
44 asyncMiddleware(removeFollowingValidator), 43 asyncMiddleware(removeFollowingValidator),
@@ -62,43 +61,41 @@ export {
62// --------------------------------------------------------------------------- 61// ---------------------------------------------------------------------------
63 62
64async function listFollowing (req: express.Request, res: express.Response, next: express.NextFunction) { 63async function listFollowing (req: express.Request, res: express.Response, next: express.NextFunction) {
65 const serverAccount = await getServerAccount() 64 const serverActor = await getServerActor()
66 const resultList = await AccountFollowModel.listFollowingForApi(serverAccount.id, req.query.start, req.query.count, req.query.sort) 65 const resultList = await ActorFollowModel.listFollowingForApi(serverActor.id, req.query.start, req.query.count, req.query.sort)
67 66
68 return res.json(getFormattedObjects(resultList.data, resultList.total)) 67 return res.json(getFormattedObjects(resultList.data, resultList.total))
69} 68}
70 69
71async function listFollowers (req: express.Request, res: express.Response, next: express.NextFunction) { 70async function listFollowers (req: express.Request, res: express.Response, next: express.NextFunction) {
72 const serverAccount = await getServerAccount() 71 const serverActor = await getServerActor()
73 const resultList = await AccountFollowModel.listFollowersForApi(serverAccount.id, req.query.start, req.query.count, req.query.sort) 72 const resultList = await ActorFollowModel.listFollowersForApi(serverActor.id, req.query.start, req.query.count, req.query.sort)
74 73
75 return res.json(getFormattedObjects(resultList.data, resultList.total)) 74 return res.json(getFormattedObjects(resultList.data, resultList.total))
76} 75}
77 76
78async function followRetry (req: express.Request, res: express.Response, next: express.NextFunction) { 77async function followRetry (req: express.Request, res: express.Response, next: express.NextFunction) {
79 const hosts = req.body.hosts as string[] 78 const hosts = req.body.hosts as string[]
80 const fromAccount = await getServerAccount() 79 const fromActor = await getServerActor()
81 80
82 const tasks: Promise<any>[] = [] 81 const tasks: Promise<any>[] = []
83 const accountName = SERVER_ACCOUNT_NAME 82 const actorName = SERVER_ACTOR_NAME
84 83
85 for (const host of hosts) { 84 for (const host of hosts) {
86
87 // We process each host in a specific transaction 85 // We process each host in a specific transaction
88 // First, we add the follow request in the database 86 // First, we add the follow request in the database
89 // Then we send the follow request to other account 87 // Then we send the follow request to other actor
90 const p = loadLocalOrGetAccountFromWebfinger(accountName, host) 88 const p = loadActorUrlOrGetFromWebfinger(actorName, host)
91 .then(accountResult => { 89 .then(actorUrl => getOrCreateActorAndServerAndModel(actorUrl))
92 let targetAccount = accountResult.account 90 .then(targetActor => {
93
94 const options = { 91 const options = {
95 arguments: [ fromAccount, targetAccount, accountResult.loadedFromDB ], 92 arguments: [ fromActor, targetActor ],
96 errorMessage: 'Cannot follow with many retries.' 93 errorMessage: 'Cannot follow with many retries.'
97 } 94 }
98 95
99 return retryTransactionWrapper(follow, options) 96 return retryTransactionWrapper(follow, options)
100 }) 97 })
101 .catch(err => logger.warn('Cannot follow server %s.', `${accountName}@${host}`, err)) 98 .catch(err => logger.warn('Cannot follow server %s.', host, err))
102 99
103 tasks.push(p) 100 tasks.push(p)
104 } 101 }
@@ -110,42 +107,32 @@ async function followRetry (req: express.Request, res: express.Response, next: e
110 return res.status(204).end() 107 return res.status(204).end()
111} 108}
112 109
113async function follow (fromAccount: AccountModel, targetAccount: AccountModel, targetAlreadyInDB: boolean) { 110function follow (fromActor: ActorModel, targetActor: ActorModel) {
114 try { 111 return sequelizeTypescript.transaction(async t => {
115 await sequelizeTypescript.transaction(async t => { 112 const [ actorFollow ] = await ActorFollowModel.findOrCreate({
116 if (targetAlreadyInDB === false) { 113 where: {
117 await saveAccountAndServerIfNotExist(targetAccount, t) 114 actorId: fromActor.id,
118 } 115 targetActorId: targetActor.id
119 116 },
120 const [ accountFollow ] = await AccountFollowModel.findOrCreate({ 117 defaults: {
121 where: { 118 state: 'pending',
122 accountId: fromAccount.id, 119 actorId: fromActor.id,
123 targetAccountId: targetAccount.id 120 targetActorId: targetActor.id
124 }, 121 },
125 defaults: { 122 transaction: t
126 state: 'pending',
127 accountId: fromAccount.id,
128 targetAccountId: targetAccount.id
129 },
130 transaction: t
131 })
132 accountFollow.AccountFollowing = targetAccount
133 accountFollow.AccountFollower = fromAccount
134
135 // Send a notification to remote server
136 if (accountFollow.state === 'pending') {
137 await sendFollow(accountFollow, t)
138 }
139 }) 123 })
140 } catch (err) { 124 actorFollow.ActorFollowing = targetActor
141 // Reset target account 125 actorFollow.ActorFollower = fromActor
142 targetAccount.isNewRecord = !targetAlreadyInDB 126
143 throw err 127 // Send a notification to remote server
144 } 128 if (actorFollow.state === 'pending') {
129 await sendFollow(actorFollow, t)
130 }
131 })
145} 132}
146 133
147async function removeFollow (req: express.Request, res: express.Response, next: express.NextFunction) { 134async function removeFollow (req: express.Request, res: express.Response, next: express.NextFunction) {
148 const follow: AccountFollowModel = res.locals.follow 135 const follow: ActorFollowModel = res.locals.follow
149 136
150 await sequelizeTypescript.transaction(async t => { 137 await sequelizeTypescript.transaction(async t => {
151 if (follow.state === 'accepted') await sendUndoFollow(follow, t) 138 if (follow.state === 'accepted') await sendUndoFollow(follow, t)
@@ -153,24 +140,11 @@ async function removeFollow (req: express.Request, res: express.Response, next:
153 await follow.destroy({ transaction: t }) 140 await follow.destroy({ transaction: t })
154 }) 141 })
155 142
156 // Destroy the account that will destroy video channels, videos and video files too 143 // Destroy the actor that will destroy video channels, videos and video files too
157 // This could be long so don't wait this task 144 // This could be long so don't wait this task
158 const following = follow.AccountFollowing 145 const following = follow.ActorFollowing
159 following.destroy() 146 following.destroy()
160 .catch(err => logger.error('Cannot destroy account that we do not follow anymore %s.', following.Actor.url, err)) 147 .catch(err => logger.error('Cannot destroy actor that we do not follow anymore %s.', following.url, err))
161 148
162 return res.status(204).end() 149 return res.status(204).end()
163} 150}
164
165async function loadLocalOrGetAccountFromWebfinger (name: string, host: string) {
166 let loadedFromDB = true
167 let account = await AccountModel.loadByNameAndHost(name, host)
168
169 if (!account) {
170 const nameWithDomain = name + '@' + host
171 account = await getAccountFromWebfinger(nameWithDomain)
172 loadedFromDB = false
173 }
174
175 return { account, loadedFromDB }
176}
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'
2import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared' 2import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared'
3import { getFormattedObjects, logger, retryTransactionWrapper } from '../../helpers' 3import { getFormattedObjects, logger, retryTransactionWrapper } from '../../helpers'
4import { CONFIG } from '../../initializers' 4import { CONFIG } from '../../initializers'
5import { createUserAccountAndChannel } from '../../lib' 5import { createUserAccountAndChannel } from '../../lib/user'
6import { 6import {
7 asyncMiddleware, 7 asyncMiddleware,
8 authenticate, 8 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 @@
1import * as express from 'express' 1import * as express from 'express'
2import { 2import { UserRight, VideoAbuseCreate } from '../../../../shared'
3 logger, 3import { getFormattedObjects, logger, retryTransactionWrapper } from '../../../helpers'
4 getFormattedObjects,
5 retryTransactionWrapper
6} from '../../../helpers'
7import { sequelizeTypescript } from '../../../initializers' 4import { sequelizeTypescript } from '../../../initializers'
5import { sendVideoAbuse } from '../../../lib/activitypub/send'
8import { 6import {
7 asyncMiddleware,
9 authenticate, 8 authenticate,
10 ensureUserHasRight, 9 ensureUserHasRight,
11 paginationValidator, 10 paginationValidator,
12 videoAbuseReportValidator,
13 videoAbusesSortValidator,
14 setVideoAbusesSort,
15 setPagination, 11 setPagination,
16 asyncMiddleware 12 setVideoAbusesSort,
13 videoAbuseReportValidator,
14 videoAbusesSortValidator
17} from '../../../middlewares' 15} from '../../../middlewares'
18import { VideoAbuseCreate, UserRight } from '../../../../shared'
19import { sendVideoAbuse } from '../../../lib/index'
20import { AccountModel } from '../../../models/account/account' 16import { AccountModel } from '../../../models/account/account'
21import { VideoModel } from '../../../models/video/video' 17import { VideoModel } from '../../../models/video/video'
22import { VideoAbuseModel } from '../../../models/video/video-abuse' 18import { VideoAbuseModel } from '../../../models/video/video-abuse'
@@ -80,7 +76,7 @@ async function reportVideoAbuse (req: express.Request, res: express.Response) {
80 76
81 // We send the video abuse to the origin server 77 // We send the video abuse to the origin server
82 if (videoInstance.isOwned() === false) { 78 if (videoInstance.isOwned() === false) {
83 await sendVideoAbuse(reporterAccount, videoAbuseInstance, videoInstance, t) 79 await sendVideoAbuse(reporterAccount.Actor, videoAbuseInstance, videoInstance, t)
84 } 80 }
85 }) 81 })
86 82
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'
2import { VideoChannelCreate, VideoChannelUpdate } from '../../../../shared' 2import { VideoChannelCreate, VideoChannelUpdate } from '../../../../shared'
3import { getFormattedObjects, logger, resetSequelizeInstance, retryTransactionWrapper } from '../../../helpers' 3import { getFormattedObjects, logger, resetSequelizeInstance, retryTransactionWrapper } from '../../../helpers'
4import { sequelizeTypescript } from '../../../initializers' 4import { sequelizeTypescript } from '../../../initializers'
5import { createVideoChannel } from '../../../lib' 5import { setAsyncActorKeys } from '../../../lib/activitypub'
6import { sendUpdateVideoChannel } from '../../../lib/activitypub/send/send-update' 6import { createVideoChannel } from '../../../lib/video-channel'
7import { 7import {
8 asyncMiddleware, 8 asyncMiddleware,
9 authenticate, 9 authenticate,
@@ -92,15 +92,17 @@ async function addVideoChannelRetryWrapper (req: express.Request, res: express.R
92 return res.type('json').status(204).end() 92 return res.type('json').status(204).end()
93} 93}
94 94
95function addVideoChannel (req: express.Request, res: express.Response) { 95async function addVideoChannel (req: express.Request, res: express.Response) {
96 const videoChannelInfo: VideoChannelCreate = req.body 96 const videoChannelInfo: VideoChannelCreate = req.body
97 const account: AccountModel = res.locals.oauth.token.User.Account 97 const account: AccountModel = res.locals.oauth.token.User.Account
98 98
99 return sequelizeTypescript.transaction(async t => { 99 const videoChannelCreated = await sequelizeTypescript.transaction(async t => {
100 const videoChannelCreated = await createVideoChannel(videoChannelInfo, account, t) 100 return createVideoChannel(videoChannelInfo, account, t)
101
102 logger.info('Video channel with uuid %s created.', videoChannelCreated.uuid)
103 }) 101 })
102
103 setAsyncActorKeys(videoChannelCreated.Actor)
104
105 logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid)
104} 106}
105 107
106async function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { 108async function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
@@ -128,12 +130,13 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
128 if (videoChannelInfoToUpdate.name !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.name) 130 if (videoChannelInfoToUpdate.name !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.name)
129 if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description) 131 if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description)
130 132
131 const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions) 133 await videoChannelInstance.save(sequelizeOptions)
132 134
133 await sendUpdateVideoChannel(videoChannelInstanceUpdated, t) 135 // TODO
136 // await sendUpdateVideoChannel(videoChannelInstanceUpdated, t)
134 }) 137 })
135 138
136 logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.uuid) 139 logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.Actor.uuid)
137 } catch (err) { 140 } catch (err) {
138 logger.debug('Cannot update the video channel.', err) 141 logger.debug('Cannot update the video channel.', err)
139 142
@@ -160,11 +163,12 @@ async function removeVideoChannelRetryWrapper (req: express.Request, res: expres
160async function removeVideoChannel (req: express.Request, res: express.Response) { 163async function removeVideoChannel (req: express.Request, res: express.Response) {
161 const videoChannelInstance: VideoChannelModel = res.locals.videoChannel 164 const videoChannelInstance: VideoChannelModel = res.locals.videoChannel
162 165
163 await sequelizeTypescript.transaction(async t => { 166 return sequelizeTypescript.transaction(async t => {
164 await videoChannelInstance.destroy({ transaction: t }) 167 await videoChannelInstance.destroy({ transaction: t })
168
169 logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.Actor.uuid)
165 }) 170 })
166 171
167 logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.uuid)
168} 172}
169 173
170async function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) { 174async 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 {
11 resetSequelizeInstance, 11 resetSequelizeInstance,
12 retryTransactionWrapper 12 retryTransactionWrapper
13} from '../../../helpers' 13} from '../../../helpers'
14import { getServerAccount } from '../../../helpers/utils' 14import { getServerActor } from '../../../helpers/utils'
15import { 15import {
16 CONFIG, 16 CONFIG,
17 sequelizeTypescript, 17 sequelizeTypescript,
@@ -22,8 +22,7 @@ import {
22 VIDEO_PRIVACIES 22 VIDEO_PRIVACIES
23} from '../../../initializers' 23} from '../../../initializers'
24import { fetchRemoteVideoDescription, getVideoActivityPubUrl, shareVideoByServer } from '../../../lib/activitypub' 24import { fetchRemoteVideoDescription, getVideoActivityPubUrl, shareVideoByServer } from '../../../lib/activitypub'
25import { sendAddVideo, sendCreateViewToOrigin, sendUpdateVideo } from '../../../lib/activitypub/send' 25import { sendCreateVideo, sendCreateViewToOrigin, sendCreateViewToVideoFollowers, sendUpdateVideo } from '../../../lib/activitypub/send'
26import { sendCreateViewToVideoFollowers } from '../../../lib/index'
27import { transcodingJobScheduler } from '../../../lib/jobs/transcoding-job-scheduler' 26import { transcodingJobScheduler } from '../../../lib/jobs/transcoding-job-scheduler'
28import { 27import {
29 asyncMiddleware, 28 asyncMiddleware,
@@ -248,7 +247,8 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi
248 // Don't send video to remote servers, it is private 247 // Don't send video to remote servers, it is private
249 if (video.privacy === VideoPrivacy.PRIVATE) return videoCreated 248 if (video.privacy === VideoPrivacy.PRIVATE) return videoCreated
250 249
251 await sendAddVideo(video, t) 250 await sendCreateVideo(video, t)
251 // TODO: share by video channel
252 await shareVideoByServer(video, t) 252 await shareVideoByServer(video, t)
253 253
254 logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoCreated.uuid) 254 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) {
304 304
305 // Video is not private anymore, send a create action to remote servers 305 // Video is not private anymore, send a create action to remote servers
306 if (wasPrivateVideo === true && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE) { 306 if (wasPrivateVideo === true && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE) {
307 await sendAddVideo(videoInstanceUpdated, t) 307 await sendCreateVideo(videoInstanceUpdated, t)
308 // TODO: Send by video channel
308 await shareVideoByServer(videoInstanceUpdated, t) 309 await shareVideoByServer(videoInstanceUpdated, t)
309 } 310 }
310 }) 311 })
@@ -330,7 +331,7 @@ async function viewVideo (req: express.Request, res: express.Response) {
330 const videoInstance = res.locals.video 331 const videoInstance = res.locals.video
331 332
332 await videoInstance.increment('views') 333 await videoInstance.increment('views')
333 const serverAccount = await getServerAccount() 334 const serverAccount = await getServerActor()
334 335
335 if (videoInstance.isOwned()) { 336 if (videoInstance.isOwned()) {
336 await sendCreateViewToVideoFollowers(serverAccount, videoInstance, undefined) 337 await sendCreateViewToVideoFollowers(serverAccount, videoInstance, undefined)