mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-06-22 08:53:41 +02:00
Update:Listening sessions table for multi-select, sorting and rows per page
- Updated get all sessions API endpoint to include sorting - Added sessions API endpoint for batch deleting
This commit is contained in:
parent
46ec59c74e
commit
76119445a3
25 changed files with 375 additions and 62 deletions
|
@ -1,6 +1,6 @@
|
|||
const Logger = require('../Logger')
|
||||
const Database = require('../Database')
|
||||
const { toNumber } = require('../utils/index')
|
||||
const { toNumber, isUUID } = require('../utils/index')
|
||||
|
||||
class SessionController {
|
||||
constructor() { }
|
||||
|
@ -9,35 +9,97 @@ class SessionController {
|
|||
return res.json(req.playbackSession)
|
||||
}
|
||||
|
||||
/**
|
||||
* GET: /api/sessions
|
||||
* @this import('../routers/ApiRouter')
|
||||
*
|
||||
* @param {import('express').Request} req
|
||||
* @param {import('express').Response} res
|
||||
*/
|
||||
async getAllWithUserData(req, res) {
|
||||
if (!req.user.isAdminOrUp) {
|
||||
Logger.error(`[SessionController] getAllWithUserData: Non-admin user requested all session data ${req.user.id}/"${req.user.username}"`)
|
||||
return res.sendStatus(404)
|
||||
}
|
||||
|
||||
let listeningSessions = []
|
||||
if (req.query.user) {
|
||||
listeningSessions = await this.getUserListeningSessionsHelper(req.query.user)
|
||||
} else {
|
||||
listeningSessions = await this.getAllSessionsWithUserData()
|
||||
// Validate "user" query
|
||||
let userId = req.query.user
|
||||
if (userId && !isUUID(userId)) {
|
||||
Logger.warn(`[SessionController] Invalid "user" query string "${userId}"`)
|
||||
userId = null
|
||||
}
|
||||
// Validate "sort" query
|
||||
const validSortOrders = ['displayTitle', 'duration', 'playMethod', 'startTime', 'currentTime', 'timeListening', 'updatedAt', 'createdAt']
|
||||
let orderKey = req.query.sort || 'updatedAt'
|
||||
if (!validSortOrders.includes(orderKey)) {
|
||||
Logger.warn(`[SessionController] Invalid "sort" query string "${orderKey}" (Must be one of "${validSortOrders.join('|')}")`)
|
||||
orderKey = 'updatedAt'
|
||||
}
|
||||
let orderDesc = req.query.desc === '1' ? 'DESC' : 'ASC'
|
||||
// Validate "itemsPerPage" and "page" query
|
||||
let itemsPerPage = toNumber(req.query.itemsPerPage, 10) || 10
|
||||
if (itemsPerPage < 1) {
|
||||
Logger.warn(`[SessionController] Invalid "itemsPerPage" query string "${itemsPerPage}"`)
|
||||
itemsPerPage = 10
|
||||
}
|
||||
let page = toNumber(req.query.page, 0)
|
||||
if (page < 0) {
|
||||
Logger.warn(`[SessionController] Invalid "page" query string "${page}"`)
|
||||
page = 0
|
||||
}
|
||||
|
||||
const itemsPerPage = toNumber(req.query.itemsPerPage, 10) || 10
|
||||
const page = toNumber(req.query.page, 0)
|
||||
let where = null
|
||||
const include = [
|
||||
{
|
||||
model: Database.models.device
|
||||
}
|
||||
]
|
||||
|
||||
const start = page * itemsPerPage
|
||||
const sessions = listeningSessions.slice(start, start + itemsPerPage)
|
||||
if (userId) {
|
||||
where = {
|
||||
userId
|
||||
}
|
||||
} else {
|
||||
include.push({
|
||||
model: Database.userModel,
|
||||
attributes: ['id', 'username']
|
||||
})
|
||||
}
|
||||
|
||||
const { rows, count } = await Database.playbackSessionModel.findAndCountAll({
|
||||
where,
|
||||
include,
|
||||
order: [
|
||||
[orderKey, orderDesc]
|
||||
],
|
||||
limit: itemsPerPage,
|
||||
offset: itemsPerPage * page
|
||||
})
|
||||
|
||||
// Map playback sessions to old playback sessions
|
||||
const sessions = rows.map(session => {
|
||||
const oldPlaybackSession = Database.playbackSessionModel.getOldPlaybackSession(session)
|
||||
if (session.user) {
|
||||
return {
|
||||
...oldPlaybackSession,
|
||||
user: {
|
||||
id: session.user.id,
|
||||
username: session.user.username
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return oldPlaybackSession.toJSON()
|
||||
}
|
||||
})
|
||||
|
||||
const payload = {
|
||||
total: listeningSessions.length,
|
||||
numPages: Math.ceil(listeningSessions.length / itemsPerPage),
|
||||
total: count,
|
||||
numPages: Math.ceil(count / itemsPerPage),
|
||||
page,
|
||||
itemsPerPage,
|
||||
sessions
|
||||
}
|
||||
|
||||
if (req.query.user) {
|
||||
payload.userFilter = req.query.user
|
||||
if (userId) {
|
||||
payload.userId = userId
|
||||
}
|
||||
|
||||
res.json(payload)
|
||||
|
@ -92,6 +154,49 @@ class SessionController {
|
|||
res.sendStatus(200)
|
||||
}
|
||||
|
||||
/**
|
||||
* POST: /api/sessions/batch/delete
|
||||
* @this import('../routers/ApiRouter')
|
||||
*
|
||||
* @typedef batchDeleteReqBody
|
||||
* @property {string[]} sessions
|
||||
*
|
||||
* @param {import('express').Request<{}, {}, batchDeleteReqBody, {}} req
|
||||
* @param {import('express').Response} res
|
||||
*/
|
||||
async batchDelete(req, res) {
|
||||
if (!req.user.isAdminOrUp) {
|
||||
Logger.error(`[SessionController] Non-admin user attempted to batch delete sessions "${req.user.username}"`)
|
||||
return res.sendStatus(403)
|
||||
}
|
||||
// Validate session ids
|
||||
if (!req.body.sessions?.length || !Array.isArray(req.body.sessions) || req.body.sessions.some(s => !isUUID(s))) {
|
||||
Logger.error(`[SessionController] Invalid request body. "sessions" array is required`, req.body)
|
||||
return res.status(400).send('Invalid request body. "sessions" array of session id strings is required.')
|
||||
}
|
||||
|
||||
// Check if any of these sessions are open and close it
|
||||
for (const sessionId of req.body.sessions) {
|
||||
const openSession = this.playbackSessionManager.getSession(sessionId)
|
||||
if (openSession) {
|
||||
await this.playbackSessionManager.removeSession(sessionId)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const sessionsRemoved = await Database.playbackSessionModel.destroy({
|
||||
where: {
|
||||
id: req.body.sessions
|
||||
}
|
||||
})
|
||||
Logger.info(`[SessionController] ${sessionsRemoved} playback sessions removed by "${req.user.username}"`)
|
||||
res.sendStatus(200)
|
||||
} catch (error) {
|
||||
Logger.error(`[SessionController] Failed to remove playback sessions`, error)
|
||||
res.status(500).send('Failed to remove sessions')
|
||||
}
|
||||
}
|
||||
|
||||
// POST: api/session/local
|
||||
syncLocal(req, res) {
|
||||
this.playbackSessionManager.syncLocalSessionRequest(req, res)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue