1
0
mirror of https://github.com/advplyr/audiobookshelf.git synced 2025-01-08 00:08:14 +01:00

Update:Express middleware sets req.user to new data model, openid permissions functions moved to new data model

This commit is contained in:
advplyr 2024-08-11 16:07:29 -05:00
parent 29a15858f4
commit 2472b86284
29 changed files with 474 additions and 430 deletions

View File

@ -152,6 +152,8 @@ class Auth {
/**
* Finds an existing user by OpenID subject identifier, or by email/username based on server settings,
* or creates a new user if configured to do so.
*
* @returns {import('./models/User')|null}
*/
async findOrCreateUser(userinfo) {
let user = await Database.userModel.getUserByOpenIDSub(userinfo.sub)
@ -307,9 +309,8 @@ class Auth {
const absPermissions = userinfo[absPermissionsClaim]
if (!absPermissions) throw new Error(`Advanced permissions claim ${absPermissionsClaim} not found in userinfo`)
if (user.updatePermissionsFromExternalJSON(absPermissions)) {
if (await user.updatePermissionsFromExternalJSON(absPermissions)) {
Logger.info(`[Auth] openid callback: Updating advanced perms for user "${user.username}" using "${JSON.stringify(absPermissions)}"`)
await Database.userModel.updateFromOld(user)
}
}
@ -921,7 +922,7 @@ class Auth {
async userChangePassword(req, res) {
let { password, newPassword } = req.body
newPassword = newPassword || ''
const matchingUser = req.userNew
const matchingUser = req.user
// Only root can have an empty password
if (matchingUser.type !== 'root' && !newPassword) {

View File

@ -91,8 +91,6 @@ class Server {
/**
* Middleware to check if the current request is authenticated
* req.user is set if authenticated to the OLD user object
* req.userNew is set if authenticated to the NEW user object
*
* @param {import('express').Request} req
* @param {import('express').Response} res
@ -100,14 +98,7 @@ class Server {
*/
authMiddleware(req, res, next) {
// ask passportjs if the current request is authenticated
this.auth.isAuthenticated(req, res, () => {
if (req.user) {
// TODO: req.userNew to become req.user
req.userNew = req.user
req.user = Database.userModel.getOldUser(req.user)
}
next()
})
this.auth.isAuthenticated(req, res, next)
}
cancelLibraryScan(libraryId) {

View File

@ -24,7 +24,7 @@ class AuthorController {
// Used on author landing page to include library items and items grouped in series
if (include.includes('items')) {
authorJson.libraryItems = await Database.libraryItemModel.getForAuthor(req.author, req.userNew)
authorJson.libraryItems = await Database.libraryItemModel.getForAuthor(req.author, req.user)
if (include.includes('series')) {
const seriesMap = {}
@ -222,8 +222,8 @@ class AuthorController {
* @param {import('express').Response} res
*/
async uploadImage(req, res) {
if (!req.userNew.canUpload) {
Logger.warn(`User "${req.userNew.username}" attempted to upload an image without permission`)
if (!req.user.canUpload) {
Logger.warn(`User "${req.user.username}" attempted to upload an image without permission`)
return res.sendStatus(403)
}
if (!req.body.url) {
@ -362,11 +362,11 @@ class AuthorController {
const author = await Database.authorModel.getOldById(req.params.id)
if (!author) return res.sendStatus(404)
if (req.method == 'DELETE' && !req.userNew.canDelete) {
Logger.warn(`[AuthorController] User "${req.userNew.username}" attempted to delete without permission`)
if (req.method == 'DELETE' && !req.user.canDelete) {
Logger.warn(`[AuthorController] User "${req.user.username}" attempted to delete without permission`)
return res.sendStatus(403)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.userNew.canUpdate) {
Logger.warn(`[AuthorController] User "${req.userNew.username}" attempted to update without permission`)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
Logger.warn(`[AuthorController] User "${req.user.username}" attempted to update without permission`)
return res.sendStatus(403)
}

View File

@ -113,8 +113,8 @@ class BackupController {
}
middleware(req, res, next) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[BackupController] Non-admin user "${req.userNew.username}" attempting to access backups`)
if (!req.user.isAdminOrUp) {
Logger.error(`[BackupController] Non-admin user "${req.user.username}" attempting to access backups`)
return res.sendStatus(403)
}

View File

@ -5,7 +5,7 @@ class CacheController {
// POST: api/cache/purge
async purgeCache(req, res) {
if (!req.userNew.isAdminOrUp) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(403)
}
await CacheManager.purgeAll()
@ -14,7 +14,7 @@ class CacheController {
// POST: api/cache/items/purge
async purgeItemsCache(req, res) {
if (!req.userNew.isAdminOrUp) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(403)
}
await CacheManager.purgeItems()

View File

@ -16,7 +16,7 @@ class CollectionController {
*/
async create(req, res) {
const newCollection = new Collection()
req.body.userId = req.userNew.id
req.body.userId = req.user.id
if (!newCollection.setData(req.body)) {
return res.status(400).send('Invalid collection data')
}
@ -50,7 +50,7 @@ class CollectionController {
}
async findAll(req, res) {
const collectionsExpanded = await Database.collectionModel.getOldCollectionsJsonExpanded(req.userNew)
const collectionsExpanded = await Database.collectionModel.getOldCollectionsJsonExpanded(req.user)
res.json({
collections: collectionsExpanded
})
@ -59,7 +59,7 @@ class CollectionController {
async findOne(req, res) {
const includeEntities = (req.query.include || '').split(',')
const collectionExpanded = await req.collection.getOldJsonExpanded(req.userNew, includeEntities)
const collectionExpanded = await req.collection.getOldJsonExpanded(req.user, includeEntities)
if (!collectionExpanded) {
// This may happen if the user is restricted from all books
return res.sendStatus(404)
@ -334,11 +334,11 @@ class CollectionController {
req.collection = collection
}
if (req.method == 'DELETE' && !req.userNew.canDelete) {
Logger.warn(`[CollectionController] User "${req.userNew.username}" attempted to delete without permission`)
if (req.method == 'DELETE' && !req.user.canDelete) {
Logger.warn(`[CollectionController] User "${req.user.username}" attempted to delete without permission`)
return res.sendStatus(403)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.userNew.canUpdate) {
Logger.warn(`[CollectionController] User "${req.userNew.username}" attempted to update without permission`)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
Logger.warn(`[CollectionController] User "${req.user.username}" attempted to update without permission`)
return res.sendStatus(403)
}

View File

@ -101,8 +101,8 @@ class CustomMetadataProviderController {
* @param {import('express').NextFunction} next
*/
async middleware(req, res, next) {
if (!req.userNew.isAdminOrUp) {
Logger.warn(`[CustomMetadataProviderController] Non-admin user "${req.userNew.username}" attempted access route "${req.path}"`)
if (!req.user.isAdminOrUp) {
Logger.warn(`[CustomMetadataProviderController] Non-admin user "${req.user.username}" attempted access route "${req.path}"`)
return res.sendStatus(403)
}

View File

@ -59,7 +59,7 @@ class EmailController {
* @param {import('express').Response} res
*/
async sendEBookToDevice(req, res) {
Logger.debug(`[EmailController] Send ebook to device requested by user "${req.userNew.username}" for libraryItemId=${req.body.libraryItemId}, deviceName=${req.body.deviceName}`)
Logger.debug(`[EmailController] Send ebook to device requested by user "${req.user.username}" for libraryItemId=${req.body.libraryItemId}, deviceName=${req.body.deviceName}`)
const device = Database.emailSettings.getEReaderDevice(req.body.deviceName)
if (!device) {
@ -67,7 +67,7 @@ class EmailController {
}
// Check user has access to device
if (!Database.emailSettings.checkUserCanAccessDevice(device, req.userNew)) {
if (!Database.emailSettings.checkUserCanAccessDevice(device, req.user)) {
return res.sendStatus(403)
}
@ -77,7 +77,7 @@ class EmailController {
}
// Check user has access to library item
if (!req.userNew.checkCanAccessLibraryItem(libraryItem)) {
if (!req.user.checkCanAccessLibraryItem(libraryItem)) {
return res.sendStatus(403)
}
@ -90,7 +90,7 @@ class EmailController {
}
adminMiddleware(req, res, next) {
if (!req.userNew.isAdminOrUp) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(404)
}

View File

@ -13,8 +13,8 @@ class FileSystemController {
* @param {import('express').Response} res
*/
async getPaths(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[FileSystemController] Non-admin user "${req.userNew.username}" attempting to get filesystem paths`)
if (!req.user.isAdminOrUp) {
Logger.error(`[FileSystemController] Non-admin user "${req.user.username}" attempting to get filesystem paths`)
return res.sendStatus(403)
}
@ -69,8 +69,8 @@ class FileSystemController {
// POST: api/filesystem/pathexists
async checkPathExists(req, res) {
if (!req.userNew.canUpload) {
Logger.error(`[FileSystemController] Non-admin user "${req.userNew.username}" attempting to check path exists`)
if (!req.user.canUpload) {
Logger.error(`[FileSystemController] Non-admin user "${req.user.username}" attempting to check path exists`)
return res.sendStatus(403)
}

View File

@ -83,7 +83,7 @@ class LibraryController {
async findAll(req, res) {
const libraries = await Database.libraryModel.getAllOldLibraries()
const librariesAccessible = req.userNew.permissions?.librariesAccessible || []
const librariesAccessible = req.user.permissions?.librariesAccessible || []
if (librariesAccessible.length) {
return res.json({
libraries: libraries.filter((lib) => librariesAccessible.includes(lib.id)).map((lib) => lib.toJSON())
@ -110,7 +110,7 @@ class LibraryController {
return res.json({
filterdata,
issues: filterdata.numIssues,
numUserPlaylists: await Database.playlistModel.getNumPlaylistsForUserAndLibrary(req.userNew.id, req.library.id),
numUserPlaylists: await Database.playlistModel.getNumPlaylistsForUserAndLibrary(req.user.id, req.library.id),
customMetadataProviders,
library: req.library
})
@ -327,9 +327,9 @@ class LibraryController {
const filterByValue = filterByGroup ? libraryFilters.decode(payload.filterBy.replace(`${filterByGroup}.`, '')) : null
if (filterByGroup === 'series' && filterByValue !== 'no-series' && payload.collapseseries) {
const seriesId = libraryFilters.decode(payload.filterBy.split('.')[1])
payload.results = await libraryHelpers.handleCollapseSubseries(payload, seriesId, req.userNew, req.library)
payload.results = await libraryHelpers.handleCollapseSubseries(payload, seriesId, req.user, req.library)
} else {
const { libraryItems, count } = await Database.libraryItemModel.getByFilterAndSort(req.library, req.userNew, payload)
const { libraryItems, count } = await Database.libraryItemModel.getByFilterAndSort(req.library, req.user, payload)
payload.results = libraryItems
payload.total = count
}
@ -420,7 +420,7 @@ class LibraryController {
}
const offset = payload.page * payload.limit
const { series, count } = await seriesFilters.getFilteredSeries(req.library, req.userNew, payload.filterBy, payload.sortBy, payload.sortDesc, include, payload.limit, offset)
const { series, count } = await seriesFilters.getFilteredSeries(req.library, req.user, payload.filterBy, payload.sortBy, payload.sortDesc, include, payload.limit, offset)
payload.total = count
payload.results = series
@ -447,11 +447,11 @@ class LibraryController {
if (!series) return res.sendStatus(404)
const oldSeries = series.getOldSeries()
const libraryItemsInSeries = await libraryItemsBookFilters.getLibraryItemsForSeries(oldSeries, req.userNew)
const libraryItemsInSeries = await libraryItemsBookFilters.getLibraryItemsForSeries(oldSeries, req.user)
const seriesJson = oldSeries.toJSON()
if (include.includes('progress')) {
const libraryItemsFinished = libraryItemsInSeries.filter((li) => !!req.userNew.getMediaProgress(li.media.id)?.isFinished)
const libraryItemsFinished = libraryItemsInSeries.filter((li) => !!req.user.getMediaProgress(li.media.id)?.isFinished)
seriesJson.progress = {
libraryItemIds: libraryItemsInSeries.map((li) => li.id),
libraryItemIdsFinished: libraryItemsFinished.map((li) => li.id),
@ -492,7 +492,7 @@ class LibraryController {
}
// TODO: Create paginated queries
let collections = await Database.collectionModel.getOldCollectionsJsonExpanded(req.userNew, req.library.id, include)
let collections = await Database.collectionModel.getOldCollectionsJsonExpanded(req.user, req.library.id, include)
payload.total = collections.length
@ -512,7 +512,7 @@ class LibraryController {
* @param {*} res
*/
async getUserPlaylistsForLibrary(req, res) {
let playlistsForUser = await Database.playlistModel.getOldPlaylistsForUserAndLibrary(req.userNew.id, req.library.id)
let playlistsForUser = await Database.playlistModel.getOldPlaylistsForUserAndLibrary(req.user.id, req.library.id)
const payload = {
results: [],
@ -552,7 +552,7 @@ class LibraryController {
.split(',')
.map((v) => v.trim().toLowerCase())
.filter((v) => !!v)
const shelves = await Database.libraryItemModel.getPersonalizedShelves(req.library, req.userNew, include, limitPerShelf)
const shelves = await Database.libraryItemModel.getPersonalizedShelves(req.library, req.user, include, limitPerShelf)
res.json(shelves)
}
@ -563,8 +563,8 @@ class LibraryController {
* @param {import('express').Response} res
*/
async reorder(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[LibraryController] Non-admin user "${req.userNew}" attempted to reorder libraries`)
if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryController] Non-admin user "${req.user}" attempted to reorder libraries`)
return res.sendStatus(403)
}
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 query = asciiOnlyToLowerCase(req.query.q.trim())
const matches = await libraryItemFilters.search(req.userNew, req.library, query, limit)
const matches = await libraryItemFilters.search(req.user, req.library, query, limit)
res.json(matches)
}
@ -662,7 +662,7 @@ class LibraryController {
* @param {import('express').Response} res
*/
async getAuthors(req, res) {
const { bookWhere, replacements } = libraryItemsBookFilters.getUserPermissionBookWhereQuery(req.userNew)
const { bookWhere, replacements } = libraryItemsBookFilters.getUserPermissionBookWhereQuery(req.user)
const authors = await Database.authorModel.findAll({
where: {
libraryId: req.library.id
@ -672,7 +672,7 @@ class LibraryController {
model: Database.bookModel,
attributes: ['id', 'tags', 'explicit'],
where: bookWhere,
required: !req.userNew.isAdminOrUp, // Only show authors with 0 books for admin users or up
required: !req.user.isAdminOrUp, // Only show authors with 0 books for admin users or up
through: {
attributes: []
}
@ -746,8 +746,8 @@ class LibraryController {
* @param {*} res
*/
async updateNarrator(req, res) {
if (!req.userNew.canUpdate) {
Logger.error(`[LibraryController] Unauthorized user "${req.userNew.username}" attempted to update narrator`)
if (!req.user.canUpdate) {
Logger.error(`[LibraryController] Unauthorized user "${req.user.username}" attempted to update narrator`)
return res.sendStatus(403)
}
@ -796,8 +796,8 @@ class LibraryController {
* @param {*} res
*/
async removeNarrator(req, res) {
if (!req.userNew.canUpdate) {
Logger.error(`[LibraryController] Unauthorized user "${req.userNew.username}" attempted to remove narrator`)
if (!req.user.canUpdate) {
Logger.error(`[LibraryController] Unauthorized user "${req.user.username}" attempted to remove narrator`)
return res.sendStatus(403)
}
@ -839,8 +839,8 @@ class LibraryController {
* @param {import('express').Response} res
*/
async matchAll(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[LibraryController] Non-root user "${req.userNew.username}" attempted to match library items`)
if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryController] Non-root user "${req.user.username}" attempted to match library items`)
return res.sendStatus(403)
}
Scanner.matchLibraryItems(req.library)
@ -856,8 +856,8 @@ class LibraryController {
* @param {import('express').Response} res
*/
async scan(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[LibraryController] Non-admin user "${req.userNew.username}" attempted to scan library`)
if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryController] Non-admin user "${req.user.username}" attempted to scan library`)
return res.sendStatus(403)
}
res.sendStatus(200)
@ -887,7 +887,7 @@ class LibraryController {
}
const offset = payload.page * payload.limit
payload.episodes = await libraryItemsPodcastFilters.getRecentEpisodes(req.userNew, req.library, payload.limit, offset)
payload.episodes = await libraryItemsPodcastFilters.getRecentEpisodes(req.user, req.library, payload.limit, offset)
res.json(payload)
}
@ -898,7 +898,7 @@ class LibraryController {
* @param {import('express').Response} res
*/
async getOPMLFile(req, res) {
const userPermissionPodcastWhere = libraryItemsPodcastFilters.getUserPermissionPodcastWhereQuery(req.userNew)
const userPermissionPodcastWhere = libraryItemsPodcastFilters.getUserPermissionPodcastWhereQuery(req.user)
const podcasts = await Database.podcastModel.findAll({
attributes: ['id', 'feedURL', 'title', 'description', 'itunesPageURL', 'language'],
where: userPermissionPodcastWhere.podcastWhere,
@ -924,8 +924,8 @@ class LibraryController {
* @param {import('express').Response} res
*/
async removeAllMetadataFiles(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[LibraryController] Non-admin user "${req.userNew.username}" attempted to remove all metadata files`)
if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryController] Non-admin user "${req.user.username}" attempted to remove all metadata files`)
return res.sendStatus(403)
}
@ -974,8 +974,8 @@ class LibraryController {
* @param {import('express').NextFunction} next
*/
async middleware(req, res, next) {
if (!req.userNew.checkCanAccessLibrary(req.params.id)) {
Logger.warn(`[LibraryController] Library ${req.params.id} not accessible to user ${req.userNew.username}`)
if (!req.user.checkCanAccessLibrary(req.params.id)) {
Logger.warn(`[LibraryController] Library ${req.params.id} not accessible to user ${req.user.username}`)
return res.sendStatus(403)
}

View File

@ -18,8 +18,7 @@ const ShareManager = require('../managers/ShareManager')
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*/
@ -33,8 +32,8 @@ class LibraryItemController {
* ?include=progress,rssfeed,downloads,share
* ?expanded=1
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async findOne(req, res) {
const includeEntities = (req.query.include || '').split(',')
@ -44,7 +43,7 @@ class LibraryItemController {
// Include users media progress
if (includeEntities.includes('progress')) {
var episodeId = req.query.episode || null
item.userMediaProgress = req.userNew.getOldMediaProgress(item.id, episodeId)
item.userMediaProgress = req.user.getOldMediaProgress(item.id, episodeId)
}
if (includeEntities.includes('rssfeed')) {
@ -52,7 +51,7 @@ class LibraryItemController {
item.rssFeed = feedData?.toJSONMinified() || null
}
if (item.mediaType === 'book' && req.userNew.isAdminOrUp && includeEntities.includes('share')) {
if (item.mediaType === 'book' && req.user.isAdminOrUp && includeEntities.includes('share')) {
item.mediaItemShare = ShareManager.findByMediaItemId(item.media.id)
}
@ -69,6 +68,11 @@ class LibraryItemController {
res.json(req.libraryItem)
}
/**
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async update(req, res) {
var libraryItem = req.libraryItem
// Item has cover and update is removing cover so purge it from cache
@ -91,8 +95,8 @@ class LibraryItemController {
* Optional query params:
* ?hard=1
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async delete(req, res) {
const hardDelete = req.query.hard == 1 // Delete from file system
@ -114,12 +118,12 @@ class LibraryItemController {
* GET: /api/items/:id/download
* Download library item. Zip file if multiple files.
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
download(req, res) {
if (!req.userNew.canDownload) {
Logger.warn(`User "${req.userNew.username}" attempted to download without permission`)
if (!req.user.canDownload) {
Logger.warn(`User "${req.user.username}" attempted to download without permission`)
return res.sendStatus(403)
}
const libraryItemPath = req.libraryItem.path
@ -132,12 +136,12 @@ class LibraryItemController {
if (audioMimeType) {
res.setHeader('Content-Type', audioMimeType)
}
Logger.info(`[LibraryItemController] User "${req.userNew.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
res.download(libraryItemPath, req.libraryItem.relPath)
return
}
Logger.info(`[LibraryItemController] User "${req.userNew.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
const filename = `${itemTitle}.zip`
zipHelpers.zipDirectoryPipe(libraryItemPath, filename, res)
}
@ -146,8 +150,8 @@ class LibraryItemController {
* PATCH: /items/:id/media
* Update media for a library item. Will create new authors & series when necessary
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async updateMedia(req, res) {
const libraryItem = req.libraryItem
@ -207,10 +211,16 @@ class LibraryItemController {
})
}
// POST: api/items/:id/cover
/**
* POST: /api/items/:id/cover
*
* @param {RequestWithUser} req
* @param {Response} res
* @param {boolean} [updateAndReturnJson=true]
*/
async uploadCover(req, res, updateAndReturnJson = true) {
if (!req.userNew.canUpload) {
Logger.warn(`User "${req.userNew.username}" attempted to upload a cover without permission`)
if (!req.user.canUpload) {
Logger.warn(`User "${req.user.username}" attempted to upload a cover without permission`)
return res.sendStatus(403)
}
@ -243,7 +253,12 @@ class LibraryItemController {
}
}
// PATCH: api/items/:id/cover
/**
* PATCH: /api/items/:id/cover
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async updateCover(req, res) {
const libraryItem = req.libraryItem
if (!req.body.cover) {
@ -264,7 +279,12 @@ class LibraryItemController {
})
}
// DELETE: api/items/:id/cover
/**
* DELETE: /api/items/:id/cover
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async removeCover(req, res) {
var libraryItem = req.libraryItem
@ -279,10 +299,10 @@ class LibraryItemController {
}
/**
* GET: api/items/:id/cover
* GET: /api/items/:id/cover
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async getCover(req, res) {
const {
@ -308,7 +328,7 @@ class LibraryItemController {
}
// Check if user can access this library item
if (!req.userNew.checkCanAccessLibraryItem(libraryItem)) {
if (!req.user.checkCanAccessLibraryItem(libraryItem)) {
return res.sendStatus(403)
}
@ -377,7 +397,12 @@ class LibraryItemController {
this.playbackSessionManager.startSessionRequest(req, res, episodeId)
}
// PATCH: api/items/:id/tracks
/**
* PATCH: /api/items/:id/tracks
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async updateTracks(req, res) {
var libraryItem = req.libraryItem
var orderedFileData = req.body.orderedFileData
@ -391,7 +416,12 @@ class LibraryItemController {
res.json(libraryItem.toJSON())
}
// POST api/items/:id/match
/**
* POST /api/items/:id/match
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async match(req, res) {
var libraryItem = req.libraryItem
@ -406,12 +436,12 @@ class LibraryItemController {
* Optional query params:
* ?hard=1
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async batchDelete(req, res) {
if (!req.userNew.canDelete) {
Logger.warn(`[LibraryItemController] User "${req.userNew.username}" attempted to delete without permission`)
if (!req.user.canDelete) {
Logger.warn(`[LibraryItemController] User "${req.user.username}" attempted to delete without permission`)
return res.sendStatus(403)
}
const hardDelete = req.query.hard == 1 // Delete files from filesystem
@ -447,7 +477,12 @@ class LibraryItemController {
res.sendStatus(200)
}
// POST: api/items/batch/update
/**
* POST: /api/items/batch/update
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async batchUpdate(req, res) {
const updatePayloads = req.body
if (!updatePayloads?.length) {
@ -493,7 +528,12 @@ class LibraryItemController {
})
}
// POST: api/items/batch/get
/**
* POST: /api/items/batch/get
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async batchGet(req, res) {
const libraryItemIds = req.body.libraryItemIds || []
if (!libraryItemIds.length) {
@ -507,10 +547,15 @@ class LibraryItemController {
})
}
// POST: api/items/batch/quickmatch
/**
* POST: /api/items/batch/quickmatch
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async batchQuickMatch(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.warn(`Non-admin user "${req.userNew.username}" other than admin attempted to batch quick match library items`)
if (!req.user.isAdminOrUp) {
Logger.warn(`Non-admin user "${req.user.username}" other than admin attempted to batch quick match library items`)
return res.sendStatus(403)
}
@ -545,13 +590,18 @@ class LibraryItemController {
updates: itemsUpdated,
unmatched: itemsUnmatched
}
SocketAuthority.clientEmitter(req.userNew.id, 'batch_quickmatch_complete', result)
SocketAuthority.clientEmitter(req.user.id, 'batch_quickmatch_complete', result)
}
// POST: api/items/batch/scan
/**
* POST: /api/items/batch/scan
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async batchScan(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.warn(`Non-admin user "${req.userNew.username}" other than admin attempted to batch scan library items`)
if (!req.user.isAdminOrUp) {
Logger.warn(`Non-admin user "${req.user.username}" other than admin attempted to batch scan library items`)
return res.sendStatus(403)
}
@ -583,10 +633,15 @@ class LibraryItemController {
await Database.resetLibraryIssuesFilterData(libraryId)
}
// POST: api/items/:id/scan
/**
* POST: /api/items/:id/scan
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async scan(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[LibraryItemController] Non-admin user "${req.userNew.username}" attempted to scan library item`)
if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryItemController] Non-admin user "${req.user.username}" attempted to scan library item`)
return res.sendStatus(403)
}
@ -602,9 +657,15 @@ class LibraryItemController {
})
}
/**
* GET: /api/items/:id/metadata-object
*
* @param {RequestWithUser} req
* @param {Response} res
*/
getMetadataObject(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[LibraryItemController] Non-admin user "${req.userNew.username}" attempted to get metadata object`)
if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryItemController] Non-admin user "${req.user.username}" attempted to get metadata object`)
return res.sendStatus(403)
}
@ -616,10 +677,15 @@ class LibraryItemController {
res.json(this.audioMetadataManager.getMetadataObjectForApi(req.libraryItem))
}
// POST: api/items/:id/chapters
/**
* POST: /api/items/:id/chapters
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async updateMediaChapters(req, res) {
if (!req.userNew.canUpdate) {
Logger.error(`[LibraryItemController] User "${req.userNew.username}" attempted to update chapters with invalid permissions`)
if (!req.user.canUpdate) {
Logger.error(`[LibraryItemController] User "${req.user.username}" attempted to update chapters with invalid permissions`)
return res.sendStatus(403)
}
@ -647,15 +713,15 @@ class LibraryItemController {
}
/**
* GET api/items/:id/ffprobe/:fileid
* GET: /api/items/:id/ffprobe/:fileid
* FFProbe JSON result from audio file
*
* @param {express.Request} req
* @param {express.Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async getFFprobeData(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[LibraryItemController] Non-admin user "${req.userNew.username}" attempted to get ffprobe data`)
if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryItemController] Non-admin user "${req.user.username}" attempted to get ffprobe data`)
return res.sendStatus(403)
}
if (req.libraryFile.fileType !== 'audio') {
@ -676,8 +742,8 @@ class LibraryItemController {
/**
* GET api/items/:id/file/:fileid
*
* @param {express.Request} req
* @param {express.Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async getLibraryFile(req, res) {
const libraryFile = req.libraryFile
@ -699,13 +765,13 @@ class LibraryItemController {
/**
* DELETE api/items/:id/file/:fileid
*
* @param {express.Request} req
* @param {express.Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async deleteLibraryFile(req, res) {
const libraryFile = req.libraryFile
Logger.info(`[LibraryItemController] User "${req.userNew.username}" requested file delete at "${libraryFile.metadata.path}"`)
Logger.info(`[LibraryItemController] User "${req.user.username}" requested file delete at "${libraryFile.metadata.path}"`)
await fs.remove(libraryFile.metadata.path).catch((error) => {
Logger.error(`[LibraryItemController] Failed to delete library file at "${libraryFile.metadata.path}"`, error)
@ -727,18 +793,19 @@ class LibraryItemController {
/**
* GET api/items/:id/file/:fileid/download
* Same as GET api/items/:id/file/:fileid but allows logging and restricting downloads
* @param {express.Request} req
* @param {express.Response} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async downloadLibraryFile(req, res) {
const libraryFile = req.libraryFile
if (!req.userNew.canDownload) {
Logger.error(`[LibraryItemController] User "${req.userNew.username}" without download permission attempted to download file "${libraryFile.metadata.path}"`)
if (!req.user.canDownload) {
Logger.error(`[LibraryItemController] User "${req.user.username}" without download permission attempted to download file "${libraryFile.metadata.path}"`)
return res.sendStatus(403)
}
Logger.info(`[LibraryItemController] User "${req.userNew.username}" requested download for item "${req.libraryItem.media.metadata.title}" file at "${libraryFile.metadata.path}"`)
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${req.libraryItem.media.metadata.title}" file at "${libraryFile.metadata.path}"`)
if (global.XAccel) {
const encodedURI = encodeUriPath(global.XAccel + libraryFile.metadata.path)
@ -761,8 +828,8 @@ class LibraryItemController {
* fileid is only required when reading a supplementary ebook
* when no fileid is passed in the primary ebook will be returned
*
* @param {express.Request} req
* @param {express.Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async getEBookFile(req, res) {
let ebookFile = null
@ -782,7 +849,7 @@ class LibraryItemController {
}
const ebookFilePath = ebookFile.metadata.path
Logger.info(`[LibraryItemController] User "${req.userNew.username}" requested download for item "${req.libraryItem.media.metadata.title}" ebook at "${ebookFilePath}"`)
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${req.libraryItem.media.metadata.title}" ebook at "${ebookFilePath}"`)
if (global.XAccel) {
const encodedURI = encodeUriPath(global.XAccel + ebookFilePath)
@ -799,8 +866,8 @@ class LibraryItemController {
* if an ebook file is the primary ebook, then it will be changed to supplementary
* if an ebook file is supplementary, then it will be changed to primary
*
* @param {express.Request} req
* @param {express.Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async updateEbookFileStatus(req, res) {
const ebookLibraryFile = req.libraryItem.libraryFiles.find((lf) => lf.ino === req.params.fileid)
@ -826,16 +893,16 @@ class LibraryItemController {
/**
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {import('express').NextFunction} next
* @param {RequestWithUser} req
* @param {Response} res
* @param {NextFunction} next
*/
async middleware(req, res, next) {
req.libraryItem = await Database.libraryItemModel.getOldById(req.params.id)
if (!req.libraryItem?.media) return res.sendStatus(404)
// Check user can access this library item
if (!req.userNew.checkCanAccessLibraryItem(req.libraryItem)) {
if (!req.user.checkCanAccessLibraryItem(req.libraryItem)) {
return res.sendStatus(403)
}
@ -850,11 +917,11 @@ class LibraryItemController {
if (req.path.includes('/play')) {
// allow POST requests using /play and /play/:episodeId
} else if (req.method == 'DELETE' && !req.userNew.canDelete) {
Logger.warn(`[LibraryItemController] User "${req.userNew.username}" attempted to delete without permission`)
} else if (req.method == 'DELETE' && !req.user.canDelete) {
Logger.warn(`[LibraryItemController] User "${req.user.username}" attempted to delete without permission`)
return res.sendStatus(403)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.userNew.canUpdate) {
Logger.warn(`[LibraryItemController] User "${req.userNew.username}" attempted to update without permission`)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
Logger.warn(`[LibraryItemController] User "${req.user.username}" attempted to update without permission`)
return res.sendStatus(403)
}

View File

@ -8,8 +8,7 @@ const userStats = require('../utils/queries/userStats')
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*/
@ -24,7 +23,7 @@ class MeController {
* @param {Response} res
*/
getCurrentUser(req, res) {
res.json(req.userNew.toOldJSONForBrowser())
res.json(req.user.toOldJSONForBrowser())
}
/**
@ -36,7 +35,7 @@ class MeController {
* @param {Response} res
*/
async getListeningSessions(req, res) {
const listeningSessions = await this.getUserListeningSessionsHelper(req.userNew.id)
const listeningSessions = await this.getUserListeningSessionsHelper(req.user.id)
const itemsPerPage = toNumber(req.query.itemsPerPage, 10) || 10
const page = toNumber(req.query.page, 0)
@ -73,7 +72,7 @@ class MeController {
}
const mediaItemId = episode?.id || libraryItem.mediaId
let listeningSessions = await this.getUserItemListeningSessionsHelper(req.userNew.id, mediaItemId)
let listeningSessions = await this.getUserItemListeningSessionsHelper(req.user.id, mediaItemId)
const itemsPerPage = toNumber(req.query.itemsPerPage, 10) || 10
const page = toNumber(req.query.page, 0)
@ -101,7 +100,7 @@ class MeController {
* @param {Response} res
*/
async getListeningStats(req, res) {
const listeningStats = await this.getUserListeningStatsHelpers(req.userNew.id)
const listeningStats = await this.getUserListeningStatsHelpers(req.user.id)
res.json(listeningStats)
}
@ -112,7 +111,7 @@ class MeController {
* @param {Response} res
*/
async getMediaProgress(req, res) {
const mediaProgress = req.userNew.getOldMediaProgress(req.params.id, req.params.episodeId || null)
const mediaProgress = req.user.getOldMediaProgress(req.params.id, req.params.episodeId || null)
if (!mediaProgress) {
return res.sendStatus(404)
}
@ -127,9 +126,9 @@ class MeController {
*/
async removeMediaProgress(req, res) {
await Database.mediaProgressModel.removeById(req.params.id)
req.userNew.mediaProgresses = req.userNew.mediaProgresses.filter((mp) => mp.id !== req.params.id)
req.user.mediaProgresses = req.user.mediaProgresses.filter((mp) => mp.id !== req.params.id)
SocketAuthority.clientEmitter(req.userNew.id, 'user_updated', req.userNew.toOldJSONForBrowser())
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toOldJSONForBrowser())
res.sendStatus(200)
}
@ -146,12 +145,12 @@ class MeController {
libraryItemId: req.params.libraryItemId,
episodeId: req.params.episodeId
}
const mediaProgressResponse = await req.userNew.createUpdateMediaProgressFromPayload(progressUpdatePayload)
const mediaProgressResponse = await req.user.createUpdateMediaProgressFromPayload(progressUpdatePayload)
if (mediaProgressResponse.error) {
return res.status(mediaProgressResponse.statusCode || 400).send(mediaProgressResponse.error)
}
SocketAuthority.clientEmitter(req.userNew.id, 'user_updated', req.userNew.toOldJSONForBrowser())
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toOldJSONForBrowser())
res.sendStatus(200)
}
@ -170,7 +169,7 @@ class MeController {
let hasUpdated = false
for (const itemProgress of itemProgressPayloads) {
const mediaProgressResponse = await req.userNew.createUpdateMediaProgressFromPayload(itemProgress)
const mediaProgressResponse = await req.user.createUpdateMediaProgressFromPayload(itemProgress)
if (mediaProgressResponse.error) {
Logger.error(`[MeController] batchUpdateMediaProgress: ${mediaProgressResponse.error}`)
continue
@ -180,7 +179,7 @@ class MeController {
}
if (hasUpdated) {
SocketAuthority.clientEmitter(req.userNew.id, 'user_updated', req.userNew.toOldJSONForBrowser())
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toOldJSONForBrowser())
}
res.sendStatus(200)
@ -205,8 +204,8 @@ class MeController {
return res.status(400).send('Invalid title')
}
const bookmark = await req.userNew.createBookmark(req.params.id, time, title)
SocketAuthority.clientEmitter(req.userNew.id, 'user_updated', req.userNew.toOldJSONForBrowser())
const bookmark = await req.user.createBookmark(req.params.id, time, title)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toOldJSONForBrowser())
res.json(bookmark)
}
@ -229,13 +228,13 @@ class MeController {
return res.status(400).send('Invalid title')
}
const bookmark = await req.userNew.updateBookmark(req.params.id, time, title)
const bookmark = await req.user.updateBookmark(req.params.id, time, title)
if (!bookmark) {
Logger.error(`[MeController] updateBookmark not found for library item id "${req.params.id}" and time "${time}"`)
return res.sendStatus(404)
}
SocketAuthority.clientEmitter(req.userNew.id, 'user_updated', req.userNew.toOldJSONForBrowser())
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toOldJSONForBrowser())
res.json(bookmark)
}
@ -253,14 +252,14 @@ class MeController {
return res.status(400).send('Invalid time')
}
if (!req.userNew.findBookmark(req.params.id, time)) {
if (!req.user.findBookmark(req.params.id, time)) {
Logger.error(`[MeController] removeBookmark not found`)
return res.sendStatus(404)
}
await req.userNew.removeBookmark(req.params.id, time)
await req.user.removeBookmark(req.params.id, time)
SocketAuthority.clientEmitter(req.userNew.id, 'user_updated', req.userNew.toOldJSONForBrowser())
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toOldJSONForBrowser())
res.sendStatus(200)
}
@ -275,8 +274,8 @@ class MeController {
* @param {Response} res
*/
updatePassword(req, res) {
if (req.userNew.isGuest) {
Logger.error(`[MeController] Guest user "${req.userNew.username}" attempted to change password`)
if (req.user.isGuest) {
Logger.error(`[MeController] Guest user "${req.user.username}" attempted to change password`)
return res.sendStatus(500)
}
this.auth.userChangePassword(req, res)
@ -294,7 +293,7 @@ class MeController {
async getAllLibraryItemsInProgress(req, res) {
const limit = !isNaN(req.query.limit) ? Number(req.query.limit) || 25 : 25
const mediaProgressesInProgress = req.userNew.mediaProgresses.filter((mp) => !mp.isFinished && (mp.currentTime > 0 || mp.ebookProgress > 0))
const mediaProgressesInProgress = req.user.mediaProgresses.filter((mp) => !mp.isFinished && (mp.currentTime > 0 || mp.ebookProgress > 0))
const libraryItemsIds = [...new Set(mediaProgressesInProgress.map((mp) => mp.extraData?.libraryItemId).filter((id) => id))]
const libraryItems = await Database.libraryItemModel.getAllOldLibraryItems({ id: libraryItemsIds })
@ -344,11 +343,11 @@ class MeController {
return res.sendStatus(404)
}
const hasUpdated = await req.userNew.addSeriesToHideFromContinueListening(req.params.id)
const hasUpdated = await req.user.addSeriesToHideFromContinueListening(req.params.id)
if (hasUpdated) {
SocketAuthority.clientEmitter(req.userNew.id, 'user_updated', req.userNew.toOldJSONForBrowser())
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toOldJSONForBrowser())
}
res.json(req.userNew.toOldJSONForBrowser())
res.json(req.user.toOldJSONForBrowser())
}
/**
@ -363,11 +362,11 @@ class MeController {
return res.sendStatus(404)
}
const hasUpdated = await req.userNew.removeSeriesFromHideFromContinueListening(req.params.id)
const hasUpdated = await req.user.removeSeriesFromHideFromContinueListening(req.params.id)
if (hasUpdated) {
SocketAuthority.clientEmitter(req.userNew.id, 'user_updated', req.userNew.toOldJSONForBrowser())
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toOldJSONForBrowser())
}
res.json(req.userNew.toOldJSONForBrowser())
res.json(req.user.toOldJSONForBrowser())
}
/**
@ -377,22 +376,22 @@ class MeController {
* @param {Response} res
*/
async removeItemFromContinueListening(req, res) {
const mediaProgress = req.userNew.mediaProgresses.find((mp) => mp.id === req.params.id)
const mediaProgress = req.user.mediaProgresses.find((mp) => mp.id === req.params.id)
if (!mediaProgress) {
return res.sendStatus(404)
}
// Already hidden
if (mediaProgress.hideFromContinueListening) {
return res.json(req.userNew.toOldJSONForBrowser())
return res.json(req.user.toOldJSONForBrowser())
}
mediaProgress.hideFromContinueListening = true
await mediaProgress.save()
SocketAuthority.clientEmitter(req.userNew.id, 'user_updated', req.userNew.toOldJSONForBrowser())
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toOldJSONForBrowser())
res.json(req.userNew.toOldJSONForBrowser())
res.json(req.user.toOldJSONForBrowser())
}
/**
@ -407,7 +406,7 @@ class MeController {
Logger.error(`[MeController] Invalid year "${year}"`)
return res.status(400).send('Invalid year')
}
const data = await userStats.getStatsForYear(req.userNew.id, year)
const data = await userStats.getStatsForYear(req.user.id, year)
res.json(data)
}
}

View File

@ -16,8 +16,7 @@ const adminStats = require('../utils/queries/adminStats')
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*/
@ -33,8 +32,8 @@ class MiscController {
* @param {Response} res
*/
async handleUpload(req, res) {
if (!req.userNew.canUpload) {
Logger.warn(`User "${req.userNew.username}" attempted to upload without permission`)
if (!req.user.canUpload) {
Logger.warn(`User "${req.user.username}" attempted to upload without permission`)
return res.sendStatus(403)
}
if (!req.files) {
@ -118,8 +117,8 @@ class MiscController {
* @param {Response} res
*/
async updateServerSettings(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`User "${req.userNew.username}" other than admin attempting to update server settings`)
if (!req.user.isAdminOrUp) {
Logger.error(`User "${req.user.username}" other than admin attempting to update server settings`)
return res.sendStatus(403)
}
const settingsUpdate = req.body
@ -149,8 +148,8 @@ class MiscController {
* @param {Response} res
*/
async updateSortingPrefixes(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`User "${req.userNew.username}" other than admin attempting to update server sorting prefixes`)
if (!req.user.isAdminOrUp) {
Logger.error(`User "${req.user.username}" other than admin attempting to update server sorting prefixes`)
return res.sendStatus(403)
}
let sortingPrefixes = req.body.sortingPrefixes
@ -249,7 +248,7 @@ class MiscController {
* @param {Response} res
*/
async authorize(req, res) {
const userResponse = await this.auth.getUserLoginResponsePayload(req.userNew)
const userResponse = await this.auth.getUserLoginResponsePayload(req.user)
res.json(userResponse)
}
@ -261,8 +260,8 @@ class MiscController {
* @param {Response} res
*/
async getAllTags(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.userNew.username}" attempted to getAllTags`)
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.user.username}" attempted to getAllTags`)
return res.sendStatus(403)
}
@ -305,8 +304,8 @@ class MiscController {
* @param {Response} res
*/
async renameTag(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.userNew.username}" attempted to renameTag`)
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.user.username}" attempted to renameTag`)
return res.sendStatus(403)
}
@ -360,8 +359,8 @@ class MiscController {
* @param {Response} res
*/
async deleteTag(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.userNew.username}" attempted to deleteTag`)
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.user.username}" attempted to deleteTag`)
return res.sendStatus(403)
}
@ -400,8 +399,8 @@ class MiscController {
* @param {Response} res
*/
async getAllGenres(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.userNew.username}" attempted to getAllGenres`)
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.user.username}" attempted to getAllGenres`)
return res.sendStatus(403)
}
const genres = []
@ -443,8 +442,8 @@ class MiscController {
* @param {Response} res
*/
async renameGenre(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.userNew.username}" attempted to renameGenre`)
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.user.username}" attempted to renameGenre`)
return res.sendStatus(403)
}
@ -498,8 +497,8 @@ class MiscController {
* @param {Response} res
*/
async deleteGenre(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.userNew.username}" attempted to deleteGenre`)
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.user.username}" attempted to deleteGenre`)
return res.sendStatus(403)
}
@ -543,8 +542,8 @@ class MiscController {
* @param {Response} res
*/
updateWatchedPath(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.userNew.username}" attempted to updateWatchedPath`)
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.user.username}" attempted to updateWatchedPath`)
return res.sendStatus(403)
}
@ -601,8 +600,8 @@ class MiscController {
* @param {Response} res
*/
getAuthSettings(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.userNew.username}" attempted to get auth settings`)
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.user.username}" attempted to get auth settings`)
return res.sendStatus(403)
}
return res.json(Database.serverSettings.authenticationSettings)
@ -616,8 +615,8 @@ class MiscController {
* @param {Response} res
*/
async updateAuthSettings(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.userNew.username}" attempted to update auth settings`)
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.user.username}" attempted to update auth settings`)
return res.sendStatus(403)
}
@ -721,8 +720,8 @@ class MiscController {
* @param {Response} res
*/
async getAdminStatsForYear(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.userNew.username}" attempted to get admin stats for year`)
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.user.username}" attempted to get admin stats for year`)
return res.sendStatus(403)
}
const year = Number(req.params.year)
@ -742,8 +741,8 @@ class MiscController {
* @param {Response} res
*/
async getLoggerData(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.userNew.username}" attempted to get logger data`)
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user "${req.user.username}" attempted to get logger data`)
return res.sendStatus(403)
}

View File

@ -4,8 +4,7 @@ const { version } = require('../../package.json')
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*/
@ -135,7 +134,7 @@ class NotificationController {
* @param {NextFunction} next
*/
middleware(req, res, next) {
if (!req.userNew.isAdminOrUp) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(403)
}

View File

@ -7,8 +7,7 @@ const Playlist = require('../objects/Playlist')
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*/
@ -25,7 +24,7 @@ class PlaylistController {
*/
async create(req, res) {
const oldPlaylist = new Playlist()
req.body.userId = req.userNew.id
req.body.userId = req.user.id
const success = oldPlaylist.setData(req.body)
if (!success) {
return res.status(400).send('Invalid playlist request data')
@ -75,7 +74,7 @@ class PlaylistController {
async findAllForUser(req, res) {
const playlistsForUser = await Database.playlistModel.findAll({
where: {
userId: req.userNew.id
userId: req.user.id
}
})
const playlists = []
@ -415,7 +414,7 @@ class PlaylistController {
return res.status(404).send('Collection not found')
}
// Expand collection to get library items
const collectionExpanded = await collection.getOldJsonExpanded(req.userNew)
const collectionExpanded = await collection.getOldJsonExpanded(req.user)
if (!collectionExpanded) {
// This can happen if the user has no access to all items in collection
return res.status(404).send('Collection not found')
@ -428,7 +427,7 @@ class PlaylistController {
const oldPlaylist = new Playlist()
oldPlaylist.setData({
userId: req.userNew.id,
userId: req.user.id,
libraryId: collection.libraryId,
name: collection.name,
description: collection.description || null
@ -467,8 +466,8 @@ class PlaylistController {
if (!playlist) {
return res.status(404).send('Playlist not found')
}
if (playlist.userId !== req.userNew.id) {
Logger.warn(`[PlaylistController] Playlist ${req.params.id} requested by user ${req.userNew.id} that is not the owner`)
if (playlist.userId !== req.user.id) {
Logger.warn(`[PlaylistController] Playlist ${req.params.id} requested by user ${req.user.id} that is not the owner`)
return res.sendStatus(403)
}
req.playlist = playlist

View File

@ -16,8 +16,7 @@ const LibraryItem = require('../objects/LibraryItem')
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*/
@ -33,8 +32,8 @@ class PodcastController {
* @param {Response} res
*/
async create(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.userNew.username}" attempted to create podcast`)
if (!req.user.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.user.username}" attempted to create podcast`)
return res.sendStatus(403)
}
const payload = req.body
@ -134,8 +133,8 @@ class PodcastController {
* @param {Response} res
*/
async getPodcastFeed(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.userNew.username}" attempted to get podcast feed`)
if (!req.user.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.user.username}" attempted to get podcast feed`)
return res.sendStatus(403)
}
@ -160,8 +159,8 @@ class PodcastController {
* @param {Response} res
*/
async getFeedsFromOPMLText(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.userNew.username}" attempted to get feeds from opml`)
if (!req.user.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.user.username}" attempted to get feeds from opml`)
return res.sendStatus(403)
}
@ -183,8 +182,8 @@ class PodcastController {
* @param {Response} res
*/
async bulkCreatePodcastsFromOpmlFeedUrls(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.userNew.username}" attempted to bulk create podcasts`)
if (!req.user.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.user.username}" attempted to bulk create podcasts`)
return res.sendStatus(403)
}
@ -218,8 +217,8 @@ class PodcastController {
* @param {Response} res
*/
async checkNewEpisodes(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.userNew.username}" attempted to check/download episodes`)
if (!req.user.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.user.username}" attempted to check/download episodes`)
return res.sendStatus(403)
}
@ -246,8 +245,8 @@ class PodcastController {
* @param {Response} res
*/
clearEpisodeDownloadQueue(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.userNew.username}" attempting to clear download queue`)
if (!req.user.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.user.username}" attempting to clear download queue`)
return res.sendStatus(403)
}
this.podcastManager.clearDownloadQueue(req.params.id)
@ -297,8 +296,8 @@ class PodcastController {
* @param {Response} res
*/
async downloadEpisodes(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.userNew.username}" attempted to download episodes`)
if (!req.user.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.user.username}" attempted to download episodes`)
return res.sendStatus(403)
}
const libraryItem = req.libraryItem
@ -320,8 +319,8 @@ class PodcastController {
* @param {Response} res
*/
async quickMatchEpisodes(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.userNew.username}" attempted to download episodes`)
if (!req.user.isAdminOrUp) {
Logger.error(`[PodcastController] Non-admin user "${req.user.username}" attempted to download episodes`)
return res.sendStatus(403)
}
@ -469,15 +468,15 @@ class PodcastController {
}
// Check user can access this library item
if (!req.userNew.checkCanAccessLibraryItem(item)) {
if (!req.user.checkCanAccessLibraryItem(item)) {
return res.sendStatus(403)
}
if (req.method == 'DELETE' && !req.userNew.canDelete) {
Logger.warn(`[PodcastController] User "${req.userNew.username}" attempted to delete without permission`)
if (req.method == 'DELETE' && !req.user.canDelete) {
Logger.warn(`[PodcastController] User "${req.user.username}" attempted to delete without permission`)
return res.sendStatus(403)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.userNew.canUpdate) {
Logger.warn(`[PodcastController] User "${req.userNew.username}" attempted to update without permission`)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
Logger.warn(`[PodcastController] User "${req.user.username}" attempted to update without permission`)
return res.sendStatus(403)
}

View File

@ -5,8 +5,7 @@ const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilter
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*/
@ -45,8 +44,8 @@ class RSSFeedController {
if (!item) return res.sendStatus(404)
// Check user can access this library item
if (!req.userNew.checkCanAccessLibraryItem(item)) {
Logger.error(`[RSSFeedController] User "${req.userNew.username}" attempted to open an RSS feed for item "${item.media.metadata.title}" that they don\'t have access to`)
if (!req.user.checkCanAccessLibraryItem(item)) {
Logger.error(`[RSSFeedController] User "${req.user.username}" attempted to open an RSS feed for item "${item.media.metadata.title}" that they don\'t have access to`)
return res.sendStatus(403)
}
@ -68,7 +67,7 @@ class RSSFeedController {
return res.status(400).send('Slug already in use')
}
const feed = await this.rssFeedManager.openFeedForItem(req.userNew.id, item, req.body)
const feed = await this.rssFeedManager.openFeedForItem(req.user.id, item, req.body)
res.json({
feed: feed.toJSONMinified()
})
@ -109,7 +108,7 @@ class RSSFeedController {
return res.status(400).send('Collection has no audio tracks')
}
const feed = await this.rssFeedManager.openFeedForCollection(req.userNew.id, collectionExpanded, req.body)
const feed = await this.rssFeedManager.openFeedForCollection(req.user.id, collectionExpanded, req.body)
res.json({
feed: feed.toJSONMinified()
})
@ -152,7 +151,7 @@ class RSSFeedController {
return res.status(400).send('Series has no audio tracks')
}
const feed = await this.rssFeedManager.openFeedForSeries(req.userNew.id, seriesJson, req.body)
const feed = await this.rssFeedManager.openFeedForSeries(req.user.id, seriesJson, req.body)
res.json({
feed: feed.toJSONMinified()
})
@ -177,9 +176,9 @@ class RSSFeedController {
* @param {NextFunction} next
*/
middleware(req, res, next) {
if (!req.userNew.isAdminOrUp) {
if (!req.user.isAdminOrUp) {
// Only admins can manage rss feeds
Logger.error(`[RSSFeedController] Non-admin user "${req.userNew.username}" attempted to make a request to an RSS feed route`)
Logger.error(`[RSSFeedController] Non-admin user "${req.user.username}" attempted to make a request to an RSS feed route`)
return res.sendStatus(403)
}

View File

@ -9,8 +9,7 @@ const { isValidASIN } = require('../utils')
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*/

View File

@ -6,8 +6,7 @@ const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilter
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*/
@ -37,7 +36,7 @@ class SeriesController {
if (include.includes('progress')) {
const libraryItemsInSeries = req.libraryItemsInSeries
const libraryItemsFinished = libraryItemsInSeries.filter((li) => {
return req.userNew.getMediaProgress(li.media.id)?.isFinished
return req.user.getMediaProgress(li.media.id)?.isFinished
})
seriesJson.progress = {
libraryItemIds: libraryItemsInSeries.map((li) => li.id),
@ -81,17 +80,17 @@ class SeriesController {
/**
* Filter out any library items not accessible to user
*/
const libraryItems = await libraryItemsBookFilters.getLibraryItemsForSeries(series, req.userNew)
const libraryItems = await libraryItemsBookFilters.getLibraryItemsForSeries(series, req.user)
if (!libraryItems.length) {
Logger.warn(`[SeriesController] User "${req.userNew.username}" attempted to access series "${series.id}" with no accessible books`)
Logger.warn(`[SeriesController] User "${req.user.username}" attempted to access series "${series.id}" with no accessible books`)
return res.sendStatus(404)
}
if (req.method == 'DELETE' && !req.userNew.canDelete) {
Logger.warn(`[SeriesController] User "${req.userNew.username}" attempted to delete without permission`)
if (req.method == 'DELETE' && !req.user.canDelete) {
Logger.warn(`[SeriesController] User "${req.user.username}" attempted to delete without permission`)
return res.sendStatus(403)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.userNew.canUpdate) {
Logger.warn(`[SeriesController] User "${req.userNew.username}" attempted to update without permission`)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
Logger.warn(`[SeriesController] User "${req.user.username}" attempted to update without permission`)
return res.sendStatus(403)
}

View File

@ -7,8 +7,7 @@ const ShareManager = require('../managers/ShareManager')
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*/
@ -25,8 +24,8 @@ class SessionController {
* @param {Response} res
*/
async getAllWithUserData(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[SessionController] getAllWithUserData: Non-admin user "${req.userNew.username}" requested all session data`)
if (!req.user.isAdminOrUp) {
Logger.error(`[SessionController] getAllWithUserData: Non-admin user "${req.user.username}" requested all session data`)
return res.sendStatus(404)
}
// Validate "user" query
@ -120,8 +119,8 @@ class SessionController {
* @param {Response} res
*/
async getOpenSessions(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[SessionController] getOpenSessions: Non-admin user "${req.userNew.username}" requested open session data`)
if (!req.user.isAdminOrUp) {
Logger.error(`[SessionController] getOpenSessions: Non-admin user "${req.user.username}" requested open session data`)
return res.sendStatus(404)
}
@ -164,7 +163,7 @@ class SessionController {
* @param {Response} res
*/
sync(req, res) {
this.playbackSessionManager.syncSessionRequest(req.userNew, req.playbackSession, req.body, res)
this.playbackSessionManager.syncSessionRequest(req.user, req.playbackSession, req.body, res)
}
/**
@ -178,7 +177,7 @@ class SessionController {
close(req, res) {
let syncData = req.body
if (syncData && !Object.keys(syncData).length) syncData = null
this.playbackSessionManager.closeSessionRequest(req.userNew, req.playbackSession, syncData, res)
this.playbackSessionManager.closeSessionRequest(req.user, req.playbackSession, syncData, res)
}
/**
@ -211,8 +210,8 @@ class SessionController {
* @param {Response} res
*/
async batchDelete(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[SessionController] Non-admin user "${req.userNew.username}" attempted to batch delete sessions`)
if (!req.user.isAdminOrUp) {
Logger.error(`[SessionController] Non-admin user "${req.user.username}" attempted to batch delete sessions`)
return res.sendStatus(403)
}
// Validate session ids
@ -235,7 +234,7 @@ class SessionController {
id: req.body.sessions
}
})
Logger.info(`[SessionController] ${sessionsRemoved} playback sessions removed by "${req.userNew.username}"`)
Logger.info(`[SessionController] ${sessionsRemoved} playback sessions removed by "${req.user.username}"`)
res.sendStatus(200)
} catch (error) {
Logger.error(`[SessionController] Failed to remove playback sessions`, error)
@ -277,8 +276,8 @@ class SessionController {
var playbackSession = this.playbackSessionManager.getSession(req.params.id)
if (!playbackSession) return res.sendStatus(404)
if (playbackSession.userId !== req.userNew.id) {
Logger.error(`[SessionController] User "${req.userNew.username}" attempting to access session belonging to another user "${req.params.id}"`)
if (playbackSession.userId !== req.user.id) {
Logger.error(`[SessionController] User "${req.user.username}" attempting to access session belonging to another user "${req.params.id}"`)
return res.sendStatus(404)
}
@ -299,11 +298,11 @@ class SessionController {
return res.sendStatus(404)
}
if (req.method == 'DELETE' && !req.userNew.canDelete) {
Logger.warn(`[SessionController] User "${req.userNew.username}" attempted to delete without permission`)
if (req.method == 'DELETE' && !req.user.canDelete) {
Logger.warn(`[SessionController] User "${req.user.username}" attempted to delete without permission`)
return res.sendStatus(403)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.userNew.canUpdate) {
Logger.warn(`[SessionController] User "${req.userNew.username}" attempted to update without permission`)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
Logger.warn(`[SessionController] User "${req.user.username}" attempted to update without permission`)
return res.sendStatus(403)
}

View File

@ -13,8 +13,7 @@ const ShareManager = require('../managers/ShareManager')
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*/
@ -255,8 +254,8 @@ class ShareController {
* @param {Response} res
*/
async createMediaItemShare(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[ShareController] Non-admin user "${req.userNew.username}" attempted to create item share`)
if (!req.user.isAdminOrUp) {
Logger.error(`[ShareController] Non-admin user "${req.user.username}" attempted to create item share`)
return res.sendStatus(403)
}
@ -299,7 +298,7 @@ class ShareController {
expiresAt: expiresAt || null,
mediaItemId,
mediaItemType,
userId: req.userNew.id
userId: req.user.id
})
ShareManager.openMediaItemShare(mediaItemShare)
@ -319,8 +318,8 @@ class ShareController {
* @param {Response} res
*/
async deleteMediaItemShare(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[ShareController] Non-admin user "${req.userNew.username}" attempted to delete item share`)
if (!req.user.isAdminOrUp) {
Logger.error(`[ShareController] Non-admin user "${req.user.username}" attempted to delete item share`)
return res.sendStatus(403)
}

View File

@ -4,8 +4,7 @@ const Database = require('../Database')
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*/
@ -39,7 +38,7 @@ class ToolsController {
}
const options = req.query || {}
this.abMergeManager.startAudiobookMerge(req.userNew.id, req.libraryItem, options)
this.abMergeManager.startAudiobookMerge(req.user.id, req.libraryItem, options)
res.sendStatus(200)
}
@ -86,7 +85,7 @@ class ToolsController {
forceEmbedChapters: req.query.forceEmbedChapters === '1',
backup: req.query.backup === '1'
}
this.audioMetadataManager.updateMetadataForItem(req.userNew.id, req.libraryItem, options)
this.audioMetadataManager.updateMetadataForItem(req.user.id, req.libraryItem, options)
res.sendStatus(200)
}
@ -114,8 +113,8 @@ class ToolsController {
}
// Check user can access this library item
if (!req.userNew.checkCanAccessLibraryItem(libraryItem)) {
Logger.error(`[ToolsController] Batch embed metadata library item (${libraryItemId}) not accessible to user "${req.userNew.username}"`)
if (!req.user.checkCanAccessLibraryItem(libraryItem)) {
Logger.error(`[ToolsController] Batch embed metadata library item (${libraryItemId}) not accessible to user "${req.user.username}"`)
return res.sendStatus(403)
}
@ -136,7 +135,7 @@ class ToolsController {
forceEmbedChapters: req.query.forceEmbedChapters === '1',
backup: req.query.backup === '1'
}
this.audioMetadataManager.handleBatchEmbed(req.userNew.id, libraryItems, options)
this.audioMetadataManager.handleBatchEmbed(req.user.id, libraryItems, options)
res.sendStatus(200)
}
@ -147,8 +146,8 @@ class ToolsController {
* @param {NextFunction} next
*/
async middleware(req, res, next) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`[LibraryItemController] Non-root user "${req.userNew.username}" attempted to access tools route`)
if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryItemController] Non-root user "${req.user.username}" attempted to access tools route`)
return res.sendStatus(403)
}
@ -157,7 +156,7 @@ class ToolsController {
if (!item?.media) return res.sendStatus(404)
// Check user can access this library item
if (!req.userNew.checkCanAccessLibraryItem(item)) {
if (!req.user.checkCanAccessLibraryItem(item)) {
return res.sendStatus(403)
}

View File

@ -10,14 +10,12 @@ const { toNumber } = require('../utils/index')
/**
* @typedef RequestUserObjects
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
*
* @typedef UserControllerRequestProps
* @property {import('../models/User')} userNew
* @property {import('../objects/user/User')} user - User that made the request
* @property {import('../models/User')} user - User that made the request
* @property {import('../objects/user/User')} [reqUser] - User for req param id
*
* @typedef {Request & UserControllerRequestProps} UserControllerRequest
@ -32,8 +30,8 @@ class UserController {
* @param {Response} res
*/
async findAll(req, res) {
if (!req.userNew.isAdminOrUp) return res.sendStatus(403)
const hideRootToken = !req.userNew.isRoot
if (!req.user.isAdminOrUp) return res.sendStatus(403)
const hideRootToken = !req.user.isRoot
const includes = (req.query.include || '').split(',').map((i) => i.trim())
@ -62,8 +60,8 @@ class UserController {
* @param {Response} res
*/
async findOne(req, res) {
if (!req.userNew.isAdminOrUp) {
Logger.error(`Non-admin user "${req.userNew.username}" attempted to get user`)
if (!req.user.isAdminOrUp) {
Logger.error(`Non-admin user "${req.user.username}" attempted to get user`)
return res.sendStatus(403)
}
@ -102,7 +100,7 @@ class UserController {
return oldMediaProgress
})
const userJson = req.reqUser.toJSONForBrowser(!req.userNew.isRoot)
const userJson = req.reqUser.toJSONForBrowser(!req.user.isRoot)
userJson.mediaProgress = oldMediaProgresses
@ -155,8 +153,8 @@ class UserController {
async update(req, res) {
const user = req.reqUser
if (user.type === 'root' && !req.userNew.isRoot) {
Logger.error(`[UserController] Admin user "${req.userNew.username}" attempted to update root user`)
if (user.type === 'root' && !req.user.isRoot) {
Logger.error(`[UserController] Admin user "${req.user.username}" attempted to update root user`)
return res.sendStatus(403)
}
@ -184,7 +182,7 @@ class UserController {
Logger.info(`[UserController] User ${user.username} was generated a new api token`)
}
await Database.updateUser(user)
SocketAuthority.clientEmitter(req.userNew.id, 'user_updated', user.toJSONForBrowser())
SocketAuthority.clientEmitter(req.user.id, 'user_updated', user.toJSONForBrowser())
}
res.json({
@ -205,8 +203,8 @@ class UserController {
Logger.error('[UserController] Attempt to delete root user. Root user cannot be deleted')
return res.sendStatus(400)
}
if (req.userNew.id === req.params.id) {
Logger.error(`[UserController] User ${req.userNew.username} is attempting to delete self`)
if (req.user.id === req.params.id) {
Logger.error(`[UserController] User ${req.user.username} is attempting to delete self`)
return res.sendStatus(400)
}
const user = req.reqUser
@ -241,7 +239,7 @@ class UserController {
Logger.debug(`[UserController] Unlinking user "${req.reqUser.username}" from OpenID with sub "${req.reqUser.authOpenIDSub}"`)
req.reqUser.authOpenIDSub = null
if (await Database.userModel.updateFromOld(req.reqUser)) {
SocketAuthority.clientEmitter(req.userNew.id, 'user_updated', req.reqUser.toJSONForBrowser())
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.reqUser.toJSONForBrowser())
res.sendStatus(200)
} else {
res.sendStatus(500)
@ -296,7 +294,7 @@ class UserController {
* @param {Response} res
*/
async getOnlineUsers(req, res) {
if (!req.userNew.isAdminOrUp) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(403)
}
@ -313,9 +311,9 @@ class UserController {
* @param {NextFunction} next
*/
async middleware(req, res, next) {
if (!req.userNew.isAdminOrUp && req.userNew.id !== req.params.id) {
if (!req.user.isAdminOrUp && req.user.id !== req.params.id) {
return res.sendStatus(403)
} else if ((req.method == 'PATCH' || req.method == 'POST' || req.method == 'DELETE') && !req.userNew.isAdminOrUp) {
} else if ((req.method == 'PATCH' || req.method == 'POST' || req.method == 'DELETE') && !req.user.isAdminOrUp) {
return res.sendStatus(403)
}

View File

@ -42,7 +42,7 @@ class ApiCacheManager {
Logger.debug(`[ApiCacheManager] Skipping cache for random sort`)
return next()
}
const key = { user: req.userNew.username, url: req.url }
const key = { user: req.user.username, url: req.url }
const stringifiedKey = JSON.stringify(key)
Logger.debug(`[ApiCacheManager] count: ${this.cache.size} size: ${this.cache.calculatedSize}`)
const cached = this.cache.get(stringifiedKey)

View File

@ -48,7 +48,7 @@ class PlaybackSessionManager {
const ip = requestIp.getClientIp(req)
const deviceInfo = new DeviceInfo()
deviceInfo.setData(ip, ua, clientDeviceInfo, serverVersion, req.userNew?.id)
deviceInfo.setData(ip, ua, clientDeviceInfo, serverVersion, req.user?.id)
if (clientDeviceInfo?.deviceId) {
const existingDevice = await Database.getDeviceByDeviceId(clientDeviceInfo.deviceId)
@ -75,7 +75,7 @@ class PlaybackSessionManager {
const deviceInfo = await this.getDeviceInfo(req, req.body?.deviceInfo)
Logger.debug(`[PlaybackSessionManager] startSessionRequest for device ${deviceInfo.deviceDescription}`)
const { libraryItem, body: options } = req
const session = await this.startSession(req.userNew, deviceInfo, libraryItem, episodeId, options)
const session = await this.startSession(req.user, deviceInfo, libraryItem, episodeId, options)
res.json(session.toJSONForClient(libraryItem))
}
@ -96,7 +96,7 @@ class PlaybackSessionManager {
async syncLocalSessionsRequest(req, res) {
const deviceInfo = await this.getDeviceInfo(req, req.body?.deviceInfo)
const user = req.userNew
const user = req.user
const sessions = req.body.sessions || []
const syncResults = []
@ -239,7 +239,7 @@ class PlaybackSessionManager {
async syncLocalSessionRequest(req, res) {
const deviceInfo = await this.getDeviceInfo(req, req.body?.deviceInfo)
const sessionJson = req.body
const result = await this.syncLocalSession(req.userNew, sessionJson, deviceInfo)
const result = await this.syncLocalSession(req.user, sessionJson, deviceInfo)
if (result.error) {
res.status(500).send(result.error)
} else {

View File

@ -2,7 +2,6 @@ const uuidv4 = require('uuid').v4
const sequelize = require('sequelize')
const Logger = require('../Logger')
const oldUser = require('../objects/user/User')
const AudioBookmark = require('../objects/user/AudioBookmark')
const SocketAuthority = require('../SocketAuthority')
const { isNullOrNaN } = require('../utils')
@ -52,6 +51,47 @@ class User extends Model {
this.mediaProgresses
}
/**
* List of expected permission properties from the client
* Only used for OpenID
*/
static permissionMapping = {
canDownload: 'download',
canUpload: 'upload',
canDelete: 'delete',
canUpdate: 'update',
canAccessExplicitContent: 'accessExplicitContent',
canAccessAllLibraries: 'accessAllLibraries',
canAccessAllTags: 'accessAllTags',
tagsAreDenylist: 'selectedTagsNotAccessible',
// Direct mapping for array-based permissions
allowedLibraries: 'librariesAccessible',
allowedTags: 'itemTagsSelected'
}
/**
* Get a sample to show how a JSON for updatePermissionsFromExternalJSON should look like
* Only used for OpenID
*
* @returns {string} JSON string
*/
static getSampleAbsPermissions() {
// Start with a template object where all permissions are false for simplicity
const samplePermissions = Object.keys(User.permissionMapping).reduce((acc, key) => {
// For array-based permissions, provide a sample array
if (key === 'allowedLibraries') {
acc[key] = [`5406ba8a-16e1-451d-96d7-4931b0a0d966`, `918fd848-7c1d-4a02-818a-847435a879ca`]
} else if (key === 'allowedTags') {
acc[key] = [`ExampleTag`, `AnotherTag`, `ThirdTag`]
} else {
acc[key] = false
}
return acc
}, {})
return JSON.stringify(samplePermissions, null, 2) // Pretty print the JSON
}
/**
*
* @param {string} type
@ -818,6 +858,69 @@ class User extends Model {
await this.save()
return true
}
/**
* Update user permissions from external JSON
*
* @param {Object} absPermissions JSON containing user permissions
* @returns {Promise<boolean>} true if updates were made
*/
async updatePermissionsFromExternalJSON(absPermissions) {
if (!this.permissions) this.permissions = {}
let hasUpdates = false
// Map the boolean permissions from absPermissions
Object.keys(absPermissions).forEach((absKey) => {
const userPermKey = User.permissionMapping[absKey]
if (!userPermKey) {
throw new Error(`Unexpected permission property: ${absKey}`)
}
if (!['librariesAccessible', 'itemTagsSelected'].includes(userPermKey)) {
if (this.permissions[userPermKey] !== !!absPermissions[absKey]) {
this.permissions[userPermKey] = !!absPermissions[absKey]
hasUpdates = true
}
}
})
// Handle allowedLibraries
const librariesAccessible = this.permissions.librariesAccessible || []
if (this.permissions.accessAllLibraries) {
if (librariesAccessible.length) {
this.permissions.librariesAccessible = []
hasUpdates = true
}
} else if (absPermissions.allowedLibraries?.length && absPermissions.allowedLibraries.join(',') !== librariesAccessible.join(',')) {
if (absPermissions.allowedLibraries.some((lid) => typeof lid !== 'string')) {
throw new Error('Invalid permission property "allowedLibraries", expecting array of strings')
}
this.permissions.librariesAccessible = absPermissions.allowedLibraries
hasUpdates = true
}
// Handle allowedTags
const itemTagsSelected = this.permissions.itemTagsSelected || []
if (this.permissions.accessAllTags) {
if (itemTagsSelected.length) {
this.permissions.itemTagsSelected = []
hasUpdates = true
}
} else if (absPermissions.allowedTags?.length && absPermissions.allowedTags.join(',') !== itemTagsSelected.join(',')) {
if (absPermissions.allowedTags.some((tag) => typeof tag !== 'string')) {
throw new Error('Invalid permission property "allowedTags", expecting array of strings')
}
this.permissions.itemTagsSelected = absPermissions.allowedTags
hasUpdates = true
}
if (hasUpdates) {
this.changed('permissions', true)
await this.save()
}
return hasUpdates
}
}
module.exports = User

View File

@ -2,7 +2,7 @@ const Path = require('path')
const packageJson = require('../../../package.json')
const { BookshelfView } = require('../../utils/constants')
const Logger = require('../../Logger')
const User = require('../user/User')
const User = require('../../models/User')
class ServerSettings {
constructor(settings) {

View File

@ -1,4 +1,3 @@
const Logger = require('../../Logger')
const AudioBookmark = require('./AudioBookmark')
const MediaProgress = require('./MediaProgress')
@ -268,109 +267,5 @@ class User {
}
return hasUpdates
}
// List of expected permission properties from the client
static permissionMapping = {
canDownload: 'download',
canUpload: 'upload',
canDelete: 'delete',
canUpdate: 'update',
canAccessExplicitContent: 'accessExplicitContent',
canAccessAllLibraries: 'accessAllLibraries',
canAccessAllTags: 'accessAllTags',
tagsAreDenylist: 'selectedTagsNotAccessible',
// Direct mapping for array-based permissions
allowedLibraries: 'librariesAccessible',
allowedTags: 'itemTagsSelected'
}
/**
* Update user permissions from external JSON
*
* @param {Object} absPermissions JSON containing user permissions
* @returns {boolean} true if updates were made
*/
updatePermissionsFromExternalJSON(absPermissions) {
let hasUpdates = false
let updatedUserPermissions = {}
// Initialize all permissions to false first
Object.keys(User.permissionMapping).forEach((mappingKey) => {
const userPermKey = User.permissionMapping[mappingKey]
if (typeof this.permissions[userPermKey] === 'boolean') {
updatedUserPermissions[userPermKey] = false // Default to false for boolean permissions
}
})
// Map the boolean permissions from absPermissions
Object.keys(absPermissions).forEach((absKey) => {
const userPermKey = User.permissionMapping[absKey]
if (!userPermKey) {
throw new Error(`Unexpected permission property: ${absKey}`)
}
if (updatedUserPermissions[userPermKey] !== undefined) {
updatedUserPermissions[userPermKey] = !!absPermissions[absKey]
}
})
// Update user permissions if changes were made
if (JSON.stringify(this.permissions) !== JSON.stringify(updatedUserPermissions)) {
this.permissions = updatedUserPermissions
hasUpdates = true
}
// Handle allowedLibraries
if (this.permissions.accessAllLibraries) {
if (this.librariesAccessible.length) {
this.librariesAccessible = []
hasUpdates = true
}
} else if (absPermissions.allowedLibraries?.length && absPermissions.allowedLibraries.join(',') !== this.librariesAccessible.join(',')) {
if (absPermissions.allowedLibraries.some((lid) => typeof lid !== 'string')) {
throw new Error('Invalid permission property "allowedLibraries", expecting array of strings')
}
this.librariesAccessible = absPermissions.allowedLibraries
hasUpdates = true
}
// Handle allowedTags
if (this.permissions.accessAllTags) {
if (this.itemTagsSelected.length) {
this.itemTagsSelected = []
hasUpdates = true
}
} else if (absPermissions.allowedTags?.length && absPermissions.allowedTags.join(',') !== this.itemTagsSelected.join(',')) {
if (absPermissions.allowedTags.some((tag) => typeof tag !== 'string')) {
throw new Error('Invalid permission property "allowedTags", expecting array of strings')
}
this.itemTagsSelected = absPermissions.allowedTags
hasUpdates = true
}
return hasUpdates
}
/**
* Get a sample to show how a JSON for updatePermissionsFromExternalJSON should look like
*
* @returns {string} JSON string
*/
static getSampleAbsPermissions() {
// Start with a template object where all permissions are false for simplicity
const samplePermissions = Object.keys(User.permissionMapping).reduce((acc, key) => {
// For array-based permissions, provide a sample array
if (key === 'allowedLibraries') {
acc[key] = [`5406ba8a-16e1-451d-96d7-4931b0a0d966`, `918fd848-7c1d-4a02-818a-847435a879ca`]
} else if (key === 'allowedTags') {
acc[key] = [`ExampleTag`, `AnotherTag`, `ThirdTag`]
} else {
acc[key] = false
}
return acc
}, {})
return JSON.stringify(samplePermissions, null, 2) // Pretty print the JSON
}
}
module.exports = User

View File

@ -12,7 +12,7 @@ describe('ApiCacheManager', () => {
beforeEach(() => {
cache = { get: sinon.stub(), set: sinon.spy() }
req = { user: { username: 'testUser' }, userNew: { username: 'testUser' }, url: '/test-url', query: {} }
req = { user: { username: 'testUser' }, url: '/test-url', query: {} }
res = { send: sinon.spy(), getHeaders: sinon.stub(), statusCode: 200, status: sinon.spy(), set: sinon.spy() }
next = sinon.spy()
})