diff --git a/client/components/cards/AuthorCard.vue b/client/components/cards/AuthorCard.vue
index fddb9b55..430c5a86 100644
--- a/client/components/cards/AuthorCard.vue
+++ b/client/components/cards/AuthorCard.vue
@@ -20,6 +20,10 @@
{{ name }}
{{ numBooks }} Book{{ numBooks === 1 ? '' : 's' }}
+
+
+ search
+
@@ -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() {}
}
\ No newline at end of file
diff --git a/server/ApiController.js b/server/ApiController.js
index 89c19d4a..68adf139 100644
--- a/server/ApiController.js
+++ b/server/ApiController.js
@@ -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)
diff --git a/server/controllers/AuthorController.js b/server/controllers/AuthorController.js
new file mode 100644
index 00000000..52004f62
--- /dev/null
+++ b/server/controllers/AuthorController.js
@@ -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()
\ No newline at end of file
diff --git a/server/finders/AuthorFinder.js b/server/finders/AuthorFinder.js
index d4936a04..9504b698 100644
--- a/server/finders/AuthorFinder.js
+++ b/server/finders/AuthorFinder.js
@@ -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
diff --git a/server/objects/entities/Author.js b/server/objects/entities/Author.js
index 5f60d88f..4c1d4358 100644
--- a/server/objects/entities/Author.js
+++ b/server/objects/entities/Author.js
@@ -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
diff --git a/server/objects/entities/Series.js b/server/objects/entities/Series.js
index cf4450ce..18f3b4a3 100644
--- a/server/objects/entities/Series.js
+++ b/server/objects/entities/Series.js
@@ -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()
}