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, * 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. * or creates a new user if configured to do so.
*
* @returns {import('./models/User')|null}
*/ */
async findOrCreateUser(userinfo) { async findOrCreateUser(userinfo) {
let user = await Database.userModel.getUserByOpenIDSub(userinfo.sub) let user = await Database.userModel.getUserByOpenIDSub(userinfo.sub)
@ -307,9 +309,8 @@ class Auth {
const absPermissions = userinfo[absPermissionsClaim] const absPermissions = userinfo[absPermissionsClaim]
if (!absPermissions) throw new Error(`Advanced permissions claim ${absPermissionsClaim} not found in userinfo`) 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)}"`) 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) { async userChangePassword(req, res) {
let { password, newPassword } = req.body let { password, newPassword } = req.body
newPassword = newPassword || '' newPassword = newPassword || ''
const matchingUser = req.userNew const matchingUser = req.user
// Only root can have an empty password // Only root can have an empty password
if (matchingUser.type !== 'root' && !newPassword) { if (matchingUser.type !== 'root' && !newPassword) {

View File

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

View File

@ -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.userNew) authorJson.libraryItems = await Database.libraryItemModel.getForAuthor(req.author, req.user)
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.userNew.canUpload) { if (!req.user.canUpload) {
Logger.warn(`User "${req.userNew.username}" attempted to upload an image without permission`) Logger.warn(`User "${req.user.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.userNew.canDelete) { if (req.method == 'DELETE' && !req.user.canDelete) {
Logger.warn(`[AuthorController] User "${req.userNew.username}" attempted to delete without permission`) Logger.warn(`[AuthorController] User "${req.user.username}" attempted to delete without permission`)
return res.sendStatus(403) return res.sendStatus(403)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.userNew.canUpdate) { } else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
Logger.warn(`[AuthorController] User "${req.userNew.username}" attempted to update without permission`) Logger.warn(`[AuthorController] User "${req.user.username}" attempted to update without permission`)
return res.sendStatus(403) return res.sendStatus(403)
} }

View File

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

View File

@ -5,7 +5,7 @@ class CacheController {
// POST: api/cache/purge // POST: api/cache/purge
async purgeCache(req, res) { async purgeCache(req, res) {
if (!req.userNew.isAdminOrUp) { if (!req.user.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.userNew.isAdminOrUp) { if (!req.user.isAdminOrUp) {
return res.sendStatus(403) return res.sendStatus(403)
} }
await CacheManager.purgeItems() await CacheManager.purgeItems()

View File

@ -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.userNew.id req.body.userId = req.user.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')
} }
@ -50,7 +50,7 @@ class CollectionController {
} }
async findAll(req, res) { async findAll(req, res) {
const collectionsExpanded = await Database.collectionModel.getOldCollectionsJsonExpanded(req.userNew) const collectionsExpanded = await Database.collectionModel.getOldCollectionsJsonExpanded(req.user)
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.userNew, includeEntities) const collectionExpanded = await req.collection.getOldJsonExpanded(req.user, 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)
@ -334,11 +334,11 @@ class CollectionController {
req.collection = collection req.collection = collection
} }
if (req.method == 'DELETE' && !req.userNew.canDelete) { if (req.method == 'DELETE' && !req.user.canDelete) {
Logger.warn(`[CollectionController] User "${req.userNew.username}" attempted to delete without permission`) Logger.warn(`[CollectionController] User "${req.user.username}" attempted to delete without permission`)
return res.sendStatus(403) return res.sendStatus(403)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.userNew.canUpdate) { } else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
Logger.warn(`[CollectionController] User "${req.userNew.username}" attempted to update without permission`) Logger.warn(`[CollectionController] User "${req.user.username}" attempted to update without permission`)
return res.sendStatus(403) return res.sendStatus(403)
} }

View File

@ -101,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.userNew.isAdminOrUp) { if (!req.user.isAdminOrUp) {
Logger.warn(`[CustomMetadataProviderController] Non-admin user "${req.userNew.username}" attempted access route "${req.path}"`) Logger.warn(`[CustomMetadataProviderController] Non-admin user "${req.user.username}" attempted access route "${req.path}"`)
return res.sendStatus(403) return res.sendStatus(403)
} }

View File

@ -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.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) 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.userNew)) { if (!Database.emailSettings.checkUserCanAccessDevice(device, req.user)) {
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.userNew.checkCanAccessLibraryItem(libraryItem)) { if (!req.user.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.userNew.isAdminOrUp) { if (!req.user.isAdminOrUp) {
return res.sendStatus(404) return res.sendStatus(404)
} }

View File

@ -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.userNew.isAdminOrUp) { if (!req.user.isAdminOrUp) {
Logger.error(`[FileSystemController] Non-admin user "${req.userNew.username}" attempting to get filesystem paths`) Logger.error(`[FileSystemController] Non-admin user "${req.user.username}" attempting to get filesystem paths`)
return res.sendStatus(403) return res.sendStatus(403)
} }
@ -69,8 +69,8 @@ class FileSystemController {
// POST: api/filesystem/pathexists // POST: api/filesystem/pathexists
async checkPathExists(req, res) { async checkPathExists(req, res) {
if (!req.userNew.canUpload) { if (!req.user.canUpload) {
Logger.error(`[FileSystemController] Non-admin user "${req.userNew.username}" attempting to check path exists`) Logger.error(`[FileSystemController] Non-admin user "${req.user.username}" attempting to check path exists`)
return res.sendStatus(403) return res.sendStatus(403)
} }

View File

@ -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.userNew.permissions?.librariesAccessible || [] const librariesAccessible = req.user.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.userNew.id, req.library.id), numUserPlaylists: await Database.playlistModel.getNumPlaylistsForUserAndLibrary(req.user.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.userNew, req.library) payload.results = await libraryHelpers.handleCollapseSubseries(payload, seriesId, req.user, req.library)
} else { } 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.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.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.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.userNew) const libraryItemsInSeries = await libraryItemsBookFilters.getLibraryItemsForSeries(oldSeries, req.user)
const seriesJson = oldSeries.toJSON() const seriesJson = oldSeries.toJSON()
if (include.includes('progress')) { 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 = { 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.userNew, req.library.id, include) let collections = await Database.collectionModel.getOldCollectionsJsonExpanded(req.user, 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.userNew.id, req.library.id) let playlistsForUser = await Database.playlistModel.getOldPlaylistsForUserAndLibrary(req.user.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.userNew, include, limitPerShelf) const shelves = await Database.libraryItemModel.getPersonalizedShelves(req.library, req.user, 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.userNew.isAdminOrUp) { if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryController] Non-admin user "${req.userNew}" attempted to reorder libraries`) Logger.error(`[LibraryController] Non-admin user "${req.user}" 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.userNew, req.library, query, limit) const matches = await libraryItemFilters.search(req.user, 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.userNew) const { bookWhere, replacements } = libraryItemsBookFilters.getUserPermissionBookWhereQuery(req.user)
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.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: { through: {
attributes: [] attributes: []
} }
@ -746,8 +746,8 @@ class LibraryController {
* @param {*} res * @param {*} res
*/ */
async updateNarrator(req, res) { async updateNarrator(req, res) {
if (!req.userNew.canUpdate) { if (!req.user.canUpdate) {
Logger.error(`[LibraryController] Unauthorized user "${req.userNew.username}" attempted to update narrator`) Logger.error(`[LibraryController] Unauthorized user "${req.user.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.userNew.canUpdate) { if (!req.user.canUpdate) {
Logger.error(`[LibraryController] Unauthorized user "${req.userNew.username}" attempted to remove narrator`) Logger.error(`[LibraryController] Unauthorized user "${req.user.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.userNew.isAdminOrUp) { if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryController] Non-root user "${req.userNew.username}" attempted to match library items`) Logger.error(`[LibraryController] Non-root user "${req.user.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.userNew.isAdminOrUp) { if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryController] Non-admin user "${req.userNew.username}" attempted to scan library`) Logger.error(`[LibraryController] Non-admin user "${req.user.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.userNew, req.library, payload.limit, offset) payload.episodes = await libraryItemsPodcastFilters.getRecentEpisodes(req.user, 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.userNew) const userPermissionPodcastWhere = libraryItemsPodcastFilters.getUserPermissionPodcastWhereQuery(req.user)
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.userNew.isAdminOrUp) { if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryController] Non-admin user "${req.userNew.username}" attempted to remove all metadata files`) Logger.error(`[LibraryController] Non-admin user "${req.user.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.userNew.checkCanAccessLibrary(req.params.id)) { if (!req.user.checkCanAccessLibrary(req.params.id)) {
Logger.warn(`[LibraryController] Library ${req.params.id} not accessible to user ${req.userNew.username}`) Logger.warn(`[LibraryController] Library ${req.params.id} not accessible to user ${req.user.username}`)
return res.sendStatus(403) return res.sendStatus(403)
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,8 +5,7 @@ const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilter
/** /**
* @typedef RequestUserObjects * @typedef RequestUserObjects
* @property {import('../models/User')} userNew * @property {import('../models/User')} user
* @property {import('../objects/user/User')} user
* *
* @typedef {Request & RequestUserObjects} RequestWithUser * @typedef {Request & RequestUserObjects} RequestWithUser
*/ */
@ -45,8 +44,8 @@ class RSSFeedController {
if (!item) return res.sendStatus(404) if (!item) return res.sendStatus(404)
// Check user can access this library item // Check user can access this library item
if (!req.userNew.checkCanAccessLibraryItem(item)) { if (!req.user.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`) 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) return res.sendStatus(403)
} }
@ -68,7 +67,7 @@ class RSSFeedController {
return res.status(400).send('Slug already in use') 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({ res.json({
feed: feed.toJSONMinified() feed: feed.toJSONMinified()
}) })
@ -109,7 +108,7 @@ class RSSFeedController {
return res.status(400).send('Collection has no audio tracks') 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({ res.json({
feed: feed.toJSONMinified() feed: feed.toJSONMinified()
}) })
@ -152,7 +151,7 @@ class RSSFeedController {
return res.status(400).send('Series has no audio tracks') 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({ res.json({
feed: feed.toJSONMinified() feed: feed.toJSONMinified()
}) })
@ -177,9 +176,9 @@ class RSSFeedController {
* @param {NextFunction} next * @param {NextFunction} next
*/ */
middleware(req, res, next) { middleware(req, res, next) {
if (!req.userNew.isAdminOrUp) { if (!req.user.isAdminOrUp) {
// Only admins can manage rss feeds // 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) return res.sendStatus(403)
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -42,7 +42,7 @@ class ApiCacheManager {
Logger.debug(`[ApiCacheManager] Skipping cache for random sort`) Logger.debug(`[ApiCacheManager] Skipping cache for random sort`)
return next() 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) const stringifiedKey = JSON.stringify(key)
Logger.debug(`[ApiCacheManager] count: ${this.cache.size} size: ${this.cache.calculatedSize}`) Logger.debug(`[ApiCacheManager] count: ${this.cache.size} size: ${this.cache.calculatedSize}`)
const cached = this.cache.get(stringifiedKey) const cached = this.cache.get(stringifiedKey)

View File

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

View File

@ -2,7 +2,6 @@ const uuidv4 = require('uuid').v4
const sequelize = require('sequelize') const sequelize = require('sequelize')
const Logger = require('../Logger') const Logger = require('../Logger')
const oldUser = require('../objects/user/User') const oldUser = require('../objects/user/User')
const AudioBookmark = require('../objects/user/AudioBookmark')
const SocketAuthority = require('../SocketAuthority') const SocketAuthority = require('../SocketAuthority')
const { isNullOrNaN } = require('../utils') const { isNullOrNaN } = require('../utils')
@ -52,6 +51,47 @@ class User extends Model {
this.mediaProgresses 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 * @param {string} type
@ -818,6 +858,69 @@ class User extends Model {
await this.save() await this.save()
return true 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 module.exports = User

View File

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

View File

@ -1,4 +1,3 @@
const Logger = require('../../Logger')
const AudioBookmark = require('./AudioBookmark') const AudioBookmark = require('./AudioBookmark')
const MediaProgress = require('./MediaProgress') const MediaProgress = require('./MediaProgress')
@ -268,109 +267,5 @@ class User {
} }
return hasUpdates 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 module.exports = User

View File

@ -12,7 +12,7 @@ describe('ApiCacheManager', () => {
beforeEach(() => { beforeEach(() => {
cache = { get: sinon.stub(), set: sinon.spy() } 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() } res = { send: sinon.spy(), getHeaders: sinon.stub(), statusCode: 200, status: sinon.spy(), set: sinon.spy() }
next = sinon.spy() next = sinon.spy()
}) })