diff options
Diffstat (limited to 'server/controllers')
-rw-r--r-- | server/controllers/api/abuse.ts | 15 | ||||
-rw-r--r-- | server/controllers/api/blocklist.ts | 108 | ||||
-rw-r--r-- | server/controllers/api/config.ts | 12 | ||||
-rw-r--r-- | server/controllers/api/index.ts | 2 | ||||
-rw-r--r-- | server/controllers/api/plugins.ts | 7 | ||||
-rw-r--r-- | server/controllers/api/server/stats.ts | 4 | ||||
-rw-r--r-- | server/controllers/api/users/my-subscriptions.ts | 21 | ||||
-rw-r--r-- | server/controllers/api/videos/import.ts | 17 | ||||
-rw-r--r-- | server/controllers/api/videos/live.ts | 4 | ||||
-rw-r--r-- | server/controllers/api/videos/update.ts | 32 | ||||
-rw-r--r-- | server/controllers/api/videos/upload.ts | 12 |
11 files changed, 196 insertions, 38 deletions
diff --git a/server/controllers/api/abuse.ts b/server/controllers/api/abuse.ts index 72c418e74..a6d0b0512 100644 --- a/server/controllers/api/abuse.ts +++ b/server/controllers/api/abuse.ts | |||
@@ -167,7 +167,11 @@ async function reportAbuse (req: express.Request, res: express.Response) { | |||
167 | const body: AbuseCreate = req.body | 167 | const body: AbuseCreate = req.body |
168 | 168 | ||
169 | const { id } = await sequelizeTypescript.transaction(async t => { | 169 | const { id } = await sequelizeTypescript.transaction(async t => { |
170 | const reporterAccount = await AccountModel.load(res.locals.oauth.token.User.Account.id, t) | 170 | const user = res.locals.oauth.token.User |
171 | // Don't send abuse notification if reporter is an admin/moderator | ||
172 | const skipNotification = user.hasRight(UserRight.MANAGE_ABUSES) | ||
173 | |||
174 | const reporterAccount = await AccountModel.load(user.Account.id, t) | ||
171 | const predefinedReasons = body.predefinedReasons?.map(r => abusePredefinedReasonsMap[r]) | 175 | const predefinedReasons = body.predefinedReasons?.map(r => abusePredefinedReasonsMap[r]) |
172 | 176 | ||
173 | const baseAbuse = { | 177 | const baseAbuse = { |
@@ -184,7 +188,8 @@ async function reportAbuse (req: express.Request, res: express.Response) { | |||
184 | reporterAccount, | 188 | reporterAccount, |
185 | transaction: t, | 189 | transaction: t, |
186 | startAt: body.video.startAt, | 190 | startAt: body.video.startAt, |
187 | endAt: body.video.endAt | 191 | endAt: body.video.endAt, |
192 | skipNotification | ||
188 | }) | 193 | }) |
189 | } | 194 | } |
190 | 195 | ||
@@ -193,7 +198,8 @@ async function reportAbuse (req: express.Request, res: express.Response) { | |||
193 | baseAbuse, | 198 | baseAbuse, |
194 | commentInstance, | 199 | commentInstance, |
195 | reporterAccount, | 200 | reporterAccount, |
196 | transaction: t | 201 | transaction: t, |
202 | skipNotification | ||
197 | }) | 203 | }) |
198 | } | 204 | } |
199 | 205 | ||
@@ -202,7 +208,8 @@ async function reportAbuse (req: express.Request, res: express.Response) { | |||
202 | baseAbuse, | 208 | baseAbuse, |
203 | accountInstance, | 209 | accountInstance, |
204 | reporterAccount, | 210 | reporterAccount, |
205 | transaction: t | 211 | transaction: t, |
212 | skipNotification | ||
206 | }) | 213 | }) |
207 | }) | 214 | }) |
208 | 215 | ||
diff --git a/server/controllers/api/blocklist.ts b/server/controllers/api/blocklist.ts new file mode 100644 index 000000000..1e936ad10 --- /dev/null +++ b/server/controllers/api/blocklist.ts | |||
@@ -0,0 +1,108 @@ | |||
1 | import express from 'express' | ||
2 | import { handleToNameAndHost } from '@server/helpers/actors' | ||
3 | import { AccountBlocklistModel } from '@server/models/account/account-blocklist' | ||
4 | import { getServerActor } from '@server/models/application/application' | ||
5 | import { ServerBlocklistModel } from '@server/models/server/server-blocklist' | ||
6 | import { MActorAccountId, MUserAccountId } from '@server/types/models' | ||
7 | import { BlockStatus } from '@shared/models' | ||
8 | import { asyncMiddleware, blocklistStatusValidator, optionalAuthenticate } from '../../middlewares' | ||
9 | import { logger } from '@server/helpers/logger' | ||
10 | |||
11 | const blocklistRouter = express.Router() | ||
12 | |||
13 | blocklistRouter.get('/status', | ||
14 | optionalAuthenticate, | ||
15 | blocklistStatusValidator, | ||
16 | asyncMiddleware(getBlocklistStatus) | ||
17 | ) | ||
18 | |||
19 | // --------------------------------------------------------------------------- | ||
20 | |||
21 | export { | ||
22 | blocklistRouter | ||
23 | } | ||
24 | |||
25 | // --------------------------------------------------------------------------- | ||
26 | |||
27 | async function getBlocklistStatus (req: express.Request, res: express.Response) { | ||
28 | const hosts = req.query.hosts as string[] | ||
29 | const accounts = req.query.accounts as string[] | ||
30 | const user = res.locals.oauth?.token.User | ||
31 | |||
32 | const serverActor = await getServerActor() | ||
33 | |||
34 | const byAccountIds = [ serverActor.Account.id ] | ||
35 | if (user) byAccountIds.push(user.Account.id) | ||
36 | |||
37 | const status: BlockStatus = { | ||
38 | accounts: {}, | ||
39 | hosts: {} | ||
40 | } | ||
41 | |||
42 | const baseOptions = { | ||
43 | byAccountIds, | ||
44 | user, | ||
45 | serverActor, | ||
46 | status | ||
47 | } | ||
48 | |||
49 | await Promise.all([ | ||
50 | populateServerBlocklistStatus({ ...baseOptions, hosts }), | ||
51 | populateAccountBlocklistStatus({ ...baseOptions, accounts }) | ||
52 | ]) | ||
53 | |||
54 | return res.json(status) | ||
55 | } | ||
56 | |||
57 | async function populateServerBlocklistStatus (options: { | ||
58 | byAccountIds: number[] | ||
59 | user?: MUserAccountId | ||
60 | serverActor: MActorAccountId | ||
61 | hosts: string[] | ||
62 | status: BlockStatus | ||
63 | }) { | ||
64 | const { byAccountIds, user, serverActor, hosts, status } = options | ||
65 | |||
66 | if (!hosts || hosts.length === 0) return | ||
67 | |||
68 | const serverBlocklistStatus = await ServerBlocklistModel.getBlockStatus(byAccountIds, hosts) | ||
69 | |||
70 | logger.debug('Got server blocklist status.', { serverBlocklistStatus, byAccountIds, hosts }) | ||
71 | |||
72 | for (const host of hosts) { | ||
73 | const block = serverBlocklistStatus.find(b => b.host === host) | ||
74 | |||
75 | status.hosts[host] = getStatus(block, serverActor, user) | ||
76 | } | ||
77 | } | ||
78 | |||
79 | async function populateAccountBlocklistStatus (options: { | ||
80 | byAccountIds: number[] | ||
81 | user?: MUserAccountId | ||
82 | serverActor: MActorAccountId | ||
83 | accounts: string[] | ||
84 | status: BlockStatus | ||
85 | }) { | ||
86 | const { byAccountIds, user, serverActor, accounts, status } = options | ||
87 | |||
88 | if (!accounts || accounts.length === 0) return | ||
89 | |||
90 | const accountBlocklistStatus = await AccountBlocklistModel.getBlockStatus(byAccountIds, accounts) | ||
91 | |||
92 | logger.debug('Got account blocklist status.', { accountBlocklistStatus, byAccountIds, accounts }) | ||
93 | |||
94 | for (const account of accounts) { | ||
95 | const sanitizedHandle = handleToNameAndHost(account) | ||
96 | |||
97 | const block = accountBlocklistStatus.find(b => b.name === sanitizedHandle.name && b.host === sanitizedHandle.host) | ||
98 | |||
99 | status.accounts[sanitizedHandle.handle] = getStatus(block, serverActor, user) | ||
100 | } | ||
101 | } | ||
102 | |||
103 | function getStatus (block: { accountId: number }, serverActor: MActorAccountId, user?: MUserAccountId) { | ||
104 | return { | ||
105 | blockedByServer: !!(block && block.accountId === serverActor.Account.id), | ||
106 | blockedByUser: !!(block && user && block.accountId === user.Account.id) | ||
107 | } | ||
108 | } | ||
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 805ad99c7..b253db397 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -169,6 +169,18 @@ function customConfig (): CustomConfig { | |||
169 | whitelisted: CONFIG.SERVICES.TWITTER.WHITELISTED | 169 | whitelisted: CONFIG.SERVICES.TWITTER.WHITELISTED |
170 | } | 170 | } |
171 | }, | 171 | }, |
172 | client: { | ||
173 | videos: { | ||
174 | miniature: { | ||
175 | preferAuthorDisplayName: CONFIG.CLIENT.VIDEOS.MINIATURE.PREFER_AUTHOR_DISPLAY_NAME | ||
176 | } | ||
177 | }, | ||
178 | menu: { | ||
179 | login: { | ||
180 | redirectOnSingleExternalAuth: CONFIG.CLIENT.MENU.LOGIN.REDIRECT_ON_SINGLE_EXTERNAL_AUTH | ||
181 | } | ||
182 | } | ||
183 | }, | ||
172 | cache: { | 184 | cache: { |
173 | previews: { | 185 | previews: { |
174 | size: CONFIG.CACHE.PREVIEWS.SIZE | 186 | size: CONFIG.CACHE.PREVIEWS.SIZE |
diff --git a/server/controllers/api/index.ts b/server/controllers/api/index.ts index 9949b378a..5f49336b1 100644 --- a/server/controllers/api/index.ts +++ b/server/controllers/api/index.ts | |||
@@ -6,6 +6,7 @@ import { badRequest } from '../../helpers/express-utils' | |||
6 | import { CONFIG } from '../../initializers/config' | 6 | import { CONFIG } from '../../initializers/config' |
7 | import { abuseRouter } from './abuse' | 7 | import { abuseRouter } from './abuse' |
8 | import { accountsRouter } from './accounts' | 8 | import { accountsRouter } from './accounts' |
9 | import { blocklistRouter } from './blocklist' | ||
9 | import { bulkRouter } from './bulk' | 10 | import { bulkRouter } from './bulk' |
10 | import { configRouter } from './config' | 11 | import { configRouter } from './config' |
11 | import { customPageRouter } from './custom-page' | 12 | import { customPageRouter } from './custom-page' |
@@ -49,6 +50,7 @@ apiRouter.use('/search', searchRouter) | |||
49 | apiRouter.use('/overviews', overviewsRouter) | 50 | apiRouter.use('/overviews', overviewsRouter) |
50 | apiRouter.use('/plugins', pluginRouter) | 51 | apiRouter.use('/plugins', pluginRouter) |
51 | apiRouter.use('/custom-pages', customPageRouter) | 52 | apiRouter.use('/custom-pages', customPageRouter) |
53 | apiRouter.use('/blocklist', blocklistRouter) | ||
52 | apiRouter.use('/ping', pong) | 54 | apiRouter.use('/ping', pong) |
53 | apiRouter.use('/*', badRequest) | 55 | apiRouter.use('/*', badRequest) |
54 | 56 | ||
diff --git a/server/controllers/api/plugins.ts b/server/controllers/api/plugins.ts index 2de7fe41f..de9e055dc 100644 --- a/server/controllers/api/plugins.ts +++ b/server/controllers/api/plugins.ts | |||
@@ -144,8 +144,13 @@ async function installPlugin (req: express.Request, res: express.Response) { | |||
144 | 144 | ||
145 | const fromDisk = !!body.path | 145 | const fromDisk = !!body.path |
146 | const toInstall = body.npmName || body.path | 146 | const toInstall = body.npmName || body.path |
147 | |||
148 | const pluginVersion = body.pluginVersion && body.npmName | ||
149 | ? body.pluginVersion | ||
150 | : undefined | ||
151 | |||
147 | try { | 152 | try { |
148 | const plugin = await PluginManager.Instance.install(toInstall, undefined, fromDisk) | 153 | const plugin = await PluginManager.Instance.install(toInstall, pluginVersion, fromDisk) |
149 | 154 | ||
150 | return res.json(plugin.toFormattedJSON()) | 155 | return res.json(plugin.toFormattedJSON()) |
151 | } catch (err) { | 156 | } catch (err) { |
diff --git a/server/controllers/api/server/stats.ts b/server/controllers/api/server/stats.ts index d661144ca..2ab398f4d 100644 --- a/server/controllers/api/server/stats.ts +++ b/server/controllers/api/server/stats.ts | |||
@@ -3,6 +3,7 @@ import { StatsManager } from '@server/lib/stat-manager' | |||
3 | import { ROUTE_CACHE_LIFETIME } from '../../../initializers/constants' | 3 | import { ROUTE_CACHE_LIFETIME } from '../../../initializers/constants' |
4 | import { asyncMiddleware } from '../../../middlewares' | 4 | import { asyncMiddleware } from '../../../middlewares' |
5 | import { cacheRoute } from '../../../middlewares/cache/cache' | 5 | import { cacheRoute } from '../../../middlewares/cache/cache' |
6 | import { Hooks } from '@server/lib/plugins/hooks' | ||
6 | 7 | ||
7 | const statsRouter = express.Router() | 8 | const statsRouter = express.Router() |
8 | 9 | ||
@@ -12,7 +13,8 @@ statsRouter.get('/stats', | |||
12 | ) | 13 | ) |
13 | 14 | ||
14 | async function getStats (_req: express.Request, res: express.Response) { | 15 | async function getStats (_req: express.Request, res: express.Response) { |
15 | const data = await StatsManager.Instance.getStats() | 16 | let data = await StatsManager.Instance.getStats() |
17 | data = await Hooks.wrapObject(data, 'filter:api.server.stats.get.result') | ||
16 | 18 | ||
17 | return res.json(data) | 19 | return res.json(data) |
18 | } | 20 | } |
diff --git a/server/controllers/api/users/my-subscriptions.ts b/server/controllers/api/users/my-subscriptions.ts index 6799ca8c5..fb1f68635 100644 --- a/server/controllers/api/users/my-subscriptions.ts +++ b/server/controllers/api/users/my-subscriptions.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import 'multer' | 1 | import 'multer' |
2 | import express from 'express' | 2 | import express from 'express' |
3 | import { handlesToNameAndHost } from '@server/helpers/actors' | ||
3 | import { pickCommonVideoQuery } from '@server/helpers/query' | 4 | import { pickCommonVideoQuery } from '@server/helpers/query' |
4 | import { sendUndoFollow } from '@server/lib/activitypub/send' | 5 | import { sendUndoFollow } from '@server/lib/activitypub/send' |
5 | import { guessAdditionalAttributesFromQuery } from '@server/models/video/formatter/video-format-utils' | 6 | import { guessAdditionalAttributesFromQuery } from '@server/models/video/formatter/video-format-utils' |
@@ -7,7 +8,6 @@ import { VideoChannelModel } from '@server/models/video/video-channel' | |||
7 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | 8 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' |
8 | import { buildNSFWFilter, getCountVideos } from '../../../helpers/express-utils' | 9 | import { buildNSFWFilter, getCountVideos } from '../../../helpers/express-utils' |
9 | import { getFormattedObjects } from '../../../helpers/utils' | 10 | import { getFormattedObjects } from '../../../helpers/utils' |
10 | import { WEBSERVER } from '../../../initializers/constants' | ||
11 | import { sequelizeTypescript } from '../../../initializers/database' | 11 | import { sequelizeTypescript } from '../../../initializers/database' |
12 | import { JobQueue } from '../../../lib/job-queue' | 12 | import { JobQueue } from '../../../lib/job-queue' |
13 | import { | 13 | import { |
@@ -89,28 +89,23 @@ async function areSubscriptionsExist (req: express.Request, res: express.Respons | |||
89 | const uris = req.query.uris as string[] | 89 | const uris = req.query.uris as string[] |
90 | const user = res.locals.oauth.token.User | 90 | const user = res.locals.oauth.token.User |
91 | 91 | ||
92 | const handles = uris.map(u => { | 92 | const sanitizedHandles = handlesToNameAndHost(uris) |
93 | let [ name, host ] = u.split('@') | ||
94 | if (host === WEBSERVER.HOST) host = null | ||
95 | 93 | ||
96 | return { name, host, uri: u } | 94 | const results = await ActorFollowModel.listSubscriptionsOf(user.Account.Actor.id, sanitizedHandles) |
97 | }) | ||
98 | |||
99 | const results = await ActorFollowModel.listSubscriptionsOf(user.Account.Actor.id, handles) | ||
100 | 95 | ||
101 | const existObject: { [id: string ]: boolean } = {} | 96 | const existObject: { [id: string ]: boolean } = {} |
102 | for (const handle of handles) { | 97 | for (const sanitizedHandle of sanitizedHandles) { |
103 | const obj = results.find(r => { | 98 | const obj = results.find(r => { |
104 | const server = r.ActorFollowing.Server | 99 | const server = r.ActorFollowing.Server |
105 | 100 | ||
106 | return r.ActorFollowing.preferredUsername === handle.name && | 101 | return r.ActorFollowing.preferredUsername === sanitizedHandle.name && |
107 | ( | 102 | ( |
108 | (!server && !handle.host) || | 103 | (!server && !sanitizedHandle.host) || |
109 | (server.host === handle.host) | 104 | (server.host === sanitizedHandle.host) |
110 | ) | 105 | ) |
111 | }) | 106 | }) |
112 | 107 | ||
113 | existObject[handle.uri] = obj !== undefined | 108 | existObject[sanitizedHandle.handle] = obj !== undefined |
114 | } | 109 | } |
115 | 110 | ||
116 | return res.json(existObject) | 111 | return res.json(existObject) |
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index eddb9b32d..52864bdfd 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts | |||
@@ -38,6 +38,7 @@ import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoIm | |||
38 | import { VideoModel } from '../../../models/video/video' | 38 | import { VideoModel } from '../../../models/video/video' |
39 | import { VideoCaptionModel } from '../../../models/video/video-caption' | 39 | import { VideoCaptionModel } from '../../../models/video/video-caption' |
40 | import { VideoImportModel } from '../../../models/video/video-import' | 40 | import { VideoImportModel } from '../../../models/video/video-import' |
41 | import { Hooks } from '@server/lib/plugins/hooks' | ||
41 | 42 | ||
42 | const auditLogger = auditLoggerFactory('video-imports') | 43 | const auditLogger = auditLoggerFactory('video-imports') |
43 | const videoImportsRouter = express.Router() | 44 | const videoImportsRouter = express.Router() |
@@ -94,7 +95,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to | |||
94 | videoName = result.name | 95 | videoName = result.name |
95 | } | 96 | } |
96 | 97 | ||
97 | const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName }) | 98 | const video = await buildVideo(res.locals.videoChannel.id, body, { name: videoName }) |
98 | 99 | ||
99 | const thumbnailModel = await processThumbnail(req, video) | 100 | const thumbnailModel = await processThumbnail(req, video) |
100 | const previewModel = await processPreview(req, video) | 101 | const previewModel = await processPreview(req, video) |
@@ -151,7 +152,7 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response) | |||
151 | }) | 152 | }) |
152 | } | 153 | } |
153 | 154 | ||
154 | const video = buildVideo(res.locals.videoChannel.id, body, youtubeDLInfo) | 155 | const video = await buildVideo(res.locals.videoChannel.id, body, youtubeDLInfo) |
155 | 156 | ||
156 | // Process video thumbnail from request.files | 157 | // Process video thumbnail from request.files |
157 | let thumbnailModel = await processThumbnail(req, video) | 158 | let thumbnailModel = await processThumbnail(req, video) |
@@ -210,8 +211,8 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response) | |||
210 | return res.json(videoImport.toFormattedJSON()).end() | 211 | return res.json(videoImport.toFormattedJSON()).end() |
211 | } | 212 | } |
212 | 213 | ||
213 | function buildVideo (channelId: number, body: VideoImportCreate, importData: YoutubeDLInfo): MVideoThumbnail { | 214 | async function buildVideo (channelId: number, body: VideoImportCreate, importData: YoutubeDLInfo): Promise<MVideoThumbnail> { |
214 | const videoData = { | 215 | let videoData = { |
215 | name: body.name || importData.name || 'Unknown name', | 216 | name: body.name || importData.name || 'Unknown name', |
216 | remote: false, | 217 | remote: false, |
217 | category: body.category || importData.category, | 218 | category: body.category || importData.category, |
@@ -231,6 +232,14 @@ function buildVideo (channelId: number, body: VideoImportCreate, importData: You | |||
231 | ? new Date(body.originallyPublishedAt) | 232 | ? new Date(body.originallyPublishedAt) |
232 | : importData.originallyPublishedAt | 233 | : importData.originallyPublishedAt |
233 | } | 234 | } |
235 | |||
236 | videoData = await Hooks.wrapObject( | ||
237 | videoData, | ||
238 | body.targetUrl | ||
239 | ? 'filter:api.video.import-url.video-attribute.result' | ||
240 | : 'filter:api.video.import-torrent.video-attribute.result' | ||
241 | ) | ||
242 | |||
234 | const video = new VideoModel(videoData) | 243 | const video = new VideoModel(videoData) |
235 | video.url = getLocalVideoActivityPubUrl(video) | 244 | video.url = getLocalVideoActivityPubUrl(video) |
236 | 245 | ||
diff --git a/server/controllers/api/videos/live.ts b/server/controllers/api/videos/live.ts index e29615ff5..3e1480cf2 100644 --- a/server/controllers/api/videos/live.ts +++ b/server/controllers/api/videos/live.ts | |||
@@ -83,7 +83,9 @@ async function addLiveVideo (req: express.Request, res: express.Response) { | |||
83 | const videoInfo: LiveVideoCreate = req.body | 83 | const videoInfo: LiveVideoCreate = req.body |
84 | 84 | ||
85 | // Prepare data so we don't block the transaction | 85 | // Prepare data so we don't block the transaction |
86 | const videoData = buildLocalVideoFromReq(videoInfo, res.locals.videoChannel.id) | 86 | let videoData = buildLocalVideoFromReq(videoInfo, res.locals.videoChannel.id) |
87 | videoData = await Hooks.wrapObject(videoData, 'filter:api.video.live.video-attribute.result') | ||
88 | |||
87 | videoData.isLive = true | 89 | videoData.isLive = true |
88 | videoData.state = VideoState.WAITING_FOR_LIVE | 90 | videoData.state = VideoState.WAITING_FOR_LIVE |
89 | videoData.duration = 0 | 91 | videoData.duration = 0 |
diff --git a/server/controllers/api/videos/update.ts b/server/controllers/api/videos/update.ts index 3fcff3e86..589556f47 100644 --- a/server/controllers/api/videos/update.ts +++ b/server/controllers/api/videos/update.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { Transaction } from 'sequelize/types' | 2 | import { Transaction } from 'sequelize/types' |
3 | import { updateTorrentMetadata } from '@server/helpers/webtorrent' | ||
3 | import { changeVideoChannelShare } from '@server/lib/activitypub/share' | 4 | import { changeVideoChannelShare } from '@server/lib/activitypub/share' |
4 | import { buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video' | 5 | import { buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video' |
5 | import { openapiOperationDoc } from '@server/middlewares/doc' | 6 | import { openapiOperationDoc } from '@server/middlewares/doc' |
@@ -68,7 +69,7 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
68 | }) | 69 | }) |
69 | 70 | ||
70 | try { | 71 | try { |
71 | const videoInstanceUpdated = await sequelizeTypescript.transaction(async t => { | 72 | const { videoInstanceUpdated, isNewVideo } = await sequelizeTypescript.transaction(async t => { |
72 | // Refresh video since thumbnails to prevent concurrent updates | 73 | // Refresh video since thumbnails to prevent concurrent updates |
73 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoFromReq.id, t) | 74 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoFromReq.id, t) |
74 | 75 | ||
@@ -137,8 +138,6 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
137 | transaction: t | 138 | transaction: t |
138 | }) | 139 | }) |
139 | 140 | ||
140 | await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t) | ||
141 | |||
142 | auditLogger.update( | 141 | auditLogger.update( |
143 | getAuditIdFromRes(res), | 142 | getAuditIdFromRes(res), |
144 | new VideoAuditView(videoInstanceUpdated.toFormattedDetailsJSON()), | 143 | new VideoAuditView(videoInstanceUpdated.toFormattedDetailsJSON()), |
@@ -146,12 +145,14 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
146 | ) | 145 | ) |
147 | logger.info('Video with name %s and uuid %s updated.', video.name, video.uuid, lTags(video.uuid)) | 146 | logger.info('Video with name %s and uuid %s updated.', video.name, video.uuid, lTags(video.uuid)) |
148 | 147 | ||
149 | return videoInstanceUpdated | 148 | return { videoInstanceUpdated, isNewVideo } |
150 | }) | 149 | }) |
151 | 150 | ||
152 | if (wasConfidentialVideo) { | 151 | if (videoInfoToUpdate.name) await updateTorrentsMetadata(videoInstanceUpdated) |
153 | Notifier.Instance.notifyOnNewVideoIfNeeded(videoInstanceUpdated) | 152 | |
154 | } | 153 | await sequelizeTypescript.transaction(t => federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t)) |
154 | |||
155 | if (wasConfidentialVideo) Notifier.Instance.notifyOnNewVideoIfNeeded(videoInstanceUpdated) | ||
155 | 156 | ||
156 | Hooks.runAction('action:api.video.updated', { video: videoInstanceUpdated, body: req.body, req, res }) | 157 | Hooks.runAction('action:api.video.updated', { video: videoInstanceUpdated, body: req.body, req, res }) |
157 | } catch (err) { | 158 | } catch (err) { |
@@ -199,3 +200,20 @@ function updateSchedule (videoInstance: MVideoFullLight, videoInfoToUpdate: Vide | |||
199 | return ScheduleVideoUpdateModel.deleteByVideoId(videoInstance.id, transaction) | 200 | return ScheduleVideoUpdateModel.deleteByVideoId(videoInstance.id, transaction) |
200 | } | 201 | } |
201 | } | 202 | } |
203 | |||
204 | async function updateTorrentsMetadata (video: MVideoFullLight) { | ||
205 | for (const file of (video.VideoFiles || [])) { | ||
206 | await updateTorrentMetadata(video, file) | ||
207 | |||
208 | await file.save() | ||
209 | } | ||
210 | |||
211 | const hls = video.getHLSPlaylist() | ||
212 | if (!hls) return | ||
213 | |||
214 | for (const file of (hls.VideoFiles || [])) { | ||
215 | await updateTorrentMetadata(hls, file) | ||
216 | |||
217 | await file.save() | ||
218 | } | ||
219 | } | ||
diff --git a/server/controllers/api/videos/upload.ts b/server/controllers/api/videos/upload.ts index 6773b500f..1be87f746 100644 --- a/server/controllers/api/videos/upload.ts +++ b/server/controllers/api/videos/upload.ts | |||
@@ -8,6 +8,7 @@ import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' | |||
8 | import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url' | 8 | import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url' |
9 | import { generateWebTorrentVideoFilename } from '@server/lib/paths' | 9 | import { generateWebTorrentVideoFilename } from '@server/lib/paths' |
10 | import { Redis } from '@server/lib/redis' | 10 | import { Redis } from '@server/lib/redis' |
11 | import { uploadx } from '@server/lib/uploadx' | ||
11 | import { | 12 | import { |
12 | addMoveToObjectStorageJob, | 13 | addMoveToObjectStorageJob, |
13 | addOptimizeOrMergeAudioJob, | 14 | addOptimizeOrMergeAudioJob, |
@@ -19,7 +20,6 @@ import { VideoPathManager } from '@server/lib/video-path-manager' | |||
19 | import { buildNextVideoState } from '@server/lib/video-state' | 20 | import { buildNextVideoState } from '@server/lib/video-state' |
20 | import { openapiOperationDoc } from '@server/middlewares/doc' | 21 | import { openapiOperationDoc } from '@server/middlewares/doc' |
21 | import { MVideo, MVideoFile, MVideoFullLight } from '@server/types/models' | 22 | import { MVideo, MVideoFile, MVideoFullLight } from '@server/types/models' |
22 | import { Uploadx } from '@uploadx/core' | ||
23 | import { VideoCreate, VideoState } from '../../../../shared' | 23 | import { VideoCreate, VideoState } from '../../../../shared' |
24 | import { HttpStatusCode } from '../../../../shared/models' | 24 | import { HttpStatusCode } from '../../../../shared/models' |
25 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' | 25 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' |
@@ -41,8 +41,8 @@ import { | |||
41 | authenticate, | 41 | authenticate, |
42 | videosAddLegacyValidator, | 42 | videosAddLegacyValidator, |
43 | videosAddResumableInitValidator, | 43 | videosAddResumableInitValidator, |
44 | videosResumableUploadIdValidator, | 44 | videosAddResumableValidator, |
45 | videosAddResumableValidator | 45 | videosResumableUploadIdValidator |
46 | } from '../../../middlewares' | 46 | } from '../../../middlewares' |
47 | import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update' | 47 | import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update' |
48 | import { VideoModel } from '../../../models/video/video' | 48 | import { VideoModel } from '../../../models/video/video' |
@@ -52,9 +52,6 @@ const lTags = loggerTagsFactory('api', 'video') | |||
52 | const auditLogger = auditLoggerFactory('videos') | 52 | const auditLogger = auditLoggerFactory('videos') |
53 | const uploadRouter = express.Router() | 53 | const uploadRouter = express.Router() |
54 | 54 | ||
55 | const uploadx = new Uploadx({ directory: getResumableUploadPath() }) | ||
56 | uploadx.getUserId = (_, res: express.Response) => res.locals.oauth?.token.user.id | ||
57 | |||
58 | const reqVideoFileAdd = createReqFiles( | 55 | const reqVideoFileAdd = createReqFiles( |
59 | [ 'videofile', 'thumbnailfile', 'previewfile' ], | 56 | [ 'videofile', 'thumbnailfile', 'previewfile' ], |
60 | Object.assign({}, MIMETYPES.VIDEO.MIMETYPE_EXT, MIMETYPES.IMAGE.MIMETYPE_EXT), | 57 | Object.assign({}, MIMETYPES.VIDEO.MIMETYPE_EXT, MIMETYPES.IMAGE.MIMETYPE_EXT), |
@@ -156,7 +153,8 @@ async function addVideo (options: { | |||
156 | const videoChannel = res.locals.videoChannel | 153 | const videoChannel = res.locals.videoChannel |
157 | const user = res.locals.oauth.token.User | 154 | const user = res.locals.oauth.token.User |
158 | 155 | ||
159 | const videoData = buildLocalVideoFromReq(videoInfo, videoChannel.id) | 156 | let videoData = buildLocalVideoFromReq(videoInfo, videoChannel.id) |
157 | videoData = await Hooks.wrapObject(videoData, 'filter:api.video.upload.video-attribute.result') | ||
160 | 158 | ||
161 | videoData.state = buildNextVideoState() | 159 | videoData.state = buildNextVideoState() |
162 | videoData.duration = videoPhysicalFile.duration // duration was added by a previous middleware | 160 | videoData.duration = videoPhysicalFile.duration // duration was added by a previous middleware |