From 345ff1aa6602dc6dbe6c7526281d1dc68d9a9845 Mon Sep 17 00:00:00 2001 From: advplyr Date: Sun, 6 Aug 2023 15:06:45 -0500 Subject: [PATCH] Update author API endpoints to load library items from DB --- server/controllers/AuthorController.js | 25 +++------ server/controllers/LibraryItemController.js | 4 +- server/models/LibraryItem.js | 51 +++++++++++++++++++ server/utils/queries/libraryFilters.js | 16 ++++++ .../utils/queries/libraryItemsBookFilters.js | 6 ++- 5 files changed, 80 insertions(+), 22 deletions(-) diff --git a/server/controllers/AuthorController.js b/server/controllers/AuthorController.js index 9c8fc7bd..5133d1cb 100644 --- a/server/controllers/AuthorController.js +++ b/server/controllers/AuthorController.js @@ -15,18 +15,13 @@ class AuthorController { constructor() { } async findOne(req, res) { - const libraryId = req.query.library const include = (req.query.include || '').split(',') const authorJson = req.author.toJSON() // Used on author landing page to include library items and items grouped in series if (include.includes('items')) { - authorJson.libraryItems = Database.libraryItems.filter(li => { - if (libraryId && li.libraryId !== libraryId) return false - if (!req.user.checkCanAccessLibraryItem(li)) return false // filter out library items user cannot access - return li.media.metadata.hasAuthor && li.media.metadata.hasAuthor(req.author.id) - }) + authorJson.libraryItems = await Database.models.libraryItem.getForAuthor(req.author, req.user) if (include.includes('series')) { const seriesMap = {} @@ -101,7 +96,7 @@ class AuthorController { const existingAuthor = authorNameUpdate ? Database.authors.find(au => au.id !== req.author.id && payload.name === au.name) : false if (existingAuthor) { const bookAuthorsToCreate = [] - const itemsWithAuthor = Database.libraryItems.filter(li => li.mediaType === 'book' && li.media.metadata.hasAuthor(req.author.id)) + const itemsWithAuthor = await Database.models.libraryItem.getForAuthor(req.author) itemsWithAuthor.forEach(libraryItem => { // Replace old author with merging author for each book libraryItem.media.metadata.replaceAuthor(req.author, existingAuthor) bookAuthorsToCreate.push({ @@ -120,9 +115,7 @@ class AuthorController { SocketAuthority.emitter('author_removed', req.author.toJSON()) // Send updated num books for merged author - const numBooks = Database.libraryItems.filter(li => { - return li.media.metadata.hasAuthor && li.media.metadata.hasAuthor(existingAuthor.id) - }).length + const numBooks = await Database.models.libraryItem.getForAuthor(existingAuthor).length SocketAuthority.emitter('author_updated', existingAuthor.toJSONExpanded(numBooks)) res.json({ @@ -137,8 +130,8 @@ class AuthorController { if (hasUpdated) { req.author.updatedAt = Date.now() + const itemsWithAuthor = await Database.models.libraryItem.getForAuthor(req.author) if (authorNameUpdate) { // Update author name on all books - const itemsWithAuthor = Database.libraryItems.filter(li => li.mediaType === 'book' && li.media.metadata.hasAuthor(req.author.id)) itemsWithAuthor.forEach(libraryItem => { libraryItem.media.metadata.updateAuthor(req.author) }) @@ -148,10 +141,7 @@ class AuthorController { } await Database.updateAuthor(req.author) - const numBooks = Database.libraryItems.filter(li => { - return li.media.metadata.hasAuthor && li.media.metadata.hasAuthor(req.author.id) - }).length - SocketAuthority.emitter('author_updated', req.author.toJSONExpanded(numBooks)) + SocketAuthority.emitter('author_updated', req.author.toJSONExpanded(itemsWithAuthor.length)) } res.json({ @@ -211,9 +201,8 @@ class AuthorController { req.author.updatedAt = Date.now() await Database.updateAuthor(req.author) - const numBooks = Database.libraryItems.filter(li => { - return li.media.metadata.hasAuthor && li.media.metadata.hasAuthor(req.author.id) - }).length + + const numBooks = await Database.models.libraryItem.getForAuthor(req.author).length SocketAuthority.emitter('author_updated', req.author.toJSONExpanded(numBooks)) } diff --git a/server/controllers/LibraryItemController.js b/server/controllers/LibraryItemController.js index 4e10baa9..9c0be842 100644 --- a/server/controllers/LibraryItemController.js +++ b/server/controllers/LibraryItemController.js @@ -679,8 +679,8 @@ class LibraryItemController { res.sendStatus(200) } - middleware(req, res, next) { - req.libraryItem = Database.libraryItems.find(li => li.id === req.params.id) + async middleware(req, res, next) { + req.libraryItem = await Database.models.libraryItem.getOldById(req.params.id) if (!req.libraryItem?.media) return res.sendStatus(404) // Check user can access this library item diff --git a/server/models/LibraryItem.js b/server/models/LibraryItem.js index d84761c0..1932ee5f 100644 --- a/server/models/LibraryItem.js +++ b/server/models/LibraryItem.js @@ -400,6 +400,46 @@ module.exports = (sequelize) => { }) } + /** + * Get old library item by id + * @param {string} libraryItemId + * @returns {oldLibraryItem} + */ + static async getOldById(libraryItemId) { + if (!libraryItemId) return null + const libraryItem = await this.findByPk(libraryItemId, { + include: [ + { + model: sequelize.models.book, + include: [ + { + model: sequelize.models.author, + through: { + attributes: [] + } + }, + { + model: sequelize.models.series, + through: { + attributes: ['sequence'] + } + } + ] + }, + { + model: sequelize.models.podcast, + include: [ + { + model: sequelize.models.podcastEpisode + } + ] + } + ] + }) + if (!libraryItem) return null + return this.getOldLibraryItem(libraryItem) + } + /** * Get library items using filter and sort * @param {oldLibrary} library @@ -609,6 +649,17 @@ module.exports = (sequelize) => { return shelves } + /** + * Get book library items for author, optional use user permissions + * @param {oldAuthor} author + * @param {[oldUser]} user + * @returns {oldLibraryItem[]} + */ + static async getForAuthor(author, user = null) { + const { libraryItems } = await libraryFilters.getLibraryItemsForAuthor(author, user, undefined, undefined) + return libraryItems.map(li => this.getOldLibraryItem(li)) + } + getMedia(options) { if (!this.mediaType) return Promise.resolve(null) const mixinMethodName = `get${sequelize.uppercaseFirst(this.mediaType)}` diff --git a/server/utils/queries/libraryFilters.js b/server/utils/queries/libraryFilters.js index 2aa90d03..79a4015a 100644 --- a/server/utils/queries/libraryFilters.js +++ b/server/utils/queries/libraryFilters.js @@ -357,5 +357,21 @@ module.exports = { return oldLibraryItem }) } + }, + + /** + * Get library items for an author, optional use user permissions + * @param {oldAuthor} author + * @param {[oldUser]} user + * @param {number} limit + * @param {number} offset + * @returns {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) + return { + count, + libraryItems + } } } \ No newline at end of file diff --git a/server/utils/queries/libraryItemsBookFilters.js b/server/utils/queries/libraryItemsBookFilters.js index cf4618e8..78d6b05e 100644 --- a/server/utils/queries/libraryItemsBookFilters.js +++ b/server/utils/queries/libraryItemsBookFilters.js @@ -11,6 +11,8 @@ module.exports = { getUserPermissionBookWhereQuery(user) { const bookWhere = [] const replacements = {} + if (!user) return { bookWhere, replacements } + if (!user.canAccessExplicitContent) { bookWhere.push({ explicit: false @@ -325,7 +327,7 @@ module.exports = { /** * Get library items for book media type using filter and sort * @param {string} libraryId - * @param {oldUser} user + * @param {[oldUser]} user * @param {[string]} filterGroup * @param {[string]} filterValue * @param {string} sortBy @@ -467,7 +469,7 @@ module.exports = { isInvalid: true } ] - } else if (filterGroup === 'progress') { + } else if (filterGroup === 'progress' && user) { bookIncludes.push({ model: Database.models.mediaProgress, attributes: ['id', 'isFinished', 'currentTime', 'ebookProgress', 'updatedAt'],