From 00494d6e2ae915741f47869dcd359d9728a0af91 Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Sat, 27 Jun 2020 13:12:30 +0200 Subject: allow limiting video-comments rss feeds to an account or video channel --- server/controllers/feeds.ts | 55 +++++++++++++++++++++++++++------- server/middlewares/validators/feeds.ts | 6 ++++ server/models/video/video-comment.ts | 34 ++++++++++++++++----- 3 files changed, 78 insertions(+), 17 deletions(-) (limited to 'server') diff --git a/server/controllers/feeds.ts b/server/controllers/feeds.ts index cb82bfc6d..bfcd3fe36 100644 --- a/server/controllers/feeds.ts +++ b/server/controllers/feeds.ts @@ -27,6 +27,7 @@ feedsRouter.get('/feeds/video-comments.:format', 'Content-Type' ] })(ROUTE_CACHE_LIFETIME.FEEDS)), + asyncMiddleware(videoFeedsValidator), asyncMiddleware(videoCommentsFeedsValidator), asyncMiddleware(generateVideoCommentsFeed) ) @@ -58,13 +59,36 @@ async function generateVideoCommentsFeed (req: express.Request, res: express.Res const start = 0 const video = res.locals.videoAll - const videoId: number = video ? video.id : undefined + const account = res.locals.account + const videoChannel = res.locals.videoChannel - const comments = await VideoCommentModel.listForFeed(start, FEEDS.COUNT, videoId) + const comments = await VideoCommentModel.listForFeed({ + start, + count: FEEDS.COUNT, + videoId: video ? video.id : undefined, + accountId: account ? account.id : undefined, + videoChannelId: videoChannel ? videoChannel.id : undefined + }) - const name = video ? video.name : CONFIG.INSTANCE.NAME - const description = video ? video.description : CONFIG.INSTANCE.DESCRIPTION - const feed = initFeed(name, description) + let name: string + let description: string + + if (videoChannel) { + name = videoChannel.getDisplayName() + description = videoChannel.description + } else if (account) { + name = account.getDisplayName() + description = account.description + } else { + name = video ? video.name : CONFIG.INSTANCE.NAME + description = video ? video.description : CONFIG.INSTANCE.DESCRIPTION + } + const feed = initFeed({ + name, + description, + resourceType: 'video-comments', + queryString: new URL(WEBSERVER.URL + req.originalUrl).search + }) // Adding video items to the feed, one at a time for (const comment of comments) { @@ -116,7 +140,12 @@ async function generateVideoFeed (req: express.Request, res: express.Response) { description = CONFIG.INSTANCE.DESCRIPTION } - const feed = initFeed(name, description) + const feed = initFeed({ + name, + description, + resourceType: 'videos', + queryString: new URL(WEBSERVER.URL + req.url).search + }) const resultList = await VideoModel.listForApi({ start, @@ -207,8 +236,14 @@ async function generateVideoFeed (req: express.Request, res: express.Response) { return sendFeed(feed, req, res) } -function initFeed (name: string, description: string) { +function initFeed (parameters: { + name: string + description: string + resourceType?: 'videos' | 'video-comments' + queryString?: string +}) { const webserverUrl = WEBSERVER.URL + const { name, description, resourceType, queryString } = parameters return new Feed({ title: name, @@ -222,9 +257,9 @@ function initFeed (name: string, description: string) { ` and potential licenses granted by each content's rightholder.`, generator: `Toraifōsu`, // ^.~ feedLinks: { - json: `${webserverUrl}/feeds/videos.json`, - atom: `${webserverUrl}/feeds/videos.atom`, - rss: `${webserverUrl}/feeds/videos.xml` + json: `${webserverUrl}/feeds/${resourceType}.json${queryString}`, + atom: `${webserverUrl}/feeds/${resourceType}.atom${queryString}`, + rss: `${webserverUrl}/feeds/${resourceType}.xml${queryString}` }, author: { name: 'Instance admin of ' + CONFIG.INSTANCE.NAME, diff --git a/server/middlewares/validators/feeds.ts b/server/middlewares/validators/feeds.ts index f34c2b174..c3de0f5fe 100644 --- a/server/middlewares/validators/feeds.ts +++ b/server/middlewares/validators/feeds.ts @@ -70,6 +70,12 @@ const videoCommentsFeedsValidator = [ if (areValidationErrors(req, res)) return + if (req.query.videoId && (req.query.videoChannelId || req.query.videoChannelName)) { + return res.status(400).send({ + message: 'videoId cannot be mixed with a channel filter' + }).end() + } + if (req.query.videoId && !await doesVideoExist(req.query.videoId, res)) return return next() diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index 091cc2a88..c465eb3e7 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts @@ -427,8 +427,31 @@ export class VideoCommentModel extends Model { return VideoCommentModel.findAndCountAll(query) } - static async listForFeed (start: number, count: number, videoId?: number): Promise { + static async listForFeed (parameters: { + start: number + count: number + videoId?: number + accountId?: number + videoChannelId?: number + }): Promise { const serverActor = await getServerActor() + const { start, count, videoId, accountId, videoChannelId } = parameters + + const accountExclusion = { + [Op.notIn]: Sequelize.literal( + '(' + buildBlockedAccountSQL([ serverActor.Account.id, '"Video->VideoChannel"."accountId"' ]) + ')' + ) + } + const accountWhere = accountId + ? { + [Op.and]: { + ...accountExclusion, + [Op.eq]: accountId + } + } + : accountExclusion + + const videoChannelWhere = videoChannelId ? { id: videoChannelId } : undefined const query = { order: [ [ 'createdAt', 'DESC' ] ] as Order, @@ -436,11 +459,7 @@ export class VideoCommentModel extends Model { limit: count, where: { deletedAt: null, - accountId: { - [Op.notIn]: Sequelize.literal( - '(' + buildBlockedAccountSQL([ serverActor.Account.id, '"Video->VideoChannel"."accountId"' ]) + ')' - ) - } + accountId: accountWhere }, include: [ { @@ -454,7 +473,8 @@ export class VideoCommentModel extends Model { { attributes: [ 'accountId' ], model: VideoChannelModel.unscoped(), - required: true + required: true, + where: videoChannelWhere } ] } -- cgit v1.2.3