feat: localize server side errors

This commit is contained in:
Gauthier Roebroeck 2021-03-11 22:47:14 +08:00
parent 07cec50417
commit cbe47ea593
10 changed files with 74 additions and 20 deletions

13
ERRORCODES.md Normal file
View file

@ -0,0 +1,13 @@
# Error codes
Code | Description
---|---
ERR_1000 | File could not be accessed during analysis
ERR_1001 | Media type is not supported during analysis
ERR_1002 | Encrypted RAR archives are not supported
ERR_1003 | Solid RAR archives are not supported
ERR_1004 | Multi-Volume RAR archives are not supported
ERR_1005 | Unknown error while analyzing book
ERR_1006 | Book does not contain any page
ERR_1007 | Some entries could not be analyzed
ERR_1008 | Unknown error while getting book's entries

View file

@ -11,7 +11,9 @@ export function getBookFormatFromMediaType (mediaType: string): BookFormat {
return { type: 'PDF', color: '#FF5722' } return { type: 'PDF', color: '#FF5722' }
case 'application/epub+zip': case 'application/epub+zip':
return { type: 'EPUB', color: '#ff5ab1' } return { type: 'EPUB', color: '#ff5ab1' }
case 'application/x-rar-compressed; version=5':
return { type: 'RAR5', color: '#000000' }
default: default:
return { type: '?', color: '#000000' } return { type: mediaType, color: '#000000' }
} }
} }

View file

@ -0,0 +1,10 @@
import i18n from "@/i18n";
export function convertErrorCodes(message: string): string {
const match = message.match(/ERR_\d{4}/g)
let r = message
if(match){
match.forEach(x => r = r.replace(x, i18n.t(`error_codes.${x}`).toString()))
}
return r
}

View file

@ -243,6 +243,7 @@
"button_confirm_edit": "Edit", "button_confirm_edit": "Edit",
"dialog_title_add": "Add Library", "dialog_title_add": "Add Library",
"dialot_title_edit": "Edit Library", "dialot_title_edit": "Edit Library",
"field_import_barcode_isbn": "ISBN barcode",
"field_import_comicinfo_book": "Book metadata", "field_import_comicinfo_book": "Book metadata",
"field_import_comicinfo_collections": "Collections", "field_import_comicinfo_collections": "Collections",
"field_import_comicinfo_readlists": "Read lists", "field_import_comicinfo_readlists": "Read lists",
@ -256,14 +257,13 @@
"field_scanner_force_directory_modified_time": "Force directory modified time", "field_scanner_force_directory_modified_time": "Force directory modified time",
"file_browser_dialog_button_confirm": "Choose", "file_browser_dialog_button_confirm": "Choose",
"file_browser_dialog_title": "Library's root folder", "file_browser_dialog_title": "Library's root folder",
"label_import_barcode_isbn": "Import ISBN within barcode",
"label_import_comicinfo": "Import metadata for CBR/CBZ containing a ComicInfo.xml file", "label_import_comicinfo": "Import metadata for CBR/CBZ containing a ComicInfo.xml file",
"label_import_epub": "Import metadata from EPUB files", "label_import_epub": "Import metadata from EPUB files",
"label_import_local": "Import local media assets", "label_import_local": "Import local media assets",
"label_scanner": "Scanner", "label_scanner": "Scanner",
"tab_general": "General", "tab_general": "General",
"tab_options": "Options", "tab_options": "Options"
"field_import_barcode_isbn": "ISBN barcode",
"label_import_barcode_isbn": "Import ISBN within barcode"
}, },
"edit_readlist": { "edit_readlist": {
"button_cancel": "Cancel", "button_cancel": "Cancel",
@ -352,6 +352,17 @@
"ONGOING": "Ongoing" "ONGOING": "Ongoing"
} }
}, },
"error_codes": {
"ERR_1000": "File could not be accessed during analysis",
"ERR_1001": "Media type is not supported",
"ERR_1002": "Encrypted RAR archives are not supported",
"ERR_1003": "Solid RAR archives are not supported",
"ERR_1004": "Multi-Volume RAR archives are not supported",
"ERR_1005": "Unknown error while analyzing book",
"ERR_1006": "Book does not contain any page",
"ERR_1007": "Some entries could not be analyzed",
"ERR_1008": "Unknown error while getting book's entries"
},
"filter": { "filter": {
"age_rating": "age rating", "age_rating": "age rating",
"age_rating_none": "None", "age_rating_none": "None",

View file

@ -347,6 +347,17 @@
"ONGOING": "En cours" "ONGOING": "En cours"
} }
}, },
"error_codes": {
"ERR_1000": "Le fichier n'etait pas accessible pendant l'analyse",
"ERR_1001": "Le type de média n'est pas supporté",
"ERR_1002": "Les archives RAR encryptées ne sont pas supportées",
"ERR_1003": "Les archives RAR solides ne sont pas supportées",
"ERR_1004": "Les archives RAR multi-volumes ne sont pas supportées",
"ERR_1005": "Erreur inconnue pendant l'analyse",
"ERR_1006": "Le livre ne contient aucune page",
"ERR_1007": "Certaines entrées n'ont pas pu être analysées",
"ERR_1008": "Erreur inconnue pendant la recuperation des entrées"
},
"filter": { "filter": {
"age_rating": "Âge minimal", "age_rating": "Âge minimal",
"age_rating_none": "Aucun", "age_rating_none": "Aucun",

View file

@ -252,7 +252,7 @@
<v-row v-if="book.media.comment" class="align-center text-caption"> <v-row v-if="book.media.comment" class="align-center text-caption">
<v-col class="py-1" cols="4" sm="3" md="2" xl="1">{{ $t('browse_book.comment') }}</v-col> <v-col class="py-1" cols="4" sm="3" md="2" xl="1">{{ $t('browse_book.comment') }}</v-col>
<v-col class="py-1 error--text font-weight-bold" cols="8" sm="9" md="10" xl="11">{{ book.media.comment }}</v-col> <v-col class="py-1 error--text font-weight-bold" cols="8" sm="9" md="10" xl="11">{{ mediaComment }}</v-col>
</v-row> </v-row>
<v-row class="align-center text-caption"> <v-row class="align-center text-caption">
@ -294,6 +294,7 @@ import {SeriesDto} from "@/types/komga-series";
import ReadMore from "@/components/ReadMore.vue"; import ReadMore from "@/components/ReadMore.vue";
import VueHorizontal from "vue-horizontal"; import VueHorizontal from "vue-horizontal";
import {authorRoles} from "@/types/author-roles"; import {authorRoles} from "@/types/author-roles";
import {convertErrorCodes} from "@/functions/error-codes";
export default Vue.extend({ export default Vue.extend({
name: 'BrowseBook', name: 'BrowseBook',
@ -376,6 +377,9 @@ export default Vue.extend({
contextReadList(): boolean { contextReadList(): boolean {
return this.context.origin === ContextOrigin.READLIST return this.context.origin === ContextOrigin.READLIST
}, },
mediaComment(): string {
return convertErrorCodes(this.book.media.comment)
},
}, },
methods: { methods: {
libraryDeleted(event: EventLibraryDeleted) { libraryDeleted(event: EventLibraryDeleted) {

View file

@ -24,6 +24,7 @@
import Vue from 'vue' import Vue from 'vue'
import {MediaStatus} from '@/types/enum-books' import {MediaStatus} from '@/types/enum-books'
import {BookDto} from '@/types/komga-books' import {BookDto} from '@/types/komga-books'
import {convertErrorCodes} from "@/functions/error-codes";
export default Vue.extend({ export default Vue.extend({
name: 'SettingsMediaAnalysis', name: 'SettingsMediaAnalysis',
@ -59,6 +60,7 @@ export default Vue.extend({
...b, ...b,
media: { media: {
...b.media, ...b.media,
comment: convertErrorCodes(b.media.comment),
status: this.$t(`enums.media_status.${b.media.status}`).toString()}, status: this.$t(`enums.media_status.${b.media.status}`).toString()},
})) }))
}, },

View file

@ -1,9 +1,10 @@
package org.gotson.komga.domain.model package org.gotson.komga.domain.model
open class CodedException(message: String, val code: String) : Exception(message)
class MediaNotReadyException : Exception() class MediaNotReadyException : Exception()
class MediaUnsupportedException(message: String) : Exception(message) class MediaUnsupportedException(message: String, code: String = "") : CodedException(message, code)
class ImageConversionException(message: String) : Exception(message) class ImageConversionException(message: String, code: String = "") : CodedException(message, code)
class DirectoryNotFoundException(message: String) : Exception(message) class DirectoryNotFoundException(message: String, code: String = "") : CodedException(message, code)
class DuplicateNameException(message: String) : Exception(message) class DuplicateNameException(message: String, code: String = "") : CodedException(message, code)
class PathContainedInPath(message: String) : Exception(message) class PathContainedInPath(message: String, code: String = "") : CodedException(message, code)
class UserEmailAlreadyExistsException(message: String) : Exception(message) class UserEmailAlreadyExistsException(message: String, code: String = "") : CodedException(message, code)

View file

@ -36,15 +36,15 @@ class BookAnalyzer(
val mediaType = contentDetector.detectMediaType(book.path()) val mediaType = contentDetector.detectMediaType(book.path())
logger.info { "Detected media type: $mediaType" } logger.info { "Detected media type: $mediaType" }
if (!supportedMediaTypes.containsKey(mediaType)) if (!supportedMediaTypes.containsKey(mediaType))
return Media(mediaType = mediaType, status = Media.Status.UNSUPPORTED, comment = "Media type $mediaType is not supported") return Media(mediaType = mediaType, status = Media.Status.UNSUPPORTED, comment = "ERR_1001")
val entries = try { val entries = try {
supportedMediaTypes.getValue(mediaType).getEntries(book.path()) supportedMediaTypes.getValue(mediaType).getEntries(book.path())
} catch (ex: MediaUnsupportedException) { } catch (ex: MediaUnsupportedException) {
return Media(mediaType = mediaType, status = Media.Status.UNSUPPORTED, comment = ex.message) return Media(mediaType = mediaType, status = Media.Status.UNSUPPORTED, comment = ex.code)
} catch (ex: Exception) { } catch (ex: Exception) {
logger.error(ex) { "Error while analyzing book: $book" } logger.error(ex) { "Error while analyzing book: $book" }
return Media(mediaType = mediaType, status = Media.Status.ERROR, comment = ex.message) return Media(mediaType = mediaType, status = Media.Status.ERROR, comment = "ERR_1008")
} }
val (pages, others) = entries val (pages, others) = entries
@ -61,11 +61,11 @@ class BookAnalyzer(
.filter { it.mediaType.isNullOrBlank() } .filter { it.mediaType.isNullOrBlank() }
.map { it.name } .map { it.name }
.ifEmpty { null } .ifEmpty { null }
?.joinToString(prefix = "Some entries could not be analyzed: [", postfix = "]") { it } ?.joinToString(prefix = "ERR_1007 [", postfix = "]") { it }
if (pages.isEmpty()) { if (pages.isEmpty()) {
logger.warn { "Book $book does not contain any pages" } logger.warn { "Book $book does not contain any pages" }
return Media(mediaType = mediaType, status = Media.Status.ERROR, comment = "Book does not contain any pages") return Media(mediaType = mediaType, status = Media.Status.ERROR, comment = "ERR_1006")
} }
logger.info { "Book has ${pages.size} pages" } logger.info { "Book has ${pages.size} pages" }

View file

@ -27,9 +27,9 @@ class RarExtractor(
override fun getEntries(path: Path): List<MediaContainerEntry> = override fun getEntries(path: Path): List<MediaContainerEntry> =
Archive(path.toFile()).use { rar -> Archive(path.toFile()).use { rar ->
if (rar.isPasswordProtected) throw MediaUnsupportedException("Encrypted RAR archives are not supported") if (rar.isPasswordProtected) throw MediaUnsupportedException("Encrypted RAR archives are not supported", "ERR_1002")
if (rar.mainHeader.isSolid) throw MediaUnsupportedException("Solid RAR archives are not supported") if (rar.mainHeader.isSolid) throw MediaUnsupportedException("Solid RAR archives are not supported", "ERR_1003")
if (rar.mainHeader.isMultiVolume) throw MediaUnsupportedException("Multi-Volume RAR archives are not supported") if (rar.mainHeader.isMultiVolume) throw MediaUnsupportedException("Multi-Volume RAR archives are not supported", "ERR_1004")
rar.fileHeaders rar.fileHeaders
.filter { !it.isDirectory } .filter { !it.isDirectory }
.map { hd -> .map { hd ->