feat: upload module (#486)
* feat: wip upload module * feat: local storage and serve local images * feat: protect against injections * feat: server local and s3 files * fix: use storage location when serving local files * feat: cross field env validation
This commit is contained in:
@ -0,0 +1 @@
|
||||
export * from './local-storage.interface';
|
||||
@ -0,0 +1,3 @@
|
||||
export interface LocalStorageModuleOptions {
|
||||
storagePath: string;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
import { ConfigurableModuleBuilder } from '@nestjs/common';
|
||||
import { LocalStorageModuleOptions } from './interfaces';
|
||||
|
||||
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
|
||||
new ConfigurableModuleBuilder<LocalStorageModuleOptions>({
|
||||
moduleName: 'LocalStorage',
|
||||
})
|
||||
.setClassMethodName('forRoot')
|
||||
.build();
|
||||
@ -0,0 +1,10 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { LocalStorageService } from './local-storage.service';
|
||||
import { ConfigurableModuleClass } from './local-storage.module-definition';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [LocalStorageService],
|
||||
exports: [LocalStorageService],
|
||||
})
|
||||
export class LocalStorageModule extends ConfigurableModuleClass {}
|
||||
@ -0,0 +1,25 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { LocalStorageService } from './local-storage.service';
|
||||
import { MODULE_OPTIONS_TOKEN } from './local-storage.module-definition';
|
||||
|
||||
describe('LocalStorageService', () => {
|
||||
let service: LocalStorageService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
LocalStorageService,
|
||||
{
|
||||
provide: MODULE_OPTIONS_TOKEN,
|
||||
useValue: {},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<LocalStorageService>(LocalStorageService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,35 @@
|
||||
import { Injectable, Inject } from '@nestjs/common';
|
||||
import * as fs from 'fs/promises';
|
||||
import { existsSync } from 'fs';
|
||||
import * as path from 'path';
|
||||
import { MODULE_OPTIONS_TOKEN } from './local-storage.module-definition';
|
||||
import { LocalStorageModuleOptions } from './interfaces';
|
||||
|
||||
@Injectable()
|
||||
export class LocalStorageService {
|
||||
constructor(
|
||||
@Inject(MODULE_OPTIONS_TOKEN)
|
||||
private readonly options: LocalStorageModuleOptions,
|
||||
) {}
|
||||
|
||||
async createFolder(path: string) {
|
||||
if (existsSync(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return fs.mkdir(path, { recursive: true });
|
||||
}
|
||||
|
||||
async uploadFile(params: {
|
||||
file: Buffer | Uint8Array | string;
|
||||
name: string;
|
||||
folder: string;
|
||||
}) {
|
||||
const filePath = `${this.options.storagePath}/${params.folder}/${params.name}`;
|
||||
const folderPath = path.dirname(filePath);
|
||||
|
||||
await this.createFolder(folderPath);
|
||||
|
||||
return fs.writeFile(filePath, params.file);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user