mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-09-13 04:08:22 +02:00
exception handling and exception improvements (#3858)
# Description of Changes This pull request introduces several improvements to enhance error handling, internationalization, and documentation in the codebase. The key changes include the addition of `ExceptionUtils` and `I18nUtils` utility classes for consistent exception handling and internationalized messages, updates to documentation paths, and modifications to existing methods to integrate the new utilities. ### Error Handling Enhancements: * **Added `ExceptionUtils` utility class**: Provides standardized methods for creating and handling exceptions with internationalized error messages, including specific handling for PDF corruption, encryption issues, and other file-related errors. * **Integrated `ExceptionUtils` into `CustomPDFDocumentFactory`**: Updated `loadFromFile` and `loadFromBytes` methods to log and handle exceptions using `ExceptionUtils`, ensuring consistent error handling across PDF operations. [[1]](diffhunk://#diff-10208c1fc2e04631a8cf2a2a99b2a1160e532e75a7b840ad752f3b0130b89851R358-R363) [[2]](diffhunk://#diff-10208c1fc2e04631a8cf2a2a99b2a1160e532e75a7b840ad752f3b0130b89851R375-R381) * **Updated `FileToPdf` to use `ExceptionUtils`**: Replaced direct exception throwing with `ExceptionUtils.createHtmlFileRequiredException` for unsupported file formats. ### Internationalization Improvements: * **Added `I18nUtils` utility class**: Centralized access to Spring's `MessageSource` for retrieving localized messages, enabling consistent internationalization across the application. ### Documentation Updates: * **Updated documentation paths in `CONTRIBUTING.md` and `README.md`**: Changed paths to reference the new `devGuide` folder for developer documentation and translation guides. [[1]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L28-R28) [[2]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L40-R51) [[3]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L171-L174) --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details. --------- Co-authored-by: a <a>
This commit is contained in:
@@ -170,6 +170,67 @@ sizes.medium=Medium
|
||||
sizes.large=Large
|
||||
sizes.x-large=X-Large
|
||||
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
||||
error.pdfCorrupted=PDF file appears to be corrupted or damaged. Please try using the 'Repair PDF' feature first to fix the file before proceeding with this operation.
|
||||
error.pdfCorruptedMultiple=One or more PDF files appear to be corrupted or damaged. Please try using the 'Repair PDF' feature on each file first before attempting to merge them.
|
||||
error.pdfCorruptedDuring=Error {0}: PDF file appears to be corrupted or damaged. Please try using the 'Repair PDF' feature first to fix the file before proceeding with this operation.
|
||||
|
||||
# Frontend corruption error messages
|
||||
error.pdfInvalid=The PDF file "{0}" appears to be corrupted or has an invalid structure. Please try using the 'Repair PDF' feature to fix the file before proceeding.
|
||||
error.tryRepair=Try using the Repair PDF feature to fix corrupted files.
|
||||
|
||||
# Additional error messages
|
||||
error.pdfEncryption=The PDF appears to have corrupted encryption data. This can happen when the PDF was created with incompatible encryption methods. Please try using the 'Repair PDF' feature first, or contact the document creator for a new copy.
|
||||
error.fileProcessing=An error occurred while processing the file during {0} operation: {1}
|
||||
|
||||
# Generic error message templates
|
||||
error.toolNotInstalled={0} is not installed
|
||||
error.toolRequired={0} is required for {1}
|
||||
error.conversionFailed={0} conversion failed
|
||||
error.commandFailed={0} command failed
|
||||
error.algorithmNotAvailable={0} algorithm not available
|
||||
error.optionsNotSpecified={0} options are not specified
|
||||
error.fileFormatRequired=File must be in {0} format
|
||||
error.invalidFormat=Invalid {0} format: {1}
|
||||
error.endpointDisabled=This endpoint has been disabled by the admin
|
||||
error.urlNotReachable=URL is not reachable, please provide a valid URL
|
||||
|
||||
# DPI and image rendering messages - used by frontend for dynamic translation
|
||||
# Backend sends: [TRANSLATE:messageKey:arg1,arg2] English message
|
||||
# Frontend parses this and replaces with localized versions using these keys
|
||||
error.dpiExceedsLimit=DPI value {0} exceeds maximum safe limit of {1}. High DPI values can cause memory issues and crashes. Please use a lower DPI value.
|
||||
error.pageTooBigForDpi=PDF page {0} is too large to render at {1} DPI. Please try a lower DPI value (recommended: 150 or less).
|
||||
error.pageTooBigExceedsArray=PDF page {0} is too large to render at {1} DPI. The resulting image would exceed Java's maximum array size. Please try a lower DPI value (recommended: 150 or less).
|
||||
error.pageTooBigFor300Dpi=PDF page {0} is too large to render at 300 DPI. The resulting image would exceed Java's maximum array size. Please use a lower DPI value for PDF-to-image conversion.
|
||||
|
||||
# URL and website conversion messages
|
||||
|
||||
# System requirements messages
|
||||
|
||||
# Authentication and security messages
|
||||
error.apiKeyInvalid=API key is not valid.
|
||||
error.userNotFound=User not found.
|
||||
error.passwordRequired=Password must not be null.
|
||||
error.accountLocked=Your account has been locked due to too many failed login attempts.
|
||||
error.invalidEmail=Invalid email addresses provided.
|
||||
error.emailAttachmentRequired=An attachment is required to send the email.
|
||||
error.signatureNotFound=Signature file not found.
|
||||
|
||||
# File processing messages
|
||||
error.fileNotFound=File not found with ID: {0}
|
||||
|
||||
# Database and configuration messages
|
||||
error.noBackupScripts=No backup scripts were found.
|
||||
error.unsupportedProvider={0} is not currently supported.
|
||||
error.pathTraversalDetected=Path traversal detected for security reasons.
|
||||
|
||||
# Validation messages
|
||||
error.invalidArgument=Invalid argument: {0}
|
||||
error.argumentRequired={0} must not be null
|
||||
error.operationFailed=Operation failed: {0}
|
||||
error.angleNotMultipleOf90=Angle must be a multiple of 90
|
||||
error.pdfBookmarksNotFound=No PDF bookmarks/outline found in document
|
||||
error.fontLoadingFailed=Error processing font file
|
||||
error.fontDirectoryReadFailed=Failed to read font directory
|
||||
delete=Delete
|
||||
username=Username
|
||||
password=Password
|
||||
|
||||
@@ -125,6 +125,16 @@ export class DecryptFile {
|
||||
} else if (error.code === pdfjsLib.PasswordResponses.INCORRECT_PASSWORD) {
|
||||
return {isEncrypted: true, requiresPassword: false};
|
||||
}
|
||||
} else if (error.name === 'InvalidPDFException' ||
|
||||
(error.message && error.message.includes('Invalid PDF structure'))) {
|
||||
// Handle corrupted PDF files
|
||||
console.error('Corrupted PDF detected:', error);
|
||||
this.showErrorBanner(
|
||||
`${window.stirlingPDF.pdfCorruptedMessage.replace('{0}', file.name)}`,
|
||||
error.stack || '',
|
||||
`${window.stirlingPDF.tryRepairMessage}`
|
||||
);
|
||||
throw new Error('PDF file is corrupted.');
|
||||
}
|
||||
|
||||
console.error('Error checking encryption:', error);
|
||||
|
||||
@@ -193,13 +193,13 @@
|
||||
if (error.name === 'PasswordException' && error.code === 1) {
|
||||
console.log(`PDF requires password: ${file.name}`, error);
|
||||
console.log(`Attempting to remove password from PDF: ${file.name} with password.`);
|
||||
const password = prompt(`${window.translations.decrypt.passwordPrompt}`);
|
||||
const password = prompt(`${window.decrypt.passwordPrompt}`);
|
||||
|
||||
if (!password) {
|
||||
console.error(`No password provided for encrypted PDF: ${file.name}`);
|
||||
showErrorBanner(
|
||||
`${window.translations.decrypt.noPassword.replace('{0}', file.name)}`,
|
||||
`${window.translations.decrypt.unexpectedError}`
|
||||
`${window.decrypt.noPassword.replace('{0}', file.name)}`,
|
||||
`${window.decrypt.unexpectedError}`
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
@@ -233,11 +233,20 @@
|
||||
} catch (decryptError) {
|
||||
console.error(`Failed to decrypt PDF: ${file.name}`, decryptError);
|
||||
showErrorBanner(
|
||||
`${window.translations.invalidPasswordHeader.replace('{0}', file.name)}`,
|
||||
`${window.translations.invalidPassword}`
|
||||
`${window.decrypt.invalidPasswordHeader.replace('{0}', file.name)}`,
|
||||
`${window.decrypt.invalidPassword}`
|
||||
);
|
||||
throw decryptError;
|
||||
}
|
||||
} else if (error.name === 'InvalidPDFException' ||
|
||||
(error.message && error.message.includes('Invalid PDF structure'))) {
|
||||
// Handle corrupted PDF files
|
||||
console.log(`Corrupted PDF detected: ${file.name}`, error);
|
||||
showErrorBanner(
|
||||
`${window.stirlingPDF.pdfCorruptedMessage.replace('{0}', file.name)}`,
|
||||
`${window.stirlingPDF.tryRepairMessage}`
|
||||
);
|
||||
throw error;
|
||||
} else {
|
||||
console.log(`Error loading PDF: ${file.name}`, error);
|
||||
throw error;
|
||||
|
||||
@@ -235,6 +235,13 @@ function setupFileInput(chooser) {
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error decrypting file: ${file.name}`, error);
|
||||
|
||||
// Check if this is a PDF corruption error
|
||||
if (error.message && error.message.includes('PDF file is corrupted')) {
|
||||
// The error banner is already shown by DecryptFiles.js, just continue with the file
|
||||
console.warn(`Continuing with corrupted PDF file: ${file.name}`);
|
||||
}
|
||||
|
||||
if (!file.uniqueId) file.uniqueId = UUID.uuidv4();
|
||||
return file;
|
||||
}
|
||||
|
||||
@@ -250,6 +250,8 @@
|
||||
window.stirlingPDF.uploadLimit = /*[[${@uploadLimitService.getUploadLimit()}]]*/ 0;
|
||||
window.stirlingPDF.uploadLimitExceededSingular = /*[[#{uploadLimitExceededSingular}]]*/ 'is too large. Maximum allowed size is';
|
||||
window.stirlingPDF.uploadLimitExceededPlural = /*[[#{uploadLimitExceededPlural}]]*/ 'are too large. Maximum allowed size is';
|
||||
window.stirlingPDF.pdfCorruptedMessage = /*[[#{error.pdfInvalid}]]*/ 'The PDF file "{0}" appears to be corrupted or has an invalid structure. Please try using the \'Repair PDF\' feature to fix the file before proceeding.';
|
||||
window.stirlingPDF.tryRepairMessage = /*[[#{error.tryRepair}]]*/ 'Try using the Repair PDF feature to fix corrupted files.';
|
||||
})();
|
||||
</script>
|
||||
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
||||
|
||||
@@ -37,10 +37,10 @@
|
||||
</div>
|
||||
<div class="recent-features">
|
||||
<div class="newfeature"
|
||||
th:insert="~{fragments/navbarEntryCustom :: navbarEntry('redact', '/images/redact-manual.svg#icon-redact-manual', 'home.redact.title', 'home.redact.desc', 'redact.tags', 'security')}">
|
||||
th:insert="~{fragments/navbarEntry :: navbarEntry('add-attachments', 'attachment', 'home.attachments.title', 'home.attachments.desc', 'attachments.tags', 'other')}">
|
||||
</div>
|
||||
<div class="newfeature"
|
||||
th:insert="~{fragments/navbarEntry :: navbarEntry ('multi-tool', 'construction', 'home.multiTool.title', 'home.multiTool.desc', 'multiTool.tags', 'organize')}">
|
||||
th:insert="~{fragments/navbarEntry :: navbarEntry('fake-scan', 'scanner', 'fakeScan.title', 'fakeScan.description', 'fakeScan.tags', 'advance')}">
|
||||
</div>
|
||||
<div class="newfeature"
|
||||
th:insert="~{fragments/navbarEntry :: navbarEntry('compress-pdf', 'zoom_in_map', 'home.compressPdfs.title', 'home.compressPdfs.desc', 'compressPDFs.tags', 'advance')}">
|
||||
|
||||
@@ -160,6 +160,11 @@
|
||||
success: '[[#{decrypt.success}]]',
|
||||
}
|
||||
|
||||
window.corrupt = {
|
||||
pdfInvalid: '[[#{error.pdfInvalid}]]',
|
||||
tryRepair: '[[#{error.tryRepair}]]',
|
||||
}
|
||||
|
||||
const csvInput = document.getElementById("csv-input");
|
||||
csvInput.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Enter") {
|
||||
|
||||
Reference in New Issue
Block a user