From 6040f87d143a5fa01db79867ece8197c3ce7be47 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 4 Dec 2018 16:02:49 +0100 Subject: Add tmp and redundancy directories --- server/controllers/api/users/me.ts | 4 ++-- server/controllers/api/video-channel.ts | 2 +- server/controllers/api/videos/import.ts | 6 +++--- server/controllers/api/videos/index.ts | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index 82299747d..47f2c9ec7 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts @@ -42,7 +42,7 @@ import { AccountModel } from '../../../models/account/account' const auditLogger = auditLoggerFactory('users-me') -const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR }) +const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.TMP_DIR }) const meRouter = express.Router() @@ -348,7 +348,7 @@ async function updateMe (req: express.Request, res: express.Response, next: expr return res.sendStatus(204) } -async function updateMyAvatar (req: express.Request, res: express.Response, next: express.NextFunction) { +async function updateMyAvatar (req: express.Request, res: express.Response) { const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ] const user: UserModel = res.locals.oauth.token.user const oldUserAuditView = new UserAuditView(user.toFormattedJSON()) diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index 9bf3c5fd8..63240dfa1 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts @@ -32,7 +32,7 @@ import { resetSequelizeInstance } from '../../helpers/database-utils' import { UserModel } from '../../models/account/user' const auditLogger = auditLoggerFactory('channels') -const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR }) +const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.TMP_DIR }) const videoChannelRouter = express.Router() diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index 398fd5a7f..f27d648c7 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts @@ -37,9 +37,9 @@ const reqVideoFileImport = createReqFiles( [ 'thumbnailfile', 'previewfile', 'torrentfile' ], Object.assign({}, TORRENT_MIMETYPE_EXT, IMAGE_MIMETYPE_EXT), { - thumbnailfile: CONFIG.STORAGE.THUMBNAILS_DIR, - previewfile: CONFIG.STORAGE.PREVIEWS_DIR, - torrentfile: CONFIG.STORAGE.TORRENTS_DIR + thumbnailfile: CONFIG.STORAGE.TMP_DIR, + previewfile: CONFIG.STORAGE.TMP_DIR, + torrentfile: CONFIG.STORAGE.TMP_DIR } ) diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 3d1b2e1a2..4e4697ef4 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -67,17 +67,17 @@ const reqVideoFileAdd = createReqFiles( [ 'videofile', 'thumbnailfile', 'previewfile' ], Object.assign({}, VIDEO_MIMETYPE_EXT, IMAGE_MIMETYPE_EXT), { - videofile: CONFIG.STORAGE.VIDEOS_DIR, - thumbnailfile: CONFIG.STORAGE.THUMBNAILS_DIR, - previewfile: CONFIG.STORAGE.PREVIEWS_DIR + videofile: CONFIG.STORAGE.TMP_DIR, + thumbnailfile: CONFIG.STORAGE.TMP_DIR, + previewfile: CONFIG.STORAGE.TMP_DIR } ) const reqVideoFileUpdate = createReqFiles( [ 'thumbnailfile', 'previewfile' ], IMAGE_MIMETYPE_EXT, { - thumbnailfile: CONFIG.STORAGE.THUMBNAILS_DIR, - previewfile: CONFIG.STORAGE.PREVIEWS_DIR + thumbnailfile: CONFIG.STORAGE.TMP_DIR, + previewfile: CONFIG.STORAGE.TMP_DIR } ) -- cgit v1.2.3 From 4e74e8032be8293ffe3cb3c30528d4ef7c11a798 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 5 Dec 2018 14:36:05 +0100 Subject: Remove inferred type --- server/controllers/api/accounts.ts | 4 ++-- server/controllers/api/users/me.ts | 2 +- server/controllers/api/video-channel.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/accounts.ts b/server/controllers/api/accounts.ts index 86ef2aed1..a69a83acf 100644 --- a/server/controllers/api/accounts.ts +++ b/server/controllers/api/accounts.ts @@ -74,10 +74,10 @@ async function listVideoAccountChannels (req: express.Request, res: express.Resp async function listAccountVideos (req: express.Request, res: express.Response, next: express.NextFunction) { const account: AccountModel = res.locals.account - const actorId = isUserAbleToSearchRemoteURI(res) ? null : undefined + const followerActorId = isUserAbleToSearchRemoteURI(res) ? null : undefined const resultList = await VideoModel.listForApi({ - actorId, + followerActorId, start: req.query.start, count: req.query.count, sort: req.query.sort, diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index 47f2c9ec7..d2456346b 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts @@ -238,7 +238,7 @@ async function getUserSubscriptionVideos (req: express.Request, res: express.Res nsfw: buildNSFWFilter(res, req.query.nsfw), filter: req.query.filter as VideoFilter, withFiles: false, - actorId: user.Account.Actor.id, + followerActorId: user.Account.Actor.id, user }) diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index 63240dfa1..fd143a139 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts @@ -202,10 +202,10 @@ async function getVideoChannel (req: express.Request, res: express.Response, nex async function listVideoChannelVideos (req: express.Request, res: express.Response, next: express.NextFunction) { const videoChannelInstance: VideoChannelModel = res.locals.videoChannel - const actorId = isUserAbleToSearchRemoteURI(res) ? null : undefined + const followerActorId = isUserAbleToSearchRemoteURI(res) ? null : undefined const resultList = await VideoModel.listForApi({ - actorId, + followerActorId, start: req.query.start, count: req.query.count, sort: req.query.sort, -- cgit v1.2.3 From 3b3b18203fe73e499bf8b49b15369710df95993e Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 5 Dec 2018 15:10:45 +0100 Subject: Add error when email system is not configured and using the forgot password system --- server/controllers/api/config.ts | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'server/controllers/api') diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 5233e9f68..d65e321e9 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts @@ -11,6 +11,7 @@ import { ClientHtml } from '../../lib/client-html' import { auditLoggerFactory, CustomConfigAuditView, getAuditIdFromRes } from '../../helpers/audit-logger' import { remove, writeJSON } from 'fs-extra' import { getServerCommit } from '../../helpers/utils' +import { Emailer } from '../../lib/emailer' const packageJSON = require('../../../../package.json') const configRouter = express.Router() @@ -61,6 +62,9 @@ async function getConfig (req: express.Request, res: express.Response) { css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS } }, + email: { + enabled: Emailer.Instance.isEnabled() + }, serverVersion: packageJSON.version, serverCommit, signup: { -- cgit v1.2.3 From 14e2014acc1362cfbb770c051a7254b156cd8efb Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 11 Dec 2018 14:52:50 +0100 Subject: Support additional video extensions --- server/controllers/api/config.ts | 5 ++++- server/controllers/api/users/me.ts | 4 ++-- server/controllers/api/video-channel.ts | 4 ++-- server/controllers/api/videos/captions.ts | 4 ++-- server/controllers/api/videos/import.ts | 11 ++--------- server/controllers/api/videos/index.ts | 12 +++++------- 6 files changed, 17 insertions(+), 23 deletions(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index d65e321e9..c75002aaf 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts @@ -172,7 +172,8 @@ async function updateCustomConfig (req: express.Request, res: express.Response, 'instance.defaultClientRoute', 'instance.shortDescription', 'cache.videoCaptions', - 'signup.requiresEmailVerification' + 'signup.requiresEmailVerification', + 'transcoding.allowAdditionalExtensions' ) toUpdateJSON.user['video_quota'] = toUpdate.user.videoQuota toUpdateJSON.user['video_quota_daily'] = toUpdate.user.videoQuotaDaily @@ -180,6 +181,7 @@ async function updateCustomConfig (req: express.Request, res: express.Response, toUpdateJSON.instance['short_description'] = toUpdate.instance.shortDescription toUpdateJSON.instance['default_nsfw_policy'] = toUpdate.instance.defaultNSFWPolicy toUpdateJSON.signup['requires_email_verification'] = toUpdate.signup.requiresEmailVerification + toUpdateJSON.transcoding['allow_additional_extensions'] = toUpdate.transcoding.allowAdditionalExtensions await writeJSON(CONFIG.CUSTOM_FILE, toUpdateJSON, { spaces: 2 }) @@ -247,6 +249,7 @@ function customConfig (): CustomConfig { }, transcoding: { enabled: CONFIG.TRANSCODING.ENABLED, + allowAdditionalExtensions: CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS, threads: CONFIG.TRANSCODING.THREADS, resolutions: { '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ], diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index d2456346b..f712b0f0b 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts @@ -2,7 +2,7 @@ import * as express from 'express' import 'multer' import { UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../../shared' import { getFormattedObjects } from '../../../helpers/utils' -import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../../initializers' +import { CONFIG, MIMETYPES, sequelizeTypescript } from '../../../initializers' import { sendUpdateActor } from '../../../lib/activitypub/send' import { asyncMiddleware, @@ -42,7 +42,7 @@ import { AccountModel } from '../../../models/account/account' const auditLogger = auditLoggerFactory('users-me') -const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.TMP_DIR }) +const reqAvatarFile = createReqFiles([ 'avatarfile' ], MIMETYPES.IMAGE.MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.TMP_DIR }) const meRouter = express.Router() diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index fd143a139..3d6a6af7f 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts @@ -22,7 +22,7 @@ import { createVideoChannel } from '../../lib/video-channel' import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' import { setAsyncActorKeys } from '../../lib/activitypub' import { AccountModel } from '../../models/account/account' -import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../initializers' +import { CONFIG, MIMETYPES, sequelizeTypescript } from '../../initializers' import { logger } from '../../helpers/logger' import { VideoModel } from '../../models/video/video' import { updateAvatarValidator } from '../../middlewares/validators/avatar' @@ -32,7 +32,7 @@ import { resetSequelizeInstance } from '../../helpers/database-utils' import { UserModel } from '../../models/account/user' const auditLogger = auditLoggerFactory('channels') -const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.TMP_DIR }) +const reqAvatarFile = createReqFiles([ 'avatarfile' ], MIMETYPES.IMAGE.MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.TMP_DIR }) const videoChannelRouter = express.Router() 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' import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate } from '../../../middlewares' import { addVideoCaptionValidator, deleteVideoCaptionValidator, listVideoCaptionsValidator } from '../../../middlewares/validators' import { createReqFiles } from '../../../helpers/express-utils' -import { CONFIG, sequelizeTypescript, VIDEO_CAPTIONS_MIMETYPE_EXT } from '../../../initializers' +import { CONFIG, MIMETYPES, sequelizeTypescript } from '../../../initializers' import { getFormattedObjects } from '../../../helpers/utils' import { VideoCaptionModel } from '../../../models/video/video-caption' import { VideoModel } from '../../../models/video/video' @@ -12,7 +12,7 @@ import { moveAndProcessCaptionFile } from '../../../helpers/captions-utils' const reqVideoCaptionAdd = createReqFiles( [ 'captionfile' ], - VIDEO_CAPTIONS_MIMETYPE_EXT, + MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT, { captionfile: CONFIG.STORAGE.CAPTIONS_DIR } diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index f27d648c7..099ab7b8d 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' import 'multer' import { auditLoggerFactory, getAuditIdFromRes, VideoImportAuditView } from '../../../helpers/audit-logger' import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoImportAddValidator } from '../../../middlewares' -import { - CONFIG, - IMAGE_MIMETYPE_EXT, - PREVIEWS_SIZE, - sequelizeTypescript, - THUMBNAILS_SIZE, - TORRENT_MIMETYPE_EXT -} from '../../../initializers' +import { CONFIG, MIMETYPES, PREVIEWS_SIZE, sequelizeTypescript, THUMBNAILS_SIZE } from '../../../initializers' import { getYoutubeDLInfo, YoutubeDLInfo } from '../../../helpers/youtube-dl' import { createReqFiles } from '../../../helpers/express-utils' import { logger } from '../../../helpers/logger' @@ -35,7 +28,7 @@ const videoImportsRouter = express.Router() const reqVideoFileImport = createReqFiles( [ 'thumbnailfile', 'previewfile', 'torrentfile' ], - Object.assign({}, TORRENT_MIMETYPE_EXT, IMAGE_MIMETYPE_EXT), + Object.assign({}, MIMETYPES.TORRENT.MIMETYPE_EXT, MIMETYPES.IMAGE.MIMETYPE_EXT), { thumbnailfile: CONFIG.STORAGE.TMP_DIR, previewfile: CONFIG.STORAGE.TMP_DIR, diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 4e4697ef4..00a1302d1 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -7,15 +7,13 @@ import { logger } from '../../../helpers/logger' import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' import { getFormattedObjects, getServerActor } from '../../../helpers/utils' import { - CONFIG, - IMAGE_MIMETYPE_EXT, + CONFIG, MIMETYPES, PREVIEWS_SIZE, sequelizeTypescript, THUMBNAILS_SIZE, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, - VIDEO_MIMETYPE_EXT, VIDEO_PRIVACIES } from '../../../initializers' import { @@ -57,7 +55,7 @@ import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-u import { videoCaptionsRouter } from './captions' import { videoImportsRouter } from './import' import { resetSequelizeInstance } from '../../../helpers/database-utils' -import { rename } from 'fs-extra' +import { move } from 'fs-extra' import { watchingRouter } from './watching' const auditLogger = auditLoggerFactory('videos') @@ -65,7 +63,7 @@ const videosRouter = express.Router() const reqVideoFileAdd = createReqFiles( [ 'videofile', 'thumbnailfile', 'previewfile' ], - Object.assign({}, VIDEO_MIMETYPE_EXT, IMAGE_MIMETYPE_EXT), + Object.assign({}, MIMETYPES.VIDEO.MIMETYPE_EXT, MIMETYPES.IMAGE.MIMETYPE_EXT), { videofile: CONFIG.STORAGE.TMP_DIR, thumbnailfile: CONFIG.STORAGE.TMP_DIR, @@ -74,7 +72,7 @@ const reqVideoFileAdd = createReqFiles( ) const reqVideoFileUpdate = createReqFiles( [ 'thumbnailfile', 'previewfile' ], - IMAGE_MIMETYPE_EXT, + MIMETYPES.IMAGE.MIMETYPE_EXT, { thumbnailfile: CONFIG.STORAGE.TMP_DIR, previewfile: CONFIG.STORAGE.TMP_DIR @@ -208,7 +206,7 @@ async function addVideo (req: express.Request, res: express.Response) { // Move physical file const videoDir = CONFIG.STORAGE.VIDEOS_DIR const destination = join(videoDir, video.getVideoFilename(videoFile)) - await rename(videoPhysicalFile.path, destination) + await move(videoPhysicalFile.path, destination) // This is important in case if there is another attempt in the retry process videoPhysicalFile.filename = video.getVideoFilename(videoFile) videoPhysicalFile.path = destination -- cgit v1.2.3 From f481c4f9f31e897a08e818f388fecdee07f57142 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 11 Dec 2018 15:12:38 +0100 Subject: Use move instead rename To avoid EXDEV errors --- server/controllers/api/videos/import.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index 099ab7b8d..98366cd82 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts @@ -21,7 +21,7 @@ import { VideoChannelModel } from '../../../models/video/video-channel' import * as Bluebird from 'bluebird' import * as parseTorrent from 'parse-torrent' import { getSecureTorrentName } from '../../../helpers/utils' -import { readFile, rename } from 'fs-extra' +import { readFile, move } from 'fs-extra' const auditLogger = auditLoggerFactory('video-imports') const videoImportsRouter = express.Router() @@ -71,7 +71,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to // Rename the torrent to a secured name const newTorrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, getSecureTorrentName(torrentName)) - await rename(torrentfile.path, newTorrentPath) + await move(torrentfile.path, newTorrentPath) torrentfile.path = newTorrentPath const buf = await readFile(torrentfile.path) -- cgit v1.2.3 From 8b9a525a180cc9f3a98c334cc052dcfc8f36dcd4 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 17 Dec 2018 15:52:38 +0100 Subject: Add history on server side Add ability to disable, clear and list user videos history --- server/controllers/api/users/index.ts | 2 ++ server/controllers/api/users/me.ts | 1 + server/controllers/api/users/my-history.ts | 57 ++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 server/controllers/api/users/my-history.ts (limited to 'server/controllers/api') diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index 87fab4a40..bc24792a2 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts @@ -38,6 +38,7 @@ import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../h import { meRouter } from './me' import { deleteUserToken } from '../../../lib/oauth-model' import { myBlocklistRouter } from './my-blocklist' +import { myVideosHistoryRouter } from './my-history' const auditLogger = auditLoggerFactory('users') @@ -55,6 +56,7 @@ const askSendEmailLimiter = new RateLimit({ const usersRouter = express.Router() usersRouter.use('/', myBlocklistRouter) +usersRouter.use('/', myVideosHistoryRouter) usersRouter.use('/', meRouter) usersRouter.get('/autocomplete', diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index f712b0f0b..8a3208160 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts @@ -330,6 +330,7 @@ async function updateMe (req: express.Request, res: express.Response, next: expr if (body.nsfwPolicy !== undefined) user.nsfwPolicy = body.nsfwPolicy if (body.webTorrentEnabled !== undefined) user.webTorrentEnabled = body.webTorrentEnabled if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo + if (body.videosHistoryEnabled !== undefined) user.videosHistoryEnabled = body.videosHistoryEnabled await sequelizeTypescript.transaction(async t => { const userAccount = await AccountModel.load(user.Account.id) diff --git a/server/controllers/api/users/my-history.ts b/server/controllers/api/users/my-history.ts new file mode 100644 index 000000000..6cd782c47 --- /dev/null +++ b/server/controllers/api/users/my-history.ts @@ -0,0 +1,57 @@ +import * as express from 'express' +import { + asyncMiddleware, + asyncRetryTransactionMiddleware, + authenticate, + paginationValidator, + setDefaultPagination, + userHistoryRemoveValidator +} from '../../../middlewares' +import { UserModel } from '../../../models/account/user' +import { getFormattedObjects } from '../../../helpers/utils' +import { UserVideoHistoryModel } from '../../../models/account/user-video-history' +import { sequelizeTypescript } from '../../../initializers' + +const myVideosHistoryRouter = express.Router() + +myVideosHistoryRouter.get('/me/history/videos', + authenticate, + paginationValidator, + setDefaultPagination, + asyncMiddleware(listMyVideosHistory) +) + +myVideosHistoryRouter.post('/me/history/videos/remove', + authenticate, + userHistoryRemoveValidator, + asyncRetryTransactionMiddleware(removeUserHistory) +) + +// --------------------------------------------------------------------------- + +export { + myVideosHistoryRouter +} + +// --------------------------------------------------------------------------- + +async function listMyVideosHistory (req: express.Request, res: express.Response) { + const user: UserModel = res.locals.oauth.token.User + + const resultList = await UserVideoHistoryModel.listForApi(user, req.query.start, req.query.count) + + return res.json(getFormattedObjects(resultList.data, resultList.total)) +} + +async function removeUserHistory (req: express.Request, res: express.Response) { + const user: UserModel = res.locals.oauth.token.User + const beforeDate = req.body.beforeDate || null + + await sequelizeTypescript.transaction(t => { + return UserVideoHistoryModel.removeHistoryBefore(user, beforeDate, t) + }) + + // Do not send the delete to other instances, we delete OUR copy of this video abuse + + return res.type('json').status(204).end() +} -- cgit v1.2.3 From cef534ed53e4518fe0acf581bfe880788d42fc36 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 26 Dec 2018 10:36:24 +0100 Subject: Add user notification base code --- server/controllers/api/users/index.ts | 2 + server/controllers/api/users/my-notifications.ts | 84 ++++++++++++++++++++++++ server/controllers/api/videos/abuse.ts | 3 + server/controllers/api/videos/blacklist.ts | 14 +++- server/controllers/api/videos/comment.ts | 3 + server/controllers/api/videos/index.ts | 10 ++- 6 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 server/controllers/api/users/my-notifications.ts (limited to 'server/controllers/api') diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index bc24792a2..98be46ea2 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts @@ -39,6 +39,7 @@ import { meRouter } from './me' import { deleteUserToken } from '../../../lib/oauth-model' import { myBlocklistRouter } from './my-blocklist' import { myVideosHistoryRouter } from './my-history' +import { myNotificationsRouter } from './my-notifications' const auditLogger = auditLoggerFactory('users') @@ -55,6 +56,7 @@ const askSendEmailLimiter = new RateLimit({ }) const usersRouter = express.Router() +usersRouter.use('/', myNotificationsRouter) usersRouter.use('/', myBlocklistRouter) usersRouter.use('/', myVideosHistoryRouter) usersRouter.use('/', meRouter) diff --git a/server/controllers/api/users/my-notifications.ts b/server/controllers/api/users/my-notifications.ts new file mode 100644 index 000000000..cef1d237c --- /dev/null +++ b/server/controllers/api/users/my-notifications.ts @@ -0,0 +1,84 @@ +import * as express from 'express' +import 'multer' +import { + asyncMiddleware, + asyncRetryTransactionMiddleware, + authenticate, + paginationValidator, + setDefaultPagination, + setDefaultSort, + userNotificationsSortValidator +} from '../../../middlewares' +import { UserModel } from '../../../models/account/user' +import { getFormattedObjects } from '../../../helpers/utils' +import { UserNotificationModel } from '../../../models/account/user-notification' +import { meRouter } from './me' +import { + markAsReadUserNotificationsValidator, + updateNotificationSettingsValidator +} from '../../../middlewares/validators/user-notifications' +import { UserNotificationSetting } from '../../../../shared/models/users' +import { UserNotificationSettingModel } from '../../../models/account/user-notification-setting' + +const myNotificationsRouter = express.Router() + +meRouter.put('/me/notification-settings', + authenticate, + updateNotificationSettingsValidator, + asyncRetryTransactionMiddleware(updateNotificationSettings) +) + +myNotificationsRouter.get('/me/notifications', + authenticate, + paginationValidator, + userNotificationsSortValidator, + setDefaultSort, + setDefaultPagination, + asyncMiddleware(listUserNotifications) +) + +myNotificationsRouter.post('/me/notifications/read', + authenticate, + markAsReadUserNotificationsValidator, + asyncMiddleware(markAsReadUserNotifications) +) + +export { + myNotificationsRouter +} + +// --------------------------------------------------------------------------- + +async function updateNotificationSettings (req: express.Request, res: express.Response) { + const user: UserModel = res.locals.oauth.token.User + const body: UserNotificationSetting = req.body + + const query = { + where: { + userId: user.id + } + } + + await UserNotificationSettingModel.update({ + newVideoFromSubscription: body.newVideoFromSubscription, + newCommentOnMyVideo: body.newCommentOnMyVideo + }, query) + + return res.status(204).end() +} + +async function listUserNotifications (req: express.Request, res: express.Response) { + const user: UserModel = res.locals.oauth.token.User + + const resultList = await UserNotificationModel.listForApi(user.id, req.query.start, req.query.count, req.query.sort) + + return res.json(getFormattedObjects(resultList.data, resultList.total)) +} + +async function markAsReadUserNotifications (req: express.Request, res: express.Response) { + const user: UserModel = res.locals.oauth.token.User + + await UserNotificationModel.markAsRead(user.id, req.body.ids) + + return res.status(204).end() +} diff --git a/server/controllers/api/videos/abuse.ts b/server/controllers/api/videos/abuse.ts index d0c81804b..fe0a95cd5 100644 --- a/server/controllers/api/videos/abuse.ts +++ b/server/controllers/api/videos/abuse.ts @@ -22,6 +22,7 @@ import { VideoModel } from '../../../models/video/video' import { VideoAbuseModel } from '../../../models/video/video-abuse' import { auditLoggerFactory, VideoAbuseAuditView } from '../../../helpers/audit-logger' import { UserModel } from '../../../models/account/user' +import { Notifier } from '../../../lib/notifier' const auditLogger = auditLoggerFactory('abuse') const abuseVideoRouter = express.Router() @@ -117,6 +118,8 @@ async function reportVideoAbuse (req: express.Request, res: express.Response) { await sendVideoAbuse(reporterAccount.Actor, videoAbuseInstance, videoInstance) } + Notifier.Instance.notifyOnNewVideoAbuse(videoAbuseInstance) + auditLogger.create(reporterAccount.Actor.getIdentifier(), new VideoAbuseAuditView(videoAbuseInstance.toFormattedJSON())) return videoAbuseInstance diff --git a/server/controllers/api/videos/blacklist.ts b/server/controllers/api/videos/blacklist.ts index 7f803c8e9..9ef08812b 100644 --- a/server/controllers/api/videos/blacklist.ts +++ b/server/controllers/api/videos/blacklist.ts @@ -16,6 +16,8 @@ import { } from '../../../middlewares' import { VideoBlacklistModel } from '../../../models/video/video-blacklist' import { sequelizeTypescript } from '../../../initializers' +import { Notifier } from '../../../lib/notifier' +import { VideoModel } from '../../../models/video/video' const blacklistRouter = express.Router() @@ -67,13 +69,18 @@ async function addVideoToBlacklist (req: express.Request, res: express.Response) reason: body.reason } - await VideoBlacklistModel.create(toCreate) + const blacklist = await VideoBlacklistModel.create(toCreate) + blacklist.Video = videoInstance + + Notifier.Instance.notifyOnVideoBlacklist(blacklist) + + logger.info('Video %s blacklisted.', res.locals.video.uuid) + return res.type('json').status(204).end() } async function updateVideoBlacklistController (req: express.Request, res: express.Response) { const videoBlacklist = res.locals.videoBlacklist as VideoBlacklistModel - logger.info(videoBlacklist) if (req.body.reason !== undefined) videoBlacklist.reason = req.body.reason @@ -92,11 +99,14 @@ async function listBlacklist (req: express.Request, res: express.Response, next: async function removeVideoFromBlacklistController (req: express.Request, res: express.Response, next: express.NextFunction) { const videoBlacklist = res.locals.videoBlacklist as VideoBlacklistModel + const video: VideoModel = res.locals.video await sequelizeTypescript.transaction(t => { return videoBlacklist.destroy({ transaction: t }) }) + Notifier.Instance.notifyOnVideoUnblacklist(video) + logger.info('Video %s removed from blacklist.', res.locals.video.uuid) return res.type('json').status(204).end() diff --git a/server/controllers/api/videos/comment.ts b/server/controllers/api/videos/comment.ts index 3875c8f79..70c1148ba 100644 --- a/server/controllers/api/videos/comment.ts +++ b/server/controllers/api/videos/comment.ts @@ -26,6 +26,7 @@ import { VideoCommentModel } from '../../../models/video/video-comment' import { auditLoggerFactory, CommentAuditView, getAuditIdFromRes } from '../../../helpers/audit-logger' import { AccountModel } from '../../../models/account/account' import { UserModel } from '../../../models/account/user' +import { Notifier } from '../../../lib/notifier' const auditLogger = auditLoggerFactory('comments') const videoCommentRouter = express.Router() @@ -119,6 +120,7 @@ async function addVideoCommentThread (req: express.Request, res: express.Respons }, t) }) + Notifier.Instance.notifyOnNewComment(comment) auditLogger.create(getAuditIdFromRes(res), new CommentAuditView(comment.toFormattedJSON())) return res.json({ @@ -140,6 +142,7 @@ async function addVideoCommentReply (req: express.Request, res: express.Response }, t) }) + Notifier.Instance.notifyOnNewComment(comment) auditLogger.create(getAuditIdFromRes(res), new CommentAuditView(comment.toFormattedJSON())) return res.json({ comment: comment.toFormattedJSON() }).end() diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 00a1302d1..94ed08fed 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -7,7 +7,8 @@ import { logger } from '../../../helpers/logger' import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' import { getFormattedObjects, getServerActor } from '../../../helpers/utils' import { - CONFIG, MIMETYPES, + CONFIG, + MIMETYPES, PREVIEWS_SIZE, sequelizeTypescript, THUMBNAILS_SIZE, @@ -57,6 +58,7 @@ import { videoImportsRouter } from './import' import { resetSequelizeInstance } from '../../../helpers/database-utils' import { move } from 'fs-extra' import { watchingRouter } from './watching' +import { Notifier } from '../../../lib/notifier' const auditLogger = auditLoggerFactory('videos') const videosRouter = express.Router() @@ -262,6 +264,7 @@ async function addVideo (req: express.Request, res: express.Response) { } await federateVideoIfNeeded(video, true, t) + Notifier.Instance.notifyOnNewVideo(video) auditLogger.create(getAuditIdFromRes(res), new VideoAuditView(videoCreated.toFormattedDetailsJSON())) logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoCreated.uuid) @@ -293,6 +296,7 @@ async function updateVideo (req: express.Request, res: express.Response) { const oldVideoAuditView = new VideoAuditView(videoInstance.toFormattedDetailsJSON()) const videoInfoToUpdate: VideoUpdate = req.body const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE + const wasUnlistedVideo = videoInstance.privacy === VideoPrivacy.UNLISTED // Process thumbnail or create it from the video if (req.files && req.files['thumbnailfile']) { @@ -363,6 +367,10 @@ async function updateVideo (req: express.Request, res: express.Response) { const isNewVideo = wasPrivateVideo && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t) + if (wasUnlistedVideo || wasPrivateVideo) { + Notifier.Instance.notifyOnNewVideo(videoInstanceUpdated) + } + auditLogger.update( getAuditIdFromRes(res), new VideoAuditView(videoInstanceUpdated.toFormattedDetailsJSON()), -- cgit v1.2.3 From e8d246d5267ea8b6b3114d4bcf4f34fe5f3a5241 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 28 Dec 2018 13:47:17 +0100 Subject: Add notification settings migration --- server/controllers/api/videos/index.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 94ed08fed..33521a8c1 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -264,7 +264,6 @@ async function addVideo (req: express.Request, res: express.Response) { } await federateVideoIfNeeded(video, true, t) - Notifier.Instance.notifyOnNewVideo(video) auditLogger.create(getAuditIdFromRes(res), new VideoAuditView(videoCreated.toFormattedDetailsJSON())) logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoCreated.uuid) @@ -272,6 +271,8 @@ async function addVideo (req: express.Request, res: express.Response) { return videoCreated }) + Notifier.Instance.notifyOnNewVideo(videoCreated) + if (video.state === VideoState.TO_TRANSCODE) { // Put uuid because we don't have id auto incremented for now const dataInput = { @@ -311,10 +312,8 @@ async function updateVideo (req: express.Request, res: express.Response) { } try { - await sequelizeTypescript.transaction(async t => { - const sequelizeOptions = { - transaction: t - } + const videoInstanceUpdated = await sequelizeTypescript.transaction(async t => { + const sequelizeOptions = { transaction: t } const oldVideoChannel = videoInstance.VideoChannel if (videoInfoToUpdate.name !== undefined) videoInstance.set('name', videoInfoToUpdate.name) @@ -367,17 +366,19 @@ async function updateVideo (req: express.Request, res: express.Response) { const isNewVideo = wasPrivateVideo && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t) - if (wasUnlistedVideo || wasPrivateVideo) { - Notifier.Instance.notifyOnNewVideo(videoInstanceUpdated) - } - auditLogger.update( getAuditIdFromRes(res), new VideoAuditView(videoInstanceUpdated.toFormattedDetailsJSON()), oldVideoAuditView ) logger.info('Video with name %s and uuid %s updated.', videoInstance.name, videoInstance.uuid) + + return videoInstanceUpdated }) + + if (wasUnlistedVideo || wasPrivateVideo) { + Notifier.Instance.notifyOnNewVideo(videoInstanceUpdated) + } } catch (err) { // Force fields we want to update // If the transaction is retried, sequelize will think the object has not changed -- cgit v1.2.3 From dc13348070d808d0ba3feb56a435b835c2e7e791 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 2 Jan 2019 16:37:43 +0100 Subject: Add import finished and video published notifs --- server/controllers/api/users/my-notifications.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/users/my-notifications.ts b/server/controllers/api/users/my-notifications.ts index cef1d237c..4b81777a4 100644 --- a/server/controllers/api/users/my-notifications.ts +++ b/server/controllers/api/users/my-notifications.ts @@ -14,10 +14,11 @@ import { getFormattedObjects } from '../../../helpers/utils' import { UserNotificationModel } from '../../../models/account/user-notification' import { meRouter } from './me' import { + listUserNotificationsValidator, markAsReadUserNotificationsValidator, updateNotificationSettingsValidator } from '../../../middlewares/validators/user-notifications' -import { UserNotificationSetting } from '../../../../shared/models/users' +import { UserNotificationSetting, UserNotificationSettingValue } from '../../../../shared/models/users' import { UserNotificationSettingModel } from '../../../models/account/user-notification-setting' const myNotificationsRouter = express.Router() @@ -34,6 +35,7 @@ myNotificationsRouter.get('/me/notifications', userNotificationsSortValidator, setDefaultSort, setDefaultPagination, + listUserNotificationsValidator, asyncMiddleware(listUserNotifications) ) @@ -61,7 +63,11 @@ async function updateNotificationSettings (req: express.Request, res: express.Re await UserNotificationSettingModel.update({ newVideoFromSubscription: body.newVideoFromSubscription, - newCommentOnMyVideo: body.newCommentOnMyVideo + newCommentOnMyVideo: body.newCommentOnMyVideo, + videoAbuseAsModerator: body.videoAbuseAsModerator, + blacklistOnMyVideo: body.blacklistOnMyVideo, + myVideoPublished: body.myVideoPublished, + myVideoImportFinished: body.myVideoImportFinished }, query) return res.status(204).end() @@ -70,7 +76,7 @@ async function updateNotificationSettings (req: express.Request, res: express.Re async function listUserNotifications (req: express.Request, res: express.Response) { const user: UserModel = res.locals.oauth.token.User - const resultList = await UserNotificationModel.listForApi(user.id, req.query.start, req.query.count, req.query.sort) + const resultList = await UserNotificationModel.listForApi(user.id, req.query.start, req.query.count, req.query.sort, req.query.unread) return res.json(getFormattedObjects(resultList.data, resultList.total)) } -- cgit v1.2.3 From f7cc67b455a12ccae9b0ea16876d166720364357 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 4 Jan 2019 08:56:20 +0100 Subject: Add new follow, mention and user registered notifs --- server/controllers/api/users/index.ts | 3 +++ server/controllers/api/users/my-notifications.ts | 15 ++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index 98be46ea2..9e6a019f6 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts @@ -40,6 +40,7 @@ import { deleteUserToken } from '../../../lib/oauth-model' import { myBlocklistRouter } from './my-blocklist' import { myVideosHistoryRouter } from './my-history' import { myNotificationsRouter } from './my-notifications' +import { Notifier } from '../../../lib/notifier' const auditLogger = auditLoggerFactory('users') @@ -213,6 +214,8 @@ async function registerUser (req: express.Request, res: express.Response) { await sendVerifyUserEmail(user) } + Notifier.Instance.notifyOnNewUserRegistration(user) + return res.type('json').status(204).end() } diff --git a/server/controllers/api/users/my-notifications.ts b/server/controllers/api/users/my-notifications.ts index 4b81777a4..d74d26add 100644 --- a/server/controllers/api/users/my-notifications.ts +++ b/server/controllers/api/users/my-notifications.ts @@ -18,7 +18,7 @@ import { markAsReadUserNotificationsValidator, updateNotificationSettingsValidator } from '../../../middlewares/validators/user-notifications' -import { UserNotificationSetting, UserNotificationSettingValue } from '../../../../shared/models/users' +import { UserNotificationSetting } from '../../../../shared/models/users' import { UserNotificationSettingModel } from '../../../models/account/user-notification-setting' const myNotificationsRouter = express.Router() @@ -53,7 +53,7 @@ export { async function updateNotificationSettings (req: express.Request, res: express.Response) { const user: UserModel = res.locals.oauth.token.User - const body: UserNotificationSetting = req.body + const body = req.body const query = { where: { @@ -61,14 +61,19 @@ async function updateNotificationSettings (req: express.Request, res: express.Re } } - await UserNotificationSettingModel.update({ + const values: UserNotificationSetting = { newVideoFromSubscription: body.newVideoFromSubscription, newCommentOnMyVideo: body.newCommentOnMyVideo, videoAbuseAsModerator: body.videoAbuseAsModerator, blacklistOnMyVideo: body.blacklistOnMyVideo, myVideoPublished: body.myVideoPublished, - myVideoImportFinished: body.myVideoImportFinished - }, query) + myVideoImportFinished: body.myVideoImportFinished, + newFollow: body.newFollow, + newUserRegistration: body.newUserRegistration, + commentMention: body.commentMention, + } + + await UserNotificationSettingModel.update(values, query) return res.status(204).end() } -- cgit v1.2.3 From 2f1548fda32c3ba9e53913270394eedfacd55986 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 8 Jan 2019 11:26:41 +0100 Subject: Add notifications in the client --- server/controllers/api/users/my-notifications.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/users/my-notifications.ts b/server/controllers/api/users/my-notifications.ts index d74d26add..76cf97587 100644 --- a/server/controllers/api/users/my-notifications.ts +++ b/server/controllers/api/users/my-notifications.ts @@ -45,6 +45,11 @@ myNotificationsRouter.post('/me/notifications/read', asyncMiddleware(markAsReadUserNotifications) ) +myNotificationsRouter.post('/me/notifications/read-all', + authenticate, + asyncMiddleware(markAsReadAllUserNotifications) +) + export { myNotificationsRouter } @@ -70,7 +75,7 @@ async function updateNotificationSettings (req: express.Request, res: express.Re myVideoImportFinished: body.myVideoImportFinished, newFollow: body.newFollow, newUserRegistration: body.newUserRegistration, - commentMention: body.commentMention, + commentMention: body.commentMention } await UserNotificationSettingModel.update(values, query) @@ -93,3 +98,11 @@ async function markAsReadUserNotifications (req: express.Request, res: express.R return res.status(204).end() } + +async function markAsReadAllUserNotifications (req: express.Request, res: express.Response) { + const user: UserModel = res.locals.oauth.token.User + + await UserNotificationModel.markAllAsRead(user.id) + + return res.status(204).end() +} -- cgit v1.2.3 From a4101923e699e49ceb9ff36e971c75417fafc9f0 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 9 Jan 2019 15:14:29 +0100 Subject: Implement contact form on server side --- server/controllers/api/config.ts | 55 ++++++++++++++++---------------- server/controllers/api/server/contact.ts | 28 ++++++++++++++++ server/controllers/api/server/index.ts | 2 ++ 3 files changed, 58 insertions(+), 27 deletions(-) create mode 100644 server/controllers/api/server/contact.ts (limited to 'server/controllers/api') diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index c75002aaf..43b20e078 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts @@ -1,5 +1,5 @@ import * as express from 'express' -import { omit } from 'lodash' +import { omit, snakeCase } from 'lodash' import { ServerConfig, UserRight } from '../../../shared' import { About } from '../../../shared/models/server/about.model' import { CustomConfig } from '../../../shared/models/server/custom-config.model' @@ -12,6 +12,8 @@ import { auditLoggerFactory, CustomConfigAuditView, getAuditIdFromRes } from '.. import { remove, writeJSON } from 'fs-extra' import { getServerCommit } from '../../helpers/utils' import { Emailer } from '../../lib/emailer' +import { isNumeric } from 'validator' +import { objectConverter } from '../../helpers/core-utils' const packageJSON = require('../../../../package.json') const configRouter = express.Router() @@ -65,6 +67,9 @@ async function getConfig (req: express.Request, res: express.Response) { email: { enabled: Emailer.Instance.isEnabled() }, + contactForm: { + enabled: CONFIG.CONTACT_FORM.ENABLED + }, serverVersion: packageJSON.version, serverCommit, signup: { @@ -154,34 +159,10 @@ async function deleteCustomConfig (req: express.Request, res: express.Response, } async function updateCustomConfig (req: express.Request, res: express.Response, next: express.NextFunction) { - const toUpdate: CustomConfig = req.body const oldCustomConfigAuditKeys = new CustomConfigAuditView(customConfig()) - // Force number conversion - toUpdate.cache.previews.size = parseInt('' + toUpdate.cache.previews.size, 10) - toUpdate.cache.captions.size = parseInt('' + toUpdate.cache.captions.size, 10) - toUpdate.signup.limit = parseInt('' + toUpdate.signup.limit, 10) - toUpdate.user.videoQuota = parseInt('' + toUpdate.user.videoQuota, 10) - toUpdate.user.videoQuotaDaily = parseInt('' + toUpdate.user.videoQuotaDaily, 10) - toUpdate.transcoding.threads = parseInt('' + toUpdate.transcoding.threads, 10) - - // camelCase to snake_case key - const toUpdateJSON = omit( - toUpdate, - 'user.videoQuota', - 'instance.defaultClientRoute', - 'instance.shortDescription', - 'cache.videoCaptions', - 'signup.requiresEmailVerification', - 'transcoding.allowAdditionalExtensions' - ) - toUpdateJSON.user['video_quota'] = toUpdate.user.videoQuota - toUpdateJSON.user['video_quota_daily'] = toUpdate.user.videoQuotaDaily - toUpdateJSON.instance['default_client_route'] = toUpdate.instance.defaultClientRoute - toUpdateJSON.instance['short_description'] = toUpdate.instance.shortDescription - toUpdateJSON.instance['default_nsfw_policy'] = toUpdate.instance.defaultNSFWPolicy - toUpdateJSON.signup['requires_email_verification'] = toUpdate.signup.requiresEmailVerification - toUpdateJSON.transcoding['allow_additional_extensions'] = toUpdate.transcoding.allowAdditionalExtensions + // camelCase to snake_case key + Force number conversion + const toUpdateJSON = convertCustomConfigBody(req.body) await writeJSON(CONFIG.CUSTOM_FILE, toUpdateJSON, { spaces: 2 }) @@ -243,6 +224,9 @@ function customConfig (): CustomConfig { admin: { email: CONFIG.ADMIN.EMAIL }, + contactForm: { + enabled: CONFIG.CONTACT_FORM.ENABLED + }, user: { videoQuota: CONFIG.USER.VIDEO_QUOTA, videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY @@ -271,3 +255,20 @@ function customConfig (): CustomConfig { } } } + +function convertCustomConfigBody (body: CustomConfig) { + function keyConverter (k: string) { + // Transcoding resolutions exception + if (/^\d{3,4}p$/.exec(k)) return k + + return snakeCase(k) + } + + function valueConverter (v: any) { + if (isNumeric(v + '')) return parseInt('' + v, 10) + + return v + } + + return objectConverter(body, keyConverter, valueConverter) +} diff --git a/server/controllers/api/server/contact.ts b/server/controllers/api/server/contact.ts new file mode 100644 index 000000000..b1144c94e --- /dev/null +++ b/server/controllers/api/server/contact.ts @@ -0,0 +1,28 @@ +import * as express from 'express' +import { asyncMiddleware, contactAdministratorValidator } from '../../../middlewares' +import { Redis } from '../../../lib/redis' +import { Emailer } from '../../../lib/emailer' +import { ContactForm } from '../../../../shared/models/server' + +const contactRouter = express.Router() + +contactRouter.post('/contact', + asyncMiddleware(contactAdministratorValidator), + asyncMiddleware(contactAdministrator) +) + +async function contactAdministrator (req: express.Request, res: express.Response) { + const data = req.body as ContactForm + + await Emailer.Instance.addContactFormJob(data.fromEmail, data.fromName, data.body) + + await Redis.Instance.setContactFormIp(req.ip) + + return res.status(204).end() +} + +// --------------------------------------------------------------------------- + +export { + contactRouter +} diff --git a/server/controllers/api/server/index.ts b/server/controllers/api/server/index.ts index c08192a8c..814248e5f 100644 --- a/server/controllers/api/server/index.ts +++ b/server/controllers/api/server/index.ts @@ -3,6 +3,7 @@ import { serverFollowsRouter } from './follows' import { statsRouter } from './stats' import { serverRedundancyRouter } from './redundancy' import { serverBlocklistRouter } from './server-blocklist' +import { contactRouter } from './contact' const serverRouter = express.Router() @@ -10,6 +11,7 @@ serverRouter.use('/', serverFollowsRouter) serverRouter.use('/', serverRedundancyRouter) serverRouter.use('/', statsRouter) serverRouter.use('/', serverBlocklistRouter) +serverRouter.use('/', contactRouter) // --------------------------------------------------------------------------- -- cgit v1.2.3 From d3e56c0c4b307c99e83fbafb7f2c5884cbc20055 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 10 Jan 2019 11:12:41 +0100 Subject: Implement contact form in the client --- server/controllers/api/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 43b20e078..dd06a0597 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts @@ -65,7 +65,7 @@ async function getConfig (req: express.Request, res: express.Response) { } }, email: { - enabled: Emailer.Instance.isEnabled() + enabled: Emailer.isEnabled() }, contactForm: { enabled: CONFIG.CONTACT_FORM.ENABLED -- cgit v1.2.3 From 5abb9fbbd12e7097e348d6a38622d364b1fa47ed Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 10 Jan 2019 15:39:51 +0100 Subject: Add ability to unfederate a local video (on blacklist) --- server/controllers/api/videos/blacklist.ts | 17 +++++++++++++++-- server/controllers/api/videos/index.ts | 6 +++++- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/videos/blacklist.ts b/server/controllers/api/videos/blacklist.ts index 9ef08812b..43b0516e7 100644 --- a/server/controllers/api/videos/blacklist.ts +++ b/server/controllers/api/videos/blacklist.ts @@ -18,6 +18,8 @@ import { VideoBlacklistModel } from '../../../models/video/video-blacklist' import { sequelizeTypescript } from '../../../initializers' import { Notifier } from '../../../lib/notifier' import { VideoModel } from '../../../models/video/video' +import { sendCreateVideo, sendDeleteVideo, sendUpdateVideo } from '../../../lib/activitypub/send' +import { federateVideoIfNeeded } from '../../../lib/activitypub' const blacklistRouter = express.Router() @@ -66,12 +68,17 @@ async function addVideoToBlacklist (req: express.Request, res: express.Response) const toCreate = { videoId: videoInstance.id, + unfederated: body.unfederate === true, reason: body.reason } const blacklist = await VideoBlacklistModel.create(toCreate) blacklist.Video = videoInstance + if (body.unfederate === true) { + await sendDeleteVideo(videoInstance, undefined) + } + Notifier.Instance.notifyOnVideoBlacklist(blacklist) logger.info('Video %s blacklisted.', res.locals.video.uuid) @@ -101,8 +108,14 @@ async function removeVideoFromBlacklistController (req: express.Request, res: ex const videoBlacklist = res.locals.videoBlacklist as VideoBlacklistModel const video: VideoModel = res.locals.video - await sequelizeTypescript.transaction(t => { - return videoBlacklist.destroy({ transaction: t }) + await sequelizeTypescript.transaction(async t => { + const unfederated = videoBlacklist.unfederated + await videoBlacklist.destroy({ transaction: t }) + + // Re federate the video + if (unfederated === true) { + await federateVideoIfNeeded(video, true, t) + } }) Notifier.Instance.notifyOnVideoUnblacklist(video) diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 33521a8c1..28ac26598 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -364,7 +364,11 @@ async function updateVideo (req: express.Request, res: express.Response) { } const isNewVideo = wasPrivateVideo && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE - await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t) + + // Don't send update if the video was unfederated + if (!videoInstanceUpdated.VideoBlacklist || videoInstanceUpdated.VideoBlacklist.unfederated === false) { + await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t) + } auditLogger.update( getAuditIdFromRes(res), -- cgit v1.2.3 From 9b4b15f91c485f9a7fe2ed314b4101f4b7506b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20B=C3=A9ranger?= <43744761+auberanger@users.noreply.github.com> Date: Mon, 14 Jan 2019 09:06:48 +0100 Subject: WIP : Indicate to users how "trending" works (#1458) * Get the INTERVAL_DAYS const in the video-trending component * Change Trending section title * Add a tooltip to explain how trending section works * Minor CSS fix for the my-feed popover next to the titlepage --- server/controllers/api/config.ts | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'server/controllers/api') diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index dd06a0597..255026f46 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts @@ -120,6 +120,11 @@ async function getConfig (req: express.Request, res: express.Response) { user: { videoQuota: CONFIG.USER.VIDEO_QUOTA, videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY + }, + trending: { + videos: { + intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS + } } } -- cgit v1.2.3 From cf405589f06a9ac9d5a05b09bf2183fbf88d56d7 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 14 Jan 2019 10:44:59 +0100 Subject: Move subscriptions controllers in its own file --- server/controllers/api/users/index.ts | 2 + server/controllers/api/users/me.ts | 156 +-------------------- server/controllers/api/users/my-subscriptions.ts | 170 +++++++++++++++++++++++ 3 files changed, 174 insertions(+), 154 deletions(-) create mode 100644 server/controllers/api/users/my-subscriptions.ts (limited to 'server/controllers/api') diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index 9e6a019f6..dbe0718d4 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts @@ -41,6 +41,7 @@ import { myBlocklistRouter } from './my-blocklist' import { myVideosHistoryRouter } from './my-history' import { myNotificationsRouter } from './my-notifications' import { Notifier } from '../../../lib/notifier' +import { mySubscriptionsRouter } from './my-subscriptions' const auditLogger = auditLoggerFactory('users') @@ -58,6 +59,7 @@ const askSendEmailLimiter = new RateLimit({ const usersRouter = express.Router() usersRouter.use('/', myNotificationsRouter) +usersRouter.use('/', mySubscriptionsRouter) usersRouter.use('/', myBlocklistRouter) usersRouter.use('/', myVideosHistoryRouter) usersRouter.use('/', meRouter) diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index 8a3208160..94a2b8732 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts @@ -8,36 +8,23 @@ import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, - commonVideosFiltersValidator, paginationValidator, setDefaultPagination, setDefaultSort, - userSubscriptionAddValidator, - userSubscriptionGetValidator, usersUpdateMeValidator, usersVideoRatingValidator } from '../../../middlewares' -import { - areSubscriptionsExistValidator, - deleteMeValidator, - userSubscriptionsSortValidator, - videoImportsSortValidator, - videosSortValidator -} from '../../../middlewares/validators' +import { deleteMeValidator, videoImportsSortValidator, videosSortValidator } from '../../../middlewares/validators' import { AccountVideoRateModel } from '../../../models/account/account-video-rate' import { UserModel } from '../../../models/account/user' import { VideoModel } from '../../../models/video/video' import { VideoSortField } from '../../../../client/src/app/shared/video/sort-field.type' -import { buildNSFWFilter, createReqFiles } from '../../../helpers/express-utils' +import { createReqFiles } from '../../../helpers/express-utils' import { UserVideoQuota } from '../../../../shared/models/users/user-video-quota.model' import { updateAvatarValidator } from '../../../middlewares/validators/avatar' import { updateActorAvatarFile } from '../../../lib/avatar' import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger' import { VideoImportModel } from '../../../models/video/video-import' -import { VideoFilter } from '../../../../shared/models/videos/video-query.type' -import { ActorFollowModel } from '../../../models/activitypub/actor-follow' -import { JobQueue } from '../../../lib/job-queue' -import { logger } from '../../../helpers/logger' import { AccountModel } from '../../../models/account/account' const auditLogger = auditLoggerFactory('users-me') @@ -98,51 +85,6 @@ meRouter.post('/me/avatar/pick', asyncRetryTransactionMiddleware(updateMyAvatar) ) -// ##### Subscriptions part ##### - -meRouter.get('/me/subscriptions/videos', - authenticate, - paginationValidator, - videosSortValidator, - setDefaultSort, - setDefaultPagination, - commonVideosFiltersValidator, - asyncMiddleware(getUserSubscriptionVideos) -) - -meRouter.get('/me/subscriptions/exist', - authenticate, - areSubscriptionsExistValidator, - asyncMiddleware(areSubscriptionsExist) -) - -meRouter.get('/me/subscriptions', - authenticate, - paginationValidator, - userSubscriptionsSortValidator, - setDefaultSort, - setDefaultPagination, - asyncMiddleware(getUserSubscriptions) -) - -meRouter.post('/me/subscriptions', - authenticate, - userSubscriptionAddValidator, - asyncMiddleware(addUserSubscription) -) - -meRouter.get('/me/subscriptions/:uri', - authenticate, - userSubscriptionGetValidator, - getUserSubscription -) - -meRouter.delete('/me/subscriptions/:uri', - authenticate, - userSubscriptionGetValidator, - asyncRetryTransactionMiddleware(deleteUserSubscription) -) - // --------------------------------------------------------------------------- export { @@ -151,100 +93,6 @@ export { // --------------------------------------------------------------------------- -async function areSubscriptionsExist (req: express.Request, res: express.Response) { - const uris = req.query.uris as string[] - const user = res.locals.oauth.token.User as UserModel - - const handles = uris.map(u => { - let [ name, host ] = u.split('@') - if (host === CONFIG.WEBSERVER.HOST) host = null - - return { name, host, uri: u } - }) - - const results = await ActorFollowModel.listSubscribedIn(user.Account.Actor.id, handles) - - const existObject: { [id: string ]: boolean } = {} - for (const handle of handles) { - const obj = results.find(r => { - const server = r.ActorFollowing.Server - - return r.ActorFollowing.preferredUsername === handle.name && - ( - (!server && !handle.host) || - (server.host === handle.host) - ) - }) - - existObject[handle.uri] = obj !== undefined - } - - return res.json(existObject) -} - -async function addUserSubscription (req: express.Request, res: express.Response) { - const user = res.locals.oauth.token.User as UserModel - const [ name, host ] = req.body.uri.split('@') - - const payload = { - name, - host, - followerActorId: user.Account.Actor.id - } - - JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) - .catch(err => logger.error('Cannot create follow job for subscription %s.', req.body.uri, err)) - - return res.status(204).end() -} - -function getUserSubscription (req: express.Request, res: express.Response) { - const subscription: ActorFollowModel = res.locals.subscription - - return res.json(subscription.ActorFollowing.VideoChannel.toFormattedJSON()) -} - -async function deleteUserSubscription (req: express.Request, res: express.Response) { - const subscription: ActorFollowModel = res.locals.subscription - - await sequelizeTypescript.transaction(async t => { - return subscription.destroy({ transaction: t }) - }) - - return res.type('json').status(204).end() -} - -async function getUserSubscriptions (req: express.Request, res: express.Response) { - const user = res.locals.oauth.token.User as UserModel - const actorId = user.Account.Actor.id - - const resultList = await ActorFollowModel.listSubscriptionsForApi(actorId, req.query.start, req.query.count, req.query.sort) - - return res.json(getFormattedObjects(resultList.data, resultList.total)) -} - -async function getUserSubscriptionVideos (req: express.Request, res: express.Response, next: express.NextFunction) { - const user = res.locals.oauth.token.User as UserModel - const resultList = await VideoModel.listForApi({ - start: req.query.start, - count: req.query.count, - sort: req.query.sort, - includeLocalVideos: false, - categoryOneOf: req.query.categoryOneOf, - licenceOneOf: req.query.licenceOneOf, - languageOneOf: req.query.languageOneOf, - tagsOneOf: req.query.tagsOneOf, - tagsAllOf: req.query.tagsAllOf, - nsfw: buildNSFWFilter(res, req.query.nsfw), - filter: req.query.filter as VideoFilter, - withFiles: false, - followerActorId: user.Account.Actor.id, - user - }) - - return res.json(getFormattedObjects(resultList.data, resultList.total)) -} - async function getUserVideos (req: express.Request, res: express.Response, next: express.NextFunction) { const user = res.locals.oauth.token.User as UserModel const resultList = await VideoModel.listUserVideosForApi( diff --git a/server/controllers/api/users/my-subscriptions.ts b/server/controllers/api/users/my-subscriptions.ts new file mode 100644 index 000000000..accca6d52 --- /dev/null +++ b/server/controllers/api/users/my-subscriptions.ts @@ -0,0 +1,170 @@ +import * as express from 'express' +import 'multer' +import { getFormattedObjects } from '../../../helpers/utils' +import { CONFIG, sequelizeTypescript } from '../../../initializers' +import { + asyncMiddleware, + asyncRetryTransactionMiddleware, + authenticate, + commonVideosFiltersValidator, + paginationValidator, + setDefaultPagination, + setDefaultSort, + userSubscriptionAddValidator, + userSubscriptionGetValidator +} from '../../../middlewares' +import { areSubscriptionsExistValidator, userSubscriptionsSortValidator, videosSortValidator } from '../../../middlewares/validators' +import { UserModel } from '../../../models/account/user' +import { VideoModel } from '../../../models/video/video' +import { buildNSFWFilter } from '../../../helpers/express-utils' +import { VideoFilter } from '../../../../shared/models/videos/video-query.type' +import { ActorFollowModel } from '../../../models/activitypub/actor-follow' +import { JobQueue } from '../../../lib/job-queue' +import { logger } from '../../../helpers/logger' + +const mySubscriptionsRouter = express.Router() + +mySubscriptionsRouter.get('/me/subscriptions/videos', + authenticate, + paginationValidator, + videosSortValidator, + setDefaultSort, + setDefaultPagination, + commonVideosFiltersValidator, + asyncMiddleware(getUserSubscriptionVideos) +) + +mySubscriptionsRouter.get('/me/subscriptions/exist', + authenticate, + areSubscriptionsExistValidator, + asyncMiddleware(areSubscriptionsExist) +) + +mySubscriptionsRouter.get('/me/subscriptions', + authenticate, + paginationValidator, + userSubscriptionsSortValidator, + setDefaultSort, + setDefaultPagination, + asyncMiddleware(getUserSubscriptions) +) + +mySubscriptionsRouter.post('/me/subscriptions', + authenticate, + userSubscriptionAddValidator, + asyncMiddleware(addUserSubscription) +) + +mySubscriptionsRouter.get('/me/subscriptions/:uri', + authenticate, + userSubscriptionGetValidator, + getUserSubscription +) + +mySubscriptionsRouter.delete('/me/subscriptions/:uri', + authenticate, + userSubscriptionGetValidator, + asyncRetryTransactionMiddleware(deleteUserSubscription) +) + +// --------------------------------------------------------------------------- + +export { + mySubscriptionsRouter +} + +// --------------------------------------------------------------------------- + +async function areSubscriptionsExist (req: express.Request, res: express.Response) { + const uris = req.query.uris as string[] + const user = res.locals.oauth.token.User as UserModel + + const handles = uris.map(u => { + let [ name, host ] = u.split('@') + if (host === CONFIG.WEBSERVER.HOST) host = null + + return { name, host, uri: u } + }) + + const results = await ActorFollowModel.listSubscribedIn(user.Account.Actor.id, handles) + + const existObject: { [id: string ]: boolean } = {} + for (const handle of handles) { + const obj = results.find(r => { + const server = r.ActorFollowing.Server + + return r.ActorFollowing.preferredUsername === handle.name && + ( + (!server && !handle.host) || + (server.host === handle.host) + ) + }) + + existObject[handle.uri] = obj !== undefined + } + + return res.json(existObject) +} + +async function addUserSubscription (req: express.Request, res: express.Response) { + const user = res.locals.oauth.token.User as UserModel + const [ name, host ] = req.body.uri.split('@') + + const payload = { + name, + host, + followerActorId: user.Account.Actor.id + } + + JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) + .catch(err => logger.error('Cannot create follow job for subscription %s.', req.body.uri, err)) + + return res.status(204).end() +} + +function getUserSubscription (req: express.Request, res: express.Response) { + const subscription: ActorFollowModel = res.locals.subscription + + return res.json(subscription.ActorFollowing.VideoChannel.toFormattedJSON()) +} + +async function deleteUserSubscription (req: express.Request, res: express.Response) { + const subscription: ActorFollowModel = res.locals.subscription + + await sequelizeTypescript.transaction(async t => { + return subscription.destroy({ transaction: t }) + }) + + return res.type('json').status(204).end() +} + +async function getUserSubscriptions (req: express.Request, res: express.Response) { + const user = res.locals.oauth.token.User as UserModel + const actorId = user.Account.Actor.id + + const resultList = await ActorFollowModel.listSubscriptionsForApi(actorId, req.query.start, req.query.count, req.query.sort) + + return res.json(getFormattedObjects(resultList.data, resultList.total)) +} + +async function getUserSubscriptionVideos (req: express.Request, res: express.Response, next: express.NextFunction) { + const user = res.locals.oauth.token.User as UserModel + const resultList = await VideoModel.listForApi({ + start: req.query.start, + count: req.query.count, + sort: req.query.sort, + includeLocalVideos: false, + categoryOneOf: req.query.categoryOneOf, + licenceOneOf: req.query.licenceOneOf, + languageOneOf: req.query.languageOneOf, + tagsOneOf: req.query.tagsOneOf, + tagsAllOf: req.query.tagsAllOf, + nsfw: buildNSFWFilter(res, req.query.nsfw), + filter: req.query.filter as VideoFilter, + withFiles: false, + followerActorId: user.Account.Actor.id, + user + }) + + return res.json(getFormattedObjects(resultList.data, resultList.total)) +} -- cgit v1.2.3 From 744d0eca195bce7dafeb4a958d0eb3c0046be32d Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 14 Jan 2019 11:30:15 +0100 Subject: Refresh remote actors on GET enpoints --- server/controllers/api/accounts.ts | 7 +++++++ server/controllers/api/video-channel.ts | 6 ++++++ server/controllers/api/videos/index.ts | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/accounts.ts b/server/controllers/api/accounts.ts index a69a83acf..8c0237203 100644 --- a/server/controllers/api/accounts.ts +++ b/server/controllers/api/accounts.ts @@ -14,6 +14,8 @@ import { AccountModel } from '../../models/account/account' import { VideoModel } from '../../models/video/video' import { buildNSFWFilter, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' import { VideoChannelModel } from '../../models/video/video-channel' +import { JobQueue } from '../../lib/job-queue' +import { logger } from '../../helpers/logger' const accountsRouter = express.Router() @@ -57,6 +59,11 @@ export { function getAccount (req: express.Request, res: express.Response, next: express.NextFunction) { const account: AccountModel = res.locals.account + if (account.isOutdated()) { + JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } }) + .catch(err => logger.error('Cannot create AP refresher job for actor %s.', account.Actor.url, { err })) + } + return res.json(account.toFormattedJSON()) } diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index 3d6a6af7f..db7602139 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts @@ -30,6 +30,7 @@ import { updateActorAvatarFile } from '../../lib/avatar' import { auditLoggerFactory, getAuditIdFromRes, VideoChannelAuditView } from '../../helpers/audit-logger' import { resetSequelizeInstance } from '../../helpers/database-utils' import { UserModel } from '../../models/account/user' +import { JobQueue } from '../../lib/job-queue' const auditLogger = auditLoggerFactory('channels') const reqAvatarFile = createReqFiles([ 'avatarfile' ], MIMETYPES.IMAGE.MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.TMP_DIR }) @@ -197,6 +198,11 @@ async function removeVideoChannel (req: express.Request, res: express.Response) async function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) { const videoChannelWithVideos = await VideoChannelModel.loadAndPopulateAccountAndVideos(res.locals.videoChannel.id) + if (videoChannelWithVideos.isOutdated()) { + JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } }) + .catch(err => logger.error('Cannot create AP refresher job for actor %s.', videoChannelWithVideos.Actor.url, { err })) + } + return res.json(videoChannelWithVideos.toFormattedJSON()) } diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 28ac26598..2b2dfa7ca 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -399,7 +399,7 @@ function getVideo (req: express.Request, res: express.Response) { const videoInstance = res.locals.video if (videoInstance.isOutdated()) { - JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', videoUrl: videoInstance.url } }) + JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: videoInstance.url } }) .catch(err => logger.error('Cannot create AP refresher job for video %s.', videoInstance.url, { err })) } -- cgit v1.2.3 From 44b9c0ba31c4a97e3d874f33226ad935c3a90dd5 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 15 Jan 2019 09:45:54 +0100 Subject: Add totalLocalVideoFilesSize in stats --- server/controllers/api/server/stats.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/server/stats.ts b/server/controllers/api/server/stats.ts index 85803f69e..89ffd1717 100644 --- a/server/controllers/api/server/stats.ts +++ b/server/controllers/api/server/stats.ts @@ -8,6 +8,7 @@ import { VideoCommentModel } from '../../../models/video/video-comment' import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' import { CONFIG, ROUTE_CACHE_LIFETIME } from '../../../initializers/constants' import { cacheRoute } from '../../../middlewares/cache' +import { VideoFileModel } from '../../../models/video/video-file' const statsRouter = express.Router() @@ -16,11 +17,12 @@ statsRouter.get('/stats', asyncMiddleware(getStats) ) -async function getStats (req: express.Request, res: express.Response, next: express.NextFunction) { +async function getStats (req: express.Request, res: express.Response) { const { totalLocalVideos, totalLocalVideoViews, totalVideos } = await VideoModel.getStats() const { totalLocalVideoComments, totalVideoComments } = await VideoCommentModel.getStats() const { totalUsers } = await UserModel.getStats() const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats() + const { totalLocalVideoFilesSize } = await VideoFileModel.getStats() const videosRedundancyStats = await Promise.all( CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.map(r => { @@ -32,8 +34,9 @@ async function getStats (req: express.Request, res: express.Response, next: expr const data: ServerStats = { totalLocalVideos, totalLocalVideoViews, - totalVideos, + totalLocalVideoFilesSize, totalLocalVideoComments, + totalVideos, totalVideoComments, totalUsers, totalInstanceFollowers, -- cgit v1.2.3