New data model authors routes

This commit is contained in:
advplyr 2022-03-13 06:42:43 -05:00
parent 65df377a49
commit dad12537b6
6 changed files with 102 additions and 65 deletions

View File

@ -20,6 +20,10 @@
<p class="text-center font-semibold truncate" :style="{ fontSize: sizeMultiplier + 'rem' }">{{ name }}</p>
<p class="text-center text-gray-200" :style="{ fontSize: sizeMultiplier * 0.85 + 'rem' }">{{ numBooks }} Book{{ numBooks === 1 ? '' : 's' }}</p>
</div>
<div class="absolute top-0 right-0 p-2 cursor-pointer hover:text-white text-gray-200" @click.stop="searchAuthor">
<span class="material-icons">search</span>
</div>
</div>
</div>
</div>
@ -74,7 +78,15 @@ export default {
return url.href + `?token=${this.userToken}&ts=${this.lastUpdate}`
}
},
methods: {},
methods: {
async searchAuthor() {
var author = await this.$axios.$post(`/api/authors/${this.authorId}/match`, { q: this.name }).catch((error) => {
console.error('Failed', error)
return null
})
console.log('Got author', author)
}
},
mounted() {}
}
</script>

View File

@ -16,6 +16,7 @@ const MeController = require('./controllers/MeController')
const BackupController = require('./controllers/BackupController')
const LibraryItemController = require('./controllers/LibraryItemController')
const SeriesController = require('./controllers/SeriesController')
const AuthorController = require('./controllers/AuthorController')
const BookFinder = require('./finders/BookFinder')
const AuthorFinder = require('./finders/AuthorFinder')
@ -161,12 +162,9 @@ class ApiController {
//
// Author Routes
//
this.router.get('/authors', this.getAuthors.bind(this))
this.router.get('/authors/search', this.searchAuthors.bind(this))
this.router.get('/authors/:id', this.getAuthor.bind(this))
this.router.post('/authors', this.createAuthor.bind(this))
this.router.patch('/authors/:id', this.updateAuthor.bind(this))
this.router.delete('/authors/:id', this.deleteAuthor.bind(this))
this.router.get('/authors/:id', AuthorController.middleware.bind(this), AuthorController.findOne.bind(this))
this.router.post('/authors/:id/match', AuthorController.middleware.bind(this), AuthorController.match.bind(this))
this.router.get('/authors/search', AuthorController.search.bind(this))
//
// Series Routes
@ -230,64 +228,6 @@ class ApiController {
res.json({ user: req.user })
}
async getAuthors(req, res) {
res.json(this.db.authors)
}
searchAuthors(req, res) {
var query = req.query.q || ''
var limit = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 100
var authors = this.db.authors.filter(au => au.name.toLowerCase().includes(query.toLowerCase()))
authors = authors.slice(0, limit)
res.json(authors)
}
async getAuthor(req, res) {
var author = this.db.authors.find(p => p.id === req.params.id)
if (!author) {
return res.status(404).send('Author not found')
}
res.json(author.toJSON())
}
async createAuthor(req, res) {
var author = await this.authorFinder.createAuthor(req.body)
if (!author) {
return res.status(500).send('Failed to create author')
}
await this.db.insertEntity('author', author)
this.emitter('author_added', author.toJSON())
res.json(author)
}
async updateAuthor(req, res) {
var author = this.db.authors.find(p => p.id === req.params.id)
if (!author) {
return res.status(404).send('Author not found')
}
var wasUpdated = author.update(req.body)
if (wasUpdated) {
await this.db.updateEntity('author', author)
this.emitter('author_updated', author.toJSON())
}
res.json(author)
}
async deleteAuthor(req, res) {
var author = this.db.authors.find(p => p.id === req.params.id)
if (!author) {
return res.status(404).send('Author not found')
}
var authorJson = author.toJSON()
await this.db.removeEntity('author', author.id)
this.emitter('author_removed', authorJson)
res.sendStatus(200)
}
async updateServerSettings(req, res) {
if (!req.user.isRoot) {
Logger.error('User other than root attempting to update server settings', req.user)

View File

@ -0,0 +1,56 @@
const Logger = require('../Logger')
class AuthorController {
constructor() { }
async findOne(req, res) {
return res.json(req.author)
}
async search(req, res) {
var q = (req.query.q || '').toLowerCase()
if (!q) return res.json([])
var limit = (req.query.limit && !isNaN(req.query.limit)) ? Number(req.query.limit) : 25
var authors = this.db.authors.filter(au => au.name.toLowerCase().includes(q))
authors = authors.slice(0, limit)
res.json(authors)
}
async match(req, res) {
var authorData = await this.authorFinder.findAuthorByName(req.body.q)
if (!authorData) {
return res.status(404).send('Author not found')
}
req.author.asin = authorData.asin
if (authorData.image) {
var imageData = await this.authorFinder.saveAuthorImage(req.author.id, authorData.image)
if (imageData) {
req.author.imagePath = imageData.path
req.author.relImagePath = imageData.relPath
}
}
if (authorData.description) {
req.author.description = authorData.description
}
await this.db.updateEntity('author', req.author)
this.emitter('author_updated', req.author)
res.json(req.author)
}
middleware(req, res, next) {
var author = this.db.authors.find(au => au.id === req.params.id)
if (!author) return res.sendStatus(404)
if (req.method == 'DELETE' && !req.user.canDelete) {
Logger.warn(`[AuthorController] User attempted to delete without permission`, req.user)
return res.sendStatus(403)
} else if ((req.method == 'PATCH' || req.method == 'POST') && !req.user.canUpdate) {
Logger.warn('[AuthorController] User attempted to update without permission', req.user)
return res.sendStatus(403)
}
req.author = author
next()
}
}
module.exports = new AuthorController()

View File

@ -31,6 +31,27 @@ class AuthorFinder {
return author
}
async saveAuthorImage(authorId, url) {
var authorDir = this.AuthorPath
var relAuthorDir = Path.posix.join('/metadata', 'authors')
await fs.ensureDir(authorDir)
var imageExtension = url.toLowerCase().split('.').pop()
var ext = imageExtension === 'png' ? 'png' : 'jpg'
var filename = authorId + '.' + ext
var outputPath = Path.posix.join(authorDir, filename)
var relPath = Path.posix.join(relAuthorDir, filename)
var success = await this.downloadImage(url, outputPath)
if (!success) {
return null
}
return {
path: outputPath,
relPath
}
}
async createAuthor(payload) {
if (!payload || !payload.name) return null

View File

@ -5,6 +5,7 @@ class Author {
this.id = null
this.asin = null
this.name = null
this.description = null
this.imagePath = null
this.relImagePath = null
this.addedAt = null
@ -19,6 +20,7 @@ class Author {
this.id = author.id
this.asin = author.asin
this.name = author.name
this.description = author.description || null
this.imagePath = author.imagePath
this.relImagePath = author.relImagePath
this.addedAt = author.addedAt
@ -30,6 +32,7 @@ class Author {
id: this.id,
asin: this.asin,
name: this.name,
description: this.description,
imagePath: this.imagePath,
relImagePath: this.relImagePath,
addedAt: this.addedAt,
@ -47,6 +50,7 @@ class Author {
setData(data) {
this.id = getId('aut')
this.name = data.name
this.description = data.description || null
this.asin = data.asin || null
this.imagePath = data.imagePath || null
this.relImagePath = data.relImagePath || null

View File

@ -4,6 +4,7 @@ class Series {
constructor(series) {
this.id = null
this.name = null
this.description = null
this.addedAt = null
this.updatedAt = null
@ -15,6 +16,7 @@ class Series {
construct(series) {
this.id = series.id
this.name = series.name
this.description = series.description || null
this.addedAt = series.addedAt
this.updatedAt = series.updatedAt
}
@ -23,6 +25,7 @@ class Series {
return {
id: this.id,
name: this.name,
description: this.description,
addedAt: this.addedAt,
updatedAt: this.updatedAt
}
@ -39,6 +42,7 @@ class Series {
setData(data) {
this.id = getId('ser')
this.name = data.name
this.description = data.description || null
this.addedAt = Date.now()
this.updatedAt = Date.now()
}