Fix socket events check user permissions for library items #4199

This commit is contained in:
advplyr 2025-04-12 17:39:51 -05:00
parent 26309019e7
commit bc1b99efd6
10 changed files with 69 additions and 61 deletions

View File

@ -84,6 +84,42 @@ class SocketAuthority {
} }
} }
/**
* Emits event with library item to all clients that can access the library item
* Note: Emits toOldJSONExpanded()
*
* @param {string} evt
* @param {import('./models/LibraryItem')} libraryItem
*/
libraryItemEmitter(evt, libraryItem) {
for (const socketId in this.clients) {
if (this.clients[socketId].user?.checkCanAccessLibraryItem(libraryItem)) {
this.clients[socketId].socket.emit(evt, libraryItem.toOldJSONExpanded())
}
}
}
/**
* Emits event with library items to all clients that can access the library items
* Note: Emits toOldJSONExpanded()
*
* @param {string} evt
* @param {import('./models/LibraryItem')[]} libraryItems
*/
libraryItemsEmitter(evt, libraryItems) {
for (const socketId in this.clients) {
if (this.clients[socketId].user) {
const libraryItemsAccessibleToUser = libraryItems.filter((li) => this.clients[socketId].user.checkCanAccessLibraryItem(li))
if (libraryItemsAccessibleToUser.length) {
this.clients[socketId].socket.emit(
evt,
libraryItemsAccessibleToUser.map((li) => li.toOldJSONExpanded())
)
}
}
}
}
/** /**
* Closes the Socket.IO server and disconnect all clients * Closes the Socket.IO server and disconnect all clients
* *

View File

@ -152,10 +152,7 @@ class AuthorController {
for (const libraryItem of libraryItems) { for (const libraryItem of libraryItems) {
await libraryItem.saveMetadataFile() await libraryItem.saveMetadataFile()
} }
SocketAuthority.emitter( SocketAuthority.libraryItemsEmitter('items_updated', libraryItems)
'items_updated',
libraryItems.map((li) => li.toOldJSONExpanded())
)
} }
// Remove old author // Remove old author
@ -210,10 +207,7 @@ class AuthorController {
} }
if (libraryItems.length) { if (libraryItems.length) {
SocketAuthority.emitter( SocketAuthority.libraryItemsEmitter('items_updated', libraryItems)
'items_updated',
libraryItems.map((li) => li.toOldJSONExpanded())
)
} }
} else { } else {
numBooksForAuthor = await Database.bookAuthorModel.getCountForAuthor(req.author.id) numBooksForAuthor = await Database.bookAuthorModel.getCountForAuthor(req.author.id)

View File

@ -1188,10 +1188,7 @@ class LibraryController {
} }
if (itemsUpdated.length) { if (itemsUpdated.length) {
SocketAuthority.emitter( SocketAuthority.libraryItemsEmitter('items_updated', itemsUpdated)
'items_updated',
itemsUpdated.map((li) => li.toOldJSONExpanded())
)
} }
res.json({ res.json({
@ -1232,10 +1229,7 @@ class LibraryController {
} }
if (itemsUpdated.length) { if (itemsUpdated.length) {
SocketAuthority.emitter( SocketAuthority.libraryItemsEmitter('items_updated', itemsUpdated)
'items_updated',
itemsUpdated.map((li) => li.toOldJSONExpanded())
)
} }
res.json({ res.json({

View File

@ -253,7 +253,7 @@ class LibraryItemController {
} }
Logger.debug(`[LibraryItemController] Updated library item media ${req.libraryItem.media.title}`) Logger.debug(`[LibraryItemController] Updated library item media ${req.libraryItem.media.title}`)
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
} }
res.json({ res.json({
updated: hasUpdates, updated: hasUpdates,
@ -300,7 +300,7 @@ class LibraryItemController {
req.libraryItem.changed('updatedAt', true) req.libraryItem.changed('updatedAt', true)
await req.libraryItem.save() await req.libraryItem.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
res.json({ res.json({
success: true, success: true,
cover: result.cover cover: result.cover
@ -332,7 +332,7 @@ class LibraryItemController {
req.libraryItem.changed('updatedAt', true) req.libraryItem.changed('updatedAt', true)
await req.libraryItem.save() await req.libraryItem.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
} }
res.json({ res.json({
success: true, success: true,
@ -358,7 +358,7 @@ class LibraryItemController {
await CacheManager.purgeCoverCache(req.libraryItem.id) await CacheManager.purgeCoverCache(req.libraryItem.id)
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
} }
res.sendStatus(200) res.sendStatus(200)
@ -485,7 +485,7 @@ class LibraryItemController {
req.libraryItem.media.changed('audioFiles', true) req.libraryItem.media.changed('audioFiles', true)
await req.libraryItem.media.save() await req.libraryItem.media.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
res.json(req.libraryItem.toOldJSON()) res.json(req.libraryItem.toOldJSON())
} }
@ -663,7 +663,7 @@ class LibraryItemController {
await libraryItem.saveMetadataFile() await libraryItem.saveMetadataFile()
Logger.debug(`[LibraryItemController] Updated library item media "${libraryItem.media.title}"`) Logger.debug(`[LibraryItemController] Updated library item media "${libraryItem.media.title}"`)
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
itemsUpdated++ itemsUpdated++
} }
} }
@ -894,7 +894,7 @@ class LibraryItemController {
await req.libraryItem.saveMetadataFile() await req.libraryItem.saveMetadataFile()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
} }
res.json({ res.json({
@ -1005,7 +1005,7 @@ class LibraryItemController {
await req.libraryItem.save() await req.libraryItem.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
res.sendStatus(200) res.sendStatus(200)
} }
@ -1153,7 +1153,7 @@ class LibraryItemController {
await req.libraryItem.save() await req.libraryItem.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
res.sendStatus(200) res.sendStatus(200)
} }

View File

@ -343,7 +343,7 @@ class MiscController {
}) })
await libraryItem.saveMetadataFile() await libraryItem.saveMetadataFile()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
numItemsUpdated++ numItemsUpdated++
} }
} }
@ -386,7 +386,7 @@ class MiscController {
}) })
await libraryItem.saveMetadataFile() await libraryItem.saveMetadataFile()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
numItemsUpdated++ numItemsUpdated++
} }
@ -481,7 +481,7 @@ class MiscController {
}) })
await libraryItem.saveMetadataFile() await libraryItem.saveMetadataFile()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
numItemsUpdated++ numItemsUpdated++
} }
} }
@ -524,7 +524,7 @@ class MiscController {
}) })
await libraryItem.saveMetadataFile() await libraryItem.saveMetadataFile()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
numItemsUpdated++ numItemsUpdated++
} }

View File

@ -161,7 +161,7 @@ class PodcastController {
} }
} }
SocketAuthority.emitter('item_added', newLibraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_added', newLibraryItem)
res.json(newLibraryItem.toOldJSONExpanded()) res.json(newLibraryItem.toOldJSONExpanded())
@ -379,7 +379,7 @@ class PodcastController {
const overrideDetails = req.query.override === '1' const overrideDetails = req.query.override === '1'
const episodesUpdated = await Scanner.quickMatchPodcastEpisodes(req.libraryItem, { overrideDetails }) const episodesUpdated = await Scanner.quickMatchPodcastEpisodes(req.libraryItem, { overrideDetails })
if (episodesUpdated) { if (episodesUpdated) {
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
} }
res.json({ res.json({
@ -418,7 +418,7 @@ class PodcastController {
Logger.info(`[PodcastController] Updated episode "${episode.title}" keys`, episode.changed()) Logger.info(`[PodcastController] Updated episode "${episode.title}" keys`, episode.changed())
await episode.save() await episode.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
} else { } else {
Logger.info(`[PodcastController] No changes to episode "${episode.title}"`) Logger.info(`[PodcastController] No changes to episode "${episode.title}"`)
} }
@ -504,7 +504,7 @@ class PodcastController {
req.libraryItem.media.numEpisodes = req.libraryItem.media.podcastEpisodes.length req.libraryItem.media.numEpisodes = req.libraryItem.media.podcastEpisodes.length
await req.libraryItem.media.save() await req.libraryItem.media.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
res.json(req.libraryItem.toOldJSON()) res.json(req.libraryItem.toOldJSON())
} }

View File

@ -254,7 +254,7 @@ class PodcastManager {
await libraryItem.media.save() await libraryItem.media.save()
} }
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
const podcastEpisodeExpanded = podcastEpisode.toOldJSONExpanded(libraryItem.id) const podcastEpisodeExpanded = podcastEpisode.toOldJSONExpanded(libraryItem.id)
podcastEpisodeExpanded.libraryItem = libraryItem.toOldJSONExpanded() podcastEpisodeExpanded.libraryItem = libraryItem.toOldJSONExpanded()
SocketAuthority.emitter('episode_added', podcastEpisodeExpanded) SocketAuthority.emitter('episode_added', podcastEpisodeExpanded)
@ -367,7 +367,7 @@ class PodcastManager {
libraryItem.changed('updatedAt', true) libraryItem.changed('updatedAt', true)
await libraryItem.save() await libraryItem.save()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
return libraryItem.media.autoDownloadEpisodes return libraryItem.media.autoDownloadEpisodes
} }
@ -425,7 +425,7 @@ class PodcastManager {
libraryItem.changed('updatedAt', true) libraryItem.changed('updatedAt', true)
await libraryItem.save() await libraryItem.save()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
return newEpisodes || [] return newEpisodes || []
} }
@ -712,7 +712,7 @@ class PodcastManager {
} }
} }
SocketAuthority.emitter('item_added', newLibraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_added', newLibraryItem)
// Turn on podcast auto download cron if not already on // Turn on podcast auto download cron if not already on
if (newLibraryItem.media.autoDownloadEpisodes) { if (newLibraryItem.media.autoDownloadEpisodes) {

View File

@ -64,7 +64,7 @@ class LibraryItemScanner {
const { libraryItem: expandedLibraryItem, wasUpdated } = await this.rescanLibraryItemMedia(libraryItem, libraryItemScanData, library.settings, scanLogger) const { libraryItem: expandedLibraryItem, wasUpdated } = await this.rescanLibraryItemMedia(libraryItem, libraryItemScanData, library.settings, scanLogger)
if (libraryItemDataUpdated || wasUpdated) { if (libraryItemDataUpdated || wasUpdated) {
SocketAuthority.emitter('item_updated', expandedLibraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', expandedLibraryItem)
await this.checkAuthorsAndSeriesRemovedFromBooks(library.id, scanLogger) await this.checkAuthorsAndSeriesRemovedFromBooks(library.id, scanLogger)

View File

@ -223,11 +223,7 @@ class LibraryScanner {
// Emit item updates in chunks of 10 to client // Emit item updates in chunks of 10 to client
if (libraryItemsUpdated.length === 10) { if (libraryItemsUpdated.length === 10) {
// TODO: Should only emit to clients where library item is accessible SocketAuthority.libraryItemsEmitter('items_updated', libraryItemsUpdated)
SocketAuthority.emitter(
'items_updated',
libraryItemsUpdated.map((li) => li.toOldJSONExpanded())
)
libraryItemsUpdated = [] libraryItemsUpdated = []
} }
@ -235,11 +231,7 @@ class LibraryScanner {
} }
// Emit item updates to client // Emit item updates to client
if (libraryItemsUpdated.length) { if (libraryItemsUpdated.length) {
// TODO: Should only emit to clients where library item is accessible SocketAuthority.libraryItemsEmitter('items_updated', libraryItemsUpdated)
SocketAuthority.emitter(
'items_updated',
libraryItemsUpdated.map((li) => li.toOldJSONExpanded())
)
} }
// Authors and series that were removed from books should be removed if they are now empty // Authors and series that were removed from books should be removed if they are now empty
@ -277,11 +269,7 @@ class LibraryScanner {
// Emit new items in chunks of 10 to client // Emit new items in chunks of 10 to client
if (newLibraryItems.length === 10) { if (newLibraryItems.length === 10) {
// TODO: Should only emit to clients where library item is accessible SocketAuthority.libraryItemsEmitter('items_added', newLibraryItems)
SocketAuthority.emitter(
'items_added',
newLibraryItems.map((li) => li.toOldJSONExpanded())
)
newLibraryItems = [] newLibraryItems = []
} }
@ -289,11 +277,7 @@ class LibraryScanner {
} }
// Emit new items to client // Emit new items to client
if (newLibraryItems.length) { if (newLibraryItems.length) {
// TODO: Should only emit to clients where library item is accessible SocketAuthority.libraryItemsEmitter('items_added', newLibraryItems)
SocketAuthority.emitter(
'items_added',
newLibraryItems.map((li) => li.toOldJSONExpanded())
)
} }
} }
@ -609,7 +593,7 @@ class LibraryScanner {
Logger.info(`[LibraryScanner] Scanning file update group and library item was deleted "${existingLibraryItem.media.title}" - marking as missing`) Logger.info(`[LibraryScanner] Scanning file update group and library item was deleted "${existingLibraryItem.media.title}" - marking as missing`)
existingLibraryItem.isMissing = true existingLibraryItem.isMissing = true
await existingLibraryItem.save() await existingLibraryItem.save()
SocketAuthority.emitter('item_updated', existingLibraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', existingLibraryItem)
itemGroupingResults[itemDir] = ScanResult.REMOVED itemGroupingResults[itemDir] = ScanResult.REMOVED
continue continue
@ -643,7 +627,7 @@ class LibraryScanner {
const isSingleMediaItem = isSingleMediaFile(fileUpdateGroup, itemDir) const isSingleMediaItem = isSingleMediaFile(fileUpdateGroup, itemDir)
const newLibraryItem = await LibraryItemScanner.scanPotentialNewLibraryItem(fullPath, library, folder, isSingleMediaItem) const newLibraryItem = await LibraryItemScanner.scanPotentialNewLibraryItem(fullPath, library, folder, isSingleMediaItem)
if (newLibraryItem) { if (newLibraryItem) {
SocketAuthority.emitter('item_added', newLibraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_added', newLibraryItem)
} }
itemGroupingResults[itemDir] = newLibraryItem ? ScanResult.ADDED : ScanResult.NOTHING itemGroupingResults[itemDir] = newLibraryItem ? ScanResult.ADDED : ScanResult.NOTHING
} }

View File

@ -126,7 +126,7 @@ class Scanner {
await libraryItem.saveMetadataFile() await libraryItem.saveMetadataFile()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded()) SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
} }
return { return {