mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-28 14:04:43 -04:00
Merge pull request #953 from hedgedoc/mediaBackendErrors
This commit is contained in:
commit
75be4611d3
5 changed files with 49 additions and 4 deletions
|
@ -9,6 +9,7 @@ import {
|
||||||
Controller,
|
Controller,
|
||||||
Delete,
|
Delete,
|
||||||
Headers,
|
Headers,
|
||||||
|
InternalServerErrorException,
|
||||||
NotFoundException,
|
NotFoundException,
|
||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
|
@ -21,6 +22,7 @@ import {
|
||||||
import { FileInterceptor } from '@nestjs/platform-express';
|
import { FileInterceptor } from '@nestjs/platform-express';
|
||||||
import {
|
import {
|
||||||
ClientError,
|
ClientError,
|
||||||
|
MediaBackendError,
|
||||||
NotInDBError,
|
NotInDBError,
|
||||||
PermissionError,
|
PermissionError,
|
||||||
} from '../../../errors/errors';
|
} from '../../../errors/errors';
|
||||||
|
@ -66,6 +68,11 @@ export class MediaController {
|
||||||
if (e instanceof ClientError || e instanceof NotInDBError) {
|
if (e instanceof ClientError || e instanceof NotInDBError) {
|
||||||
throw new BadRequestException(e.message);
|
throw new BadRequestException(e.message);
|
||||||
}
|
}
|
||||||
|
if (e instanceof MediaBackendError) {
|
||||||
|
throw new InternalServerErrorException(
|
||||||
|
'There was an error in the media backend',
|
||||||
|
);
|
||||||
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,6 +93,11 @@ export class MediaController {
|
||||||
if (e instanceof NotInDBError) {
|
if (e instanceof NotInDBError) {
|
||||||
throw new NotFoundException(e.message);
|
throw new NotFoundException(e.message);
|
||||||
}
|
}
|
||||||
|
if (e instanceof MediaBackendError) {
|
||||||
|
throw new InternalServerErrorException(
|
||||||
|
'There was an error in the media backend',
|
||||||
|
);
|
||||||
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,3 +31,7 @@ export class TooManyTokensError extends Error {
|
||||||
export class PermissionsUpdateInconsistentError extends Error {
|
export class PermissionsUpdateInconsistentError extends Error {
|
||||||
name = 'PermissionsUpdateInconsistentError';
|
name = 'PermissionsUpdateInconsistentError';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class MediaBackendError extends Error {
|
||||||
|
name = 'MediaBackendError';
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { ConsoleLoggerService } from '../../logger/console-logger.service';
|
||||||
import { MediaBackend } from '../media-backend.interface';
|
import { MediaBackend } from '../media-backend.interface';
|
||||||
import { BackendData } from '../media-upload.entity';
|
import { BackendData } from '../media-upload.entity';
|
||||||
import { MediaConfig } from '../../config/media.config';
|
import { MediaConfig } from '../../config/media.config';
|
||||||
|
import { MediaBackendError } from '../../errors/errors';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FilesystemBackend implements MediaBackend {
|
export class FilesystemBackend implements MediaBackend {
|
||||||
|
@ -33,12 +34,23 @@ export class FilesystemBackend implements MediaBackend {
|
||||||
const filePath = this.getFilePath(fileName);
|
const filePath = this.getFilePath(fileName);
|
||||||
this.logger.debug(`Writing file to: ${filePath}`, 'saveFile');
|
this.logger.debug(`Writing file to: ${filePath}`, 'saveFile');
|
||||||
await this.ensureDirectory();
|
await this.ensureDirectory();
|
||||||
await fs.writeFile(filePath, buffer, null);
|
try {
|
||||||
return ['/' + filePath, null];
|
await fs.writeFile(filePath, buffer, null);
|
||||||
|
return ['/' + filePath, null];
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(e.message, e.stack, 'saveFile');
|
||||||
|
throw new MediaBackendError(`Could not save '${filePath}'`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteFile(fileName: string, _: BackendData): Promise<void> {
|
async deleteFile(fileName: string, _: BackendData): Promise<void> {
|
||||||
return fs.unlink(this.getFilePath(fileName));
|
const filePath = this.getFilePath(fileName);
|
||||||
|
try {
|
||||||
|
return fs.unlink(filePath);
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(e.message, e.stack, 'deleteFile');
|
||||||
|
throw new MediaBackendError(`Could not delete '${filePath}'`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getFileURL(fileName: string, _: BackendData): Promise<string> {
|
getFileURL(fileName: string, _: BackendData): Promise<string> {
|
||||||
|
@ -55,7 +67,17 @@ export class FilesystemBackend implements MediaBackend {
|
||||||
try {
|
try {
|
||||||
await fs.access(this.uploadDirectory);
|
await fs.access(this.uploadDirectory);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await fs.mkdir(this.uploadDirectory);
|
try {
|
||||||
|
this.logger.debug(
|
||||||
|
`The directory '${this.uploadDirectory}' can't be accessed. Trying to create the directory`,
|
||||||
|
);
|
||||||
|
await fs.mkdir(this.uploadDirectory);
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(e.message, e.stack, 'deleteFile');
|
||||||
|
throw new MediaBackendError(
|
||||||
|
`Could not create '${this.uploadDirectory}'`,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ export interface MediaBackend {
|
||||||
* Saves a file according to backend internals.
|
* Saves a file according to backend internals.
|
||||||
* @param buffer File data
|
* @param buffer File data
|
||||||
* @param fileName Name of the file to save. Can include a file extension.
|
* @param fileName Name of the file to save. Can include a file extension.
|
||||||
|
* @throws {MediaBackendError} - there was an error saving the file
|
||||||
* @return Tuple of file URL and internal backend data, which should be saved.
|
* @return Tuple of file URL and internal backend data, which should be saved.
|
||||||
*/
|
*/
|
||||||
saveFile(buffer: Buffer, fileName: string): Promise<[string, BackendData]>;
|
saveFile(buffer: Buffer, fileName: string): Promise<[string, BackendData]>;
|
||||||
|
@ -19,6 +20,7 @@ export interface MediaBackend {
|
||||||
* Retrieve the URL of a previously saved file.
|
* Retrieve the URL of a previously saved file.
|
||||||
* @param fileName String to identify the file
|
* @param fileName String to identify the file
|
||||||
* @param backendData Internal backend data
|
* @param backendData Internal backend data
|
||||||
|
* @throws {MediaBackendError} - there was an error deleting the file
|
||||||
*/
|
*/
|
||||||
getFileURL(fileName: string, backendData: BackendData): Promise<string>;
|
getFileURL(fileName: string, backendData: BackendData): Promise<string>;
|
||||||
|
|
||||||
|
@ -26,6 +28,7 @@ export interface MediaBackend {
|
||||||
* Delete a file from the backend
|
* Delete a file from the backend
|
||||||
* @param fileName String to identify the file
|
* @param fileName String to identify the file
|
||||||
* @param backendData Internal backend data
|
* @param backendData Internal backend data
|
||||||
|
* @throws {MediaBackendError} - there was an error retrieving the url
|
||||||
*/
|
*/
|
||||||
deleteFile(fileName: string, backendData: BackendData): Promise<void>;
|
deleteFile(fileName: string, backendData: BackendData): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,8 @@ export class MediaService {
|
||||||
* @param {string} noteId - the id or alias of the note which will be associated with the new file.
|
* @param {string} noteId - the id or alias of the note which will be associated with the new file.
|
||||||
* @return {string} the url of the saved file
|
* @return {string} the url of the saved file
|
||||||
* @throws {ClientError} the MIME type of the file is not supported.
|
* @throws {ClientError} the MIME type of the file is not supported.
|
||||||
|
* @throws {NotInDBError} - the note or user is not in the database
|
||||||
|
* @throws {MediaBackendError} - there was an error saving the file
|
||||||
*/
|
*/
|
||||||
async saveFile(
|
async saveFile(
|
||||||
fileBuffer: Buffer,
|
fileBuffer: Buffer,
|
||||||
|
@ -110,6 +112,7 @@ export class MediaService {
|
||||||
* @return {string} the url of the saved file
|
* @return {string} the url of the saved file
|
||||||
* @throws {PermissionError} the user is not permitted to delete this file.
|
* @throws {PermissionError} the user is not permitted to delete this file.
|
||||||
* @throws {NotInDBError} - the file entry specified is not in the database
|
* @throws {NotInDBError} - the file entry specified is not in the database
|
||||||
|
* @throws {MediaBackendError} - there was an error deleting the file
|
||||||
*/
|
*/
|
||||||
async deleteFile(filename: string, username: string): Promise<void> {
|
async deleteFile(filename: string, username: string): Promise<void> {
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
|
@ -136,6 +139,7 @@ export class MediaService {
|
||||||
* @param {string} filename - the name of the file entry to find
|
* @param {string} filename - the name of the file entry to find
|
||||||
* @return {MediaUpload} the file entry, that was searched for
|
* @return {MediaUpload} the file entry, that was searched for
|
||||||
* @throws {NotInDBError} - the file entry specified is not in the database
|
* @throws {NotInDBError} - the file entry specified is not in the database
|
||||||
|
* @throws {MediaBackendError} - there was an error retrieving the url
|
||||||
*/
|
*/
|
||||||
async findUploadByFilename(filename: string): Promise<MediaUpload> {
|
async findUploadByFilename(filename: string): Promise<MediaUpload> {
|
||||||
const mediaUpload = await this.mediaUploadRepository.findOne(filename, {
|
const mediaUpload = await this.mediaUploadRepository.findOne(filename, {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue