Update API JS docs

This commit is contained in:
advplyr 2024-08-11 17:01:25 -05:00
parent 2472b86284
commit e53ac6566b
24 changed files with 390 additions and 175 deletions

View File

@ -390,16 +390,6 @@ class Database {
return this.models.user.updateFromOld(oldUser)
}
removeUser(userId) {
if (!this.sequelize) return false
return this.models.user.removeById(userId)
}
upsertMediaProgress(oldMediaProgress) {
if (!this.sequelize) return false
return this.models.mediaProgress.upsertFromOld(oldMediaProgress)
}
updateBulkBooks(oldBooks) {
if (!this.sequelize) return false
return Promise.all(oldBooks.map((oldBook) => this.models.book.saveFromOld(oldBook)))

View File

@ -1,3 +1,4 @@
const { Request, Response, NextFunction } = require('express')
const sequelize = require('sequelize')
const fs = require('../libs/fsExtra')
const { createNewSortInstance } = require('../libs/fastSort')
@ -14,9 +15,23 @@ const { reqSupportsWebp, isValidASIN } = require('../utils/index')
const naturalSort = createNewSortInstance({
comparer: new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare
})
/**
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class AuthorController {
constructor() {}
/**
* GET: /api/authors/:id
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async findOne(req, res) {
const include = (req.query.include || '').split(',')
@ -63,9 +78,10 @@ class AuthorController {
}
/**
* PATCH: /api/authors/:id
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async update(req, res) {
const payload = req.body
@ -194,8 +210,8 @@ class AuthorController {
* DELETE: /api/authors/:id
* Remove author from all books and delete
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async delete(req, res) {
Logger.info(`[AuthorController] Removing author "${req.author.name}"`)
@ -218,8 +234,8 @@ class AuthorController {
* POST: /api/authors/:id/image
* Upload author image from web URL
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async uploadImage(req, res) {
if (!req.user.canUpload) {
@ -263,8 +279,8 @@ class AuthorController {
* DELETE: /api/authors/:id/image
* Remove author image & delete image file
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async deleteImage(req, res) {
if (!req.author.imagePath) {
@ -284,6 +300,12 @@ class AuthorController {
})
}
/**
* POST: /api/authors/:id/match
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async match(req, res) {
let authorData = null
const region = req.body.region || 'us'
@ -334,7 +356,12 @@ class AuthorController {
})
}
// GET api/authors/:id/image
/**
* GET: /api/authors/:id/image
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async getImage(req, res) {
const {
query: { width, height, format, raw },
@ -358,6 +385,12 @@ class AuthorController {
return CacheManager.handleAuthorCache(res, author, options)
}
/**
*
* @param {RequestWithUser} req
* @param {Response} res
* @param {NextFunction} next
*/
async middleware(req, res, next) {
const author = await Database.authorModel.getOldById(req.params.id)
if (!author) return res.sendStatus(404)

View File

@ -1,12 +1,28 @@
const { Request, Response, NextFunction } = require('express')
const Path = require('path')
const fs = require('../libs/fsExtra')
const Logger = require('../Logger')
const Database = require('../Database')
const fileUtils = require('../utils/fileUtils')
/**
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class BackupController {
constructor() {}
/**
* GET: /api/backups
*
* @this import('../routers/ApiRouter')
*
* @param {RequestWithUser} req
* @param {Response} res
*/
getAll(req, res) {
res.json({
backups: this.backupManager.backups.map((b) => b.toJSON()),
@ -15,10 +31,26 @@ class BackupController {
})
}
/**
* POST: /api/backups
*
* @this import('../routers/ApiRouter')
*
* @param {RequestWithUser} req
* @param {Response} res
*/
create(req, res) {
this.backupManager.requestCreateBackup(res)
}
/**
* DELETE: /api/backups/:id
*
* @this import('../routers/ApiRouter')
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async delete(req, res) {
await this.backupManager.removeBackup(req.backup)
@ -27,6 +59,14 @@ class BackupController {
})
}
/**
* POST: /api/backups/upload
*
* @this import('../routers/ApiRouter')
*
* @param {RequestWithUser} req
* @param {Response} res
*/
upload(req, res) {
if (!req.files.file) {
Logger.error('[BackupController] Upload backup invalid')
@ -41,8 +81,8 @@ class BackupController {
*
* @this import('../routers/ApiRouter')
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async updatePath(req, res) {
// Validate path is not empty and is a string
@ -86,10 +126,10 @@ class BackupController {
}
/**
* api/backups/:id/download
* GET: /api/backups/:id/download
*
* @param {*} req
* @param {*} res
* @param {RequestWithUser} req
* @param {Response} res
*/
download(req, res) {
if (global.XAccel) {
@ -104,14 +144,23 @@ class BackupController {
}
/**
* GET: /api/backups/:id/apply
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @this import('../routers/ApiRouter')
*
* @param {RequestWithUser} req
* @param {Response} res
*/
apply(req, res) {
this.backupManager.requestApplyBackup(this.apiCacheManager, req.backup, res)
}
/**
*
* @param {RequestWithUser} req
* @param {Response} res
* @param {NextFunction} next
*/
middleware(req, res, next) {
if (!req.user.isAdminOrUp) {
Logger.error(`[BackupController] Non-admin user "${req.user.username}" attempting to access backups`)

View File

@ -1,9 +1,22 @@
const { Request, Response } = require('express')
const CacheManager = require('../managers/CacheManager')
/**
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class CacheController {
constructor() {}
// POST: api/cache/purge
/**
* POST: /api/cache/purge
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async purgeCache(req, res) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(403)
@ -12,7 +25,12 @@ class CacheController {
res.sendStatus(200)
}
// POST: api/cache/items/purge
/**
* POST: /api/cache/items/purge
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async purgeItemsCache(req, res) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(403)

View File

@ -1,3 +1,4 @@
const { Request, Response, NextFunction } = require('express')
const Sequelize = require('sequelize')
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
@ -5,14 +6,22 @@ const Database = require('../Database')
const Collection = require('../objects/Collection')
/**
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class CollectionController {
constructor() {}
/**
* POST: /api/collections
* Create new collection
* @param {*} req
* @param {*} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async create(req, res) {
const newCollection = new Collection()
@ -49,6 +58,12 @@ class CollectionController {
res.json(jsonExpanded)
}
/**
* GET: /api/collections
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async findAll(req, res) {
const collectionsExpanded = await Database.collectionModel.getOldCollectionsJsonExpanded(req.user)
res.json({
@ -56,6 +71,12 @@ class CollectionController {
})
}
/**
* GET: /api/collections/:id
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async findOne(req, res) {
const includeEntities = (req.query.include || '').split(',')
@ -71,8 +92,9 @@ class CollectionController {
/**
* PATCH: /api/collections/:id
* Update collection
* @param {*} req
* @param {*} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async update(req, res) {
let wasUpdated = false
@ -123,6 +145,12 @@ class CollectionController {
res.json(jsonExpanded)
}
/**
* DELETE: /api/collections/:id
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async delete(req, res) {
const jsonExpanded = await req.collection.getOldJsonExpanded()
@ -139,8 +167,9 @@ class CollectionController {
* POST: /api/collections/:id/book
* Add a single book to a collection
* Req.body { id: <library item id> }
* @param {*} req
* @param {*} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async addBook(req, res) {
const libraryItem = await Database.libraryItemModel.getOldById(req.body.id)
@ -172,8 +201,9 @@ class CollectionController {
* DELETE: /api/collections/:id/book/:bookId
* Remove a single book from a collection. Re-order books
* TODO: bookId is actually libraryItemId. Clients need updating to use bookId
* @param {*} req
* @param {*} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async removeBook(req, res) {
const libraryItem = await Database.libraryItemModel.getOldById(req.params.bookId)
@ -216,8 +246,9 @@ class CollectionController {
* POST: /api/collections/:id/batch/add
* Add multiple books to collection
* Req.body { books: <Array of library item ids> }
* @param {*} req
* @param {*} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async addBatch(req, res) {
// filter out invalid libraryItemIds
@ -274,8 +305,9 @@ class CollectionController {
* POST: /api/collections/:id/batch/remove
* Remove multiple books from collection
* Req.body { books: <Array of library item ids> }
* @param {*} req
* @param {*} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async removeBatch(req, res) {
// filter out invalid libraryItemIds
@ -325,6 +357,12 @@ class CollectionController {
res.json(jsonExpanded)
}
/**
*
* @param {RequestWithUser} req
* @param {Response} res
* @param {NextFunction} next
*/
async middleware(req, res, next) {
if (req.params.id) {
const collection = await Database.collectionModel.findByPk(req.params.id)

View File

@ -1,20 +1,25 @@
const { Request, Response, NextFunction } = require('express')
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
const { validateUrl } = require('../utils/index')
//
// This is a controller for routes that don't have a home yet :(
//
/**
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class CustomMetadataProviderController {
constructor() {}
/**
* GET: /api/custom-metadata-providers
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async getAll(req, res) {
const providers = await Database.customMetadataProviderModel.findAll()
@ -27,8 +32,8 @@ class CustomMetadataProviderController {
/**
* POST: /api/custom-metadata-providers
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async create(req, res) {
const { name, url, mediaType, authHeaderValue } = req.body
@ -61,8 +66,8 @@ class CustomMetadataProviderController {
/**
* DELETE: /api/custom-metadata-providers/:id
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async delete(req, res) {
const slug = `custom-${req.params.id}`
@ -96,9 +101,9 @@ class CustomMetadataProviderController {
/**
* Middleware that requires admin or up
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {import('express').NextFunction} next
* @param {RequestWithUser} req
* @param {Response} res
* @param {NextFunction} next
*/
async middleware(req, res, next) {
if (!req.user.isAdminOrUp) {

View File

@ -1,16 +1,36 @@
const { Request, Response, NextFunction } = require('express')
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
/**
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class EmailController {
constructor() {}
/**
* GET: /api/emails/settings
*
* @param {RequestWithUser} req
* @param {Response} res
*/
getSettings(req, res) {
res.json({
settings: Database.emailSettings
})
}
/**
* PATCH: /api/emails/settings
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async updateSettings(req, res) {
const updated = Database.emailSettings.update(req.body)
if (updated) {
@ -21,10 +41,24 @@ class EmailController {
})
}
/**
* POST: /api/emails/test
*
* @this {import('../routers/ApiRouter')}
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async sendTest(req, res) {
this.emailManager.sendTest(res)
}
/**
* POST: /api/emails/ereader-devices
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async updateEReaderDevices(req, res) {
if (!req.body.ereaderDevices || !Array.isArray(req.body.ereaderDevices)) {
return res.status(400).send('Invalid payload. ereaderDevices array required')
@ -52,11 +86,12 @@ class EmailController {
}
/**
* POST: /api/emails/send-ebook-to-device
* Send ebook to device
* User must have access to device and library item
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async sendEBookToDevice(req, res) {
Logger.debug(`[EmailController] Send ebook to device requested by user "${req.user.username}" for libraryItemId=${req.body.libraryItemId}, deviceName=${req.body.deviceName}`)
@ -89,6 +124,12 @@ class EmailController {
this.emailManager.sendEBookToDevice(ebookFile, device, res)
}
/**
*
* @param {RequestWithUser} req
* @param {Response} res
* @param {NextFunction} next
*/
adminMiddleware(req, res, next) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(404)

View File

@ -1,16 +1,24 @@
const { Request, Response } = require('express')
const Path = require('path')
const Logger = require('../Logger')
const fs = require('../libs/fsExtra')
const { toNumber } = require('../utils/index')
const fileUtils = require('../utils/fileUtils')
/**
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class FileSystemController {
constructor() {}
/**
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async getPaths(req, res) {
if (!req.user.isAdminOrUp) {
@ -67,7 +75,12 @@ class FileSystemController {
})
}
// POST: api/filesystem/pathexists
/**
* POST: /api/filesystem/pathexists
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async checkPathExists(req, res) {
if (!req.user.canUpload) {
Logger.error(`[FileSystemController] Non-admin user "${req.user.username}" attempting to check path exists`)

View File

@ -1,3 +1,4 @@
const { Request, Response, NextFunction } = require('express')
const Sequelize = require('sequelize')
const Path = require('path')
const fs = require('../libs/fsExtra')
@ -22,9 +23,23 @@ const libraryFilters = require('../utils/queries/libraryFilters')
const libraryItemsPodcastFilters = require('../utils/queries/libraryItemsPodcastFilters')
const authorFilters = require('../utils/queries/authorFilters')
/**
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class LibraryController {
constructor() {}
/**
* POST: /api/libraries
* Create a new library
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async create(req, res) {
const newLibraryPayload = {
...req.body
@ -98,8 +113,8 @@ class LibraryController {
/**
* GET: /api/libraries/:id
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async findOne(req, res) {
const includeArray = (req.query.include || '').split(',')
@ -121,8 +136,8 @@ class LibraryController {
/**
* GET: /api/libraries/:id/episode-downloads
* Get podcast episodes in download queue
* @param {*} req
* @param {*} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async getEpisodeDownloadQueue(req, res) {
const libraryDownloadQueueDetails = this.podcastManager.getDownloadQueueDetails(req.library.id)
@ -132,8 +147,8 @@ class LibraryController {
/**
* PATCH: /api/libraries/:id
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async update(req, res) {
/** @type {import('../objects/Library')} */
@ -235,8 +250,9 @@ class LibraryController {
/**
* DELETE: /api/libraries/:id
* Delete a library
* @param {*} req
* @param {*} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async delete(req, res) {
const library = req.library
@ -298,8 +314,8 @@ class LibraryController {
/**
* GET /api/libraries/:id/items
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async getLibraryItems(req, res) {
const include = (req.query.include || '')
@ -340,8 +356,8 @@ class LibraryController {
/**
* DELETE: /libraries/:id/issues
* Remove all library items missing or invalid
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async removeLibraryItemsWithIssues(req, res) {
const libraryItemsWithIssues = await Database.libraryItemModel.findAll({
@ -398,8 +414,8 @@ class LibraryController {
* GET: /api/libraries/:id/series
* Optional query string: `?include=rssfeed` that adds `rssFeed` to series if a feed is open
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async getAllSeriesForLibrary(req, res) {
const include = (req.query.include || '')
@ -434,8 +450,8 @@ class LibraryController {
* rssfeed: adds `rssFeed` to series object if a feed is open
* progress: adds `progress` to series object with { libraryItemIds:Array<llid>, libraryItemIdsFinished:Array<llid>, isFinished:boolean }
*
* @param {import('express').Request} req
* @param {import('express').Response} res - Series
* @param {RequestWithUser} req
* @param {Response} res - Series
*/
async getSeriesForLibrary(req, res) {
const include = (req.query.include || '')
@ -470,8 +486,9 @@ class LibraryController {
/**
* GET: /api/libraries/:id/collections
* Get all collections for library
* @param {*} req
* @param {*} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async getCollectionsForLibrary(req, res) {
const include = (req.query.include || '')
@ -508,8 +525,9 @@ class LibraryController {
/**
* GET: /api/libraries/:id/playlists
* Get playlists for user in library
* @param {*} req
* @param {*} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async getUserPlaylistsForLibrary(req, res) {
let playlistsForUser = await Database.playlistModel.getOldPlaylistsForUserAndLibrary(req.user.id, req.library.id)
@ -532,8 +550,9 @@ class LibraryController {
/**
* GET: /api/libraries/:id/filterdata
* @param {import('express').Request} req
* @param {import('express').Response} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async getLibraryFilterData(req, res) {
const filterData = await libraryFilters.getFilterData(req.library.mediaType, req.library.id)
@ -543,8 +562,9 @@ class LibraryController {
/**
* GET: /api/libraries/:id/personalized
* Home page shelves
* @param {import('express').Request} req
* @param {import('express').Response} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async getUserPersonalizedShelves(req, res) {
const limitPerShelf = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) || 10 : 10
@ -559,8 +579,9 @@ class LibraryController {
/**
* POST: /api/libraries/order
* Change the display order of libraries
* @param {import('express').Request} req
* @param {import('express').Response} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async reorder(req, res) {
if (!req.user.isAdminOrUp) {
@ -598,9 +619,10 @@ class LibraryController {
/**
* GET: /api/libraries/:id/search
* Search library items with query
*
* ?q=search
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async search(req, res) {
if (!req.query.q || typeof req.query.q !== 'string') {
@ -616,8 +638,9 @@ class LibraryController {
/**
* GET: /api/libraries/:id/stats
* Get stats for library
* @param {import('express').Request} req
* @param {import('express').Response} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async stats(req, res) {
const stats = {
@ -658,8 +681,9 @@ class LibraryController {
/**
* GET: /api/libraries/:id/authors
* Get authors for library
* @param {import('express').Request} req
* @param {import('express').Response} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async getAuthors(req, res) {
const { bookWhere, replacements } = libraryItemsBookFilters.getUserPermissionBookWhereQuery(req.user)
@ -696,8 +720,9 @@ class LibraryController {
/**
* GET: /api/libraries/:id/narrators
* @param {*} req
* @param {*} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async getNarrators(req, res) {
// Get all books with narrators
@ -742,8 +767,9 @@ class LibraryController {
* Update narrator name
* :narratorId is base64 encoded name
* req.body { name }
* @param {*} req
* @param {*} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async updateNarrator(req, res) {
if (!req.user.canUpdate) {
@ -792,8 +818,9 @@ class LibraryController {
* DELETE: /api/libraries/:id/narrators/:narratorId
* Remove narrator
* :narratorId is base64 encoded name
* @param {*} req
* @param {*} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async removeNarrator(req, res) {
if (!req.user.canUpdate) {
@ -835,8 +862,8 @@ class LibraryController {
* GET: /api/libraries/:id/matchall
* Quick match all library items. Book libraries only.
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async matchAll(req, res) {
if (!req.user.isAdminOrUp) {
@ -852,8 +879,8 @@ class LibraryController {
* Optional query:
* ?force=1
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async scan(req, res) {
if (!req.user.isAdminOrUp) {
@ -872,8 +899,9 @@ class LibraryController {
/**
* GET: /api/libraries/:id/recent-episodes
* Used for latest page
* @param {import('express').Request} req
* @param {import('express').Response} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async getRecentEpisodes(req, res) {
if (!req.library.isPodcast) {
@ -894,8 +922,9 @@ class LibraryController {
/**
* GET: /api/libraries/:id/opml
* Get OPML file for a podcast library
* @param {import('express').Request} req
* @param {import('express').Response} res
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async getOPMLFile(req, res) {
const userPermissionPodcastWhere = libraryItemsPodcastFilters.getUserPermissionPodcastWhereQuery(req.user)
@ -920,8 +949,8 @@ class LibraryController {
/**
* Remove all metadata.json or metadata.abs files in library item folders
*
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {RequestWithUser} req
* @param {Response} res
*/
async removeAllMetadataFiles(req, res) {
if (!req.user.isAdminOrUp) {
@ -968,10 +997,10 @@ class LibraryController {
}
/**
* Middleware that is not using libraryItems from memory
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {import('express').NextFunction} next
*
* @param {RequestWithUser} req
* @param {Response} res
* @param {NextFunction} next
*/
async middleware(req, res, next) {
if (!req.user.checkCanAccessLibrary(req.params.id)) {

View File

@ -17,10 +17,10 @@ const CoverManager = require('../managers/CoverManager')
const ShareManager = require('../managers/ShareManager')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class LibraryItemController {

View File

@ -7,10 +7,10 @@ const { toNumber, isNullOrNaN } = require('../utils/index')
const userStats = require('../utils/queries/userStats')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class MeController {

View File

@ -15,10 +15,10 @@ const TaskManager = require('../managers/TaskManager')
const adminStats = require('../utils/queries/adminStats')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class MiscController {

View File

@ -3,10 +3,10 @@ const Database = require('../Database')
const { version } = require('../../package.json')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class NotificationController {

View File

@ -6,10 +6,10 @@ const Database = require('../Database')
const Playlist = require('../objects/Playlist')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class PlaylistController {

View File

@ -15,10 +15,10 @@ const CoverManager = require('../managers/CoverManager')
const LibraryItem = require('../objects/LibraryItem')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class PodcastController {
@ -129,7 +129,7 @@ class PodcastController {
* @typedef getPodcastFeedReqBody
* @property {string} rssFeed
*
* @param {Request<{}, {}, getPodcastFeedReqBody, {}> & RequestUserObjects} req
* @param {Request<{}, {}, getPodcastFeedReqBody, {}> & RequestUserObject} req
* @param {Response} res
*/
async getPodcastFeed(req, res) {

View File

@ -4,10 +4,10 @@ const Database = require('../Database')
const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class RSSFeedController {

View File

@ -8,10 +8,10 @@ const Database = require('../Database')
const { isValidASIN } = require('../utils')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class SearchController {

View File

@ -5,10 +5,10 @@ const Database = require('../Database')
const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class SeriesController {

View File

@ -6,10 +6,10 @@ const { toNumber, isUUID } = require('../utils/index')
const ShareManager = require('../managers/ShareManager')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class SessionController {
@ -206,7 +206,7 @@ class SessionController {
* @typedef batchDeleteReqBody
* @property {string[]} sessions
*
* @param {Request<{}, {}, batchDeleteReqBody, {}> & RequestUserObjects} req
* @param {Request<{}, {}, batchDeleteReqBody, {}> & RequestUserObject} req
* @param {Response} res
*/
async batchDelete(req, res) {

View File

@ -12,10 +12,10 @@ const PlaybackSession = require('../objects/PlaybackSession')
const ShareManager = require('../managers/ShareManager')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class ShareController {

View File

@ -3,10 +3,10 @@ const Logger = require('../Logger')
const Database = require('../Database')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class ToolsController {

View File

@ -9,16 +9,15 @@ const User = require('../objects/user/User')
const { toNumber } = require('../utils/index')
/**
* @typedef RequestUserObjects
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObjects} RequestWithUser
* @typedef {Request & RequestUserObject} RequestWithUser
*
* @typedef UserControllerRequestProps
* @property {import('../models/User')} user - User that made the request
* @property {import('../objects/user/User')} [reqUser] - User for req param id
* @typedef RequestEntityObject
* @property {import('../models/User')} reqUser
*
* @typedef {Request & UserControllerRequestProps} UserControllerRequest
* @typedef {RequestWithUser & RequestEntityObject} UserControllerRequest
*/
class UserController {
@ -26,7 +25,7 @@ class UserController {
/**
*
* @param {UserControllerRequest} req
* @param {RequestWithUser} req
* @param {Response} res
*/
async findAll(req, res) {
@ -100,7 +99,7 @@ class UserController {
return oldMediaProgress
})
const userJson = req.reqUser.toJSONForBrowser(!req.user.isRoot)
const userJson = req.reqUser.toOldJSONForBrowser(!req.user.isRoot)
userJson.mediaProgress = oldMediaProgresses
@ -122,7 +121,7 @@ class UserController {
const usernameExists = await Database.userModel.checkUserExistsWithUsername(username)
if (usernameExists) {
return res.status(500).send('Username already taken')
return res.status(400).send('Username already taken')
}
account.id = uuidv4()
@ -132,6 +131,7 @@ class UserController {
account.createdAt = Date.now()
const newUser = new User(account)
// TODO: Create with new User model
const success = await Database.createUser(newUser)
if (success) {
SocketAuthority.adminEmitter('user_added', newUser.toJSONForBrowser())
@ -147,6 +147,8 @@ class UserController {
* PATCH: /api/users/:id
* Update user
*
* @this {import('../routers/ApiRouter')}
*
* @param {UserControllerRequest} req
* @param {Response} res
*/
@ -158,12 +160,12 @@ class UserController {
return res.sendStatus(403)
}
var account = req.body
var shouldUpdateToken = false
const updatePayload = req.body
let shouldUpdateToken = false
// When changing username create a new API token
if (account.username !== undefined && account.username !== user.username) {
const usernameExists = await Database.userModel.checkUserExistsWithUsername(account.username)
if (updatePayload.username !== undefined && updatePayload.username !== user.username) {
const usernameExists = await Database.userModel.checkUserExistsWithUsername(updatePayload.username)
if (usernameExists) {
return res.status(500).send('Username already taken')
}
@ -171,23 +173,25 @@ class UserController {
}
// Updating password
if (account.password) {
account.pash = await this.auth.hashPass(account.password)
delete account.password
if (updatePayload.password) {
updatePayload.pash = await this.auth.hashPass(updatePayload.password)
delete updatePayload.password
}
if (user.update(account)) {
// TODO: Update with new User model
const oldUser = Database.userModel.getOldUser(user)
if (oldUser.update(updatePayload)) {
if (shouldUpdateToken) {
user.token = await this.auth.generateAccessToken(user)
Logger.info(`[UserController] User ${user.username} was generated a new api token`)
oldUser.token = await this.auth.generateAccessToken(oldUser)
Logger.info(`[UserController] User ${oldUser.username} has generated a new api token`)
}
await Database.updateUser(user)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', user.toJSONForBrowser())
await Database.updateUser(oldUser)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', oldUser.toJSONForBrowser())
}
res.json({
success: true,
user: user.toJSONForBrowser()
user: oldUser.toJSONForBrowser()
})
}
@ -221,8 +225,8 @@ class UserController {
await playlist.destroy()
}
const userJson = user.toJSONForBrowser()
await Database.removeUser(user.id)
const userJson = user.toOldJSONForBrowser()
await user.destroy()
SocketAuthority.adminEmitter('user_removed', userJson)
res.json({
success: true
@ -237,13 +241,16 @@ class UserController {
*/
async unlinkFromOpenID(req, res) {
Logger.debug(`[UserController] Unlinking user "${req.reqUser.username}" from OpenID with sub "${req.reqUser.authOpenIDSub}"`)
req.reqUser.authOpenIDSub = null
if (await Database.userModel.updateFromOld(req.reqUser)) {
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.reqUser.toJSONForBrowser())
res.sendStatus(200)
} else {
res.sendStatus(500)
if (!req.reqUser.authOpenIDSub) {
return res.sendStatus(200)
}
req.reqUser.extraData.authOpenIDSub = null
req.reqUser.changed('extraData', true)
await req.reqUser.save()
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.reqUser.toOldJSONForBrowser())
res.sendStatus(200)
}
/**
@ -318,8 +325,7 @@ class UserController {
}
if (req.params.id) {
// TODO: Update to use new user model
req.reqUser = await Database.userModel.getOldUserById(req.params.id)
req.reqUser = await Database.userModel.getUserById(req.params.id)
if (!req.reqUser) {
return res.sendStatus(404)
}

View File

@ -217,14 +217,6 @@ class User extends Model {
}
}
static removeById(userId) {
return this.destroy({
where: {
id: userId
}
})
}
/**
* Create root user
* @param {string} username

View File

@ -56,6 +56,7 @@ class ApiRouter {
this.cronManager = Server.cronManager
/** @type {import('../managers/NotificationManager')} */
this.notificationManager = Server.notificationManager
/** @type {import('../managers/EmailManager')} */
this.emailManager = Server.emailManager
this.apiCacheManager = Server.apiCacheManager