mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-03-19 18:08:19 +01:00
Update controllers to use new user model
This commit is contained in:
parent
202ceb02b5
commit
68ef3a07a7
@ -24,7 +24,7 @@ class AuthorController {
|
|||||||
|
|
||||||
// Used on author landing page to include library items and items grouped in series
|
// Used on author landing page to include library items and items grouped in series
|
||||||
if (include.includes('items')) {
|
if (include.includes('items')) {
|
||||||
authorJson.libraryItems = await Database.libraryItemModel.getForAuthor(req.author, req.user)
|
authorJson.libraryItems = await Database.libraryItemModel.getForAuthor(req.author, req.userNew)
|
||||||
|
|
||||||
if (include.includes('series')) {
|
if (include.includes('series')) {
|
||||||
const seriesMap = {}
|
const seriesMap = {}
|
||||||
@ -222,8 +222,8 @@ class AuthorController {
|
|||||||
* @param {import('express').Response} res
|
* @param {import('express').Response} res
|
||||||
*/
|
*/
|
||||||
async uploadImage(req, res) {
|
async uploadImage(req, res) {
|
||||||
if (!req.user.canUpload) {
|
if (!req.userNew.canUpload) {
|
||||||
Logger.warn('User attempted to upload an image without permission', req.user)
|
Logger.warn(`User "${req.userNew.username}" attempted to upload an image without permission`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
if (!req.body.url) {
|
if (!req.body.url) {
|
||||||
@ -362,11 +362,11 @@ class AuthorController {
|
|||||||
const author = await Database.authorModel.getOldById(req.params.id)
|
const author = await Database.authorModel.getOldById(req.params.id)
|
||||||
if (!author) return res.sendStatus(404)
|
if (!author) return res.sendStatus(404)
|
||||||
|
|
||||||
if (req.method == 'DELETE' && !req.user.canDelete) {
|
if (req.method == 'DELETE' && !req.userNew.canDelete) {
|
||||||
Logger.warn(`[AuthorController] User attempted to delete without permission`, req.user)
|
Logger.warn(`[AuthorController] User "${req.userNew.username}" attempted to delete without permission`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
|
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
|
||||||
Logger.warn('[AuthorController] User attempted to update without permission', req.user)
|
Logger.warn(`[AuthorController] User "${req.userNew.username}" attempted to update without permission`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,8 +113,8 @@ class BackupController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
middleware(req, res, next) {
|
middleware(req, res, next) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
Logger.error(`[BackupController] Non-admin user attempting to access backups`, req.user)
|
Logger.error(`[BackupController] Non-admin user "${req.userNew.username}" attempting to access backups`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ class CacheController {
|
|||||||
|
|
||||||
// POST: api/cache/purge
|
// POST: api/cache/purge
|
||||||
async purgeCache(req, res) {
|
async purgeCache(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
await CacheManager.purgeAll()
|
await CacheManager.purgeAll()
|
||||||
@ -14,7 +14,7 @@ class CacheController {
|
|||||||
|
|
||||||
// POST: api/cache/items/purge
|
// POST: api/cache/items/purge
|
||||||
async purgeItemsCache(req, res) {
|
async purgeItemsCache(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
await CacheManager.purgeItems()
|
await CacheManager.purgeItems()
|
||||||
|
@ -16,7 +16,7 @@ class CollectionController {
|
|||||||
*/
|
*/
|
||||||
async create(req, res) {
|
async create(req, res) {
|
||||||
const newCollection = new Collection()
|
const newCollection = new Collection()
|
||||||
req.body.userId = req.user.id
|
req.body.userId = req.userNew.id
|
||||||
if (!newCollection.setData(req.body)) {
|
if (!newCollection.setData(req.body)) {
|
||||||
return res.status(400).send('Invalid collection data')
|
return res.status(400).send('Invalid collection data')
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ class CollectionController {
|
|||||||
let order = 1
|
let order = 1
|
||||||
const collectionBooksToAdd = []
|
const collectionBooksToAdd = []
|
||||||
for (const libraryItemId of newCollection.books) {
|
for (const libraryItemId of newCollection.books) {
|
||||||
const libraryItem = libraryItemsInCollection.find(li => li.id === libraryItemId)
|
const libraryItem = libraryItemsInCollection.find((li) => li.id === libraryItemId)
|
||||||
if (libraryItem) {
|
if (libraryItem) {
|
||||||
collectionBooksToAdd.push({
|
collectionBooksToAdd.push({
|
||||||
collectionId: newCollection.id,
|
collectionId: newCollection.id,
|
||||||
@ -50,7 +50,7 @@ class CollectionController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async findAll(req, res) {
|
async findAll(req, res) {
|
||||||
const collectionsExpanded = await Database.collectionModel.getOldCollectionsJsonExpanded(req.user)
|
const collectionsExpanded = await Database.collectionModel.getOldCollectionsJsonExpanded(req.userNew)
|
||||||
res.json({
|
res.json({
|
||||||
collections: collectionsExpanded
|
collections: collectionsExpanded
|
||||||
})
|
})
|
||||||
@ -59,7 +59,7 @@ class CollectionController {
|
|||||||
async findOne(req, res) {
|
async findOne(req, res) {
|
||||||
const includeEntities = (req.query.include || '').split(',')
|
const includeEntities = (req.query.include || '').split(',')
|
||||||
|
|
||||||
const collectionExpanded = await req.collection.getOldJsonExpanded(req.user, includeEntities)
|
const collectionExpanded = await req.collection.getOldJsonExpanded(req.userNew, includeEntities)
|
||||||
if (!collectionExpanded) {
|
if (!collectionExpanded) {
|
||||||
// This may happen if the user is restricted from all books
|
// This may happen if the user is restricted from all books
|
||||||
return res.sendStatus(404)
|
return res.sendStatus(404)
|
||||||
@ -102,8 +102,8 @@ class CollectionController {
|
|||||||
order: [['order', 'ASC']]
|
order: [['order', 'ASC']]
|
||||||
})
|
})
|
||||||
collectionBooks.sort((a, b) => {
|
collectionBooks.sort((a, b) => {
|
||||||
const aIndex = req.body.books.findIndex(lid => lid === a.book.libraryItem.id)
|
const aIndex = req.body.books.findIndex((lid) => lid === a.book.libraryItem.id)
|
||||||
const bIndex = req.body.books.findIndex(lid => lid === b.book.libraryItem.id)
|
const bIndex = req.body.books.findIndex((lid) => lid === b.book.libraryItem.id)
|
||||||
return aIndex - bIndex
|
return aIndex - bIndex
|
||||||
})
|
})
|
||||||
for (let i = 0; i < collectionBooks.length; i++) {
|
for (let i = 0; i < collectionBooks.length; i++) {
|
||||||
@ -153,7 +153,7 @@ class CollectionController {
|
|||||||
|
|
||||||
// Check if book is already in collection
|
// Check if book is already in collection
|
||||||
const collectionBooks = await req.collection.getCollectionBooks()
|
const collectionBooks = await req.collection.getCollectionBooks()
|
||||||
if (collectionBooks.some(cb => cb.bookId === libraryItem.media.id)) {
|
if (collectionBooks.some((cb) => cb.bookId === libraryItem.media.id)) {
|
||||||
return res.status(400).send('Book already in collection')
|
return res.status(400).send('Book already in collection')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ class CollectionController {
|
|||||||
})
|
})
|
||||||
|
|
||||||
let jsonExpanded = null
|
let jsonExpanded = null
|
||||||
const collectionBookToRemove = collectionBooks.find(cb => cb.bookId === libraryItem.media.id)
|
const collectionBookToRemove = collectionBooks.find((cb) => cb.bookId === libraryItem.media.id)
|
||||||
if (collectionBookToRemove) {
|
if (collectionBookToRemove) {
|
||||||
// Remove collection book record
|
// Remove collection book record
|
||||||
await collectionBookToRemove.destroy()
|
await collectionBookToRemove.destroy()
|
||||||
@ -221,7 +221,7 @@ class CollectionController {
|
|||||||
*/
|
*/
|
||||||
async addBatch(req, res) {
|
async addBatch(req, res) {
|
||||||
// filter out invalid libraryItemIds
|
// filter out invalid libraryItemIds
|
||||||
const bookIdsToAdd = (req.body.books || []).filter(b => !!b && typeof b == 'string')
|
const bookIdsToAdd = (req.body.books || []).filter((b) => !!b && typeof b == 'string')
|
||||||
if (!bookIdsToAdd.length) {
|
if (!bookIdsToAdd.length) {
|
||||||
return res.status(500).send('Invalid request body')
|
return res.status(500).send('Invalid request body')
|
||||||
}
|
}
|
||||||
@ -247,7 +247,7 @@ class CollectionController {
|
|||||||
|
|
||||||
// Check and set new collection books to add
|
// Check and set new collection books to add
|
||||||
for (const libraryItem of libraryItems) {
|
for (const libraryItem of libraryItems) {
|
||||||
if (!collectionBooks.some(cb => cb.bookId === libraryItem.media.id)) {
|
if (!collectionBooks.some((cb) => cb.bookId === libraryItem.media.id)) {
|
||||||
collectionBooksToAdd.push({
|
collectionBooksToAdd.push({
|
||||||
collectionId: req.collection.id,
|
collectionId: req.collection.id,
|
||||||
bookId: libraryItem.media.id,
|
bookId: libraryItem.media.id,
|
||||||
@ -279,7 +279,7 @@ class CollectionController {
|
|||||||
*/
|
*/
|
||||||
async removeBatch(req, res) {
|
async removeBatch(req, res) {
|
||||||
// filter out invalid libraryItemIds
|
// filter out invalid libraryItemIds
|
||||||
const bookIdsToRemove = (req.body.books || []).filter(b => !!b && typeof b == 'string')
|
const bookIdsToRemove = (req.body.books || []).filter((b) => !!b && typeof b == 'string')
|
||||||
if (!bookIdsToRemove.length) {
|
if (!bookIdsToRemove.length) {
|
||||||
return res.status(500).send('Invalid request body')
|
return res.status(500).send('Invalid request body')
|
||||||
}
|
}
|
||||||
@ -305,7 +305,7 @@ class CollectionController {
|
|||||||
let order = 1
|
let order = 1
|
||||||
let hasUpdated = false
|
let hasUpdated = false
|
||||||
for (const collectionBook of collectionBooks) {
|
for (const collectionBook of collectionBooks) {
|
||||||
if (libraryItems.some(li => li.media.id === collectionBook.bookId)) {
|
if (libraryItems.some((li) => li.media.id === collectionBook.bookId)) {
|
||||||
await collectionBook.destroy()
|
await collectionBook.destroy()
|
||||||
hasUpdated = true
|
hasUpdated = true
|
||||||
continue
|
continue
|
||||||
@ -334,11 +334,11 @@ class CollectionController {
|
|||||||
req.collection = collection
|
req.collection = collection
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.method == 'DELETE' && !req.user.canDelete) {
|
if (req.method == 'DELETE' && !req.userNew.canDelete) {
|
||||||
Logger.warn(`[CollectionController] User attempted to delete without permission`, req.user.username)
|
Logger.warn(`[CollectionController] User "${req.userNew.username}" attempted to delete without permission`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
|
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
|
||||||
Logger.warn('[CollectionController] User attempted to update without permission', req.user.username)
|
Logger.warn(`[CollectionController] User "${req.userNew.username}" attempted to update without permission`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class CustomMetadataProviderController {
|
|||||||
name,
|
name,
|
||||||
mediaType,
|
mediaType,
|
||||||
url,
|
url,
|
||||||
authHeaderValue: !authHeaderValue ? null : authHeaderValue,
|
authHeaderValue: !authHeaderValue ? null : authHeaderValue
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: Necessary to emit to all clients?
|
// TODO: Necessary to emit to all clients?
|
||||||
@ -76,13 +76,16 @@ class CustomMetadataProviderController {
|
|||||||
await provider.destroy()
|
await provider.destroy()
|
||||||
|
|
||||||
// Libraries using this provider fallback to default provider
|
// Libraries using this provider fallback to default provider
|
||||||
await Database.libraryModel.update({
|
await Database.libraryModel.update(
|
||||||
|
{
|
||||||
provider: fallbackProvider
|
provider: fallbackProvider
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
where: {
|
where: {
|
||||||
provider: slug
|
provider: slug
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// TODO: Necessary to emit to all clients?
|
// TODO: Necessary to emit to all clients?
|
||||||
SocketAuthority.emitter('custom_metadata_provider_removed', providerClientJson)
|
SocketAuthority.emitter('custom_metadata_provider_removed', providerClientJson)
|
||||||
@ -98,8 +101,8 @@ class CustomMetadataProviderController {
|
|||||||
* @param {import('express').NextFunction} next
|
* @param {import('express').NextFunction} next
|
||||||
*/
|
*/
|
||||||
async middleware(req, res, next) {
|
async middleware(req, res, next) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
Logger.warn(`[CustomMetadataProviderController] Non-admin user "${req.user.username}" attempted access route "${req.path}"`)
|
Logger.warn(`[CustomMetadataProviderController] Non-admin user "${req.userNew.username}" attempted access route "${req.path}"`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ class EmailController {
|
|||||||
* @param {import('express').Response} res
|
* @param {import('express').Response} res
|
||||||
*/
|
*/
|
||||||
async sendEBookToDevice(req, res) {
|
async sendEBookToDevice(req, res) {
|
||||||
Logger.debug(`[EmailController] Send ebook to device requested by user "${req.user.username}" for libraryItemId=${req.body.libraryItemId}, deviceName=${req.body.deviceName}`)
|
Logger.debug(`[EmailController] Send ebook to device requested by user "${req.userNew.username}" for libraryItemId=${req.body.libraryItemId}, deviceName=${req.body.deviceName}`)
|
||||||
|
|
||||||
const device = Database.emailSettings.getEReaderDevice(req.body.deviceName)
|
const device = Database.emailSettings.getEReaderDevice(req.body.deviceName)
|
||||||
if (!device) {
|
if (!device) {
|
||||||
@ -67,7 +67,7 @@ class EmailController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check user has access to device
|
// Check user has access to device
|
||||||
if (!Database.emailSettings.checkUserCanAccessDevice(device, req.user)) {
|
if (!Database.emailSettings.checkUserCanAccessDevice(device, req.userNew)) {
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ class EmailController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check user has access to library item
|
// Check user has access to library item
|
||||||
if (!req.user.checkCanAccessLibraryItem(libraryItem)) {
|
if (!req.userNew.checkCanAccessLibraryItem(libraryItem)) {
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ class EmailController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
adminMiddleware(req, res, next) {
|
adminMiddleware(req, res, next) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
return res.sendStatus(404)
|
return res.sendStatus(404)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ class FileSystemController {
|
|||||||
* @param {import('express').Response} res
|
* @param {import('express').Response} res
|
||||||
*/
|
*/
|
||||||
async getPaths(req, res) {
|
async getPaths(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
Logger.error(`[FileSystemController] Non-admin user attempting to get filesystem paths`, req.user)
|
Logger.error(`[FileSystemController] Non-admin user "${req.userNew.username}" attempting to get filesystem paths`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ class FileSystemController {
|
|||||||
const level = toNumber(req.query.level, 0)
|
const level = toNumber(req.query.level, 0)
|
||||||
|
|
||||||
// Validate path. Must be absolute
|
// Validate path. Must be absolute
|
||||||
if (relpath && (!Path.isAbsolute(relpath) || !await fs.pathExists(relpath))) {
|
if (relpath && (!Path.isAbsolute(relpath) || !(await fs.pathExists(relpath)))) {
|
||||||
Logger.error(`[FileSystemController] Invalid path in query string "${relpath}"`)
|
Logger.error(`[FileSystemController] Invalid path in query string "${relpath}"`)
|
||||||
return res.status(400).send('Invalid "path" query string')
|
return res.status(400).send('Invalid "path" query string')
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ class FileSystemController {
|
|||||||
return []
|
return []
|
||||||
})
|
})
|
||||||
if (drives.length) {
|
if (drives.length) {
|
||||||
directories = drives.map(d => {
|
directories = drives.map((d) => {
|
||||||
return {
|
return {
|
||||||
path: d,
|
path: d,
|
||||||
dirname: d,
|
dirname: d,
|
||||||
@ -54,10 +54,10 @@ class FileSystemController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exclude some dirs from this project to be cleaner in Docker
|
// Exclude some dirs from this project to be cleaner in Docker
|
||||||
const excludedDirs = ['node_modules', 'client', 'server', '.git', 'static', 'build', 'dist', 'metadata', 'config', 'sys', 'proc', '.devcontainer', '.nyc_output', '.github', '.vscode'].map(dirname => {
|
const excludedDirs = ['node_modules', 'client', 'server', '.git', 'static', 'build', 'dist', 'metadata', 'config', 'sys', 'proc', '.devcontainer', '.nyc_output', '.github', '.vscode'].map((dirname) => {
|
||||||
return fileUtils.filePathToPOSIX(Path.join(global.appRoot, dirname))
|
return fileUtils.filePathToPOSIX(Path.join(global.appRoot, dirname))
|
||||||
})
|
})
|
||||||
directories = directories.filter(dir => {
|
directories = directories.filter((dir) => {
|
||||||
return !excludedDirs.includes(dir.path)
|
return !excludedDirs.includes(dir.path)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -69,8 +69,8 @@ class FileSystemController {
|
|||||||
|
|
||||||
// POST: api/filesystem/pathexists
|
// POST: api/filesystem/pathexists
|
||||||
async checkPathExists(req, res) {
|
async checkPathExists(req, res) {
|
||||||
if (!req.user.canUpload) {
|
if (!req.userNew.canUpload) {
|
||||||
Logger.error(`[FileSystemController] Non-admin user attempting to check path exists`, req.user)
|
Logger.error(`[FileSystemController] Non-admin user "${req.userNew.username}" attempting to check path exists`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ class LibraryController {
|
|||||||
async findAll(req, res) {
|
async findAll(req, res) {
|
||||||
const libraries = await Database.libraryModel.getAllOldLibraries()
|
const libraries = await Database.libraryModel.getAllOldLibraries()
|
||||||
|
|
||||||
const librariesAccessible = req.user.librariesAccessible || []
|
const librariesAccessible = req.userNew.permissions?.librariesAccessible || []
|
||||||
if (librariesAccessible.length) {
|
if (librariesAccessible.length) {
|
||||||
return res.json({
|
return res.json({
|
||||||
libraries: libraries.filter((lib) => librariesAccessible.includes(lib.id)).map((lib) => lib.toJSON())
|
libraries: libraries.filter((lib) => librariesAccessible.includes(lib.id)).map((lib) => lib.toJSON())
|
||||||
@ -110,7 +110,7 @@ class LibraryController {
|
|||||||
return res.json({
|
return res.json({
|
||||||
filterdata,
|
filterdata,
|
||||||
issues: filterdata.numIssues,
|
issues: filterdata.numIssues,
|
||||||
numUserPlaylists: await Database.playlistModel.getNumPlaylistsForUserAndLibrary(req.user.id, req.library.id),
|
numUserPlaylists: await Database.playlistModel.getNumPlaylistsForUserAndLibrary(req.userNew.id, req.library.id),
|
||||||
customMetadataProviders,
|
customMetadataProviders,
|
||||||
library: req.library
|
library: req.library
|
||||||
})
|
})
|
||||||
@ -327,9 +327,9 @@ class LibraryController {
|
|||||||
const filterByValue = filterByGroup ? libraryFilters.decode(payload.filterBy.replace(`${filterByGroup}.`, '')) : null
|
const filterByValue = filterByGroup ? libraryFilters.decode(payload.filterBy.replace(`${filterByGroup}.`, '')) : null
|
||||||
if (filterByGroup === 'series' && filterByValue !== 'no-series' && payload.collapseseries) {
|
if (filterByGroup === 'series' && filterByValue !== 'no-series' && payload.collapseseries) {
|
||||||
const seriesId = libraryFilters.decode(payload.filterBy.split('.')[1])
|
const seriesId = libraryFilters.decode(payload.filterBy.split('.')[1])
|
||||||
payload.results = await libraryHelpers.handleCollapseSubseries(payload, seriesId, req.user, req.library)
|
payload.results = await libraryHelpers.handleCollapseSubseries(payload, seriesId, req.userNew, req.library)
|
||||||
} else {
|
} else {
|
||||||
const { libraryItems, count } = await Database.libraryItemModel.getByFilterAndSort(req.library, req.user, payload)
|
const { libraryItems, count } = await Database.libraryItemModel.getByFilterAndSort(req.library, req.userNew, payload)
|
||||||
payload.results = libraryItems
|
payload.results = libraryItems
|
||||||
payload.total = count
|
payload.total = count
|
||||||
}
|
}
|
||||||
@ -420,7 +420,7 @@ class LibraryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const offset = payload.page * payload.limit
|
const offset = payload.page * payload.limit
|
||||||
const { series, count } = await seriesFilters.getFilteredSeries(req.library, req.user, payload.filterBy, payload.sortBy, payload.sortDesc, include, payload.limit, offset)
|
const { series, count } = await seriesFilters.getFilteredSeries(req.library, req.userNew, payload.filterBy, payload.sortBy, payload.sortDesc, include, payload.limit, offset)
|
||||||
|
|
||||||
payload.total = count
|
payload.total = count
|
||||||
payload.results = series
|
payload.results = series
|
||||||
@ -447,11 +447,11 @@ class LibraryController {
|
|||||||
if (!series) return res.sendStatus(404)
|
if (!series) return res.sendStatus(404)
|
||||||
const oldSeries = series.getOldSeries()
|
const oldSeries = series.getOldSeries()
|
||||||
|
|
||||||
const libraryItemsInSeries = await libraryItemsBookFilters.getLibraryItemsForSeries(oldSeries, req.user)
|
const libraryItemsInSeries = await libraryItemsBookFilters.getLibraryItemsForSeries(oldSeries, req.userNew)
|
||||||
|
|
||||||
const seriesJson = oldSeries.toJSON()
|
const seriesJson = oldSeries.toJSON()
|
||||||
if (include.includes('progress')) {
|
if (include.includes('progress')) {
|
||||||
const libraryItemsFinished = libraryItemsInSeries.filter((li) => !!req.user.getMediaProgress(li.id)?.isFinished)
|
const libraryItemsFinished = libraryItemsInSeries.filter((li) => !!req.userNew.getMediaProgress(li.media.id)?.isFinished)
|
||||||
seriesJson.progress = {
|
seriesJson.progress = {
|
||||||
libraryItemIds: libraryItemsInSeries.map((li) => li.id),
|
libraryItemIds: libraryItemsInSeries.map((li) => li.id),
|
||||||
libraryItemIdsFinished: libraryItemsFinished.map((li) => li.id),
|
libraryItemIdsFinished: libraryItemsFinished.map((li) => li.id),
|
||||||
@ -492,7 +492,7 @@ class LibraryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Create paginated queries
|
// TODO: Create paginated queries
|
||||||
let collections = await Database.collectionModel.getOldCollectionsJsonExpanded(req.user, req.library.id, include)
|
let collections = await Database.collectionModel.getOldCollectionsJsonExpanded(req.userNew, req.library.id, include)
|
||||||
|
|
||||||
payload.total = collections.length
|
payload.total = collections.length
|
||||||
|
|
||||||
@ -512,7 +512,7 @@ class LibraryController {
|
|||||||
* @param {*} res
|
* @param {*} res
|
||||||
*/
|
*/
|
||||||
async getUserPlaylistsForLibrary(req, res) {
|
async getUserPlaylistsForLibrary(req, res) {
|
||||||
let playlistsForUser = await Database.playlistModel.getOldPlaylistsForUserAndLibrary(req.user.id, req.library.id)
|
let playlistsForUser = await Database.playlistModel.getOldPlaylistsForUserAndLibrary(req.userNew.id, req.library.id)
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
results: [],
|
results: [],
|
||||||
@ -552,7 +552,7 @@ class LibraryController {
|
|||||||
.split(',')
|
.split(',')
|
||||||
.map((v) => v.trim().toLowerCase())
|
.map((v) => v.trim().toLowerCase())
|
||||||
.filter((v) => !!v)
|
.filter((v) => !!v)
|
||||||
const shelves = await Database.libraryItemModel.getPersonalizedShelves(req.library, req.user, include, limitPerShelf)
|
const shelves = await Database.libraryItemModel.getPersonalizedShelves(req.library, req.userNew, include, limitPerShelf)
|
||||||
res.json(shelves)
|
res.json(shelves)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -563,8 +563,8 @@ class LibraryController {
|
|||||||
* @param {import('express').Response} res
|
* @param {import('express').Response} res
|
||||||
*/
|
*/
|
||||||
async reorder(req, res) {
|
async reorder(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
Logger.error('[LibraryController] ReorderLibraries invalid user', req.user)
|
Logger.error(`[LibraryController] Non-admin user "${req.userNew}" attempted to reorder libraries`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
const libraries = await Database.libraryModel.getAllOldLibraries()
|
const libraries = await Database.libraryModel.getAllOldLibraries()
|
||||||
@ -609,7 +609,7 @@ class LibraryController {
|
|||||||
const limit = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 12
|
const limit = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 12
|
||||||
const query = asciiOnlyToLowerCase(req.query.q.trim())
|
const query = asciiOnlyToLowerCase(req.query.q.trim())
|
||||||
|
|
||||||
const matches = await libraryItemFilters.search(req.user, req.library, query, limit)
|
const matches = await libraryItemFilters.search(req.userNew, req.library, query, limit)
|
||||||
res.json(matches)
|
res.json(matches)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,7 +662,7 @@ class LibraryController {
|
|||||||
* @param {import('express').Response} res
|
* @param {import('express').Response} res
|
||||||
*/
|
*/
|
||||||
async getAuthors(req, res) {
|
async getAuthors(req, res) {
|
||||||
const { bookWhere, replacements } = libraryItemsBookFilters.getUserPermissionBookWhereQuery(req.user)
|
const { bookWhere, replacements } = libraryItemsBookFilters.getUserPermissionBookWhereQuery(req.userNew)
|
||||||
const authors = await Database.authorModel.findAll({
|
const authors = await Database.authorModel.findAll({
|
||||||
where: {
|
where: {
|
||||||
libraryId: req.library.id
|
libraryId: req.library.id
|
||||||
@ -672,7 +672,7 @@ class LibraryController {
|
|||||||
model: Database.bookModel,
|
model: Database.bookModel,
|
||||||
attributes: ['id', 'tags', 'explicit'],
|
attributes: ['id', 'tags', 'explicit'],
|
||||||
where: bookWhere,
|
where: bookWhere,
|
||||||
required: !req.user.isAdminOrUp, // Only show authors with 0 books for admin users or up
|
required: !req.userNew.isAdminOrUp, // Only show authors with 0 books for admin users or up
|
||||||
through: {
|
through: {
|
||||||
attributes: []
|
attributes: []
|
||||||
}
|
}
|
||||||
@ -746,8 +746,8 @@ class LibraryController {
|
|||||||
* @param {*} res
|
* @param {*} res
|
||||||
*/
|
*/
|
||||||
async updateNarrator(req, res) {
|
async updateNarrator(req, res) {
|
||||||
if (!req.user.canUpdate) {
|
if (!req.userNew.canUpdate) {
|
||||||
Logger.error(`[LibraryController] Unauthorized user "${req.user.username}" attempted to update narrator`)
|
Logger.error(`[LibraryController] Unauthorized user "${req.userNew.username}" attempted to update narrator`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -796,8 +796,8 @@ class LibraryController {
|
|||||||
* @param {*} res
|
* @param {*} res
|
||||||
*/
|
*/
|
||||||
async removeNarrator(req, res) {
|
async removeNarrator(req, res) {
|
||||||
if (!req.user.canUpdate) {
|
if (!req.userNew.canUpdate) {
|
||||||
Logger.error(`[LibraryController] Unauthorized user "${req.user.username}" attempted to remove narrator`)
|
Logger.error(`[LibraryController] Unauthorized user "${req.userNew.username}" attempted to remove narrator`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -839,8 +839,8 @@ class LibraryController {
|
|||||||
* @param {import('express').Response} res
|
* @param {import('express').Response} res
|
||||||
*/
|
*/
|
||||||
async matchAll(req, res) {
|
async matchAll(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
Logger.error(`[LibraryController] Non-root user attempted to match library items`, req.user)
|
Logger.error(`[LibraryController] Non-root user "${req.userNew.username}" attempted to match library items`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
Scanner.matchLibraryItems(req.library)
|
Scanner.matchLibraryItems(req.library)
|
||||||
@ -856,8 +856,8 @@ class LibraryController {
|
|||||||
* @param {import('express').Response} res
|
* @param {import('express').Response} res
|
||||||
*/
|
*/
|
||||||
async scan(req, res) {
|
async scan(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
Logger.error(`[LibraryController] Non-root user attempted to scan library`, req.user)
|
Logger.error(`[LibraryController] Non-admin user "${req.userNew.username}" attempted to scan library`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
res.sendStatus(200)
|
res.sendStatus(200)
|
||||||
@ -887,7 +887,7 @@ class LibraryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const offset = payload.page * payload.limit
|
const offset = payload.page * payload.limit
|
||||||
payload.episodes = await libraryItemsPodcastFilters.getRecentEpisodes(req.user, req.library, payload.limit, offset)
|
payload.episodes = await libraryItemsPodcastFilters.getRecentEpisodes(req.userNew, req.library, payload.limit, offset)
|
||||||
res.json(payload)
|
res.json(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,7 +898,7 @@ class LibraryController {
|
|||||||
* @param {import('express').Response} res
|
* @param {import('express').Response} res
|
||||||
*/
|
*/
|
||||||
async getOPMLFile(req, res) {
|
async getOPMLFile(req, res) {
|
||||||
const userPermissionPodcastWhere = libraryItemsPodcastFilters.getUserPermissionPodcastWhereQuery(req.user)
|
const userPermissionPodcastWhere = libraryItemsPodcastFilters.getUserPermissionPodcastWhereQuery(req.userNew)
|
||||||
const podcasts = await Database.podcastModel.findAll({
|
const podcasts = await Database.podcastModel.findAll({
|
||||||
attributes: ['id', 'feedURL', 'title', 'description', 'itunesPageURL', 'language'],
|
attributes: ['id', 'feedURL', 'title', 'description', 'itunesPageURL', 'language'],
|
||||||
where: userPermissionPodcastWhere.podcastWhere,
|
where: userPermissionPodcastWhere.podcastWhere,
|
||||||
@ -924,8 +924,8 @@ class LibraryController {
|
|||||||
* @param {import('express').Response} res
|
* @param {import('express').Response} res
|
||||||
*/
|
*/
|
||||||
async removeAllMetadataFiles(req, res) {
|
async removeAllMetadataFiles(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
Logger.error(`[LibraryController] Non-admin user attempted to remove all metadata files`, req.user)
|
Logger.error(`[LibraryController] Non-admin user "${req.userNew.username}" attempted to remove all metadata files`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -974,8 +974,8 @@ class LibraryController {
|
|||||||
* @param {import('express').NextFunction} next
|
* @param {import('express').NextFunction} next
|
||||||
*/
|
*/
|
||||||
async middleware(req, res, next) {
|
async middleware(req, res, next) {
|
||||||
if (!req.user.checkCanAccessLibrary(req.params.id)) {
|
if (!req.userNew.checkCanAccessLibrary(req.params.id)) {
|
||||||
Logger.warn(`[LibraryController] Library ${req.params.id} not accessible to user ${req.user.username}`)
|
Logger.warn(`[LibraryController] Library ${req.params.id} not accessible to user ${req.userNew.username}`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ class LibraryItemController {
|
|||||||
// Include users media progress
|
// Include users media progress
|
||||||
if (includeEntities.includes('progress')) {
|
if (includeEntities.includes('progress')) {
|
||||||
var episodeId = req.query.episode || null
|
var episodeId = req.query.episode || null
|
||||||
item.userMediaProgress = req.user.getMediaProgress(item.id, episodeId)
|
item.userMediaProgress = req.userNew.getOldMediaProgress(item.id, episodeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeEntities.includes('rssfeed')) {
|
if (includeEntities.includes('rssfeed')) {
|
||||||
@ -43,7 +43,7 @@ class LibraryItemController {
|
|||||||
item.rssFeed = feedData?.toJSONMinified() || null
|
item.rssFeed = feedData?.toJSONMinified() || null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.mediaType === 'book' && req.user.isAdminOrUp && includeEntities.includes('share')) {
|
if (item.mediaType === 'book' && req.userNew.isAdminOrUp && includeEntities.includes('share')) {
|
||||||
item.mediaItemShare = ShareManager.findByMediaItemId(item.media.id)
|
item.mediaItemShare = ShareManager.findByMediaItemId(item.media.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,8 +109,8 @@ class LibraryItemController {
|
|||||||
* @param {import('express').Response} res
|
* @param {import('express').Response} res
|
||||||
*/
|
*/
|
||||||
download(req, res) {
|
download(req, res) {
|
||||||
if (!req.user.canDownload) {
|
if (!req.userNew.canDownload) {
|
||||||
Logger.warn('User attempted to download without permission', req.user)
|
Logger.warn(`User "${req.userNew.username}" attempted to download without permission`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
const libraryItemPath = req.libraryItem.path
|
const libraryItemPath = req.libraryItem.path
|
||||||
@ -123,12 +123,12 @@ class LibraryItemController {
|
|||||||
if (audioMimeType) {
|
if (audioMimeType) {
|
||||||
res.setHeader('Content-Type', audioMimeType)
|
res.setHeader('Content-Type', audioMimeType)
|
||||||
}
|
}
|
||||||
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
|
Logger.info(`[LibraryItemController] User "${req.userNew.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
|
||||||
res.download(libraryItemPath, req.libraryItem.relPath)
|
res.download(libraryItemPath, req.libraryItem.relPath)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
|
Logger.info(`[LibraryItemController] User "${req.userNew.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
|
||||||
const filename = `${itemTitle}.zip`
|
const filename = `${itemTitle}.zip`
|
||||||
zipHelpers.zipDirectoryPipe(libraryItemPath, filename, res)
|
zipHelpers.zipDirectoryPipe(libraryItemPath, filename, res)
|
||||||
}
|
}
|
||||||
@ -200,8 +200,8 @@ class LibraryItemController {
|
|||||||
|
|
||||||
// POST: api/items/:id/cover
|
// POST: api/items/:id/cover
|
||||||
async uploadCover(req, res, updateAndReturnJson = true) {
|
async uploadCover(req, res, updateAndReturnJson = true) {
|
||||||
if (!req.user.canUpload) {
|
if (!req.userNew.canUpload) {
|
||||||
Logger.warn('User attempted to upload a cover without permission', req.user)
|
Logger.warn(`User "${req.userNew.username}" attempted to upload a cover without permission`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ class LibraryItemController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if user can access this library item
|
// Check if user can access this library item
|
||||||
if (!req.user.checkCanAccessLibraryItemWithData(libraryItem.libraryId, libraryItem.media.explicit, libraryItem.media.tags)) {
|
if (!req.userNew.checkCanAccessLibraryItem(libraryItem)) {
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,8 +387,8 @@ class LibraryItemController {
|
|||||||
* @param {import('express').Response} res
|
* @param {import('express').Response} res
|
||||||
*/
|
*/
|
||||||
async batchDelete(req, res) {
|
async batchDelete(req, res) {
|
||||||
if (!req.user.canDelete) {
|
if (!req.userNew.canDelete) {
|
||||||
Logger.warn(`[LibraryItemController] User attempted to delete without permission`, req.user)
|
Logger.warn(`[LibraryItemController] User "${req.userNew.username}" attempted to delete without permission`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
const hardDelete = req.query.hard == 1 // Delete files from filesystem
|
const hardDelete = req.query.hard == 1 // Delete files from filesystem
|
||||||
@ -486,8 +486,8 @@ class LibraryItemController {
|
|||||||
|
|
||||||
// POST: api/items/batch/quickmatch
|
// POST: api/items/batch/quickmatch
|
||||||
async batchQuickMatch(req, res) {
|
async batchQuickMatch(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
Logger.warn('User other than admin attempted to batch quick match library items', req.user)
|
Logger.warn(`Non-admin user "${req.userNew.username}" other than admin attempted to batch quick match library items`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,13 +522,13 @@ class LibraryItemController {
|
|||||||
updates: itemsUpdated,
|
updates: itemsUpdated,
|
||||||
unmatched: itemsUnmatched
|
unmatched: itemsUnmatched
|
||||||
}
|
}
|
||||||
SocketAuthority.clientEmitter(req.user.id, 'batch_quickmatch_complete', result)
|
SocketAuthority.clientEmitter(req.userNew.id, 'batch_quickmatch_complete', result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST: api/items/batch/scan
|
// POST: api/items/batch/scan
|
||||||
async batchScan(req, res) {
|
async batchScan(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
Logger.warn('User other than admin attempted to batch scan library items', req.user)
|
Logger.warn(`Non-admin user "${req.userNew.username}" other than admin attempted to batch scan library items`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,8 +562,8 @@ class LibraryItemController {
|
|||||||
|
|
||||||
// POST: api/items/:id/scan
|
// POST: api/items/:id/scan
|
||||||
async scan(req, res) {
|
async scan(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
Logger.error(`[LibraryItemController] Non-admin user attempted to scan library item`, req.user)
|
Logger.error(`[LibraryItemController] Non-admin user "${req.userNew.username}" attempted to scan library item`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,8 +580,8 @@ class LibraryItemController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getMetadataObject(req, res) {
|
getMetadataObject(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
Logger.error(`[LibraryItemController] Non-admin user attempted to get metadata object`, req.user)
|
Logger.error(`[LibraryItemController] Non-admin user "${req.userNew.username}" attempted to get metadata object`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,8 +595,8 @@ class LibraryItemController {
|
|||||||
|
|
||||||
// POST: api/items/:id/chapters
|
// POST: api/items/:id/chapters
|
||||||
async updateMediaChapters(req, res) {
|
async updateMediaChapters(req, res) {
|
||||||
if (!req.user.canUpdate) {
|
if (!req.userNew.canUpdate) {
|
||||||
Logger.error(`[LibraryItemController] User attempted to update chapters with invalid permissions`, req.user.username)
|
Logger.error(`[LibraryItemController] User "${req.userNew.username}" attempted to update chapters with invalid permissions`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,8 +631,8 @@ class LibraryItemController {
|
|||||||
* @param {express.Response} res
|
* @param {express.Response} res
|
||||||
*/
|
*/
|
||||||
async getFFprobeData(req, res) {
|
async getFFprobeData(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.userNew.isAdminOrUp) {
|
||||||
Logger.error(`[LibraryItemController] Non-admin user attempted to get ffprobe data`, req.user)
|
Logger.error(`[LibraryItemController] Non-admin user "${req.userNew.username}" attempted to get ffprobe data`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
if (req.libraryFile.fileType !== 'audio') {
|
if (req.libraryFile.fileType !== 'audio') {
|
||||||
@ -682,7 +682,7 @@ class LibraryItemController {
|
|||||||
async deleteLibraryFile(req, res) {
|
async deleteLibraryFile(req, res) {
|
||||||
const libraryFile = req.libraryFile
|
const libraryFile = req.libraryFile
|
||||||
|
|
||||||
Logger.info(`[LibraryItemController] User "${req.user.username}" requested file delete at "${libraryFile.metadata.path}"`)
|
Logger.info(`[LibraryItemController] User "${req.userNew.username}" requested file delete at "${libraryFile.metadata.path}"`)
|
||||||
|
|
||||||
await fs.remove(libraryFile.metadata.path).catch((error) => {
|
await fs.remove(libraryFile.metadata.path).catch((error) => {
|
||||||
Logger.error(`[LibraryItemController] Failed to delete library file at "${libraryFile.metadata.path}"`, error)
|
Logger.error(`[LibraryItemController] Failed to delete library file at "${libraryFile.metadata.path}"`, error)
|
||||||
@ -710,12 +710,12 @@ class LibraryItemController {
|
|||||||
async downloadLibraryFile(req, res) {
|
async downloadLibraryFile(req, res) {
|
||||||
const libraryFile = req.libraryFile
|
const libraryFile = req.libraryFile
|
||||||
|
|
||||||
if (!req.user.canDownload) {
|
if (!req.userNew.canDownload) {
|
||||||
Logger.error(`[LibraryItemController] User without download permission attempted to download file "${libraryFile.metadata.path}"`, req.user)
|
Logger.error(`[LibraryItemController] User "${req.userNew.username}" without download permission attempted to download file "${libraryFile.metadata.path}"`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${req.libraryItem.media.metadata.title}" file at "${libraryFile.metadata.path}"`)
|
Logger.info(`[LibraryItemController] User "${req.userNew.username}" requested download for item "${req.libraryItem.media.metadata.title}" file at "${libraryFile.metadata.path}"`)
|
||||||
|
|
||||||
if (global.XAccel) {
|
if (global.XAccel) {
|
||||||
const encodedURI = encodeUriPath(global.XAccel + libraryFile.metadata.path)
|
const encodedURI = encodeUriPath(global.XAccel + libraryFile.metadata.path)
|
||||||
@ -759,7 +759,7 @@ class LibraryItemController {
|
|||||||
}
|
}
|
||||||
const ebookFilePath = ebookFile.metadata.path
|
const ebookFilePath = ebookFile.metadata.path
|
||||||
|
|
||||||
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${req.libraryItem.media.metadata.title}" ebook at "${ebookFilePath}"`)
|
Logger.info(`[LibraryItemController] User "${req.userNew.username}" requested download for item "${req.libraryItem.media.metadata.title}" ebook at "${ebookFilePath}"`)
|
||||||
|
|
||||||
if (global.XAccel) {
|
if (global.XAccel) {
|
||||||
const encodedURI = encodeUriPath(global.XAccel + ebookFilePath)
|
const encodedURI = encodeUriPath(global.XAccel + ebookFilePath)
|
||||||
@ -812,7 +812,7 @@ class LibraryItemController {
|
|||||||
if (!req.libraryItem?.media) return res.sendStatus(404)
|
if (!req.libraryItem?.media) return res.sendStatus(404)
|
||||||
|
|
||||||
// Check user can access this library item
|
// Check user can access this library item
|
||||||
if (!req.user.checkCanAccessLibraryItem(req.libraryItem)) {
|
if (!req.userNew.checkCanAccessLibraryItem(req.libraryItem)) {
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -827,11 +827,11 @@ class LibraryItemController {
|
|||||||
|
|
||||||
if (req.path.includes('/play')) {
|
if (req.path.includes('/play')) {
|
||||||
// allow POST requests using /play and /play/:episodeId
|
// allow POST requests using /play and /play/:episodeId
|
||||||
} else if (req.method == 'DELETE' && !req.user.canDelete) {
|
} else if (req.method == 'DELETE' && !req.userNew.canDelete) {
|
||||||
Logger.warn(`[LibraryItemController] User attempted to delete without permission`, req.user)
|
Logger.warn(`[LibraryItemController] User "${req.userNew.username}" attempted to delete without permission`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
|
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
|
||||||
Logger.warn('[LibraryItemController] User attempted to update without permission', req.user.username)
|
Logger.warn(`[LibraryItemController] User "${req.userNew.username}" attempted to update without permission`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ class PlaylistController {
|
|||||||
const newPlaylist = await Database.playlistModel.createFromOld(oldPlaylist)
|
const newPlaylist = await Database.playlistModel.createFromOld(oldPlaylist)
|
||||||
|
|
||||||
// Lookup all library items in playlist
|
// Lookup all library items in playlist
|
||||||
const libraryItemIds = oldPlaylist.items.map(i => i.libraryItemId).filter(i => i)
|
const libraryItemIds = oldPlaylist.items.map((i) => i.libraryItemId).filter((i) => i)
|
||||||
const libraryItemsInPlaylist = await Database.libraryItemModel.findAll({
|
const libraryItemsInPlaylist = await Database.libraryItemModel.findAll({
|
||||||
where: {
|
where: {
|
||||||
id: libraryItemIds
|
id: libraryItemIds
|
||||||
@ -36,7 +36,7 @@ class PlaylistController {
|
|||||||
const mediaItemsToAdd = []
|
const mediaItemsToAdd = []
|
||||||
let order = 1
|
let order = 1
|
||||||
for (const mediaItemObj of oldPlaylist.items) {
|
for (const mediaItemObj of oldPlaylist.items) {
|
||||||
const libraryItem = libraryItemsInPlaylist.find(li => li.id === mediaItemObj.libraryItemId)
|
const libraryItem = libraryItemsInPlaylist.find((li) => li.id === mediaItemObj.libraryItemId)
|
||||||
if (!libraryItem) continue
|
if (!libraryItem) continue
|
||||||
|
|
||||||
mediaItemsToAdd.push({
|
mediaItemsToAdd.push({
|
||||||
@ -104,7 +104,7 @@ class PlaylistController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If array of items is passed in then update order of playlist media items
|
// If array of items is passed in then update order of playlist media items
|
||||||
const libraryItemIds = req.body.items?.map(i => i.libraryItemId).filter(i => i) || []
|
const libraryItemIds = req.body.items?.map((i) => i.libraryItemId).filter((i) => i) || []
|
||||||
if (libraryItemIds.length) {
|
if (libraryItemIds.length) {
|
||||||
const libraryItems = await Database.libraryItemModel.findAll({
|
const libraryItems = await Database.libraryItemModel.findAll({
|
||||||
where: {
|
where: {
|
||||||
@ -118,7 +118,7 @@ class PlaylistController {
|
|||||||
// Set an array of mediaItemId
|
// Set an array of mediaItemId
|
||||||
const newMediaItemIdOrder = []
|
const newMediaItemIdOrder = []
|
||||||
for (const item of req.body.items) {
|
for (const item of req.body.items) {
|
||||||
const libraryItem = libraryItems.find(li => li.id === item.libraryItemId)
|
const libraryItem = libraryItems.find((li) => li.id === item.libraryItemId)
|
||||||
if (!libraryItem) {
|
if (!libraryItem) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -128,8 +128,8 @@ class PlaylistController {
|
|||||||
|
|
||||||
// Sort existing playlist media items into new order
|
// Sort existing playlist media items into new order
|
||||||
existingPlaylistMediaItems.sort((a, b) => {
|
existingPlaylistMediaItems.sort((a, b) => {
|
||||||
const aIndex = newMediaItemIdOrder.findIndex(i => i === a.mediaItemId)
|
const aIndex = newMediaItemIdOrder.findIndex((i) => i === a.mediaItemId)
|
||||||
const bIndex = newMediaItemIdOrder.findIndex(i => i === b.mediaItemId)
|
const bIndex = newMediaItemIdOrder.findIndex((i) => i === b.mediaItemId)
|
||||||
return aIndex - bIndex
|
return aIndex - bIndex
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -229,7 +229,7 @@ class PlaylistController {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Check if media item to delete is in playlist
|
// Check if media item to delete is in playlist
|
||||||
const mediaItemToRemove = playlistMediaItems.find(pmi => pmi.mediaItemId === mediaItemId)
|
const mediaItemToRemove = playlistMediaItems.find((pmi) => pmi.mediaItemId === mediaItemId)
|
||||||
if (!mediaItemToRemove) {
|
if (!mediaItemToRemove) {
|
||||||
return res.status(404).send('Media item not found in playlist')
|
return res.status(404).send('Media item not found in playlist')
|
||||||
}
|
}
|
||||||
@ -275,7 +275,7 @@ class PlaylistController {
|
|||||||
}
|
}
|
||||||
const itemsToAdd = req.body.items
|
const itemsToAdd = req.body.items
|
||||||
|
|
||||||
const libraryItemIds = itemsToAdd.map(i => i.libraryItemId).filter(i => i)
|
const libraryItemIds = itemsToAdd.map((i) => i.libraryItemId).filter((i) => i)
|
||||||
if (!libraryItemIds.length) {
|
if (!libraryItemIds.length) {
|
||||||
return res.status(400).send('Invalid request body')
|
return res.status(400).send('Invalid request body')
|
||||||
}
|
}
|
||||||
@ -297,12 +297,12 @@ class PlaylistController {
|
|||||||
// Setup array of playlistMediaItem records to add
|
// Setup array of playlistMediaItem records to add
|
||||||
let order = existingPlaylistMediaItems.length + 1
|
let order = existingPlaylistMediaItems.length + 1
|
||||||
for (const item of itemsToAdd) {
|
for (const item of itemsToAdd) {
|
||||||
const libraryItem = libraryItems.find(li => li.id === item.libraryItemId)
|
const libraryItem = libraryItems.find((li) => li.id === item.libraryItemId)
|
||||||
if (!libraryItem) {
|
if (!libraryItem) {
|
||||||
return res.status(404).send('Item not found with id ' + item.libraryItemId)
|
return res.status(404).send('Item not found with id ' + item.libraryItemId)
|
||||||
} else {
|
} else {
|
||||||
const mediaItemId = item.episodeId || libraryItem.mediaId
|
const mediaItemId = item.episodeId || libraryItem.mediaId
|
||||||
if (existingPlaylistMediaItems.some(pmi => pmi.mediaItemId === mediaItemId)) {
|
if (existingPlaylistMediaItems.some((pmi) => pmi.mediaItemId === mediaItemId)) {
|
||||||
// Already exists in playlist
|
// Already exists in playlist
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
@ -339,7 +339,7 @@ class PlaylistController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const itemsToRemove = req.body.items
|
const itemsToRemove = req.body.items
|
||||||
const libraryItemIds = itemsToRemove.map(i => i.libraryItemId).filter(i => i)
|
const libraryItemIds = itemsToRemove.map((i) => i.libraryItemId).filter((i) => i)
|
||||||
if (!libraryItemIds.length) {
|
if (!libraryItemIds.length) {
|
||||||
return res.status(400).send('Invalid request body')
|
return res.status(400).send('Invalid request body')
|
||||||
}
|
}
|
||||||
@ -360,10 +360,10 @@ class PlaylistController {
|
|||||||
// Remove playlist media items
|
// Remove playlist media items
|
||||||
let hasUpdated = false
|
let hasUpdated = false
|
||||||
for (const item of itemsToRemove) {
|
for (const item of itemsToRemove) {
|
||||||
const libraryItem = libraryItems.find(li => li.id === item.libraryItemId)
|
const libraryItem = libraryItems.find((li) => li.id === item.libraryItemId)
|
||||||
if (!libraryItem) continue
|
if (!libraryItem) continue
|
||||||
const mediaItemId = item.episodeId || libraryItem.mediaId
|
const mediaItemId = item.episodeId || libraryItem.mediaId
|
||||||
const existingMediaItem = existingPlaylistMediaItems.find(pmi => pmi.mediaItemId === mediaItemId)
|
const existingMediaItem = existingPlaylistMediaItems.find((pmi) => pmi.mediaItemId === mediaItemId)
|
||||||
if (!existingMediaItem) continue
|
if (!existingMediaItem) continue
|
||||||
await existingMediaItem.destroy()
|
await existingMediaItem.destroy()
|
||||||
hasUpdated = true
|
hasUpdated = true
|
||||||
@ -396,7 +396,7 @@ class PlaylistController {
|
|||||||
return res.status(404).send('Collection not found')
|
return res.status(404).send('Collection not found')
|
||||||
}
|
}
|
||||||
// Expand collection to get library items
|
// Expand collection to get library items
|
||||||
const collectionExpanded = await collection.getOldJsonExpanded(req.user)
|
const collectionExpanded = await collection.getOldJsonExpanded(req.userNew)
|
||||||
if (!collectionExpanded) {
|
if (!collectionExpanded) {
|
||||||
// This can happen if the user has no access to all items in collection
|
// This can happen if the user has no access to all items in collection
|
||||||
return res.status(404).send('Collection not found')
|
return res.status(404).send('Collection not found')
|
||||||
|
@ -17,20 +17,23 @@ class SeriesController {
|
|||||||
* @param {*} res
|
* @param {*} res
|
||||||
*/
|
*/
|
||||||
async findOne(req, res) {
|
async findOne(req, res) {
|
||||||
const include = (req.query.include || '').split(',').map(v => v.trim()).filter(v => !!v)
|
const include = (req.query.include || '')
|
||||||
|
.split(',')
|
||||||
|
.map((v) => v.trim())
|
||||||
|
.filter((v) => !!v)
|
||||||
|
|
||||||
const seriesJson = req.series.toJSON()
|
const seriesJson = req.series.toJSON()
|
||||||
|
|
||||||
// Add progress map with isFinished flag
|
// Add progress map with isFinished flag
|
||||||
if (include.includes('progress')) {
|
if (include.includes('progress')) {
|
||||||
const libraryItemsInSeries = req.libraryItemsInSeries
|
const libraryItemsInSeries = req.libraryItemsInSeries
|
||||||
const libraryItemsFinished = libraryItemsInSeries.filter(li => {
|
const libraryItemsFinished = libraryItemsInSeries.filter((li) => {
|
||||||
const mediaProgress = req.user.getMediaProgress(li.id)
|
const mediaProgress = req.user.getMediaProgress(li.id)
|
||||||
return mediaProgress?.isFinished
|
return mediaProgress?.isFinished
|
||||||
})
|
})
|
||||||
seriesJson.progress = {
|
seriesJson.progress = {
|
||||||
libraryItemIds: libraryItemsInSeries.map(li => li.id),
|
libraryItemIds: libraryItemsInSeries.map((li) => li.id),
|
||||||
libraryItemIdsFinished: libraryItemsFinished.map(li => li.id),
|
libraryItemIdsFinished: libraryItemsFinished.map((li) => li.id),
|
||||||
isFinished: libraryItemsFinished.length === libraryItemsInSeries.length
|
isFinished: libraryItemsFinished.length === libraryItemsInSeries.length
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,7 +62,7 @@ class SeriesController {
|
|||||||
/**
|
/**
|
||||||
* Filter out any library items not accessible to user
|
* Filter out any library items not accessible to user
|
||||||
*/
|
*/
|
||||||
const libraryItems = await libraryItemsBookFilters.getLibraryItemsForSeries(series, req.user)
|
const libraryItems = await libraryItemsBookFilters.getLibraryItemsForSeries(series, req.userNew)
|
||||||
if (!libraryItems.length) {
|
if (!libraryItems.length) {
|
||||||
Logger.warn(`[SeriesController] User attempted to access series "${series.id}" with no accessible books`, req.user)
|
Logger.warn(`[SeriesController] User attempted to access series "${series.id}" with no accessible books`, req.user)
|
||||||
return res.sendStatus(404)
|
return res.sendStatus(404)
|
||||||
|
@ -22,7 +22,8 @@ class Collection extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all old collections toJSONExpanded, items filtered for user permissions
|
* Get all old collections toJSONExpanded, items filtered for user permissions
|
||||||
* @param {oldUser} [user]
|
*
|
||||||
|
* @param {import('./User')} user
|
||||||
* @param {string} [libraryId]
|
* @param {string} [libraryId]
|
||||||
* @param {string[]} [include]
|
* @param {string[]} [include]
|
||||||
* @returns {Promise<oldCollection[]>} oldCollection.toJSONExpanded
|
* @returns {Promise<oldCollection[]>} oldCollection.toJSONExpanded
|
||||||
@ -116,7 +117,8 @@ class Collection extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get old collection toJSONExpanded, items filtered for user permissions
|
* Get old collection toJSONExpanded, items filtered for user permissions
|
||||||
* @param {oldUser} [user]
|
*
|
||||||
|
* @param {import('./User')|null} user
|
||||||
* @param {string[]} [include]
|
* @param {string[]} [include]
|
||||||
* @returns {Promise<oldCollection>} oldCollection.toJSONExpanded
|
* @returns {Promise<oldCollection>} oldCollection.toJSONExpanded
|
||||||
*/
|
*/
|
||||||
|
@ -543,7 +543,7 @@ class LibraryItem extends Model {
|
|||||||
/**
|
/**
|
||||||
* Get library items using filter and sort
|
* Get library items using filter and sort
|
||||||
* @param {oldLibrary} library
|
* @param {oldLibrary} library
|
||||||
* @param {oldUser} user
|
* @param {import('./User')} user
|
||||||
* @param {object} options
|
* @param {object} options
|
||||||
* @returns {{ libraryItems:oldLibraryItem[], count:number }}
|
* @returns {{ libraryItems:oldLibraryItem[], count:number }}
|
||||||
*/
|
*/
|
||||||
@ -586,7 +586,7 @@ class LibraryItem extends Model {
|
|||||||
/**
|
/**
|
||||||
* Get home page data personalized shelves
|
* Get home page data personalized shelves
|
||||||
* @param {oldLibrary} library
|
* @param {oldLibrary} library
|
||||||
* @param {oldUser} user
|
* @param {import('./User')} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {object[]} array of shelf objects
|
* @returns {object[]} array of shelf objects
|
||||||
@ -759,7 +759,7 @@ class LibraryItem extends Model {
|
|||||||
/**
|
/**
|
||||||
* Get book library items for author, optional use user permissions
|
* Get book library items for author, optional use user permissions
|
||||||
* @param {oldAuthor} author
|
* @param {oldAuthor} author
|
||||||
* @param {[oldUser]} user
|
* @param {import('./User')} user
|
||||||
* @returns {Promise<oldLibraryItem[]>}
|
* @returns {Promise<oldLibraryItem[]>}
|
||||||
*/
|
*/
|
||||||
static async getForAuthor(author, user = null) {
|
static async getForAuthor(author, user = null) {
|
||||||
|
@ -414,6 +414,21 @@ class User extends Model {
|
|||||||
get isUser() {
|
get isUser() {
|
||||||
return this.type === 'user'
|
return this.type === 'user'
|
||||||
}
|
}
|
||||||
|
get canAccessExplicitContent() {
|
||||||
|
return !!this.permissions?.accessExplicitContent && this.isActive
|
||||||
|
}
|
||||||
|
get canDelete() {
|
||||||
|
return !!this.permissions?.delete && this.isActive
|
||||||
|
}
|
||||||
|
get canUpdate() {
|
||||||
|
return !!this.permissions?.update && this.isActive
|
||||||
|
}
|
||||||
|
get canDownload() {
|
||||||
|
return !!this.permissions?.download && this.isActive
|
||||||
|
}
|
||||||
|
get canUpload() {
|
||||||
|
return !!this.permissions?.upload && this.isActive
|
||||||
|
}
|
||||||
/** @type {string|null} */
|
/** @type {string|null} */
|
||||||
get authOpenIDSub() {
|
get authOpenIDSub() {
|
||||||
return this.extraData?.authOpenIDSub || null
|
return this.extraData?.authOpenIDSub || null
|
||||||
@ -490,6 +505,40 @@ class User extends Model {
|
|||||||
return this.permissions.librariesAccessible.includes(libraryId)
|
return this.permissions.librariesAccessible.includes(libraryId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check user has access to library item with tags
|
||||||
|
*
|
||||||
|
* @param {string[]} tags
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
checkCanAccessLibraryItemWithTags(tags) {
|
||||||
|
if (this.permissions.accessAllTags) return true
|
||||||
|
const itemTagsSelected = this.permissions?.itemTagsSelected || []
|
||||||
|
if (this.permissions.selectedTagsNotAccessible) {
|
||||||
|
if (!tags?.length) return true
|
||||||
|
return tags.every((tag) => !itemTagsSelected?.includes(tag))
|
||||||
|
}
|
||||||
|
if (!tags?.length) return false
|
||||||
|
return itemTagsSelected.some((tag) => tags.includes(tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check user can access library item
|
||||||
|
* TODO: Currently supports both old and new library item models
|
||||||
|
*
|
||||||
|
* @param {import('../objects/LibraryItem')|import('./LibraryItem')} libraryItem
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
checkCanAccessLibraryItem(libraryItem) {
|
||||||
|
if (!this.checkCanAccessLibrary(libraryItem.libraryId)) return false
|
||||||
|
|
||||||
|
const libraryItemExplicit = !!libraryItem.media.explicit || !!libraryItem.media.metadata?.explicit
|
||||||
|
|
||||||
|
if (libraryItemExplicit && !this.canAccessExplicitContent) return false
|
||||||
|
|
||||||
|
return this.checkCanAccessLibraryItemWithTags(libraryItem.media.tags)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get first available library id for user
|
* Get first available library id for user
|
||||||
*
|
*
|
||||||
@ -500,6 +549,34 @@ class User extends Model {
|
|||||||
// Libraries should already be in ascending display order, find first accessible
|
// Libraries should already be in ascending display order, find first accessible
|
||||||
return libraryIds.find((lid) => this.checkCanAccessLibrary(lid)) || null
|
return libraryIds.find((lid) => this.checkCanAccessLibrary(lid)) || null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get media progress by media item id
|
||||||
|
*
|
||||||
|
* @param {string} libraryItemId
|
||||||
|
* @param {string|null} [episodeId]
|
||||||
|
* @returns {import('./MediaProgress')|null}
|
||||||
|
*/
|
||||||
|
getMediaProgress(mediaItemId) {
|
||||||
|
if (!this.mediaProgresses?.length) return null
|
||||||
|
return this.mediaProgresses.find((mp) => mp.mediaItemId === mediaItemId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get old media progress
|
||||||
|
* TODO: Update to new model
|
||||||
|
*
|
||||||
|
* @param {string} libraryItemId
|
||||||
|
* @param {string} [episodeId]
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
getOldMediaProgress(libraryItemId, episodeId = null) {
|
||||||
|
const mediaProgress = this.mediaProgresses?.find((mp) => {
|
||||||
|
if (episodeId && mp.mediaItemId === episodeId) return true
|
||||||
|
return mp.extraData?.libraryItemId === libraryItemId
|
||||||
|
})
|
||||||
|
return mediaProgress?.getOldMediaProgress() || null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = User
|
module.exports = User
|
||||||
|
@ -11,7 +11,7 @@ module.exports = {
|
|||||||
const seriesToFilterOut = {}
|
const seriesToFilterOut = {}
|
||||||
books.forEach((libraryItem) => {
|
books.forEach((libraryItem) => {
|
||||||
// get all book series for item that is not already filtered out
|
// get all book series for item that is not already filtered out
|
||||||
const bookSeries = (libraryItem.media.metadata.series || []).filter(se => !seriesToFilterOut[se.id])
|
const bookSeries = (libraryItem.media.metadata.series || []).filter((se) => !seriesToFilterOut[se.id])
|
||||||
if (!bookSeries.length) return
|
if (!bookSeries.length) return
|
||||||
|
|
||||||
bookSeries.forEach((bookSeriesObj) => {
|
bookSeries.forEach((bookSeriesObj) => {
|
||||||
@ -43,11 +43,11 @@ module.exports = {
|
|||||||
|
|
||||||
// Library setting to hide series with only 1 book
|
// Library setting to hide series with only 1 book
|
||||||
if (hideSingleBookSeries) {
|
if (hideSingleBookSeries) {
|
||||||
seriesItems = seriesItems.filter(se => se.books.length > 1)
|
seriesItems = seriesItems.filter((se) => se.books.length > 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return seriesItems.map((series) => {
|
return seriesItems.map((series) => {
|
||||||
series.books = naturalSort(series.books).asc(li => li.sequence)
|
series.books = naturalSort(series.books).asc((li) => li.sequence)
|
||||||
return series
|
return series
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -55,9 +55,7 @@ module.exports = {
|
|||||||
collapseBookSeries(libraryItems, filterSeries, hideSingleBookSeries) {
|
collapseBookSeries(libraryItems, filterSeries, hideSingleBookSeries) {
|
||||||
// Get series from the library items. If this list is being collapsed after filtering for a series,
|
// Get series from the library items. If this list is being collapsed after filtering for a series,
|
||||||
// don't collapse that series, only books that are in other series.
|
// don't collapse that series, only books that are in other series.
|
||||||
const seriesObjects = this
|
const seriesObjects = this.getSeriesFromBooks(libraryItems, filterSeries, hideSingleBookSeries).filter((s) => s.id != filterSeries)
|
||||||
.getSeriesFromBooks(libraryItems, filterSeries, hideSingleBookSeries)
|
|
||||||
.filter(s => s.id != filterSeries)
|
|
||||||
|
|
||||||
const filteredLibraryItems = []
|
const filteredLibraryItems = []
|
||||||
|
|
||||||
@ -65,22 +63,29 @@ module.exports = {
|
|||||||
if (li.mediaType != 'book') return
|
if (li.mediaType != 'book') return
|
||||||
|
|
||||||
// Handle when this is the first book in a series
|
// Handle when this is the first book in a series
|
||||||
seriesObjects.filter(s => s.books[0].id == li.id).forEach(series => {
|
seriesObjects
|
||||||
|
.filter((s) => s.books[0].id == li.id)
|
||||||
|
.forEach((series) => {
|
||||||
// Clone the library item as we need to attach data to it, but don't
|
// Clone the library item as we need to attach data to it, but don't
|
||||||
// want to change the global copy of the library item
|
// want to change the global copy of the library item
|
||||||
filteredLibraryItems.push(Object.assign(
|
filteredLibraryItems.push(Object.assign(Object.create(Object.getPrototypeOf(li)), li, { collapsedSeries: series }))
|
||||||
Object.create(Object.getPrototypeOf(li)),
|
|
||||||
li, { collapsedSeries: series }))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Only included books not contained in series
|
// Only included books not contained in series
|
||||||
if (!seriesObjects.some(s => s.books.some(b => b.id == li.id)))
|
if (!seriesObjects.some((s) => s.books.some((b) => b.id == li.id))) filteredLibraryItems.push(li)
|
||||||
filteredLibraryItems.push(li)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return filteredLibraryItems
|
return filteredLibraryItems
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} payload
|
||||||
|
* @param {string} seriesId
|
||||||
|
* @param {import('../models/User')} user
|
||||||
|
* @param {import('../objects/Library')} library
|
||||||
|
* @returns {Object[]}
|
||||||
|
*/
|
||||||
async handleCollapseSubseries(payload, seriesId, user, library) {
|
async handleCollapseSubseries(payload, seriesId, user, library) {
|
||||||
const seriesWithBooks = await Database.seriesModel.findByPk(seriesId, {
|
const seriesWithBooks = await Database.seriesModel.findByPk(seriesId, {
|
||||||
include: {
|
include: {
|
||||||
@ -112,15 +117,16 @@ module.exports = {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const books = seriesWithBooks.books
|
const books = seriesWithBooks.books
|
||||||
payload.total = books.length
|
payload.total = books.length
|
||||||
|
|
||||||
let libraryItems = books.map((book) => {
|
let libraryItems = books
|
||||||
|
.map((book) => {
|
||||||
const libraryItem = book.libraryItem
|
const libraryItem = book.libraryItem
|
||||||
libraryItem.media = book
|
libraryItem.media = book
|
||||||
return Database.libraryItemModel.getOldLibraryItem(libraryItem)
|
return Database.libraryItemModel.getOldLibraryItem(libraryItem)
|
||||||
}).filter(li => {
|
})
|
||||||
|
.filter((li) => {
|
||||||
return user.checkCanAccessLibraryItem(li)
|
return user.checkCanAccessLibraryItem(li)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -139,7 +145,8 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
[direction]: (li) => li.media.metadata.getSeries(seriesId).sequence
|
[direction]: (li) => li.media.metadata.getSeries(seriesId).sequence
|
||||||
},
|
},
|
||||||
{ // If no series sequence then fallback to sorting by title (or collapsed series name for sub-series)
|
{
|
||||||
|
// If no series sequence then fallback to sorting by title (or collapsed series name for sub-series)
|
||||||
[direction]: (li) => {
|
[direction]: (li) => {
|
||||||
if (sortingIgnorePrefix) {
|
if (sortingIgnorePrefix) {
|
||||||
return li.collapsedSeries?.nameIgnorePrefix || li.media.metadata.titleIgnorePrefix
|
return li.collapsedSeries?.nameIgnorePrefix || li.media.metadata.titleIgnorePrefix
|
||||||
@ -185,7 +192,8 @@ module.exports = {
|
|||||||
libraryItems = libraryItems.slice(startIndex, startIndex + payload.limit)
|
libraryItems = libraryItems.slice(startIndex, startIndex + payload.limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(libraryItems.map(async li => {
|
return Promise.all(
|
||||||
|
libraryItems.map(async (li) => {
|
||||||
const filteredSeries = li.media.metadata.getSeries(seriesId)
|
const filteredSeries = li.media.metadata.getSeries(seriesId)
|
||||||
const json = li.toJSONMinified()
|
const json = li.toJSONMinified()
|
||||||
json.media.metadata.series = {
|
json.media.metadata.series = {
|
||||||
@ -199,33 +207,33 @@ module.exports = {
|
|||||||
id: li.collapsedSeries.id,
|
id: li.collapsedSeries.id,
|
||||||
name: li.collapsedSeries.name,
|
name: li.collapsedSeries.name,
|
||||||
nameIgnorePrefix: li.collapsedSeries.nameIgnorePrefix,
|
nameIgnorePrefix: li.collapsedSeries.nameIgnorePrefix,
|
||||||
libraryItemIds: li.collapsedSeries.books.map(b => b.id),
|
libraryItemIds: li.collapsedSeries.books.map((b) => b.id),
|
||||||
numBooks: li.collapsedSeries.books.length
|
numBooks: li.collapsedSeries.books.length
|
||||||
}
|
}
|
||||||
|
|
||||||
// If collapsing by series and filtering by a series, generate the list of sequences the collapsed
|
// If collapsing by series and filtering by a series, generate the list of sequences the collapsed
|
||||||
// series represents in the filtered series
|
// series represents in the filtered series
|
||||||
json.collapsedSeries.seriesSequenceList =
|
json.collapsedSeries.seriesSequenceList = naturalSort(li.collapsedSeries.books.filter((b) => b.filterSeriesSequence).map((b) => b.filterSeriesSequence))
|
||||||
naturalSort(li.collapsedSeries.books.filter(b => b.filterSeriesSequence).map(b => b.filterSeriesSequence)).asc()
|
.asc()
|
||||||
.reduce((ranges, currentSequence) => {
|
.reduce((ranges, currentSequence) => {
|
||||||
let lastRange = ranges.at(-1)
|
let lastRange = ranges.at(-1)
|
||||||
let isNumber = /^(\d+|\d+\.\d*|\d*\.\d+)$/.test(currentSequence)
|
let isNumber = /^(\d+|\d+\.\d*|\d*\.\d+)$/.test(currentSequence)
|
||||||
if (isNumber) currentSequence = parseFloat(currentSequence)
|
if (isNumber) currentSequence = parseFloat(currentSequence)
|
||||||
|
|
||||||
if (lastRange && isNumber && lastRange.isNumber && ((lastRange.end + 1) == currentSequence)) {
|
if (lastRange && isNumber && lastRange.isNumber && lastRange.end + 1 == currentSequence) {
|
||||||
lastRange.end = currentSequence
|
lastRange.end = currentSequence
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ranges.push({ start: currentSequence, end: currentSequence, isNumber: isNumber })
|
ranges.push({ start: currentSequence, end: currentSequence, isNumber: isNumber })
|
||||||
}
|
}
|
||||||
|
|
||||||
return ranges
|
return ranges
|
||||||
}, [])
|
}, [])
|
||||||
.map(r => r.start == r.end ? r.start : `${r.start}-${r.end}`)
|
.map((r) => (r.start == r.end ? r.start : `${r.start}-${r.end}`))
|
||||||
.join(', ')
|
.join(', ')
|
||||||
}
|
}
|
||||||
|
|
||||||
return json
|
return json
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get library items using filter and sort
|
* Get library items using filter and sort
|
||||||
* @param {import('../../objects/Library')} library
|
* @param {import('../../objects/Library')} library
|
||||||
* @param {import('../../objects/user/User')} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {object} options
|
* @param {object} options
|
||||||
* @returns {object} { libraryItems:LibraryItem[], count:number }
|
* @returns {object} { libraryItems:LibraryItem[], count:number }
|
||||||
*/
|
*/
|
||||||
@ -42,7 +42,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get library items for continue listening & continue reading shelves
|
* Get library items for continue listening & continue reading shelves
|
||||||
* @param {import('../../objects/Library')} library
|
* @param {import('../../objects/Library')} library
|
||||||
* @param {import('../../objects/user/User')} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {Promise<{ items:import('../../models/LibraryItem')[], count:number }>}
|
* @returns {Promise<{ items:import('../../models/LibraryItem')[], count:number }>}
|
||||||
@ -79,7 +79,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get library items for most recently added shelf
|
* Get library items for most recently added shelf
|
||||||
* @param {import('../../objects/Library')} library
|
* @param {import('../../objects/Library')} library
|
||||||
* @param {oldUser} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {object} { libraryItems:LibraryItem[], count:number }
|
* @returns {object} { libraryItems:LibraryItem[], count:number }
|
||||||
@ -127,7 +127,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get library items for continue series shelf
|
* Get library items for continue series shelf
|
||||||
* @param {import('../../objects/Library')} library
|
* @param {import('../../objects/Library')} library
|
||||||
* @param {oldUser} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {object} { libraryItems:LibraryItem[], count:number }
|
* @returns {object} { libraryItems:LibraryItem[], count:number }
|
||||||
@ -155,7 +155,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get library items or podcast episodes for the "Listen Again" and "Read Again" shelf
|
* Get library items or podcast episodes for the "Listen Again" and "Read Again" shelf
|
||||||
* @param {import('../../objects/Library')} library
|
* @param {import('../../objects/Library')} library
|
||||||
* @param {oldUser} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {object} { items:object[], count:number }
|
* @returns {object} { items:object[], count:number }
|
||||||
@ -192,7 +192,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get series for recent series shelf
|
* Get series for recent series shelf
|
||||||
* @param {import('../../objects/Library')} library
|
* @param {import('../../objects/Library')} library
|
||||||
* @param {import('../../objects/user/User')} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {{ series:import('../../objects/entities/Series')[], count:number}}
|
* @returns {{ series:import('../../objects/entities/Series')[], count:number}}
|
||||||
@ -235,7 +235,7 @@ module.exports = {
|
|||||||
if (!user.canAccessExplicitContent) {
|
if (!user.canAccessExplicitContent) {
|
||||||
attrQuery += ' AND b.explicit = 0'
|
attrQuery += ' AND b.explicit = 0'
|
||||||
}
|
}
|
||||||
if (!user.permissions.accessAllTags && user.itemTagsSelected.length) {
|
if (!user.permissions?.accessAllTags && user.permissions?.itemTagsSelected?.length) {
|
||||||
if (user.permissions.selectedTagsNotAccessible) {
|
if (user.permissions.selectedTagsNotAccessible) {
|
||||||
attrQuery += ' AND (SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected)) = 0'
|
attrQuery += ' AND (SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected)) = 0'
|
||||||
} else {
|
} else {
|
||||||
@ -317,7 +317,7 @@ module.exports = {
|
|||||||
* Get most recently created authors for "Newest Authors" shelf
|
* Get most recently created authors for "Newest Authors" shelf
|
||||||
* Author must be linked to at least 1 book
|
* Author must be linked to at least 1 book
|
||||||
* @param {oldLibrary} library
|
* @param {oldLibrary} library
|
||||||
* @param {oldUser} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {object} { authors:oldAuthor[], count:number }
|
* @returns {object} { authors:oldAuthor[], count:number }
|
||||||
*/
|
*/
|
||||||
@ -360,7 +360,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get book library items for the "Discover" shelf
|
* Get book library items for the "Discover" shelf
|
||||||
* @param {oldLibrary} library
|
* @param {oldLibrary} library
|
||||||
* @param {oldUser} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {object} {libraryItems:oldLibraryItem[], count:number}
|
* @returns {object} {libraryItems:oldLibraryItem[], count:number}
|
||||||
@ -387,7 +387,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get podcast episodes most recently added
|
* Get podcast episodes most recently added
|
||||||
* @param {oldLibrary} library
|
* @param {oldLibrary} library
|
||||||
* @param {oldUser} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {object} {libraryItems:oldLibraryItem[], count:number}
|
* @returns {object} {libraryItems:oldLibraryItem[], count:number}
|
||||||
*/
|
*/
|
||||||
@ -408,7 +408,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get library items for an author, optional use user permissions
|
* Get library items for an author, optional use user permissions
|
||||||
* @param {oldAuthor} author
|
* @param {oldAuthor} author
|
||||||
* @param {[oldUser]} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @param {number} offset
|
* @param {number} offset
|
||||||
* @returns {Promise<object>} { libraryItems:LibraryItem[], count:number }
|
* @returns {Promise<object>} { libraryItems:LibraryItem[], count:number }
|
||||||
|
@ -172,17 +172,17 @@ module.exports = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Search library items
|
* Search library items
|
||||||
* @param {import('../../objects/user/User')} oldUser
|
* @param {import('../../models/User')} user
|
||||||
* @param {import('../../objects/Library')} oldLibrary
|
* @param {import('../../objects/Library')} oldLibrary
|
||||||
* @param {string} query
|
* @param {string} query
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {{book:object[], narrators:object[], authors:object[], tags:object[], series:object[], podcast:object[]}}
|
* @returns {{book:object[], narrators:object[], authors:object[], tags:object[], series:object[], podcast:object[]}}
|
||||||
*/
|
*/
|
||||||
search(oldUser, oldLibrary, query, limit) {
|
search(user, oldLibrary, query, limit) {
|
||||||
if (oldLibrary.isBook) {
|
if (oldLibrary.isBook) {
|
||||||
return libraryItemsBookFilters.search(oldUser, oldLibrary, query, limit, 0)
|
return libraryItemsBookFilters.search(user, oldLibrary, query, limit, 0)
|
||||||
} else {
|
} else {
|
||||||
return libraryItemsPodcastFilters.search(oldUser, oldLibrary, query, limit, 0)
|
return libraryItemsPodcastFilters.search(user, oldLibrary, query, limit, 0)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -208,12 +208,10 @@ module.exports = {
|
|||||||
attributes: ['id', 'title']
|
attributes: ['id', 'title']
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
order: [
|
order: [['size', 'DESC']],
|
||||||
['size', 'DESC']
|
|
||||||
],
|
|
||||||
limit
|
limit
|
||||||
})
|
})
|
||||||
return libraryItems.map(libraryItem => {
|
return libraryItems.map((libraryItem) => {
|
||||||
return {
|
return {
|
||||||
id: libraryItem.id,
|
id: libraryItem.id,
|
||||||
title: libraryItem.media.title,
|
title: libraryItem.media.title,
|
||||||
|
@ -8,7 +8,7 @@ const ShareManager = require('../../managers/ShareManager')
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
/**
|
/**
|
||||||
* User permissions to restrict books for explicit content & tags
|
* User permissions to restrict books for explicit content & tags
|
||||||
* @param {import('../../objects/user/User')} user
|
* @param {import('../../models/User')} user
|
||||||
* @returns {{ bookWhere:Sequelize.WhereOptions, replacements:object }}
|
* @returns {{ bookWhere:Sequelize.WhereOptions, replacements:object }}
|
||||||
*/
|
*/
|
||||||
getUserPermissionBookWhereQuery(user) {
|
getUserPermissionBookWhereQuery(user) {
|
||||||
@ -21,8 +21,8 @@ module.exports = {
|
|||||||
explicit: false
|
explicit: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (!user.permissions.accessAllTags && user.itemTagsSelected.length) {
|
if (!user.permissions?.accessAllTags && user.permissions?.itemTagsSelected?.length) {
|
||||||
replacements['userTagsSelected'] = user.itemTagsSelected
|
replacements['userTagsSelected'] = user.permissions.itemTagsSelected
|
||||||
if (user.permissions.selectedTagsNotAccessible) {
|
if (user.permissions.selectedTagsNotAccessible) {
|
||||||
bookWhere.push(Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected))`), 0))
|
bookWhere.push(Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected))`), 0))
|
||||||
} else {
|
} else {
|
||||||
@ -333,7 +333,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get library items for book media type using filter and sort
|
* Get library items for book media type using filter and sort
|
||||||
* @param {string} libraryId
|
* @param {string} libraryId
|
||||||
* @param {import('../../objects/user/User')} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {string|null} filterGroup
|
* @param {string|null} filterGroup
|
||||||
* @param {string|null} filterValue
|
* @param {string|null} filterValue
|
||||||
* @param {string} sortBy
|
* @param {string} sortBy
|
||||||
@ -637,7 +637,7 @@ module.exports = {
|
|||||||
* 3. Has at least 1 unfinished book
|
* 3. Has at least 1 unfinished book
|
||||||
* TODO: Reduce queries
|
* TODO: Reduce queries
|
||||||
* @param {import('../../objects/Library')} library
|
* @param {import('../../objects/Library')} library
|
||||||
* @param {import('../../objects/user/User')} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @param {number} offset
|
* @param {number} offset
|
||||||
@ -672,7 +672,7 @@ module.exports = {
|
|||||||
where: [
|
where: [
|
||||||
{
|
{
|
||||||
id: {
|
id: {
|
||||||
[Sequelize.Op.notIn]: user.seriesHideFromContinueListening
|
[Sequelize.Op.notIn]: user.extraData?.seriesHideFromContinueListening || []
|
||||||
},
|
},
|
||||||
libraryId
|
libraryId
|
||||||
},
|
},
|
||||||
@ -780,7 +780,7 @@ module.exports = {
|
|||||||
* Random selection of books that are not started
|
* Random selection of books that are not started
|
||||||
* - only includes the first book of a not-started series
|
* - only includes the first book of a not-started series
|
||||||
* @param {string} libraryId
|
* @param {string} libraryId
|
||||||
* @param {oldUser} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {object} {libraryItems:LibraryItem, count:number}
|
* @returns {object} {libraryItems:LibraryItem, count:number}
|
||||||
@ -955,25 +955,25 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get library items for series
|
* Get library items for series
|
||||||
* @param {import('../../objects/entities/Series')} oldSeries
|
* @param {import('../../objects/entities/Series')} oldSeries
|
||||||
* @param {import('../../objects/user/User')} [oldUser]
|
* @param {import('../../models/User')} [user]
|
||||||
* @returns {Promise<import('../../objects/LibraryItem')[]>}
|
* @returns {Promise<import('../../objects/LibraryItem')[]>}
|
||||||
*/
|
*/
|
||||||
async getLibraryItemsForSeries(oldSeries, oldUser) {
|
async getLibraryItemsForSeries(oldSeries, user) {
|
||||||
const { libraryItems } = await this.getFilteredLibraryItems(oldSeries.libraryId, oldUser, 'series', oldSeries.id, null, null, false, [], null, null)
|
const { libraryItems } = await this.getFilteredLibraryItems(oldSeries.libraryId, user, 'series', oldSeries.id, null, null, false, [], null, null)
|
||||||
return libraryItems.map((li) => Database.libraryItemModel.getOldLibraryItem(li))
|
return libraryItems.map((li) => Database.libraryItemModel.getOldLibraryItem(li))
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search books, authors, series
|
* Search books, authors, series
|
||||||
* @param {import('../../objects/user/User')} oldUser
|
* @param {import('../../models/User')} user
|
||||||
* @param {import('../../objects/Library')} oldLibrary
|
* @param {import('../../objects/Library')} oldLibrary
|
||||||
* @param {string} query
|
* @param {string} query
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @param {number} offset
|
* @param {number} offset
|
||||||
* @returns {{book:object[], narrators:object[], authors:object[], tags:object[], series:object[]}}
|
* @returns {{book:object[], narrators:object[], authors:object[], tags:object[], series:object[]}}
|
||||||
*/
|
*/
|
||||||
async search(oldUser, oldLibrary, query, limit, offset) {
|
async search(user, oldLibrary, query, limit, offset) {
|
||||||
const userPermissionBookWhere = this.getUserPermissionBookWhereQuery(oldUser)
|
const userPermissionBookWhere = this.getUserPermissionBookWhereQuery(user)
|
||||||
|
|
||||||
const normalizedQuery = query
|
const normalizedQuery = query
|
||||||
|
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
const Sequelize = require('sequelize')
|
const Sequelize = require('sequelize')
|
||||||
const Database = require('../../Database')
|
const Database = require('../../Database')
|
||||||
const Logger = require('../../Logger')
|
const Logger = require('../../Logger')
|
||||||
const { asciiOnlyToLowerCase } = require('../index')
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/**
|
/**
|
||||||
* User permissions to restrict podcasts for explicit content & tags
|
* User permissions to restrict podcasts for explicit content & tags
|
||||||
* @param {import('../../objects/user/User')} user
|
* @param {import('../../models/User')} user
|
||||||
* @returns {{ podcastWhere:Sequelize.WhereOptions, replacements:object }}
|
* @returns {{ podcastWhere:Sequelize.WhereOptions, replacements:object }}
|
||||||
*/
|
*/
|
||||||
getUserPermissionPodcastWhereQuery(user) {
|
getUserPermissionPodcastWhereQuery(user) {
|
||||||
@ -17,18 +16,20 @@ module.exports = {
|
|||||||
explicit: false
|
explicit: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (!user.permissions.accessAllTags && user.itemTagsSelected.length) {
|
|
||||||
replacements['userTagsSelected'] = user.itemTagsSelected
|
if (!user.permissions?.accessAllTags && user.permissions?.itemTagsSelected?.length) {
|
||||||
|
replacements['userTagsSelected'] = user.permissions.itemTagsSelected
|
||||||
if (user.permissions.selectedTagsNotAccessible) {
|
if (user.permissions.selectedTagsNotAccessible) {
|
||||||
podcastWhere.push(Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected))`), 0))
|
bookWhere.push(Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected))`), 0))
|
||||||
} else {
|
} else {
|
||||||
podcastWhere.push(
|
bookWhere.push(
|
||||||
Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected))`), {
|
Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected))`), {
|
||||||
[Sequelize.Op.gte]: 1
|
[Sequelize.Op.gte]: 1
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
podcastWhere,
|
podcastWhere,
|
||||||
replacements
|
replacements
|
||||||
@ -98,7 +99,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get library items for podcast media type using filter and sort
|
* Get library items for podcast media type using filter and sort
|
||||||
* @param {string} libraryId
|
* @param {string} libraryId
|
||||||
* @param {oldUser} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {[string]} filterGroup
|
* @param {[string]} filterGroup
|
||||||
* @param {[string]} filterValue
|
* @param {[string]} filterValue
|
||||||
* @param {string} sortBy
|
* @param {string} sortBy
|
||||||
@ -200,7 +201,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Get podcast episodes filtered and sorted
|
* Get podcast episodes filtered and sorted
|
||||||
* @param {string} libraryId
|
* @param {string} libraryId
|
||||||
* @param {oldUser} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {[string]} filterGroup
|
* @param {[string]} filterGroup
|
||||||
* @param {[string]} filterValue
|
* @param {[string]} filterValue
|
||||||
* @param {string} sortBy
|
* @param {string} sortBy
|
||||||
@ -304,15 +305,15 @@ module.exports = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Search podcasts
|
* Search podcasts
|
||||||
* @param {import('../../objects/user/User')} oldUser
|
* @param {import('../../models/User')} user
|
||||||
* @param {import('../../objects/Library')} oldLibrary
|
* @param {import('../../objects/Library')} oldLibrary
|
||||||
* @param {string} query
|
* @param {string} query
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @param {number} offset
|
* @param {number} offset
|
||||||
* @returns {{podcast:object[], tags:object[]}}
|
* @returns {{podcast:object[], tags:object[]}}
|
||||||
*/
|
*/
|
||||||
async search(oldUser, oldLibrary, query, limit, offset) {
|
async search(user, oldLibrary, query, limit, offset) {
|
||||||
const userPermissionPodcastWhere = this.getUserPermissionPodcastWhereQuery(oldUser)
|
const userPermissionPodcastWhere = this.getUserPermissionPodcastWhereQuery(user)
|
||||||
|
|
||||||
const normalizedQuery = query
|
const normalizedQuery = query
|
||||||
const matchTitle = Database.matchExpression('title', normalizedQuery)
|
const matchTitle = Database.matchExpression('title', normalizedQuery)
|
||||||
@ -410,14 +411,14 @@ module.exports = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Most recent podcast episodes not finished
|
* Most recent podcast episodes not finished
|
||||||
* @param {import('../../objects/user/User')} oldUser
|
* @param {import('../../models/User')} user
|
||||||
* @param {import('../../objects/Library')} oldLibrary
|
* @param {import('../../objects/Library')} oldLibrary
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @param {number} offset
|
* @param {number} offset
|
||||||
* @returns {Promise<object[]>}
|
* @returns {Promise<object[]>}
|
||||||
*/
|
*/
|
||||||
async getRecentEpisodes(oldUser, oldLibrary, limit, offset) {
|
async getRecentEpisodes(user, oldLibrary, limit, offset) {
|
||||||
const userPermissionPodcastWhere = this.getUserPermissionPodcastWhereQuery(oldUser)
|
const userPermissionPodcastWhere = this.getUserPermissionPodcastWhereQuery(user)
|
||||||
|
|
||||||
const episodes = await Database.podcastEpisodeModel.findAll({
|
const episodes = await Database.podcastEpisodeModel.findAll({
|
||||||
where: {
|
where: {
|
||||||
@ -441,7 +442,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
model: Database.mediaProgressModel,
|
model: Database.mediaProgressModel,
|
||||||
where: {
|
where: {
|
||||||
userId: oldUser.id
|
userId: user.id
|
||||||
},
|
},
|
||||||
required: false
|
required: false
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ module.exports = {
|
|||||||
* Get series filtered and sorted
|
* Get series filtered and sorted
|
||||||
*
|
*
|
||||||
* @param {import('../../objects/Library')} library
|
* @param {import('../../objects/Library')} library
|
||||||
* @param {import('../../objects/user/User')} user
|
* @param {import('../../models/User')} user
|
||||||
* @param {string} filterBy
|
* @param {string} filterBy
|
||||||
* @param {string} sortBy
|
* @param {string} sortBy
|
||||||
* @param {boolean} sortDesc
|
* @param {boolean} sortDesc
|
||||||
@ -93,7 +93,7 @@ module.exports = {
|
|||||||
if (!user.canAccessExplicitContent) {
|
if (!user.canAccessExplicitContent) {
|
||||||
attrQuery += ' AND b.explicit = 0'
|
attrQuery += ' AND b.explicit = 0'
|
||||||
}
|
}
|
||||||
if (!user.permissions.accessAllTags && user.itemTagsSelected.length) {
|
if (!user.permissions?.accessAllTags && user.permissions?.itemTagsSelected?.length) {
|
||||||
if (user.permissions.selectedTagsNotAccessible) {
|
if (user.permissions.selectedTagsNotAccessible) {
|
||||||
attrQuery += ' AND (SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected)) = 0'
|
attrQuery += ' AND (SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected)) = 0'
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user