diff options
Diffstat (limited to 'server/controllers/api/videos')
-rw-r--r-- | server/controllers/api/videos/abuse.ts | 5 | ||||
-rw-r--r-- | server/controllers/api/videos/blacklist.ts | 31 | ||||
-rw-r--r-- | server/controllers/api/videos/captions.ts | 4 | ||||
-rw-r--r-- | server/controllers/api/videos/comment.ts | 15 | ||||
-rw-r--r-- | server/controllers/api/videos/import.ts | 21 | ||||
-rw-r--r-- | server/controllers/api/videos/index.ts | 72 | ||||
-rw-r--r-- | server/controllers/api/videos/rate.ts | 17 |
7 files changed, 108 insertions, 57 deletions
diff --git a/server/controllers/api/videos/abuse.ts b/server/controllers/api/videos/abuse.ts index d0c81804b..32f9c4793 100644 --- a/server/controllers/api/videos/abuse.ts +++ b/server/controllers/api/videos/abuse.ts | |||
@@ -3,7 +3,6 @@ import { UserRight, VideoAbuseCreate, VideoAbuseState } from '../../../../shared | |||
3 | import { logger } from '../../../helpers/logger' | 3 | import { logger } from '../../../helpers/logger' |
4 | import { getFormattedObjects } from '../../../helpers/utils' | 4 | import { getFormattedObjects } from '../../../helpers/utils' |
5 | import { sequelizeTypescript } from '../../../initializers' | 5 | import { sequelizeTypescript } from '../../../initializers' |
6 | import { sendVideoAbuse } from '../../../lib/activitypub/send' | ||
7 | import { | 6 | import { |
8 | asyncMiddleware, | 7 | asyncMiddleware, |
9 | asyncRetryTransactionMiddleware, | 8 | asyncRetryTransactionMiddleware, |
@@ -22,6 +21,8 @@ import { VideoModel } from '../../../models/video/video' | |||
22 | import { VideoAbuseModel } from '../../../models/video/video-abuse' | 21 | import { VideoAbuseModel } from '../../../models/video/video-abuse' |
23 | import { auditLoggerFactory, VideoAbuseAuditView } from '../../../helpers/audit-logger' | 22 | import { auditLoggerFactory, VideoAbuseAuditView } from '../../../helpers/audit-logger' |
24 | import { UserModel } from '../../../models/account/user' | 23 | import { UserModel } from '../../../models/account/user' |
24 | import { Notifier } from '../../../lib/notifier' | ||
25 | import { sendVideoAbuse } from '../../../lib/activitypub/send/send-flag' | ||
25 | 26 | ||
26 | const auditLogger = auditLoggerFactory('abuse') | 27 | const auditLogger = auditLoggerFactory('abuse') |
27 | const abuseVideoRouter = express.Router() | 28 | const abuseVideoRouter = express.Router() |
@@ -117,6 +118,8 @@ async function reportVideoAbuse (req: express.Request, res: express.Response) { | |||
117 | await sendVideoAbuse(reporterAccount.Actor, videoAbuseInstance, videoInstance) | 118 | await sendVideoAbuse(reporterAccount.Actor, videoAbuseInstance, videoInstance) |
118 | } | 119 | } |
119 | 120 | ||
121 | Notifier.Instance.notifyOnNewVideoAbuse(videoAbuseInstance) | ||
122 | |||
120 | auditLogger.create(reporterAccount.Actor.getIdentifier(), new VideoAbuseAuditView(videoAbuseInstance.toFormattedJSON())) | 123 | auditLogger.create(reporterAccount.Actor.getIdentifier(), new VideoAbuseAuditView(videoAbuseInstance.toFormattedJSON())) |
121 | 124 | ||
122 | return videoAbuseInstance | 125 | return videoAbuseInstance |
diff --git a/server/controllers/api/videos/blacklist.ts b/server/controllers/api/videos/blacklist.ts index 7f803c8e9..43b0516e7 100644 --- a/server/controllers/api/videos/blacklist.ts +++ b/server/controllers/api/videos/blacklist.ts | |||
@@ -16,6 +16,10 @@ import { | |||
16 | } from '../../../middlewares' | 16 | } from '../../../middlewares' |
17 | import { VideoBlacklistModel } from '../../../models/video/video-blacklist' | 17 | import { VideoBlacklistModel } from '../../../models/video/video-blacklist' |
18 | import { sequelizeTypescript } from '../../../initializers' | 18 | import { sequelizeTypescript } from '../../../initializers' |
19 | import { Notifier } from '../../../lib/notifier' | ||
20 | import { VideoModel } from '../../../models/video/video' | ||
21 | import { sendCreateVideo, sendDeleteVideo, sendUpdateVideo } from '../../../lib/activitypub/send' | ||
22 | import { federateVideoIfNeeded } from '../../../lib/activitypub' | ||
19 | 23 | ||
20 | const blacklistRouter = express.Router() | 24 | const blacklistRouter = express.Router() |
21 | 25 | ||
@@ -64,16 +68,26 @@ async function addVideoToBlacklist (req: express.Request, res: express.Response) | |||
64 | 68 | ||
65 | const toCreate = { | 69 | const toCreate = { |
66 | videoId: videoInstance.id, | 70 | videoId: videoInstance.id, |
71 | unfederated: body.unfederate === true, | ||
67 | reason: body.reason | 72 | reason: body.reason |
68 | } | 73 | } |
69 | 74 | ||
70 | await VideoBlacklistModel.create(toCreate) | 75 | const blacklist = await VideoBlacklistModel.create(toCreate) |
76 | blacklist.Video = videoInstance | ||
77 | |||
78 | if (body.unfederate === true) { | ||
79 | await sendDeleteVideo(videoInstance, undefined) | ||
80 | } | ||
81 | |||
82 | Notifier.Instance.notifyOnVideoBlacklist(blacklist) | ||
83 | |||
84 | logger.info('Video %s blacklisted.', res.locals.video.uuid) | ||
85 | |||
71 | return res.type('json').status(204).end() | 86 | return res.type('json').status(204).end() |
72 | } | 87 | } |
73 | 88 | ||
74 | async function updateVideoBlacklistController (req: express.Request, res: express.Response) { | 89 | async function updateVideoBlacklistController (req: express.Request, res: express.Response) { |
75 | const videoBlacklist = res.locals.videoBlacklist as VideoBlacklistModel | 90 | const videoBlacklist = res.locals.videoBlacklist as VideoBlacklistModel |
76 | logger.info(videoBlacklist) | ||
77 | 91 | ||
78 | if (req.body.reason !== undefined) videoBlacklist.reason = req.body.reason | 92 | if (req.body.reason !== undefined) videoBlacklist.reason = req.body.reason |
79 | 93 | ||
@@ -92,11 +106,20 @@ async function listBlacklist (req: express.Request, res: express.Response, next: | |||
92 | 106 | ||
93 | async function removeVideoFromBlacklistController (req: express.Request, res: express.Response, next: express.NextFunction) { | 107 | async function removeVideoFromBlacklistController (req: express.Request, res: express.Response, next: express.NextFunction) { |
94 | const videoBlacklist = res.locals.videoBlacklist as VideoBlacklistModel | 108 | const videoBlacklist = res.locals.videoBlacklist as VideoBlacklistModel |
109 | const video: VideoModel = res.locals.video | ||
95 | 110 | ||
96 | await sequelizeTypescript.transaction(t => { | 111 | await sequelizeTypescript.transaction(async t => { |
97 | return videoBlacklist.destroy({ transaction: t }) | 112 | const unfederated = videoBlacklist.unfederated |
113 | await videoBlacklist.destroy({ transaction: t }) | ||
114 | |||
115 | // Re federate the video | ||
116 | if (unfederated === true) { | ||
117 | await federateVideoIfNeeded(video, true, t) | ||
118 | } | ||
98 | }) | 119 | }) |
99 | 120 | ||
121 | Notifier.Instance.notifyOnVideoUnblacklist(video) | ||
122 | |||
100 | logger.info('Video %s removed from blacklist.', res.locals.video.uuid) | 123 | logger.info('Video %s removed from blacklist.', res.locals.video.uuid) |
101 | 124 | ||
102 | return res.type('json').status(204).end() | 125 | return res.type('json').status(204).end() |
diff --git a/server/controllers/api/videos/captions.ts b/server/controllers/api/videos/captions.ts index 3ba918189..9b3661368 100644 --- a/server/controllers/api/videos/captions.ts +++ b/server/controllers/api/videos/captions.ts | |||
@@ -2,7 +2,7 @@ import * as express from 'express' | |||
2 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate } from '../../../middlewares' | 2 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate } from '../../../middlewares' |
3 | import { addVideoCaptionValidator, deleteVideoCaptionValidator, listVideoCaptionsValidator } from '../../../middlewares/validators' | 3 | import { addVideoCaptionValidator, deleteVideoCaptionValidator, listVideoCaptionsValidator } from '../../../middlewares/validators' |
4 | import { createReqFiles } from '../../../helpers/express-utils' | 4 | import { createReqFiles } from '../../../helpers/express-utils' |
5 | import { CONFIG, sequelizeTypescript, VIDEO_CAPTIONS_MIMETYPE_EXT } from '../../../initializers' | 5 | import { CONFIG, MIMETYPES, sequelizeTypescript } from '../../../initializers' |
6 | import { getFormattedObjects } from '../../../helpers/utils' | 6 | import { getFormattedObjects } from '../../../helpers/utils' |
7 | import { VideoCaptionModel } from '../../../models/video/video-caption' | 7 | import { VideoCaptionModel } from '../../../models/video/video-caption' |
8 | import { VideoModel } from '../../../models/video/video' | 8 | import { VideoModel } from '../../../models/video/video' |
@@ -12,7 +12,7 @@ import { moveAndProcessCaptionFile } from '../../../helpers/captions-utils' | |||
12 | 12 | ||
13 | const reqVideoCaptionAdd = createReqFiles( | 13 | const reqVideoCaptionAdd = createReqFiles( |
14 | [ 'captionfile' ], | 14 | [ 'captionfile' ], |
15 | VIDEO_CAPTIONS_MIMETYPE_EXT, | 15 | MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT, |
16 | { | 16 | { |
17 | captionfile: CONFIG.STORAGE.CAPTIONS_DIR | 17 | captionfile: CONFIG.STORAGE.CAPTIONS_DIR |
18 | } | 18 | } |
diff --git a/server/controllers/api/videos/comment.ts b/server/controllers/api/videos/comment.ts index 4f2b4faee..70c1148ba 100644 --- a/server/controllers/api/videos/comment.ts +++ b/server/controllers/api/videos/comment.ts | |||
@@ -8,7 +8,7 @@ import { buildFormattedCommentTree, createVideoComment } from '../../../lib/vide | |||
8 | import { | 8 | import { |
9 | asyncMiddleware, | 9 | asyncMiddleware, |
10 | asyncRetryTransactionMiddleware, | 10 | asyncRetryTransactionMiddleware, |
11 | authenticate, | 11 | authenticate, optionalAuthenticate, |
12 | paginationValidator, | 12 | paginationValidator, |
13 | setDefaultPagination, | 13 | setDefaultPagination, |
14 | setDefaultSort | 14 | setDefaultSort |
@@ -26,6 +26,7 @@ import { VideoCommentModel } from '../../../models/video/video-comment' | |||
26 | import { auditLoggerFactory, CommentAuditView, getAuditIdFromRes } from '../../../helpers/audit-logger' | 26 | import { auditLoggerFactory, CommentAuditView, getAuditIdFromRes } from '../../../helpers/audit-logger' |
27 | import { AccountModel } from '../../../models/account/account' | 27 | import { AccountModel } from '../../../models/account/account' |
28 | import { UserModel } from '../../../models/account/user' | 28 | import { UserModel } from '../../../models/account/user' |
29 | import { Notifier } from '../../../lib/notifier' | ||
29 | 30 | ||
30 | const auditLogger = auditLoggerFactory('comments') | 31 | const auditLogger = auditLoggerFactory('comments') |
31 | const videoCommentRouter = express.Router() | 32 | const videoCommentRouter = express.Router() |
@@ -36,10 +37,12 @@ videoCommentRouter.get('/:videoId/comment-threads', | |||
36 | setDefaultSort, | 37 | setDefaultSort, |
37 | setDefaultPagination, | 38 | setDefaultPagination, |
38 | asyncMiddleware(listVideoCommentThreadsValidator), | 39 | asyncMiddleware(listVideoCommentThreadsValidator), |
40 | optionalAuthenticate, | ||
39 | asyncMiddleware(listVideoThreads) | 41 | asyncMiddleware(listVideoThreads) |
40 | ) | 42 | ) |
41 | videoCommentRouter.get('/:videoId/comment-threads/:threadId', | 43 | videoCommentRouter.get('/:videoId/comment-threads/:threadId', |
42 | asyncMiddleware(listVideoThreadCommentsValidator), | 44 | asyncMiddleware(listVideoThreadCommentsValidator), |
45 | optionalAuthenticate, | ||
43 | asyncMiddleware(listVideoThreadComments) | 46 | asyncMiddleware(listVideoThreadComments) |
44 | ) | 47 | ) |
45 | 48 | ||
@@ -69,10 +72,12 @@ export { | |||
69 | 72 | ||
70 | async function listVideoThreads (req: express.Request, res: express.Response, next: express.NextFunction) { | 73 | async function listVideoThreads (req: express.Request, res: express.Response, next: express.NextFunction) { |
71 | const video = res.locals.video as VideoModel | 74 | const video = res.locals.video as VideoModel |
75 | const user: UserModel = res.locals.oauth ? res.locals.oauth.token.User : undefined | ||
76 | |||
72 | let resultList: ResultList<VideoCommentModel> | 77 | let resultList: ResultList<VideoCommentModel> |
73 | 78 | ||
74 | if (video.commentsEnabled === true) { | 79 | if (video.commentsEnabled === true) { |
75 | resultList = await VideoCommentModel.listThreadsForApi(video.id, req.query.start, req.query.count, req.query.sort) | 80 | resultList = await VideoCommentModel.listThreadsForApi(video.id, req.query.start, req.query.count, req.query.sort, user) |
76 | } else { | 81 | } else { |
77 | resultList = { | 82 | resultList = { |
78 | total: 0, | 83 | total: 0, |
@@ -85,10 +90,12 @@ async function listVideoThreads (req: express.Request, res: express.Response, ne | |||
85 | 90 | ||
86 | async function listVideoThreadComments (req: express.Request, res: express.Response, next: express.NextFunction) { | 91 | async function listVideoThreadComments (req: express.Request, res: express.Response, next: express.NextFunction) { |
87 | const video = res.locals.video as VideoModel | 92 | const video = res.locals.video as VideoModel |
93 | const user: UserModel = res.locals.oauth ? res.locals.oauth.token.User : undefined | ||
94 | |||
88 | let resultList: ResultList<VideoCommentModel> | 95 | let resultList: ResultList<VideoCommentModel> |
89 | 96 | ||
90 | if (video.commentsEnabled === true) { | 97 | if (video.commentsEnabled === true) { |
91 | resultList = await VideoCommentModel.listThreadCommentsForApi(video.id, res.locals.videoCommentThread.id) | 98 | resultList = await VideoCommentModel.listThreadCommentsForApi(video.id, res.locals.videoCommentThread.id, user) |
92 | } else { | 99 | } else { |
93 | resultList = { | 100 | resultList = { |
94 | total: 0, | 101 | total: 0, |
@@ -113,6 +120,7 @@ async function addVideoCommentThread (req: express.Request, res: express.Respons | |||
113 | }, t) | 120 | }, t) |
114 | }) | 121 | }) |
115 | 122 | ||
123 | Notifier.Instance.notifyOnNewComment(comment) | ||
116 | auditLogger.create(getAuditIdFromRes(res), new CommentAuditView(comment.toFormattedJSON())) | 124 | auditLogger.create(getAuditIdFromRes(res), new CommentAuditView(comment.toFormattedJSON())) |
117 | 125 | ||
118 | return res.json({ | 126 | return res.json({ |
@@ -134,6 +142,7 @@ async function addVideoCommentReply (req: express.Request, res: express.Response | |||
134 | }, t) | 142 | }, t) |
135 | }) | 143 | }) |
136 | 144 | ||
145 | Notifier.Instance.notifyOnNewComment(comment) | ||
137 | auditLogger.create(getAuditIdFromRes(res), new CommentAuditView(comment.toFormattedJSON())) | 146 | auditLogger.create(getAuditIdFromRes(res), new CommentAuditView(comment.toFormattedJSON())) |
138 | 147 | ||
139 | return res.json({ comment: comment.toFormattedJSON() }).end() | 148 | return res.json({ comment: comment.toFormattedJSON() }).end() |
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index 9e51e2000..7053d5253 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts | |||
@@ -3,14 +3,7 @@ import * as magnetUtil from 'magnet-uri' | |||
3 | import 'multer' | 3 | import 'multer' |
4 | import { auditLoggerFactory, getAuditIdFromRes, VideoImportAuditView } from '../../../helpers/audit-logger' | 4 | import { auditLoggerFactory, getAuditIdFromRes, VideoImportAuditView } from '../../../helpers/audit-logger' |
5 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoImportAddValidator } from '../../../middlewares' | 5 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoImportAddValidator } from '../../../middlewares' |
6 | import { | 6 | import { CONFIG, MIMETYPES, PREVIEWS_SIZE, sequelizeTypescript, THUMBNAILS_SIZE } from '../../../initializers' |
7 | CONFIG, | ||
8 | IMAGE_MIMETYPE_EXT, | ||
9 | PREVIEWS_SIZE, | ||
10 | sequelizeTypescript, | ||
11 | THUMBNAILS_SIZE, | ||
12 | TORRENT_MIMETYPE_EXT | ||
13 | } from '../../../initializers' | ||
14 | import { getYoutubeDLInfo, YoutubeDLInfo } from '../../../helpers/youtube-dl' | 7 | import { getYoutubeDLInfo, YoutubeDLInfo } from '../../../helpers/youtube-dl' |
15 | import { createReqFiles } from '../../../helpers/express-utils' | 8 | import { createReqFiles } from '../../../helpers/express-utils' |
16 | import { logger } from '../../../helpers/logger' | 9 | import { logger } from '../../../helpers/logger' |
@@ -28,18 +21,18 @@ import { VideoChannelModel } from '../../../models/video/video-channel' | |||
28 | import * as Bluebird from 'bluebird' | 21 | import * as Bluebird from 'bluebird' |
29 | import * as parseTorrent from 'parse-torrent' | 22 | import * as parseTorrent from 'parse-torrent' |
30 | import { getSecureTorrentName } from '../../../helpers/utils' | 23 | import { getSecureTorrentName } from '../../../helpers/utils' |
31 | import { readFile, rename } from 'fs-extra' | 24 | import { readFile, move } from 'fs-extra' |
32 | 25 | ||
33 | const auditLogger = auditLoggerFactory('video-imports') | 26 | const auditLogger = auditLoggerFactory('video-imports') |
34 | const videoImportsRouter = express.Router() | 27 | const videoImportsRouter = express.Router() |
35 | 28 | ||
36 | const reqVideoFileImport = createReqFiles( | 29 | const reqVideoFileImport = createReqFiles( |
37 | [ 'thumbnailfile', 'previewfile', 'torrentfile' ], | 30 | [ 'thumbnailfile', 'previewfile', 'torrentfile' ], |
38 | Object.assign({}, TORRENT_MIMETYPE_EXT, IMAGE_MIMETYPE_EXT), | 31 | Object.assign({}, MIMETYPES.TORRENT.MIMETYPE_EXT, MIMETYPES.IMAGE.MIMETYPE_EXT), |
39 | { | 32 | { |
40 | thumbnailfile: CONFIG.STORAGE.THUMBNAILS_DIR, | 33 | thumbnailfile: CONFIG.STORAGE.TMP_DIR, |
41 | previewfile: CONFIG.STORAGE.PREVIEWS_DIR, | 34 | previewfile: CONFIG.STORAGE.TMP_DIR, |
42 | torrentfile: CONFIG.STORAGE.TORRENTS_DIR | 35 | torrentfile: CONFIG.STORAGE.TMP_DIR |
43 | } | 36 | } |
44 | ) | 37 | ) |
45 | 38 | ||
@@ -78,7 +71,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to | |||
78 | 71 | ||
79 | // Rename the torrent to a secured name | 72 | // Rename the torrent to a secured name |
80 | const newTorrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, getSecureTorrentName(torrentName)) | 73 | const newTorrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, getSecureTorrentName(torrentName)) |
81 | await rename(torrentfile.path, newTorrentPath) | 74 | await move(torrentfile.path, newTorrentPath) |
82 | torrentfile.path = newTorrentPath | 75 | torrentfile.path = newTorrentPath |
83 | 76 | ||
84 | const buf = await readFile(torrentfile.path) | 77 | const buf = await readFile(torrentfile.path) |
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 7d55f06b6..76a318d13 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts | |||
@@ -8,14 +8,13 @@ import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../ | |||
8 | import { getFormattedObjects, getServerActor } from '../../../helpers/utils' | 8 | import { getFormattedObjects, getServerActor } from '../../../helpers/utils' |
9 | import { | 9 | import { |
10 | CONFIG, | 10 | CONFIG, |
11 | IMAGE_MIMETYPE_EXT, | 11 | MIMETYPES, |
12 | PREVIEWS_SIZE, | 12 | PREVIEWS_SIZE, |
13 | sequelizeTypescript, | 13 | sequelizeTypescript, |
14 | THUMBNAILS_SIZE, | 14 | THUMBNAILS_SIZE, |
15 | VIDEO_CATEGORIES, | 15 | VIDEO_CATEGORIES, |
16 | VIDEO_LANGUAGES, | 16 | VIDEO_LANGUAGES, |
17 | VIDEO_LICENCES, | 17 | VIDEO_LICENCES, |
18 | VIDEO_MIMETYPE_EXT, | ||
19 | VIDEO_PRIVACIES | 18 | VIDEO_PRIVACIES |
20 | } from '../../../initializers' | 19 | } from '../../../initializers' |
21 | import { | 20 | import { |
@@ -24,19 +23,20 @@ import { | |||
24 | fetchRemoteVideoDescription, | 23 | fetchRemoteVideoDescription, |
25 | getVideoActivityPubUrl | 24 | getVideoActivityPubUrl |
26 | } from '../../../lib/activitypub' | 25 | } from '../../../lib/activitypub' |
27 | import { sendCreateView } from '../../../lib/activitypub/send' | ||
28 | import { JobQueue } from '../../../lib/job-queue' | 26 | import { JobQueue } from '../../../lib/job-queue' |
29 | import { Redis } from '../../../lib/redis' | 27 | import { Redis } from '../../../lib/redis' |
30 | import { | 28 | import { |
31 | asyncMiddleware, | 29 | asyncMiddleware, |
32 | asyncRetryTransactionMiddleware, | 30 | asyncRetryTransactionMiddleware, |
33 | authenticate, | 31 | authenticate, |
32 | checkVideoFollowConstraints, | ||
34 | commonVideosFiltersValidator, | 33 | commonVideosFiltersValidator, |
35 | optionalAuthenticate, | 34 | optionalAuthenticate, |
36 | paginationValidator, | 35 | paginationValidator, |
37 | setDefaultPagination, | 36 | setDefaultPagination, |
38 | setDefaultSort, | 37 | setDefaultSort, |
39 | videosAddValidator, | 38 | videosAddValidator, |
39 | videosCustomGetValidator, | ||
40 | videosGetValidator, | 40 | videosGetValidator, |
41 | videosRemoveValidator, | 41 | videosRemoveValidator, |
42 | videosSortValidator, | 42 | videosSortValidator, |
@@ -56,27 +56,29 @@ import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-u | |||
56 | import { videoCaptionsRouter } from './captions' | 56 | import { videoCaptionsRouter } from './captions' |
57 | import { videoImportsRouter } from './import' | 57 | import { videoImportsRouter } from './import' |
58 | import { resetSequelizeInstance } from '../../../helpers/database-utils' | 58 | import { resetSequelizeInstance } from '../../../helpers/database-utils' |
59 | import { rename } from 'fs-extra' | 59 | import { move } from 'fs-extra' |
60 | import { watchingRouter } from './watching' | 60 | import { watchingRouter } from './watching' |
61 | import { Notifier } from '../../../lib/notifier' | ||
62 | import { sendView } from '../../../lib/activitypub/send/send-view' | ||
61 | 63 | ||
62 | const auditLogger = auditLoggerFactory('videos') | 64 | const auditLogger = auditLoggerFactory('videos') |
63 | const videosRouter = express.Router() | 65 | const videosRouter = express.Router() |
64 | 66 | ||
65 | const reqVideoFileAdd = createReqFiles( | 67 | const reqVideoFileAdd = createReqFiles( |
66 | [ 'videofile', 'thumbnailfile', 'previewfile' ], | 68 | [ 'videofile', 'thumbnailfile', 'previewfile' ], |
67 | Object.assign({}, VIDEO_MIMETYPE_EXT, IMAGE_MIMETYPE_EXT), | 69 | Object.assign({}, MIMETYPES.VIDEO.MIMETYPE_EXT, MIMETYPES.IMAGE.MIMETYPE_EXT), |
68 | { | 70 | { |
69 | videofile: CONFIG.STORAGE.VIDEOS_DIR, | 71 | videofile: CONFIG.STORAGE.TMP_DIR, |
70 | thumbnailfile: CONFIG.STORAGE.THUMBNAILS_DIR, | 72 | thumbnailfile: CONFIG.STORAGE.TMP_DIR, |
71 | previewfile: CONFIG.STORAGE.PREVIEWS_DIR | 73 | previewfile: CONFIG.STORAGE.TMP_DIR |
72 | } | 74 | } |
73 | ) | 75 | ) |
74 | const reqVideoFileUpdate = createReqFiles( | 76 | const reqVideoFileUpdate = createReqFiles( |
75 | [ 'thumbnailfile', 'previewfile' ], | 77 | [ 'thumbnailfile', 'previewfile' ], |
76 | IMAGE_MIMETYPE_EXT, | 78 | MIMETYPES.IMAGE.MIMETYPE_EXT, |
77 | { | 79 | { |
78 | thumbnailfile: CONFIG.STORAGE.THUMBNAILS_DIR, | 80 | thumbnailfile: CONFIG.STORAGE.TMP_DIR, |
79 | previewfile: CONFIG.STORAGE.PREVIEWS_DIR | 81 | previewfile: CONFIG.STORAGE.TMP_DIR |
80 | } | 82 | } |
81 | ) | 83 | ) |
82 | 84 | ||
@@ -122,8 +124,9 @@ videosRouter.get('/:id/description', | |||
122 | ) | 124 | ) |
123 | videosRouter.get('/:id', | 125 | videosRouter.get('/:id', |
124 | optionalAuthenticate, | 126 | optionalAuthenticate, |
125 | asyncMiddleware(videosGetValidator), | 127 | asyncMiddleware(videosCustomGetValidator('only-video-with-rights')), |
126 | getVideo | 128 | asyncMiddleware(checkVideoFollowConstraints), |
129 | asyncMiddleware(getVideo) | ||
127 | ) | 130 | ) |
128 | videosRouter.post('/:id/views', | 131 | videosRouter.post('/:id/views', |
129 | asyncMiddleware(videosGetValidator), | 132 | asyncMiddleware(videosGetValidator), |
@@ -207,7 +210,7 @@ async function addVideo (req: express.Request, res: express.Response) { | |||
207 | // Move physical file | 210 | // Move physical file |
208 | const videoDir = CONFIG.STORAGE.VIDEOS_DIR | 211 | const videoDir = CONFIG.STORAGE.VIDEOS_DIR |
209 | const destination = join(videoDir, video.getVideoFilename(videoFile)) | 212 | const destination = join(videoDir, video.getVideoFilename(videoFile)) |
210 | await rename(videoPhysicalFile.path, destination) | 213 | await move(videoPhysicalFile.path, destination) |
211 | // This is important in case if there is another attempt in the retry process | 214 | // This is important in case if there is another attempt in the retry process |
212 | videoPhysicalFile.filename = video.getVideoFilename(videoFile) | 215 | videoPhysicalFile.filename = video.getVideoFilename(videoFile) |
213 | videoPhysicalFile.path = destination | 216 | videoPhysicalFile.path = destination |
@@ -270,6 +273,8 @@ async function addVideo (req: express.Request, res: express.Response) { | |||
270 | return videoCreated | 273 | return videoCreated |
271 | }) | 274 | }) |
272 | 275 | ||
276 | Notifier.Instance.notifyOnNewVideo(videoCreated) | ||
277 | |||
273 | if (video.state === VideoState.TO_TRANSCODE) { | 278 | if (video.state === VideoState.TO_TRANSCODE) { |
274 | // Put uuid because we don't have id auto incremented for now | 279 | // Put uuid because we don't have id auto incremented for now |
275 | const dataInput = { | 280 | const dataInput = { |
@@ -294,6 +299,7 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
294 | const oldVideoAuditView = new VideoAuditView(videoInstance.toFormattedDetailsJSON()) | 299 | const oldVideoAuditView = new VideoAuditView(videoInstance.toFormattedDetailsJSON()) |
295 | const videoInfoToUpdate: VideoUpdate = req.body | 300 | const videoInfoToUpdate: VideoUpdate = req.body |
296 | const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE | 301 | const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE |
302 | const wasUnlistedVideo = videoInstance.privacy === VideoPrivacy.UNLISTED | ||
297 | 303 | ||
298 | // Process thumbnail or create it from the video | 304 | // Process thumbnail or create it from the video |
299 | if (req.files && req.files['thumbnailfile']) { | 305 | if (req.files && req.files['thumbnailfile']) { |
@@ -308,10 +314,8 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
308 | } | 314 | } |
309 | 315 | ||
310 | try { | 316 | try { |
311 | await sequelizeTypescript.transaction(async t => { | 317 | const videoInstanceUpdated = await sequelizeTypescript.transaction(async t => { |
312 | const sequelizeOptions = { | 318 | const sequelizeOptions = { transaction: t } |
313 | transaction: t | ||
314 | } | ||
315 | const oldVideoChannel = videoInstance.VideoChannel | 319 | const oldVideoChannel = videoInstance.VideoChannel |
316 | 320 | ||
317 | if (videoInfoToUpdate.name !== undefined) videoInstance.set('name', videoInfoToUpdate.name) | 321 | if (videoInfoToUpdate.name !== undefined) videoInstance.set('name', videoInfoToUpdate.name) |
@@ -363,7 +367,11 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
363 | } | 367 | } |
364 | 368 | ||
365 | const isNewVideo = wasPrivateVideo && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE | 369 | const isNewVideo = wasPrivateVideo && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE |
366 | await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t) | 370 | |
371 | // Don't send update if the video was unfederated | ||
372 | if (!videoInstanceUpdated.VideoBlacklist || videoInstanceUpdated.VideoBlacklist.unfederated === false) { | ||
373 | await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t) | ||
374 | } | ||
367 | 375 | ||
368 | auditLogger.update( | 376 | auditLogger.update( |
369 | getAuditIdFromRes(res), | 377 | getAuditIdFromRes(res), |
@@ -371,7 +379,13 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
371 | oldVideoAuditView | 379 | oldVideoAuditView |
372 | ) | 380 | ) |
373 | logger.info('Video with name %s and uuid %s updated.', videoInstance.name, videoInstance.uuid) | 381 | logger.info('Video with name %s and uuid %s updated.', videoInstance.name, videoInstance.uuid) |
382 | |||
383 | return videoInstanceUpdated | ||
374 | }) | 384 | }) |
385 | |||
386 | if (wasUnlistedVideo || wasPrivateVideo) { | ||
387 | Notifier.Instance.notifyOnNewVideo(videoInstanceUpdated) | ||
388 | } | ||
375 | } catch (err) { | 389 | } catch (err) { |
376 | // Force fields we want to update | 390 | // Force fields we want to update |
377 | // If the transaction is retried, sequelize will think the object has not changed | 391 | // If the transaction is retried, sequelize will think the object has not changed |
@@ -384,10 +398,17 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
384 | return res.type('json').status(204).end() | 398 | return res.type('json').status(204).end() |
385 | } | 399 | } |
386 | 400 | ||
387 | function getVideo (req: express.Request, res: express.Response) { | 401 | async function getVideo (req: express.Request, res: express.Response) { |
388 | const videoInstance = res.locals.video | 402 | // We need more attributes |
403 | const userId: number = res.locals.oauth ? res.locals.oauth.token.User.id : null | ||
404 | const video: VideoModel = await VideoModel.loadForGetAPI(res.locals.video.id, undefined, userId) | ||
389 | 405 | ||
390 | return res.json(videoInstance.toFormattedDetailsJSON()) | 406 | if (video.isOutdated()) { |
407 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } }) | ||
408 | .catch(err => logger.error('Cannot create AP refresher job for video %s.', video.url, { err })) | ||
409 | } | ||
410 | |||
411 | return res.json(video.toFormattedDetailsJSON()) | ||
391 | } | 412 | } |
392 | 413 | ||
393 | async function viewVideo (req: express.Request, res: express.Response) { | 414 | async function viewVideo (req: express.Request, res: express.Response) { |
@@ -406,8 +427,7 @@ async function viewVideo (req: express.Request, res: express.Response) { | |||
406 | ]) | 427 | ]) |
407 | 428 | ||
408 | const serverActor = await getServerActor() | 429 | const serverActor = await getServerActor() |
409 | 430 | await sendView(serverActor, videoInstance, undefined) | |
410 | await sendCreateView(serverActor, videoInstance, undefined) | ||
411 | 431 | ||
412 | return res.status(204).end() | 432 | return res.status(204).end() |
413 | } | 433 | } |
@@ -425,7 +445,7 @@ async function getVideoDescription (req: express.Request, res: express.Response) | |||
425 | return res.json({ description }) | 445 | return res.json({ description }) |
426 | } | 446 | } |
427 | 447 | ||
428 | async function listVideos (req: express.Request, res: express.Response, next: express.NextFunction) { | 448 | async function listVideos (req: express.Request, res: express.Response) { |
429 | const resultList = await VideoModel.listForApi({ | 449 | const resultList = await VideoModel.listForApi({ |
430 | start: req.query.start, | 450 | start: req.query.start, |
431 | count: req.query.count, | 451 | count: req.query.count, |
@@ -439,7 +459,7 @@ async function listVideos (req: express.Request, res: express.Response, next: ex | |||
439 | nsfw: buildNSFWFilter(res, req.query.nsfw), | 459 | nsfw: buildNSFWFilter(res, req.query.nsfw), |
440 | filter: req.query.filter as VideoFilter, | 460 | filter: req.query.filter as VideoFilter, |
441 | withFiles: false, | 461 | withFiles: false, |
442 | userId: res.locals.oauth ? res.locals.oauth.token.User.id : undefined | 462 | user: res.locals.oauth ? res.locals.oauth.token.User : undefined |
443 | }) | 463 | }) |
444 | 464 | ||
445 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 465 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
diff --git a/server/controllers/api/videos/rate.ts b/server/controllers/api/videos/rate.ts index dc322bb0c..53952a0a2 100644 --- a/server/controllers/api/videos/rate.ts +++ b/server/controllers/api/videos/rate.ts | |||
@@ -2,8 +2,8 @@ import * as express from 'express' | |||
2 | import { UserVideoRateUpdate } from '../../../../shared' | 2 | import { UserVideoRateUpdate } from '../../../../shared' |
3 | import { logger } from '../../../helpers/logger' | 3 | import { logger } from '../../../helpers/logger' |
4 | import { sequelizeTypescript, VIDEO_RATE_TYPES } from '../../../initializers' | 4 | import { sequelizeTypescript, VIDEO_RATE_TYPES } from '../../../initializers' |
5 | import { sendVideoRateChange } from '../../../lib/activitypub' | 5 | import { getRateUrl, sendVideoRateChange } from '../../../lib/activitypub' |
6 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoRateValidator } from '../../../middlewares' | 6 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoUpdateRateValidator } from '../../../middlewares' |
7 | import { AccountModel } from '../../../models/account/account' | 7 | import { AccountModel } from '../../../models/account/account' |
8 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' | 8 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' |
9 | import { VideoModel } from '../../../models/video/video' | 9 | import { VideoModel } from '../../../models/video/video' |
@@ -12,7 +12,7 @@ const rateVideoRouter = express.Router() | |||
12 | 12 | ||
13 | rateVideoRouter.put('/:id/rate', | 13 | rateVideoRouter.put('/:id/rate', |
14 | authenticate, | 14 | authenticate, |
15 | asyncMiddleware(videoRateValidator), | 15 | asyncMiddleware(videoUpdateRateValidator), |
16 | asyncRetryTransactionMiddleware(rateVideo) | 16 | asyncRetryTransactionMiddleware(rateVideo) |
17 | ) | 17 | ) |
18 | 18 | ||
@@ -28,11 +28,12 @@ async function rateVideo (req: express.Request, res: express.Response) { | |||
28 | const body: UserVideoRateUpdate = req.body | 28 | const body: UserVideoRateUpdate = req.body |
29 | const rateType = body.rating | 29 | const rateType = body.rating |
30 | const videoInstance: VideoModel = res.locals.video | 30 | const videoInstance: VideoModel = res.locals.video |
31 | const userAccount: AccountModel = res.locals.oauth.token.User.Account | ||
31 | 32 | ||
32 | await sequelizeTypescript.transaction(async t => { | 33 | await sequelizeTypescript.transaction(async t => { |
33 | const sequelizeOptions = { transaction: t } | 34 | const sequelizeOptions = { transaction: t } |
34 | 35 | ||
35 | const accountInstance = await AccountModel.load(res.locals.oauth.token.User.Account.id, t) | 36 | const accountInstance = await AccountModel.load(userAccount.id, t) |
36 | const previousRate = await AccountVideoRateModel.load(accountInstance.id, videoInstance.id, t) | 37 | const previousRate = await AccountVideoRateModel.load(accountInstance.id, videoInstance.id, t) |
37 | 38 | ||
38 | let likesToIncrement = 0 | 39 | let likesToIncrement = 0 |
@@ -44,20 +45,22 @@ async function rateVideo (req: express.Request, res: express.Response) { | |||
44 | // There was a previous rate, update it | 45 | // There was a previous rate, update it |
45 | if (previousRate) { | 46 | if (previousRate) { |
46 | // We will remove the previous rate, so we will need to update the video count attribute | 47 | // We will remove the previous rate, so we will need to update the video count attribute |
47 | if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement-- | 48 | if (previousRate.type === 'like') likesToIncrement-- |
48 | else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement-- | 49 | else if (previousRate.type === 'dislike') dislikesToIncrement-- |
49 | 50 | ||
50 | if (rateType === 'none') { // Destroy previous rate | 51 | if (rateType === 'none') { // Destroy previous rate |
51 | await previousRate.destroy(sequelizeOptions) | 52 | await previousRate.destroy(sequelizeOptions) |
52 | } else { // Update previous rate | 53 | } else { // Update previous rate |
53 | previousRate.type = rateType | 54 | previousRate.type = rateType |
55 | previousRate.url = getRateUrl(rateType, userAccount.Actor, videoInstance) | ||
54 | await previousRate.save(sequelizeOptions) | 56 | await previousRate.save(sequelizeOptions) |
55 | } | 57 | } |
56 | } else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate | 58 | } else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate |
57 | const query = { | 59 | const query = { |
58 | accountId: accountInstance.id, | 60 | accountId: accountInstance.id, |
59 | videoId: videoInstance.id, | 61 | videoId: videoInstance.id, |
60 | type: rateType | 62 | type: rateType, |
63 | url: getRateUrl(rateType, userAccount.Actor, videoInstance) | ||
61 | } | 64 | } |
62 | 65 | ||
63 | await AccountVideoRateModel.create(query, sequelizeOptions) | 66 | await AccountVideoRateModel.create(query, sequelizeOptions) |