2024-08-11 22:15:34 +02:00
const { Request , Response , NextFunction } = require ( 'express' )
2022-12-26 23:58:36 +01:00
const Logger = require ( '../Logger' )
2023-07-05 01:14:44 +02:00
const Database = require ( '../Database' )
2024-12-15 19:37:01 +01:00
const RssFeedManager = require ( '../managers/RssFeedManager' )
2022-12-26 23:58:36 +01:00
2024-08-11 22:15:34 +02:00
/ * *
2024-08-12 00:01:25 +02:00
* @ typedef RequestUserObject
2024-08-11 23:07:29 +02:00
* @ property { import ( '../models/User' ) } user
2024-08-11 22:15:34 +02:00
*
2024-08-12 00:01:25 +02:00
* @ typedef { Request & RequestUserObject } RequestWithUser
2024-08-11 22:15:34 +02:00
* /
2022-12-26 23:58:36 +01:00
2024-08-11 22:15:34 +02:00
class RSSFeedController {
constructor ( ) { }
/ * *
* GET : / a p i / f e e d s
*
* @ this { import ( '../routers/ApiRouter' ) }
*
* @ param { RequestWithUser } req
* @ param { Response } res
* /
2023-08-22 18:42:55 +02:00
async getAll ( req , res ) {
2024-12-15 19:37:01 +01:00
const feeds = await RssFeedManager . getFeeds ( )
2023-08-22 18:42:55 +02:00
res . json ( {
2024-08-11 22:15:34 +02:00
feeds : feeds . map ( ( f ) => f . toJSON ( ) ) ,
minified : feeds . map ( ( f ) => f . toJSONMinified ( ) )
2023-08-22 18:42:55 +02:00
} )
}
2024-08-11 22:15:34 +02:00
/ * *
* POST : / a p i / f e e d s / i t e m / : i t e m I d / o p e n
*
* @ this { import ( '../routers/ApiRouter' ) }
*
* @ param { RequestWithUser } req
* @ param { Response } res
* /
2022-12-26 23:58:36 +01:00
async openRSSFeedForItem ( req , res ) {
2024-12-14 23:55:56 +01:00
const reqBody = req . body || { }
2022-12-26 23:58:36 +01:00
2024-12-14 23:55:56 +01:00
const itemExpanded = await Database . libraryItemModel . getExpandedById ( req . params . itemId )
if ( ! itemExpanded ) return res . sendStatus ( 404 )
2022-12-26 23:58:36 +01:00
// Check user can access this library item
2024-12-14 23:55:56 +01:00
if ( ! req . user . checkCanAccessLibraryItem ( itemExpanded ) ) {
Logger . error ( ` [RSSFeedController] User " ${ req . user . username } " attempted to open an RSS feed for item " ${ itemExpanded . media . title } " that they don \' t have access to ` )
2022-12-26 23:58:36 +01:00
return res . sendStatus ( 403 )
}
// Check request body options exist
2024-12-14 23:55:56 +01:00
if ( ! reqBody . serverAddress || ! reqBody . slug || typeof reqBody . serverAddress !== 'string' || typeof reqBody . slug !== 'string' ) {
2022-12-26 23:58:36 +01:00
Logger . error ( ` [RSSFeedController] Invalid request body to open RSS feed ` )
return res . status ( 400 ) . send ( 'Invalid request body' )
}
// Check item has audio tracks
2024-12-14 23:55:56 +01:00
if ( ! itemExpanded . hasAudioTracks ( ) ) {
Logger . error ( ` [RSSFeedController] Cannot open RSS feed for item " ${ itemExpanded . media . title } " because it has no audio tracks ` )
2022-12-26 23:58:36 +01:00
return res . status ( 400 ) . send ( 'Item has no audio tracks' )
}
// Check that this slug is not being used for another feed (slug will also be the Feed id)
2024-12-15 19:37:01 +01:00
if ( await RssFeedManager . findFeedBySlug ( reqBody . slug ) ) {
2024-12-14 23:55:56 +01:00
Logger . error ( ` [RSSFeedController] Cannot open RSS feed because slug " ${ reqBody . slug } " is already in use ` )
2022-12-26 23:58:36 +01:00
return res . status ( 400 ) . send ( 'Slug already in use' )
}
2024-12-15 19:37:01 +01:00
const feed = await RssFeedManager . openFeedForItem ( req . user . id , itemExpanded , reqBody )
2024-12-14 23:55:56 +01:00
if ( ! feed ) {
Logger . error ( ` [RSSFeedController] Failed to open RSS feed for item " ${ itemExpanded . media . title } " ` )
return res . status ( 500 ) . send ( 'Failed to open RSS feed' )
}
2022-12-26 23:58:36 +01:00
res . json ( {
2024-12-14 23:55:56 +01:00
feed : feed . toOldJSONMinified ( )
2022-12-26 23:58:36 +01:00
} )
}
2024-08-11 22:15:34 +02:00
/ * *
* POST : / a p i / f e e d s / c o l l e c t i o n / : c o l l e c t i o n I d / o p e n
*
* @ this { import ( '../routers/ApiRouter' ) }
*
* @ param { RequestWithUser } req
* @ param { Response } res
* /
2022-12-27 00:48:39 +01:00
async openRSSFeedForCollection ( req , res ) {
2024-12-15 17:53:31 +01:00
const reqBody = req . body || { }
2022-12-27 00:48:39 +01:00
// Check request body options exist
2024-12-15 17:53:31 +01:00
if ( ! reqBody . serverAddress || ! reqBody . slug || typeof reqBody . serverAddress !== 'string' || typeof reqBody . slug !== 'string' ) {
2022-12-27 00:48:39 +01:00
Logger . error ( ` [RSSFeedController] Invalid request body to open RSS feed ` )
return res . status ( 400 ) . send ( 'Invalid request body' )
}
// Check that this slug is not being used for another feed (slug will also be the Feed id)
2024-12-15 19:37:01 +01:00
if ( await RssFeedManager . findFeedBySlug ( reqBody . slug ) ) {
2024-12-15 17:53:31 +01:00
Logger . error ( ` [RSSFeedController] Cannot open RSS feed because slug " ${ reqBody . slug } " is already in use ` )
2022-12-27 00:48:39 +01:00
return res . status ( 400 ) . send ( 'Slug already in use' )
}
2024-12-15 23:56:59 +01:00
const collection = await Database . collectionModel . getExpandedById ( req . params . collectionId )
if ( ! collection ) return res . sendStatus ( 404 )
2022-12-27 00:48:39 +01:00
// Check collection has audio tracks
2024-12-15 17:53:31 +01:00
if ( ! collection . books . some ( ( book ) => book . includedAudioFiles . length ) ) {
2022-12-27 00:48:39 +01:00
Logger . error ( ` [RSSFeedController] Cannot open RSS feed for collection " ${ collection . name } " because it has no audio tracks ` )
return res . status ( 400 ) . send ( 'Collection has no audio tracks' )
}
2024-12-15 19:37:01 +01:00
const feed = await RssFeedManager . openFeedForCollection ( req . user . id , collection , reqBody )
2024-12-15 17:53:31 +01:00
if ( ! feed ) {
Logger . error ( ` [RSSFeedController] Failed to open RSS feed for collection " ${ collection . name } " ` )
return res . status ( 500 ) . send ( 'Failed to open RSS feed' )
}
2022-12-27 00:48:39 +01:00
res . json ( {
2024-12-15 17:53:31 +01:00
feed : feed . toOldJSONMinified ( )
2022-12-27 00:48:39 +01:00
} )
}
2024-08-11 22:15:34 +02:00
/ * *
* POST : / a p i / f e e d s / s e r i e s / : s e r i e s I d / o p e n
*
* @ this { import ( '../routers/ApiRouter' ) }
*
* @ param { RequestWithUser } req
* @ param { Response } res
* /
2022-12-31 23:58:19 +01:00
async openRSSFeedForSeries ( req , res ) {
2024-12-15 18:44:07 +01:00
const reqBody = req . body || { }
2022-12-31 23:58:19 +01:00
// Check request body options exist
2024-12-15 18:44:07 +01:00
if ( ! reqBody . serverAddress || ! reqBody . slug || typeof reqBody . serverAddress !== 'string' || typeof reqBody . slug !== 'string' ) {
2022-12-31 23:58:19 +01:00
Logger . error ( ` [RSSFeedController] Invalid request body to open RSS feed ` )
return res . status ( 400 ) . send ( 'Invalid request body' )
}
// Check that this slug is not being used for another feed (slug will also be the Feed id)
2024-12-15 19:37:01 +01:00
if ( await RssFeedManager . findFeedBySlug ( reqBody . slug ) ) {
2024-12-15 18:44:07 +01:00
Logger . error ( ` [RSSFeedController] Cannot open RSS feed because slug " ${ reqBody . slug } " is already in use ` )
2022-12-31 23:58:19 +01:00
return res . status ( 400 ) . send ( 'Slug already in use' )
}
2024-12-15 23:56:59 +01:00
const series = await Database . seriesModel . getExpandedById ( req . params . seriesId )
if ( ! series ) return res . sendStatus ( 404 )
2022-12-31 23:58:19 +01:00
// Check series has audio tracks
2024-12-15 18:44:07 +01:00
if ( ! series . books . some ( ( book ) => book . includedAudioFiles . length ) ) {
Logger . error ( ` [RSSFeedController] Cannot open RSS feed for series " ${ series . name } " because it has no audio tracks ` )
2022-12-31 23:58:19 +01:00
return res . status ( 400 ) . send ( 'Series has no audio tracks' )
}
2024-12-15 19:37:01 +01:00
const feed = await RssFeedManager . openFeedForSeries ( req . user . id , series , req . body )
2024-12-15 18:44:07 +01:00
if ( ! feed ) {
Logger . error ( ` [RSSFeedController] Failed to open RSS feed for series " ${ series . name } " ` )
return res . status ( 500 ) . send ( 'Failed to open RSS feed' )
}
2022-12-31 23:58:19 +01:00
res . json ( {
2024-12-15 18:44:07 +01:00
feed : feed . toOldJSONMinified ( )
2022-12-31 23:58:19 +01:00
} )
}
2024-08-11 22:15:34 +02:00
/ * *
* POST : / a p i / f e e d s / : i d / c l o s e
*
* @ this { import ( '../routers/ApiRouter' ) }
*
* @ param { RequestWithUser } req
* @ param { Response } res
* /
2024-12-15 19:37:01 +01:00
async closeRSSFeed ( req , res ) {
const feed = await Database . feedModel . findByPk ( req . params . id )
if ( ! feed ) {
Logger . error ( ` [RSSFeedController] Cannot close RSS feed because feed " ${ req . params . id } " does not exist ` )
return res . sendStatus ( 404 )
}
await RssFeedManager . handleCloseFeed ( feed )
res . sendStatus ( 200 )
2022-12-26 23:58:36 +01:00
}
2024-08-11 22:15:34 +02:00
/ * *
*
* @ param { RequestWithUser } req
* @ param { Response } res
* @ param { NextFunction } next
* /
2022-12-26 23:58:36 +01:00
middleware ( req , res , next ) {
2024-08-11 23:07:29 +02:00
if ( ! req . user . isAdminOrUp ) {
2024-08-11 22:15:34 +02:00
// Only admins can manage rss feeds
2024-08-11 23:07:29 +02:00
Logger . error ( ` [RSSFeedController] Non-admin user " ${ req . user . username } " attempted to make a request to an RSS feed route ` )
2022-12-26 23:58:36 +01:00
return res . sendStatus ( 403 )
}
next ( )
}
}
2023-02-25 14:20:26 +01:00
module . exports = new RSSFeedController ( )