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' )
2023-08-13 22:10:26 +02:00
const libraryItemsBookFilters = require ( '../utils/queries/libraryItemsBookFilters' )
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 ) {
const feeds = await this . rssFeedManager . getFeeds ( )
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 ) {
const options = req . body || { }
2023-08-20 20:34:03 +02:00
const item = await Database . libraryItemModel . getOldById ( req . params . itemId )
2022-12-26 23:58:36 +01:00
if ( ! item ) return res . sendStatus ( 404 )
// Check user can access this library item
2024-08-11 23:07:29 +02:00
if ( ! req . user . checkCanAccessLibraryItem ( item ) ) {
Logger . error ( ` [RSSFeedController] User " ${ req . user . username } " attempted to open an RSS feed for item " ${ item . media . metadata . 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
2023-02-25 15:53:09 +01:00
if ( ! options . serverAddress || ! options . slug ) {
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
if ( ! item . media . numTracks ) {
Logger . error ( ` [RSSFeedController] Cannot open RSS feed for item " ${ item . media . metadata . title } " because it has no audio tracks ` )
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)
2023-07-17 23:48:46 +02:00
if ( await this . rssFeedManager . findFeedBySlug ( options . slug ) ) {
2022-12-26 23:58:36 +01:00
Logger . error ( ` [RSSFeedController] Cannot open RSS feed because slug " ${ options . slug } " is already in use ` )
return res . status ( 400 ) . send ( 'Slug already in use' )
}
2024-08-11 23:07:29 +02:00
const feed = await this . rssFeedManager . openFeedForItem ( req . user . id , item , req . body )
2022-12-26 23:58:36 +01:00
res . json ( {
feed : feed . toJSONMinified ( )
} )
}
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 ) {
const options = req . body || { }
2023-08-20 20:34:03 +02:00
const collection = await Database . collectionModel . findByPk ( req . params . collectionId )
2022-12-27 00:48:39 +01:00
if ( ! collection ) return res . sendStatus ( 404 )
// Check request body options exist
2023-02-25 15:53:09 +01:00
if ( ! options . serverAddress || ! options . slug ) {
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)
2023-07-17 23:48:46 +02:00
if ( await this . rssFeedManager . findFeedBySlug ( options . slug ) ) {
2022-12-27 00:48:39 +01:00
Logger . error ( ` [RSSFeedController] Cannot open RSS feed because slug " ${ options . slug } " is already in use ` )
return res . status ( 400 ) . send ( 'Slug already in use' )
}
2023-08-13 22:10:26 +02:00
const collectionExpanded = await collection . getOldJsonExpanded ( )
2024-08-11 22:15:34 +02:00
const collectionItemsWithTracks = collectionExpanded . books . filter ( ( li ) => li . media . tracks . length )
2022-12-27 00:48:39 +01:00
// Check collection has audio tracks
if ( ! collectionItemsWithTracks . length ) {
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-08-11 23:07:29 +02:00
const feed = await this . rssFeedManager . openFeedForCollection ( req . user . id , collectionExpanded , req . body )
2022-12-27 00:48:39 +01:00
res . json ( {
feed : feed . toJSONMinified ( )
} )
}
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 ) {
const options = req . body || { }
2024-09-01 22:08:56 +02:00
const series = await Database . seriesModel . findByPk ( req . params . seriesId )
2022-12-31 23:58:19 +01:00
if ( ! series ) return res . sendStatus ( 404 )
// Check request body options exist
2023-02-25 15:53:09 +01:00
if ( ! options . serverAddress || ! options . slug ) {
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)
2023-07-17 23:48:46 +02:00
if ( await this . rssFeedManager . findFeedBySlug ( options . slug ) ) {
2022-12-31 23:58:19 +01:00
Logger . error ( ` [RSSFeedController] Cannot open RSS feed because slug " ${ options . slug } " is already in use ` )
return res . status ( 400 ) . send ( 'Slug already in use' )
}
2024-09-01 22:08:56 +02:00
const seriesJson = series . toOldJSON ( )
2023-08-13 22:10:26 +02:00
2022-12-31 23:58:19 +01:00
// Get books in series that have audio tracks
2024-08-11 22:15:34 +02:00
seriesJson . books = ( await libraryItemsBookFilters . getLibraryItemsForSeries ( series ) ) . filter ( ( li ) => li . media . numTracks )
2022-12-31 23:58:19 +01:00
// Check series has audio tracks
if ( ! seriesJson . books . length ) {
Logger . error ( ` [RSSFeedController] Cannot open RSS feed for series " ${ seriesJson . name } " because it has no audio tracks ` )
return res . status ( 400 ) . send ( 'Series has no audio tracks' )
}
2024-08-11 23:07:29 +02:00
const feed = await this . rssFeedManager . openFeedForSeries ( req . user . id , seriesJson , req . body )
2022-12-31 23:58:19 +01:00
res . json ( {
feed : feed . toJSONMinified ( )
} )
}
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
* /
2023-07-07 00:07:10 +02:00
closeRSSFeed ( req , res ) {
this . rssFeedManager . closeRssFeed ( req , res )
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 ( )