mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-02-10 00:18:06 +01:00
Update library collections api endpoint to use libraryItems from db
This commit is contained in:
parent
aac2879652
commit
38029d1202
@ -8,22 +8,23 @@ class CollectionController {
|
||||
constructor() { }
|
||||
|
||||
async create(req, res) {
|
||||
var newCollection = new Collection()
|
||||
const newCollection = new Collection()
|
||||
req.body.userId = req.user.id
|
||||
var success = newCollection.setData(req.body)
|
||||
if (!success) {
|
||||
if (!newCollection.setData(req.body)) {
|
||||
return res.status(500).send('Invalid collection data')
|
||||
}
|
||||
var jsonExpanded = newCollection.toJSONExpanded(Database.libraryItems)
|
||||
|
||||
const libraryItemsInCollection = await Database.models.libraryItem.getForCollection(newCollection)
|
||||
const jsonExpanded = newCollection.toJSONExpanded(libraryItemsInCollection)
|
||||
await Database.createCollection(newCollection)
|
||||
SocketAuthority.emitter('collection_added', jsonExpanded)
|
||||
res.json(jsonExpanded)
|
||||
}
|
||||
|
||||
async findAll(req, res) {
|
||||
const collections = await Database.models.collection.getOldCollections()
|
||||
const collectionsExpanded = await Database.models.collection.getOldCollectionsJsonExpanded(req.user)
|
||||
res.json({
|
||||
collections: collections.map(c => c.toJSONExpanded(Database.libraryItems))
|
||||
collections: collectionsExpanded
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -535,8 +535,6 @@ class LibraryController {
|
||||
|
||||
// api/libraries/:id/collections
|
||||
async getCollectionsForLibrary(req, res) {
|
||||
const libraryItems = req.libraryItems
|
||||
|
||||
const include = (req.query.include || '').split(',').map(v => v.trim().toLowerCase()).filter(v => !!v)
|
||||
|
||||
const payload = {
|
||||
@ -551,23 +549,8 @@ class LibraryController {
|
||||
include: include.join(',')
|
||||
}
|
||||
|
||||
const collectionsForLibrary = await Database.models.collection.getAllForLibrary(req.library.id)
|
||||
|
||||
let collections = await Promise.all(collectionsForLibrary.map(async c => {
|
||||
const expanded = c.toJSONExpanded(libraryItems, payload.minified)
|
||||
|
||||
// If all books restricted to user in this collection then hide this collection
|
||||
if (!expanded.books.length && c.books.length) return null
|
||||
|
||||
if (include.includes('rssfeed')) {
|
||||
const feedData = await this.rssFeedManager.findFeedForEntityId(c.id)
|
||||
expanded.rssFeed = feedData?.toJSONMinified() || null
|
||||
}
|
||||
|
||||
return expanded
|
||||
}))
|
||||
|
||||
collections = collections.filter(c => !!c)
|
||||
// TODO: Create paginated queries
|
||||
let collections = await Database.models.collection.getOldCollectionsJsonExpanded(req.user, req.library.id, include)
|
||||
|
||||
payload.total = collections.length
|
||||
|
||||
@ -964,6 +947,12 @@ class LibraryController {
|
||||
res.send(opmlText)
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Replace with middlewareNew
|
||||
* @param {*} req
|
||||
* @param {*} res
|
||||
* @param {*} next
|
||||
*/
|
||||
async middleware(req, res, next) {
|
||||
if (!req.user.checkCanAccessLibrary(req.params.id)) {
|
||||
Logger.warn(`[LibraryController] Library ${req.params.id} not accessible to user ${req.user.username}`)
|
||||
@ -980,5 +969,25 @@ class LibraryController {
|
||||
})
|
||||
next()
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware that is not using libraryItems from memory
|
||||
* @param {*} req
|
||||
* @param {*} res
|
||||
* @param {*} next
|
||||
*/
|
||||
async middlewareNew(req, res, next) {
|
||||
if (!req.user.checkCanAccessLibrary(req.params.id)) {
|
||||
Logger.warn(`[LibraryController] Library ${req.params.id} not accessible to user ${req.user.username}`)
|
||||
return res.sendStatus(403)
|
||||
}
|
||||
|
||||
const library = await Database.models.library.getOldById(req.params.id)
|
||||
if (!library) {
|
||||
return res.status(404).send('Library not found')
|
||||
}
|
||||
req.library = library
|
||||
next()
|
||||
}
|
||||
}
|
||||
module.exports = new LibraryController()
|
||||
|
@ -5,6 +5,10 @@ const { areEquivalent } = require('../utils/index')
|
||||
|
||||
module.exports = (sequelize) => {
|
||||
class Collection extends Model {
|
||||
/**
|
||||
* Get all old collections
|
||||
* @returns {Promise<oldCollection[]>}
|
||||
*/
|
||||
static async getOldCollections() {
|
||||
const collections = await this.findAll({
|
||||
include: {
|
||||
@ -16,6 +20,103 @@ module.exports = (sequelize) => {
|
||||
return collections.map(c => this.getOldCollection(c))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all old collections toJSONExpanded, items filtered for user permissions
|
||||
* @param {[oldUser]} user
|
||||
* @param {[string]} libraryId
|
||||
* @param {[string[]]} include
|
||||
* @returns {Promise<object[]>} oldCollection.toJSONExpanded
|
||||
*/
|
||||
static async getOldCollectionsJsonExpanded(user, libraryId, include) {
|
||||
let collectionWhere = null
|
||||
if (libraryId) {
|
||||
collectionWhere = {
|
||||
libraryId
|
||||
}
|
||||
}
|
||||
|
||||
// Optionally include rssfeed for collection
|
||||
const collectionIncludes = []
|
||||
if (include.includes('rssfeed')) {
|
||||
collectionIncludes.push({
|
||||
model: sequelize.models.feed
|
||||
})
|
||||
}
|
||||
|
||||
const collections = await this.findAll({
|
||||
where: collectionWhere,
|
||||
include: [
|
||||
{
|
||||
model: sequelize.models.book,
|
||||
include: [
|
||||
{
|
||||
model: sequelize.models.libraryItem
|
||||
},
|
||||
{
|
||||
model: sequelize.models.author,
|
||||
through: {
|
||||
attributes: []
|
||||
}
|
||||
},
|
||||
{
|
||||
model: sequelize.models.series,
|
||||
through: {
|
||||
attributes: ['sequence']
|
||||
}
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
...collectionIncludes
|
||||
],
|
||||
order: [[sequelize.models.book, sequelize.models.collectionBook, 'order', 'ASC']]
|
||||
})
|
||||
// TODO: Handle user permission restrictions on initial query
|
||||
return collections.map(c => {
|
||||
const oldCollection = this.getOldCollection(c)
|
||||
|
||||
// Filter books using user permissions
|
||||
const books = c.books?.filter(b => {
|
||||
if (user) {
|
||||
if (b.tags?.length && !user.checkCanAccessLibraryItemWithTags(b.tags)) {
|
||||
return false
|
||||
}
|
||||
if (b.explicit === true && !user.canAccessExplicitContent) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}) || []
|
||||
|
||||
// Map to library items
|
||||
const libraryItems = books.map(b => {
|
||||
const libraryItem = b.libraryItem
|
||||
delete b.libraryItem
|
||||
libraryItem.media = b
|
||||
return sequelize.models.libraryItem.getOldLibraryItem(libraryItem)
|
||||
})
|
||||
|
||||
// Users with restricted permissions will not see this collection
|
||||
if (!books.length && oldCollection.books.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
const collectionExpanded = oldCollection.toJSONExpanded(libraryItems)
|
||||
|
||||
// Map feed if found
|
||||
if (c.feeds?.length) {
|
||||
collectionExpanded.rssFeed = sequelize.models.feed.getOldFeed(c.feeds[0])
|
||||
}
|
||||
|
||||
return collectionExpanded
|
||||
}).filter(c => c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get old collection from Collection
|
||||
* @param {Collection} collectionExpanded
|
||||
* @returns {oldCollection}
|
||||
*/
|
||||
static getOldCollection(collectionExpanded) {
|
||||
const libraryItemIds = collectionExpanded.books?.map(b => b.libraryItem?.id || null).filter(lid => lid) || []
|
||||
return new oldCollection({
|
||||
|
@ -16,6 +16,11 @@ module.exports = (sequelize) => {
|
||||
return feeds.map(f => this.getOldFeed(f))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get old feed from Feed and optionally Feed with FeedEpisodes
|
||||
* @param {Feed} feedExpanded
|
||||
* @returns {oldFeed}
|
||||
*/
|
||||
static getOldFeed(feedExpanded) {
|
||||
const episodes = feedExpanded.feedEpisodes?.map((feedEpisode) => feedEpisode.getOldEpisode())
|
||||
return new oldFeed({
|
||||
|
@ -661,13 +661,23 @@ module.exports = (sequelize) => {
|
||||
* Get book library items for author, optional use user permissions
|
||||
* @param {oldAuthor} author
|
||||
* @param {[oldUser]} user
|
||||
* @returns {oldLibraryItem[]}
|
||||
* @returns {Promise<oldLibraryItem[]>}
|
||||
*/
|
||||
static async getForAuthor(author, user = null) {
|
||||
const { libraryItems } = await libraryFilters.getLibraryItemsForAuthor(author, user, undefined, undefined)
|
||||
return libraryItems.map(li => this.getOldLibraryItem(li))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get book library items in a collection
|
||||
* @param {oldCollection} collection
|
||||
* @returns {Promise<oldLibraryItem[]>}
|
||||
*/
|
||||
static async getForCollection(collection) {
|
||||
const libraryItems = await libraryFilters.getLibraryItemsForCollection(collection)
|
||||
return libraryItems.map(li => this.getOldLibraryItem(li))
|
||||
}
|
||||
|
||||
getMedia(options) {
|
||||
if (!this.mediaType) return Promise.resolve(null)
|
||||
const mixinMethodName = `get${sequelize.uppercaseFirst(this.mediaType)}`
|
||||
|
@ -74,16 +74,16 @@ class ApiRouter {
|
||||
this.router.patch('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.update.bind(this))
|
||||
this.router.delete('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.delete.bind(this))
|
||||
|
||||
this.router.get('/libraries/:id/items2', LibraryController.middleware.bind(this), LibraryController.getLibraryItemsNew.bind(this))
|
||||
this.router.get('/libraries/:id/items2', LibraryController.middlewareNew.bind(this), LibraryController.getLibraryItemsNew.bind(this))
|
||||
this.router.get('/libraries/:id/items', LibraryController.middleware.bind(this), LibraryController.getLibraryItems.bind(this))
|
||||
this.router.delete('/libraries/:id/issues', LibraryController.middleware.bind(this), LibraryController.removeLibraryItemsWithIssues.bind(this))
|
||||
this.router.get('/libraries/:id/episode-downloads', LibraryController.middleware.bind(this), LibraryController.getEpisodeDownloadQueue.bind(this))
|
||||
this.router.get('/libraries/:id/series', LibraryController.middleware.bind(this), LibraryController.getAllSeriesForLibrary.bind(this))
|
||||
this.router.get('/libraries/:id/series/:seriesId', LibraryController.middleware.bind(this), LibraryController.getSeriesForLibrary.bind(this))
|
||||
this.router.get('/libraries/:id/collections', LibraryController.middleware.bind(this), LibraryController.getCollectionsForLibrary.bind(this))
|
||||
this.router.get('/libraries/:id/collections', LibraryController.middlewareNew.bind(this), LibraryController.getCollectionsForLibrary.bind(this))
|
||||
this.router.get('/libraries/:id/playlists', LibraryController.middleware.bind(this), LibraryController.getUserPlaylistsForLibrary.bind(this))
|
||||
this.router.get('/libraries/:id/albums', LibraryController.middleware.bind(this), LibraryController.getAlbumsForLibrary.bind(this))
|
||||
this.router.get('/libraries/:id/personalized2', LibraryController.middleware.bind(this), LibraryController.getUserPersonalizedShelves.bind(this))
|
||||
this.router.get('/libraries/:id/personalized2', LibraryController.middlewareNew.bind(this), LibraryController.getUserPersonalizedShelves.bind(this))
|
||||
this.router.get('/libraries/:id/personalized', LibraryController.middleware.bind(this), LibraryController.getLibraryUserPersonalizedOptimal.bind(this))
|
||||
this.router.get('/libraries/:id/filterdata', LibraryController.middleware.bind(this), LibraryController.getLibraryFilterData.bind(this))
|
||||
this.router.get('/libraries/:id/search', LibraryController.middleware.bind(this), LibraryController.search.bind(this))
|
||||
|
@ -365,7 +365,7 @@ module.exports = {
|
||||
* @param {[oldUser]} user
|
||||
* @param {number} limit
|
||||
* @param {number} offset
|
||||
* @returns {object} { libraryItems:LibraryItem[], count:number }
|
||||
* @returns {Promise<object>} { libraryItems:LibraryItem[], count:number }
|
||||
*/
|
||||
async getLibraryItemsForAuthor(author, user, limit, offset) {
|
||||
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(author.libraryId, user, 'authors', author.id, 'addedAt', true, false, [], limit, offset)
|
||||
@ -373,5 +373,14 @@ module.exports = {
|
||||
count,
|
||||
libraryItems
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get book library items in a collection
|
||||
* @param {oldCollection} collection
|
||||
* @returns {Promise<LibraryItem[]>}
|
||||
*/
|
||||
getLibraryItemsForCollection(collection) {
|
||||
return libraryItemsBookFilters.getLibraryItemsForCollection(collection)
|
||||
}
|
||||
}
|
@ -548,7 +548,7 @@ module.exports = {
|
||||
replacements,
|
||||
benchmark: true,
|
||||
logging: (sql, timeMs) => {
|
||||
console.log(`[Query] Elapsed ${timeMs}ms.`)
|
||||
console.log(`[Query] Elapsed ${timeMs}ms`)
|
||||
},
|
||||
include: [
|
||||
{
|
||||
@ -870,5 +870,48 @@ module.exports = {
|
||||
libraryItems,
|
||||
count
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get book library items in a collection
|
||||
* @param {oldCollection} collection
|
||||
* @returns {Promise<LibraryItem[]>}
|
||||
*/
|
||||
async getLibraryItemsForCollection(collection) {
|
||||
if (!collection?.books?.length) {
|
||||
Logger.error(`[libraryItemsBookFilters] Invalid collection`, collection)
|
||||
return []
|
||||
}
|
||||
const books = await Database.models.book.findAll({
|
||||
where: {
|
||||
id: {
|
||||
[Sequelize.Op.in]: collection.books
|
||||
}
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: Database.models.libraryItem
|
||||
},
|
||||
{
|
||||
model: sequelize.models.author,
|
||||
through: {
|
||||
attributes: []
|
||||
}
|
||||
},
|
||||
{
|
||||
model: sequelize.models.series,
|
||||
through: {
|
||||
attributes: ['sequence']
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
return books.map((book) => {
|
||||
const libraryItem = book.libraryItem
|
||||
delete book.libraryItem
|
||||
libraryItem.media = book
|
||||
return libraryItem
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user