Skip to content

Commit ba74256

Browse files
committed
Remove old Author object & fix issue deleting empty authors
1 parent acc4bdb commit ba74256

File tree

13 files changed

+227
-314
lines changed

13 files changed

+227
-314
lines changed

server/Database.js

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -462,26 +462,6 @@ class Database {
462462
await this.models.series.removeById(seriesId)
463463
}
464464

465-
async createAuthor(oldAuthor) {
466-
if (!this.sequelize) return false
467-
await this.models.author.createFromOld(oldAuthor)
468-
}
469-
470-
async createBulkAuthors(oldAuthors) {
471-
if (!this.sequelize) return false
472-
await this.models.author.createBulkFromOld(oldAuthors)
473-
}
474-
475-
updateAuthor(oldAuthor) {
476-
if (!this.sequelize) return false
477-
return this.models.author.updateFromOld(oldAuthor)
478-
}
479-
480-
async removeAuthor(authorId) {
481-
if (!this.sequelize) return false
482-
await this.models.author.removeById(authorId)
483-
}
484-
485465
async createBulkBookAuthors(bookAuthors) {
486466
if (!this.sequelize) return false
487467
await this.models.bookAuthor.bulkCreate(bookAuthors)
@@ -684,7 +664,7 @@ class Database {
684664
*/
685665
async getAuthorIdByName(libraryId, authorName) {
686666
if (!this.libraryFilterData[libraryId]) {
687-
return (await this.authorModel.getOldByNameAndLibrary(authorName, libraryId))?.id || null
667+
return (await this.authorModel.getByNameAndLibrary(authorName, libraryId))?.id || null
688668
}
689669
return this.libraryFilterData[libraryId].authors.find((au) => au.name === authorName)?.id || null
690670
}

server/controllers/AuthorController.js

Lines changed: 86 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ const naturalSort = createNewSortInstance({
2121
* @property {import('../models/User')} user
2222
*
2323
* @typedef {Request & RequestUserObject} RequestWithUser
24+
*
25+
* @typedef RequestEntityObject
26+
* @property {import('../models/Author')} author
27+
*
28+
* @typedef {RequestWithUser & RequestEntityObject} AuthorControllerRequest
2429
*/
2530

2631
class AuthorController {
@@ -29,13 +34,13 @@ class AuthorController {
2934
/**
3035
* GET: /api/authors/:id
3136
*
32-
* @param {RequestWithUser} req
37+
* @param {AuthorControllerRequest} req
3338
* @param {Response} res
3439
*/
3540
async findOne(req, res) {
3641
const include = (req.query.include || '').split(',')
3742

38-
const authorJson = req.author.toJSON()
43+
const authorJson = req.author.toOldJSON()
3944

4045
// Used on author landing page to include library items and items grouped in series
4146
if (include.includes('items')) {
@@ -80,33 +85,37 @@ class AuthorController {
8085
/**
8186
* PATCH: /api/authors/:id
8287
*
83-
* @param {RequestWithUser} req
88+
* @param {AuthorControllerRequest} req
8489
* @param {Response} res
8590
*/
8691
async update(req, res) {
87-
const payload = req.body
88-
let hasUpdated = false
89-
90-
// author imagePath must be set through other endpoints as of v2.4.5
91-
if (payload.imagePath !== undefined) {
92-
Logger.warn(`[AuthorController] Updating local author imagePath is not supported`)
93-
delete payload.imagePath
92+
const keysToUpdate = ['name', 'description', 'asin']
93+
const payload = {}
94+
for (const key in req.body) {
95+
if (keysToUpdate.includes(key) && (typeof req.body[key] === 'string' || req.body[key] === null)) {
96+
payload[key] = req.body[key]
97+
}
9498
}
99+
if (!Object.keys(payload).length) {
100+
Logger.error(`[AuthorController] Invalid request payload. No valid keys found`, req.body)
101+
return res.status(400).send('Invalid request payload. No valid keys found')
102+
}
103+
104+
let hasUpdated = false
95105

96106
const authorNameUpdate = payload.name !== undefined && payload.name !== req.author.name
97107

98108
// Check if author name matches another author and merge the authors
99109
let existingAuthor = null
100110
if (authorNameUpdate) {
101-
const author = await Database.authorModel.findOne({
111+
existingAuthor = await Database.authorModel.findOne({
102112
where: {
103113
id: {
104114
[sequelize.Op.not]: req.author.id
105115
},
106116
name: payload.name
107117
}
108118
})
109-
existingAuthor = author?.getOldAuthor()
110119
}
111120
if (existingAuthor) {
112121
Logger.info(`[AuthorController] Merging author "${req.author.name}" with "${existingAuthor.name}"`)
@@ -143,86 +152,87 @@ class AuthorController {
143152
}
144153

145154
// Remove old author
146-
await Database.removeAuthor(req.author.id)
147-
SocketAuthority.emitter('author_removed', req.author.toJSON())
155+
const oldAuthorJSON = req.author.toOldJSON()
156+
await req.author.destroy()
157+
SocketAuthority.emitter('author_removed', oldAuthorJSON)
148158
// Update filter data
149-
Database.removeAuthorFromFilterData(req.author.libraryId, req.author.id)
159+
Database.removeAuthorFromFilterData(oldAuthorJSON.libraryId, oldAuthorJSON.id)
150160

151161
// Send updated num books for merged author
152162
const numBooks = await Database.bookAuthorModel.getCountForAuthor(existingAuthor.id)
153-
SocketAuthority.emitter('author_updated', existingAuthor.toJSONExpanded(numBooks))
163+
SocketAuthority.emitter('author_updated', existingAuthor.toOldJSONExpanded(numBooks))
154164

155165
res.json({
156-
author: existingAuthor.toJSON(),
166+
author: existingAuthor.toOldJSON(),
157167
merged: true
158168
})
159-
} else {
160-
// Regular author update
161-
if (req.author.update(payload)) {
162-
hasUpdated = true
163-
}
164-
165-
if (hasUpdated) {
166-
req.author.updatedAt = Date.now()
169+
return
170+
}
167171

168-
let numBooksForAuthor = 0
169-
if (authorNameUpdate) {
170-
const allItemsWithAuthor = await Database.authorModel.getAllLibraryItemsForAuthor(req.author.id)
172+
// Regular author update
173+
req.author.set(payload)
174+
if (req.author.changed()) {
175+
await req.author.save()
176+
hasUpdated = true
177+
}
171178

172-
numBooksForAuthor = allItemsWithAuthor.length
173-
const oldLibraryItems = []
174-
// Update author name on all books
175-
for (const libraryItem of allItemsWithAuthor) {
176-
libraryItem.media.authors = libraryItem.media.authors.map((au) => {
177-
if (au.id === req.author.id) {
178-
au.name = req.author.name
179-
}
180-
return au
181-
})
182-
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem)
183-
oldLibraryItems.push(oldLibraryItem)
179+
if (hasUpdated) {
180+
let numBooksForAuthor = 0
181+
if (authorNameUpdate) {
182+
const allItemsWithAuthor = await Database.authorModel.getAllLibraryItemsForAuthor(req.author.id)
184183

185-
await libraryItem.saveMetadataFile()
186-
}
184+
numBooksForAuthor = allItemsWithAuthor.length
185+
const oldLibraryItems = []
186+
// Update author name on all books
187+
for (const libraryItem of allItemsWithAuthor) {
188+
libraryItem.media.authors = libraryItem.media.authors.map((au) => {
189+
if (au.id === req.author.id) {
190+
au.name = req.author.name
191+
}
192+
return au
193+
})
194+
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem)
195+
oldLibraryItems.push(oldLibraryItem)
187196

188-
if (oldLibraryItems.length) {
189-
SocketAuthority.emitter(
190-
'items_updated',
191-
oldLibraryItems.map((li) => li.toJSONExpanded())
192-
)
193-
}
194-
} else {
195-
numBooksForAuthor = await Database.bookAuthorModel.getCountForAuthor(req.author.id)
197+
await libraryItem.saveMetadataFile()
196198
}
197199

198-
await Database.updateAuthor(req.author)
199-
SocketAuthority.emitter('author_updated', req.author.toJSONExpanded(numBooksForAuthor))
200+
if (oldLibraryItems.length) {
201+
SocketAuthority.emitter(
202+
'items_updated',
203+
oldLibraryItems.map((li) => li.toJSONExpanded())
204+
)
205+
}
206+
} else {
207+
numBooksForAuthor = await Database.bookAuthorModel.getCountForAuthor(req.author.id)
200208
}
201209

202-
res.json({
203-
author: req.author.toJSON(),
204-
updated: hasUpdated
205-
})
210+
SocketAuthority.emitter('author_updated', req.author.toOldJSONExpanded(numBooksForAuthor))
206211
}
212+
213+
res.json({
214+
author: req.author.toOldJSON(),
215+
updated: hasUpdated
216+
})
207217
}
208218

209219
/**
210220
* DELETE: /api/authors/:id
211221
* Remove author from all books and delete
212222
*
213-
* @param {RequestWithUser} req
223+
* @param {AuthorControllerRequest} req
214224
* @param {Response} res
215225
*/
216226
async delete(req, res) {
217227
Logger.info(`[AuthorController] Removing author "${req.author.name}"`)
218228

219-
await Database.authorModel.removeById(req.author.id)
220-
221229
if (req.author.imagePath) {
222230
await CacheManager.purgeImageCache(req.author.id) // Purge cache
223231
}
224232

225-
SocketAuthority.emitter('author_removed', req.author.toJSON())
233+
await req.author.destroy()
234+
235+
SocketAuthority.emitter('author_removed', req.author.toOldJSON())
226236

227237
// Update filter data
228238
Database.removeAuthorFromFilterData(req.author.libraryId, req.author.id)
@@ -234,7 +244,7 @@ class AuthorController {
234244
* POST: /api/authors/:id/image
235245
* Upload author image from web URL
236246
*
237-
* @param {RequestWithUser} req
247+
* @param {AuthorControllerRequest} req
238248
* @param {Response} res
239249
*/
240250
async uploadImage(req, res) {
@@ -265,21 +275,22 @@ class AuthorController {
265275
}
266276

267277
req.author.imagePath = result.path
268-
req.author.updatedAt = Date.now()
269-
await Database.authorModel.updateFromOld(req.author)
278+
// imagePath may not have changed, but we still want to update the updatedAt field to bust image cache
279+
req.author.changed('imagePath', true)
280+
await req.author.save()
270281

271282
const numBooks = await Database.bookAuthorModel.getCountForAuthor(req.author.id)
272-
SocketAuthority.emitter('author_updated', req.author.toJSONExpanded(numBooks))
283+
SocketAuthority.emitter('author_updated', req.author.toOldJSONExpanded(numBooks))
273284
res.json({
274-
author: req.author.toJSON()
285+
author: req.author.toOldJSON()
275286
})
276287
}
277288

278289
/**
279290
* DELETE: /api/authors/:id/image
280291
* Remove author image & delete image file
281292
*
282-
* @param {RequestWithUser} req
293+
* @param {AuthorControllerRequest} req
283294
* @param {Response} res
284295
*/
285296
async deleteImage(req, res) {
@@ -291,19 +302,19 @@ class AuthorController {
291302
await CacheManager.purgeImageCache(req.author.id) // Purge cache
292303
await CoverManager.removeFile(req.author.imagePath)
293304
req.author.imagePath = null
294-
await Database.authorModel.updateFromOld(req.author)
305+
await req.author.save()
295306

296307
const numBooks = await Database.bookAuthorModel.getCountForAuthor(req.author.id)
297-
SocketAuthority.emitter('author_updated', req.author.toJSONExpanded(numBooks))
308+
SocketAuthority.emitter('author_updated', req.author.toOldJSONExpanded(numBooks))
298309
res.json({
299-
author: req.author.toJSON()
310+
author: req.author.toOldJSON()
300311
})
301312
}
302313

303314
/**
304315
* POST: /api/authors/:id/match
305316
*
306-
* @param {RequestWithUser} req
317+
* @param {AuthorControllerRequest} req
307318
* @param {Response} res
308319
*/
309320
async match(req, res) {
@@ -342,24 +353,22 @@ class AuthorController {
342353
}
343354

344355
if (hasUpdates) {
345-
req.author.updatedAt = Date.now()
346-
347-
await Database.updateAuthor(req.author)
356+
await req.author.save()
348357

349358
const numBooks = await Database.bookAuthorModel.getCountForAuthor(req.author.id)
350-
SocketAuthority.emitter('author_updated', req.author.toJSONExpanded(numBooks))
359+
SocketAuthority.emitter('author_updated', req.author.toOldJSONExpanded(numBooks))
351360
}
352361

353362
res.json({
354363
updated: hasUpdates,
355-
author: req.author
364+
author: req.author.toOldJSON()
356365
})
357366
}
358367

359368
/**
360369
* GET: /api/authors/:id/image
361370
*
362-
* @param {RequestWithUser} req
371+
* @param {AuthorControllerRequest} req
363372
* @param {Response} res
364373
*/
365374
async getImage(req, res) {
@@ -392,7 +401,7 @@ class AuthorController {
392401
* @param {NextFunction} next
393402
*/
394403
async middleware(req, res, next) {
395-
const author = await Database.authorModel.getOldById(req.params.id)
404+
const author = await Database.authorModel.findByPk(req.params.id)
396405
if (!author) return res.sendStatus(404)
397406

398407
if (req.method == 'DELETE' && !req.user.canDelete) {

server/controllers/LibraryController.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -887,8 +887,7 @@ class LibraryController {
887887
const oldAuthors = []
888888

889889
for (const author of authors) {
890-
const oldAuthor = author.getOldAuthor().toJSON()
891-
oldAuthor.numBooks = author.books.length
890+
const oldAuthor = author.toOldJSONExpanded(author.books.length)
892891
oldAuthor.lastFirst = author.lastFirst
893892
oldAuthors.push(oldAuthor)
894893
}

0 commit comments

Comments
 (0)