Skip to content

Commit 3539022

Browse files
WIP filestorage
1 parent 054eaeb commit 3539022

File tree

8 files changed

+477
-4
lines changed

8 files changed

+477
-4
lines changed

service/src/core/core.module.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import { AuthModule } from './auth/auth.module'
66
import { UsersModule } from './users/users.module'
77
import { CategoriesModule } from './categories/categories.module'
88
import { ProjectModule } from './projects/project.module'
9-
import { TriggersModule } from './triggers/triggers.module';
10-
import { CrontabsModule } from './crontabs/crontabs.module';
11-
import { PreferencesModule } from './preferences/preferences.module';
9+
import { TriggersModule } from './triggers/triggers.module'
10+
import { CrontabsModule } from './crontabs/crontabs.module'
11+
import { PreferencesModule } from './preferences/preferences.module'
12+
import { FilestorageModule } from './filestorage/filestorage.module'
1213

1314
@Module({
14-
imports: [AuthModule, UsersModule, CategoriesModule, ProjectModule, TriggersModule, CrontabsModule, PreferencesModule],
15+
imports: [AuthModule, UsersModule, CategoriesModule, ProjectModule, TriggersModule, CrontabsModule, PreferencesModule, FilestorageModule],
1516
providers: [CoreService],
1617
controllers: [CoreController],
1718
})
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { PartialType } from "@nestjs/swagger"
2+
3+
export class FilestorageCreateDto {
4+
5+
}
6+
7+
export class FilestorageUpdateDto extends PartialType(FilestorageCreateDto) {}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
2+
import { Document } from 'mongoose'
3+
import { AbstractSchema } from '~/_common/abstracts/schemas/abstract.schema'
4+
5+
export type FilestorageDocument = Filestorage & Document
6+
7+
@Schema({
8+
collection: 'filestorage',
9+
versionKey: false,
10+
})
11+
export class Filestorage extends AbstractSchema {
12+
@Prop({
13+
required: true,
14+
type: Number,
15+
})
16+
public type: number
17+
18+
@Prop({
19+
required: true,
20+
type: String,
21+
})
22+
public namespace: string
23+
24+
@Prop({
25+
required: true,
26+
type: String,
27+
})
28+
public path: string
29+
30+
@Prop({
31+
required: false,
32+
type: String,
33+
})
34+
public comments?: string
35+
36+
@Prop({
37+
required: true,
38+
type: Boolean,
39+
})
40+
public hidden: boolean
41+
42+
@Prop({
43+
required: false,
44+
type: Object,
45+
})
46+
public tags?: { [key: string]: any }
47+
48+
@Prop({
49+
required: false,
50+
type: Object,
51+
})
52+
public acls?: { [key: string]: any }
53+
54+
@Prop({
55+
required: false,
56+
type: Object,
57+
})
58+
public customFields?: { [key: string]: any }
59+
}
60+
61+
export const FilestorageSchema = SchemaFactory.createForClass(Filestorage)
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
import { DeleteResult } from 'mongodb'
2+
import { Test, TestingModule } from '@nestjs/testing'
3+
import { FilestorageController } from './filestorage.controller'
4+
import { FilestorageService } from './filestorage.service'
5+
import { FilestorageDto } from './_dto/filestorage.dto'
6+
import { Filestorage } from './_schemas/filestorage.schema'
7+
import { HttpException, HttpStatus } from '@nestjs/common'
8+
import { Types } from 'mongoose'
9+
import { Response, Request } from 'express'
10+
import { getMockReq, getMockRes } from '@jest-mock/express'
11+
12+
describe('FilestorageController', () => {
13+
let controller: FilestorageController
14+
let service: FilestorageService
15+
const date = new Date()
16+
const _id = new Types.ObjectId()
17+
const { res, mockClear } = getMockRes()
18+
const object: Filestorage = {
19+
_id,
20+
metadata: {
21+
createdAt: date,
22+
createdBy: 'console',
23+
lastUpdateAt: date,
24+
lastUpdateBy: 'console',
25+
},
26+
info: [],
27+
}
28+
29+
beforeEach(async () => {
30+
mockClear()
31+
const module: TestingModule = await Test.createTestingModule({
32+
controllers: [FilestorageController],
33+
providers: [
34+
FilestorageService,
35+
{
36+
provide: FilestorageService,
37+
useValue: {
38+
search: jest.fn().mockResolvedValue([[object], 1]),
39+
create: jest.fn().mockResolvedValue(object),
40+
read: jest.fn().mockResolvedValue(object),
41+
update: jest.fn().mockResolvedValue(object),
42+
remove: jest.fn().mockResolvedValue({
43+
acknowledged: true,
44+
deletedCount: 1,
45+
}),
46+
},
47+
},
48+
],
49+
}).compile()
50+
51+
controller = module.get<FilestorageController>(FilestorageController)
52+
service = module.get<FilestorageService>(FilestorageService)
53+
})
54+
55+
describe('search', () => {
56+
it('should return an array of Filestorage objects and the total count', async () => {
57+
const req = getMockReq()
58+
const query = { _id: _id.toString() }
59+
const limit = 10
60+
const skip = 1
61+
const expectedResult: [Filestorage[], number] = [[object], 1]
62+
jest.spyOn(service, 'search').mockImplementation(async () => await expectedResult)
63+
const response = await controller.search(req, res, query, limit.toString(), skip.toString(), null)
64+
expect(response.json).toHaveBeenCalledWith({ data: expectedResult[0], total: expectedResult[1] })
65+
expect(response.status).toHaveBeenCalledWith(HttpStatus.OK)
66+
})
67+
68+
it('should return an array of Filestorage objects with default pagination', async () => {
69+
const req = getMockReq()
70+
const query = { _id: _id.toString() }
71+
const limit = 0
72+
const skip = 0
73+
const expectedResult: [Filestorage[], number] = [[object], 1]
74+
jest.spyOn(service, 'search').mockImplementation(async () => await expectedResult)
75+
const response = await controller.search(req, res, query, limit.toString(), skip.toString(), null)
76+
expect(response.json).toHaveBeenCalledWith({ data: expectedResult[0], total: expectedResult[1] })
77+
expect(response.status).toHaveBeenCalledWith(HttpStatus.OK)
78+
})
79+
80+
it('should throw HttpException with BAD_REQUEST status when an error occurs', async () => {
81+
const req = {} as Request
82+
const res = {} as Response
83+
const query = { someParam: 'value' }
84+
const limit = 10
85+
const skip = 0
86+
jest.spyOn(service, 'search').mockRejectedValue(new Error('Something went wrong'))
87+
88+
try {
89+
await controller.search(req, res, query, limit.toString(), skip.toString(), null)
90+
} catch (error) {
91+
const status = error.getStatus()
92+
const response = error.getResponse()
93+
94+
expect(error).toBeInstanceOf(HttpException)
95+
expect(status).toBe(400)
96+
expect(response).toBe('Something went wrong')
97+
}
98+
})
99+
})
100+
101+
describe('read', () => {
102+
it('should return the data successfully', async () => {
103+
const expectedResult: Filestorage = object
104+
jest.spyOn(service, 'read').mockImplementation(async () => await expectedResult)
105+
const result = await controller.read(_id.toString(), res)
106+
expect(res.status).toHaveBeenCalledWith(HttpStatus.OK)
107+
expect(res.json).toHaveBeenCalledWith(expectedResult)
108+
expect(result).toEqual(res)
109+
})
110+
111+
it('should throw an HttpException with the error message', async () => {
112+
const errorMessage = 'Error message'
113+
jest.spyOn(service, 'read').mockRejectedValue(new Error(errorMessage))
114+
try {
115+
await controller.read(_id.toString(), res)
116+
} catch (error) {
117+
expect(error.getStatus()).toBe(HttpStatus.BAD_REQUEST)
118+
expect(error.getResponse()).toBe(errorMessage)
119+
}
120+
})
121+
})
122+
123+
describe('create', () => {
124+
it('should return a Filestorage object', async () => {
125+
const dto: FilestorageDto = { someProp: 'value' }
126+
const expectedResult = object
127+
jest.spyOn(service, 'create').mockImplementation(async () => await expectedResult)
128+
const response = await controller.create(dto, res)
129+
expect(response.status).toHaveBeenCalledWith(HttpStatus.CREATED)
130+
expect(response.json).toHaveBeenCalledWith(expectedResult)
131+
})
132+
133+
it('should throw HttpException with BAD_REQUEST status when an error occurs', async () => {
134+
const dto: FilestorageDto = { someProp: 'value' }
135+
jest.spyOn(service, 'create').mockRejectedValue(new Error('Something went wrong'))
136+
137+
try {
138+
await controller.create(dto, res)
139+
} catch (error) {
140+
expect(error).toBeInstanceOf(HttpException)
141+
expect(error.getStatus()).toBe(400)
142+
expect(error.getResponse()).toBe('Something went wrong')
143+
}
144+
})
145+
})
146+
147+
describe('update', () => {
148+
it('should return a Filestorage object', async () => {
149+
const id = _id.toString()
150+
const dto: FilestorageDto = { someProp: 'value' }
151+
const expectedResult: Filestorage = object
152+
jest.spyOn(service, 'update').mockImplementation(async () => await expectedResult)
153+
const response = await controller.update(id, dto, res)
154+
expect(response.status).toHaveBeenCalledWith(HttpStatus.OK)
155+
expect(response.json).toHaveBeenCalledWith(expectedResult)
156+
})
157+
158+
it('should throw HttpException with BAD_REQUEST status when an error occurs', async () => {
159+
const id = _id.toString()
160+
const dto: FilestorageDto = { someProp: 'value' }
161+
jest.spyOn(service, 'update').mockRejectedValue(new Error('Something went wrong'))
162+
163+
try {
164+
await controller.update(id, dto, res)
165+
} catch (error) {
166+
expect(error).toBeInstanceOf(HttpException)
167+
expect(error.getStatus()).toBe(400)
168+
expect(error.getResponse()).toBe('Something went wrong')
169+
}
170+
})
171+
})
172+
173+
describe('remove', () => {
174+
it('should return a Filestorage object', async () => {
175+
const id = _id.toString()
176+
const expectedResult: DeleteResult = {
177+
acknowledged: true,
178+
deletedCount: 1,
179+
}
180+
jest.spyOn(service, 'remove').mockImplementation(async () => await expectedResult)
181+
const response = await controller.remove(id, res)
182+
expect(response.status).toHaveBeenCalledWith(HttpStatus.OK)
183+
expect(response.json).toHaveBeenCalledWith(expectedResult)
184+
})
185+
186+
it('should throw HttpException with BAD_REQUEST status when an error occurs', async () => {
187+
const id = _id.toString()
188+
jest.spyOn(service, 'remove').mockRejectedValue(new Error('Something went wrong'))
189+
190+
try {
191+
await controller.remove(id, res)
192+
} catch (error) {
193+
expect(error).toBeInstanceOf(HttpException)
194+
expect(error.getStatus()).toBe(400)
195+
expect(error.getResponse()).toBe('Something went wrong')
196+
}
197+
})
198+
})
199+
})
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { Body, Controller, Delete, Get, HttpStatus, Param, Patch, Post, Req, Res } from '@nestjs/common'
2+
import { FilestorageCreateDto, FilestorageUpdateDto } from './_dto/filestorage.dto'
3+
import { FilestorageService } from './filestorage.service'
4+
import { AbstractController } from '~/_common/abstracts/abstract.controller'
5+
import { ApiParam } from '@nestjs/swagger'
6+
import { SearchFilterSchema, FilterSchema, SearchFilterOptions, FilterOptions, ObjectIdValidationPipe } from '@streamkits/nestjs_module_scrud'
7+
import { Types } from 'mongoose'
8+
import { Request, Response } from 'express'
9+
10+
@Controller('filestorage')
11+
export class FilestorageController extends AbstractController {
12+
protected readonly projection = {
13+
namespace: 1,
14+
path: 1,
15+
}
16+
17+
constructor(private readonly _service: FilestorageService) {
18+
super()
19+
}
20+
21+
@Post()
22+
public async create(@Req() req: Request, @Res() res: Response, @Body() body: FilestorageCreateDto) {
23+
const data = await this._service.create(body)
24+
return res.status(HttpStatus.CREATED).json({
25+
statusCode: HttpStatus.CREATED,
26+
data,
27+
})
28+
}
29+
30+
@Get()
31+
public async search(@Res() res: Response, @SearchFilterSchema() searchFilterSchema: FilterSchema, @SearchFilterOptions() searchFilterOptions: FilterOptions) {
32+
const [data, total] = await this._service.findAndCount(searchFilterSchema, this.projection, searchFilterOptions)
33+
return res.status(HttpStatus.OK).json({
34+
statusCode: HttpStatus.OK,
35+
total,
36+
data,
37+
})
38+
}
39+
40+
@Get(':_id([0-9a-fA-F]{24})')
41+
@ApiParam({ name: '_id', type: String })
42+
public async read(@Param('_id', ObjectIdValidationPipe) _id: Types.ObjectId, @Res() res: Response) {
43+
const data = await this._service.findById(_id)
44+
return res.status(HttpStatus.OK).json({
45+
statusCode: HttpStatus.OK,
46+
data,
47+
})
48+
}
49+
50+
@Patch(':_id([0-9a-fA-F]{24})')
51+
@ApiParam({ name: '_id', type: String })
52+
public async update(@Param('_id', ObjectIdValidationPipe) _id: Types.ObjectId, @Body() body: FilestorageUpdateDto, @Res() res: Response) {
53+
const data = await this._service.update(_id, body)
54+
return res.status(HttpStatus.OK).json({
55+
statusCode: HttpStatus.OK,
56+
data,
57+
})
58+
}
59+
60+
@Delete(':_id([0-9a-fA-F]{24})')
61+
@ApiParam({ name: '_id', type: String })
62+
public async remove(@Param('_id', ObjectIdValidationPipe) _id: Types.ObjectId, @Res() res: Response) {
63+
const data = await this._service.delete(_id)
64+
return res.status(HttpStatus.OK).json({
65+
statusCode: HttpStatus.OK,
66+
data,
67+
})
68+
}
69+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Module } from '@nestjs/common'
2+
import { MongooseModule } from '@nestjs/mongoose'
3+
import { FilestorageSchema, Filestorage } from './_schemas/filestorage.schema'
4+
import { FilestorageService } from './filestorage.service'
5+
import { FilestorageController } from './filestorage.controller'
6+
7+
@Module({
8+
imports: [
9+
MongooseModule.forFeatureAsync([
10+
{
11+
name: Filestorage.name,
12+
useFactory: () => FilestorageSchema,
13+
},
14+
]),
15+
],
16+
providers: [FilestorageService],
17+
controllers: [FilestorageController],
18+
})
19+
export class FilestorageModule {}

0 commit comments

Comments
 (0)