Add:Ereader device setting to set users that have access #1982

This commit is contained in:
advplyr 2023-10-29 11:28:34 -05:00
parent 94fd3841aa
commit 27497451d9
23 changed files with 267 additions and 55 deletions

View file

@ -51,32 +51,45 @@ class EmailController {
})
}
/**
* Send ebook to device
* User must have access to device and library item
*
* @param {import('express').Request} req
* @param {import('express').Response} res
*/
async sendEBookToDevice(req, res) {
Logger.debug(`[EmailController] Send ebook to device request for libraryItemId=${req.body.libraryItemId}, deviceName=${req.body.deviceName}`)
Logger.debug(`[EmailController] Send ebook to device requested by user "${req.user.username}" for libraryItemId=${req.body.libraryItemId}, deviceName=${req.body.deviceName}`)
const device = Database.emailSettings.getEReaderDevice(req.body.deviceName)
if (!device) {
return res.status(404).send('Ereader device not found')
}
// Check user has access to device
if (!Database.emailSettings.checkUserCanAccessDevice(device, req.user)) {
return res.sendStatus(403)
}
const libraryItem = await Database.libraryItemModel.getOldById(req.body.libraryItemId)
if (!libraryItem) {
return res.status(404).send('Library item not found')
}
// Check user has access to library item
if (!req.user.checkCanAccessLibraryItem(libraryItem)) {
return res.sendStatus(403)
}
const ebookFile = libraryItem.media.ebookFile
if (!ebookFile) {
return res.status(404).send('EBook file not found')
}
const device = Database.emailSettings.getEReaderDevice(req.body.deviceName)
if (!device) {
return res.status(404).send('E-reader device not found')
return res.status(404).send('Ebook file not found')
}
this.emailManager.sendEBookToDevice(ebookFile, device, res)
}
middleware(req, res, next) {
adminMiddleware(req, res, next) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(404)
}

View file

@ -1,6 +1,14 @@
const Logger = require('../../Logger')
const { areEquivalent, copyValue, isNullOrNaN } = require('../../utils')
/**
* @typedef EreaderDeviceObject
* @property {string} name
* @property {string} email
* @property {string} availabilityOption
* @property {string[]} users
*/
// REF: https://nodemailer.com/smtp/
class EmailSettings {
constructor(settings = null) {
@ -13,7 +21,7 @@ class EmailSettings {
this.testAddress = null
this.fromAddress = null
// Array of { name:String, email:String }
/** @type {EreaderDeviceObject[]} */
this.ereaderDevices = []
if (settings) {
@ -57,6 +65,26 @@ class EmailSettings {
if (payload.ereaderDevices !== undefined && !Array.isArray(payload.ereaderDevices)) payload.ereaderDevices = undefined
if (payload.ereaderDevices?.length) {
// Validate ereader devices
payload.ereaderDevices = payload.ereaderDevices.map((device) => {
if (!device.name || !device.email) {
Logger.error(`[EmailSettings] Update ereader device is invalid`, device)
return null
}
if (!device.availabilityOption || !['adminOrUp', 'userOrUp', 'guestOrUp', 'specificUsers'].includes(device.availabilityOption)) {
device.availabilityOption = 'adminOrUp'
}
if (device.availabilityOption === 'specificUsers' && !device.users?.length) {
device.availabilityOption = 'adminOrUp'
}
if (device.availabilityOption !== 'specificUsers' && device.users?.length) {
device.users = []
}
return device
}).filter(d => d)
}
let hasUpdates = false
const json = this.toJSON()
@ -88,15 +116,40 @@ class EmailSettings {
return payload
}
getEReaderDevices(user) {
// Only accessible to admin or up
if (!user.isAdminOrUp) {
return []
/**
*
* @param {EreaderDeviceObject} device
* @param {import('../user/User')} user
* @returns {boolean}
*/
checkUserCanAccessDevice(device, user) {
let deviceAvailability = device.availabilityOption || 'adminOrUp'
if (deviceAvailability === 'adminOrUp' && user.isAdminOrUp) return true
if (deviceAvailability === 'userOrUp' && (user.isAdminOrUp || user.isUser)) return true
if (deviceAvailability === 'guestOrUp') return true
if (deviceAvailability === 'specificUsers') {
let deviceUsers = device.users || []
return deviceUsers.includes(user.id)
}
return this.ereaderDevices.map(d => ({ ...d }))
return false
}
/**
* Get ereader devices accessible to user
*
* @param {import('../user/User')} user
* @returns {EreaderDeviceObject[]}
*/
getEReaderDevices(user) {
return this.ereaderDevices.filter((device) => this.checkUserCanAccessDevice(device, user))
}
/**
* Get ereader device by name
*
* @param {string} deviceName
* @returns {EreaderDeviceObject}
*/
getEReaderDevice(deviceName) {
return this.ereaderDevices.find(d => d.name === deviceName)
}

View file

@ -35,6 +35,9 @@ class User {
get isAdmin() {
return this.type === 'admin'
}
get isUser() {
return this.type === 'user'
}
get isGuest() {
return this.type === 'guest'
}

View file

@ -255,11 +255,11 @@ class ApiRouter {
//
// Email Routes (Admin and up)
//
this.router.get('/emails/settings', EmailController.middleware.bind(this), EmailController.getSettings.bind(this))
this.router.patch('/emails/settings', EmailController.middleware.bind(this), EmailController.updateSettings.bind(this))
this.router.post('/emails/test', EmailController.middleware.bind(this), EmailController.sendTest.bind(this))
this.router.post('/emails/ereader-devices', EmailController.middleware.bind(this), EmailController.updateEReaderDevices.bind(this))
this.router.post('/emails/send-ebook-to-device', EmailController.middleware.bind(this), EmailController.sendEBookToDevice.bind(this))
this.router.get('/emails/settings', EmailController.adminMiddleware.bind(this), EmailController.getSettings.bind(this))
this.router.patch('/emails/settings', EmailController.adminMiddleware.bind(this), EmailController.updateSettings.bind(this))
this.router.post('/emails/test', EmailController.adminMiddleware.bind(this), EmailController.sendTest.bind(this))
this.router.post('/emails/ereader-devices', EmailController.adminMiddleware.bind(this), EmailController.updateEReaderDevices.bind(this))
this.router.post('/emails/send-ebook-to-device', EmailController.sendEBookToDevice.bind(this))
//
// Search Routes