Skip to content

Commit

Permalink
Update queries to account for user permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
advplyr committed Aug 6, 2023
1 parent 83d0db0 commit 1372c24
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 184 deletions.
4 changes: 2 additions & 2 deletions server/controllers/LibraryController.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ class LibraryController {
}
payload.offset = payload.page * payload.limit

const { libraryItems, count } = await Database.models.libraryItem.getByFilterAndSort(req.library, req.user.id, payload)
const { libraryItems, count } = await Database.models.libraryItem.getByFilterAndSort(req.library, req.user, payload)
payload.results = libraryItems
payload.total = count

Expand Down Expand Up @@ -640,7 +640,7 @@ class LibraryController {
async getUserPersonalizedShelves(req, res) {
const limitPerShelf = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) || 10 : 10
const include = (req.query.include || '').split(',').map(v => v.trim().toLowerCase()).filter(v => !!v)
const shelves = await Database.models.libraryItem.getPersonalizedShelves(req.library, req.user.id, include, limitPerShelf)
const shelves = await Database.models.libraryItem.getPersonalizedShelves(req.library, req.user, include, limitPerShelf)
res.json(shelves)
}

Expand Down
30 changes: 15 additions & 15 deletions server/models/LibraryItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -403,12 +403,12 @@ module.exports = (sequelize) => {
/**
* Get library items using filter and sort
* @param {oldLibrary} library
* @param {string} userId
* @param {oldUser} user
* @param {object} options
* @returns {object} { libraryItems:oldLibraryItem[], count:number }
*/
static async getByFilterAndSort(library, userId, options) {
const { libraryItems, count } = await libraryFilters.getFilteredLibraryItems(library, userId, options)
static async getByFilterAndSort(library, user, options) {
const { libraryItems, count } = await libraryFilters.getFilteredLibraryItems(library, user, options)
return {
libraryItems: libraryItems.map(li => {
const oldLibraryItem = this.getOldLibraryItem(li).toJSONMinified()
Expand Down Expand Up @@ -440,18 +440,18 @@ module.exports = (sequelize) => {
/**
* Get home page data personalized shelves
* @param {oldLibrary} library
* @param {string} userId
* @param {oldUser} user
* @param {string[]} include
* @param {number} limit
* @returns {object[]} array of shelf objects
*/
static async getPersonalizedShelves(library, userId, include, limit) {
static async getPersonalizedShelves(library, user, include, limit) {
const fullStart = Date.now() // Used for testing load times

const shelves = []

// "Continue Listening" shelf
const itemsInProgressPayload = await libraryFilters.getMediaItemsInProgress(library, userId, include, limit, false)
const itemsInProgressPayload = await libraryFilters.getMediaItemsInProgress(library, user, include, limit, false)
if (itemsInProgressPayload.items.length) {
shelves.push({
id: 'continue-listening',
Expand All @@ -467,7 +467,7 @@ module.exports = (sequelize) => {
let start = Date.now()
if (library.isBook) {
// "Continue Reading" shelf
const ebooksInProgressPayload = await libraryFilters.getMediaItemsInProgress(library, userId, include, limit, true)
const ebooksInProgressPayload = await libraryFilters.getMediaItemsInProgress(library, user, include, limit, true)
if (ebooksInProgressPayload.items.length) {
shelves.push({
id: 'continue-reading',
Expand All @@ -482,7 +482,7 @@ module.exports = (sequelize) => {

start = Date.now()
// "Continue Series" shelf
const continueSeriesPayload = await libraryFilters.getLibraryItemsContinueSeries(library, userId, include, limit)
const continueSeriesPayload = await libraryFilters.getLibraryItemsContinueSeries(library, user, include, limit)
if (continueSeriesPayload.libraryItems.length) {
shelves.push({
id: 'continue-series',
Expand All @@ -496,7 +496,7 @@ module.exports = (sequelize) => {
Logger.debug(`Loaded ${continueSeriesPayload.libraryItems.length} of ${continueSeriesPayload.count} items for "Continue Series" in ${((Date.now() - start) / 1000).toFixed(2)}s`)
} else if (library.isPodcast) {
// "Newest Episodes" shelf
const newestEpisodesPayload = await libraryFilters.getNewestPodcastEpisodes(library, userId, limit)
const newestEpisodesPayload = await libraryFilters.getNewestPodcastEpisodes(library, user, limit)
if (newestEpisodesPayload.libraryItems.length) {
shelves.push({
id: 'newest-episodes',
Expand All @@ -512,7 +512,7 @@ module.exports = (sequelize) => {

start = Date.now()
// "Recently Added" shelf
const mostRecentPayload = await libraryFilters.getLibraryItemsMostRecentlyAdded(library, userId, include, limit)
const mostRecentPayload = await libraryFilters.getLibraryItemsMostRecentlyAdded(library, user, include, limit)
if (mostRecentPayload.libraryItems.length) {
shelves.push({
id: 'recently-added',
Expand All @@ -528,7 +528,7 @@ module.exports = (sequelize) => {
if (library.isBook) {
start = Date.now()
// "Recent Series" shelf
const seriesMostRecentPayload = await libraryFilters.getSeriesMostRecentlyAdded(library, include, 5)
const seriesMostRecentPayload = await libraryFilters.getSeriesMostRecentlyAdded(library, user, include, 5)
if (seriesMostRecentPayload.series.length) {
shelves.push({
id: 'recent-series',
Expand All @@ -543,7 +543,7 @@ module.exports = (sequelize) => {

start = Date.now()
// "Discover" shelf
const discoverLibraryItemsPayload = await libraryFilters.getLibraryItemsToDiscover(library, userId, include, limit)
const discoverLibraryItemsPayload = await libraryFilters.getLibraryItemsToDiscover(library, user, include, limit)
if (discoverLibraryItemsPayload.libraryItems.length) {
shelves.push({
id: 'discover',
Expand All @@ -559,7 +559,7 @@ module.exports = (sequelize) => {

start = Date.now()
// "Listen Again" shelf
const listenAgainPayload = await libraryFilters.getMediaFinished(library, userId, include, limit, false)
const listenAgainPayload = await libraryFilters.getMediaFinished(library, user, include, limit, false)
if (listenAgainPayload.items.length) {
shelves.push({
id: 'listen-again',
Expand All @@ -575,7 +575,7 @@ module.exports = (sequelize) => {
if (library.isBook) {
start = Date.now()
// "Read Again" shelf
const readAgainPayload = await libraryFilters.getMediaFinished(library, userId, include, limit, true)
const readAgainPayload = await libraryFilters.getMediaFinished(library, user, include, limit, true)
if (readAgainPayload.items.length) {
shelves.push({
id: 'read-again',
Expand All @@ -590,7 +590,7 @@ module.exports = (sequelize) => {

start = Date.now()
// "Newest Authors" shelf
const newestAuthorsPayload = await libraryFilters.getNewestAuthors(library, limit)
const newestAuthorsPayload = await libraryFilters.getNewestAuthors(library, user, limit)
if (newestAuthorsPayload.authors.length) {
shelves.push({
id: 'newest-authors',
Expand Down
89 changes: 59 additions & 30 deletions server/utils/queries/libraryFilters.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ module.exports = {
/**
* Get library items using filter and sort
* @param {oldLibrary} library
* @param {string} userId
* @param {oldUser} user
* @param {object} options
* @returns {object} { libraryItems:LibraryItem[], count:number }
*/
async getFilteredLibraryItems(library, userId, options) {
async getFilteredLibraryItems(library, user, options) {
const { filterBy, sortBy, sortDesc, limit, offset, collapseseries, include, mediaType } = options

let filterValue = null
Expand All @@ -29,25 +29,25 @@ module.exports = {
}

if (mediaType === 'book') {
return libraryItemsBookFilters.getFilteredLibraryItems(library.id, userId, filterGroup, filterValue, sortBy, sortDesc, collapseseries, include, limit, offset)
return libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, filterGroup, filterValue, sortBy, sortDesc, collapseseries, include, limit, offset)
} else {
return libraryItemsPodcastFilters.getFilteredLibraryItems(library.id, userId, filterGroup, filterValue, sortBy, sortDesc, include, limit, offset)
return libraryItemsPodcastFilters.getFilteredLibraryItems(library.id, user, filterGroup, filterValue, sortBy, sortDesc, include, limit, offset)
}
},

/**
* Get library items for continue listening & continue reading shelves
* @param {oldLibrary} library
* @param {string} userId
* @param {oldUser} user
* @param {string[]} include
* @param {number} limit
* @param {boolean} ebook true if continue reading shelf
* @returns {object} { items:LibraryItem[], count:number }
*/
async getMediaItemsInProgress(library, userId, include, limit, ebook = false) {
async getMediaItemsInProgress(library, user, include, limit, ebook = false) {
if (library.mediaType === 'book') {
const filterValue = ebook ? 'ebook-in-progress' : 'audio-in-progress'
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, userId, 'progress', filterValue, 'progress', true, false, include, limit, 0)
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, 'progress', filterValue, 'progress', true, false, include, limit, 0)
return {
items: libraryItems.map(li => {
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(li).toJSONMinified()
Expand All @@ -59,7 +59,7 @@ module.exports = {
count
}
} else {
const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredPodcastEpisodes(library.id, userId, 'progress', 'in-progress', 'progress', true, limit, 0)
const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredPodcastEpisodes(library.id, user, 'progress', 'in-progress', 'progress', true, limit, 0)
return {
count,
items: libraryItems.map(li => {
Expand All @@ -74,14 +74,14 @@ module.exports = {
/**
* Get library items for most recently added shelf
* @param {oldLibrary} library
* @param {string} userId
* @param {oldUser} user
* @param {string[]} include
* @param {number} limit
* @returns {object} { libraryItems:LibraryItem[], count:number }
*/
async getLibraryItemsMostRecentlyAdded(library, userId, include, limit) {
async getLibraryItemsMostRecentlyAdded(library, user, include, limit) {
if (library.mediaType === 'book') {
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, userId, null, null, 'addedAt', true, false, include, limit, 0)
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, null, null, 'addedAt', true, false, include, limit, 0)
return {
libraryItems: libraryItems.map(li => {
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(li).toJSONMinified()
Expand All @@ -96,7 +96,7 @@ module.exports = {
count
}
} else {
const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredLibraryItems(library.id, userId, null, null, 'addedAt', true, include, limit, 0)
const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredLibraryItems(library.id, user, null, null, 'addedAt', true, include, limit, 0)
return {
libraryItems: libraryItems.map(li => {
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(li).toJSONMinified()
Expand All @@ -116,13 +116,13 @@ module.exports = {
/**
* Get library items for continue series shelf
* @param {string} library
* @param {string} userId
* @param {oldUser} user
* @param {string[]} include
* @param {number} limit
* @returns {object} { libraryItems:LibraryItem[], count:number }
*/
async getLibraryItemsContinueSeries(library, userId, include, limit) {
const { libraryItems, count } = await libraryItemsBookFilters.getContinueSeriesLibraryItems(library.id, userId, include, limit, 0)
async getLibraryItemsContinueSeries(library, user, include, limit) {
const { libraryItems, count } = await libraryItemsBookFilters.getContinueSeriesLibraryItems(library.id, user, include, limit, 0)
return {
libraryItems: libraryItems.map(li => {
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(li).toJSONMinified()
Expand All @@ -141,18 +141,18 @@ module.exports = {
/**
* Get library items or podcast episodes for the "Listen Again" or "Read Again" shelf
* @param {oldLibrary} library
* @param {string} userId
* @param {oldUser} user
* @param {string[]} include
* @param {number} limit
* @param {boolean} ebook true if "Read Again" shelf
* @returns {object} { items:object[], count:number }
*/
async getMediaFinished(library, userId, include, limit, ebook = false) {
async getMediaFinished(library, user, include, limit, ebook = false) {
if (ebook && library.mediaType !== 'book') return { items: [], count: 0 }

if (library.mediaType === 'book') {
const filterValue = ebook ? 'ebook-finished' : 'finished'
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, userId, 'progress', filterValue, 'progress', true, false, include, limit, 0)
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, 'progress', filterValue, 'progress', true, false, include, limit, 0)
return {
items: libraryItems.map(li => {
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(li).toJSONMinified()
Expand All @@ -164,7 +164,7 @@ module.exports = {
count
}
} else {
const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredPodcastEpisodes(library.id, userId, 'progress', 'finished', 'progress', true, limit, 0)
const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredPodcastEpisodes(library.id, user, 'progress', 'finished', 'progress', true, limit, 0)
return {
count,
items: libraryItems.map(li => {
Expand All @@ -179,11 +179,12 @@ module.exports = {
/**
* Get series for recent series shelf
* @param {oldLibrary} library
* @param {oldUser} user
* @param {string[]} include
* @param {number} limit
* @returns {object} { series:oldSeries[], count:number}
*/
async getSeriesMostRecentlyAdded(library, include, limit) {
async getSeriesMostRecentlyAdded(library, user, include, limit) {
if (library.mediaType !== 'book') return { series: [], count: 0 }

const seriesIncludes = []
Expand All @@ -192,19 +193,46 @@ module.exports = {
model: Database.models.feed
})
}
const { rows: series, count } = await Database.models.series.findAndCountAll({
where: {

const userPermissionBookWhere = libraryItemsBookFilters.getUserPermissionBookWhereQuery(user)

const seriesWhere = [
{
libraryId: library.id
},
}
]
// Handle user permissions to only include series with at least 1 book
// TODO: Simplify to a single query
if (userPermissionBookWhere.bookWhere.length) {
let attrQuery = 'SELECT count(*) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND bs.bookId = b.id'
if (!user.canAccessExplicitContent) {
attrQuery += ' AND b.explicit = 0'
}
if (!user.permissions.accessAllTags && user.itemTagsSelected.length) {
if (user.permissions.selectedTagsNotAccessible) {
attrQuery += ' AND (SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected)) = 0'
} else {
attrQuery += ' AND (SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected)) > 0'
}
}
seriesWhere.push(Sequelize.where(Sequelize.literal(`(${attrQuery})`), {
[Sequelize.Op.gt]: 0
}))
}

const { rows: series, count } = await Database.models.series.findAndCountAll({
where: seriesWhere,
limit,
offset: 0,
distinct: true,
subQuery: false,
replacements: userPermissionBookWhere.replacements,
include: [
{
model: Database.models.bookSeries,
include: {
model: Database.models.book,
where: userPermissionBookWhere.bookWhere,
include: {
model: Database.models.libraryItem
}
Expand Down Expand Up @@ -255,10 +283,11 @@ module.exports = {
* Get most recently created authors for "Newest Authors" shelf
* Author must be linked to at least 1 book
* @param {oldLibrary} library
* @param {oldUser} user
* @param {number} limit
* @returns {object} { authors:oldAuthor[], count:number }
*/
async getNewestAuthors(library, limit) {
async getNewestAuthors(library, user, limit) {
if (library.mediaType !== 'book') return { authors: [], count: 0 }

const { rows: authors, count } = await Database.models.author.findAndCountAll({
Expand Down Expand Up @@ -288,15 +317,15 @@ module.exports = {
/**
* Get book library items for the "Discover" shelf
* @param {oldLibrary} library
* @param {string} userId
* @param {oldUser} user
* @param {string[]} include
* @param {number} limit
* @returns {object} {libraryItems:oldLibraryItem[], count:number}
*/
async getLibraryItemsToDiscover(library, userId, include, limit) {
async getLibraryItemsToDiscover(library, user, include, limit) {
if (library.mediaType !== 'book') return { libraryItems: [], count: 0 }

const { libraryItems, count } = await libraryItemsBookFilters.getDiscoverLibraryItems(library.id, userId, include, limit)
const { libraryItems, count } = await libraryItemsBookFilters.getDiscoverLibraryItems(library.id, user, include, limit)
return {
libraryItems: libraryItems.map(li => {
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(li).toJSONMinified()
Expand All @@ -312,14 +341,14 @@ module.exports = {
/**
* Get podcast episodes most recently added
* @param {oldLibrary} library
* @param {string} userId
* @param {oldUser} user
* @param {number} limit
* @returns {object} {libraryItems:oldLibraryItem[], count:number}
*/
async getNewestPodcastEpisodes(library, userId, limit) {
async getNewestPodcastEpisodes(library, user, limit) {
if (library.mediaType !== 'podcast') return { libraryItems: [], count: 0 }

const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredPodcastEpisodes(library.id, userId, null, null, 'createdAt', true, limit, 0)
const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredPodcastEpisodes(library.id, user, null, null, 'createdAt', true, limit, 0)
return {
count,
libraryItems: libraryItems.map(li => {
Expand Down
Loading

0 comments on commit 1372c24

Please sign in to comment.