Skip to content

Commit

Permalink
feat: added POST /api/subsystems endpoint
Browse files Browse the repository at this point in the history
DdeHoog authored and mvegter committed Jun 6, 2020

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
1 parent 8e7544c commit ec08049
Showing 11 changed files with 329 additions and 0 deletions.
31 changes: 31 additions & 0 deletions lib/domain/dtos/CreateSubsystemDto.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @license
* Copyright CERN and copyright holders of ALICE O2. This software is
* distributed under the terms of the GNU General Public License v3 (GPL
* Version 3), copied verbatim in the file "COPYING".
*
* See http://alice-o2.web.cern.ch/license for full licensing information.
*
* In applying this license CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

const Joi = require('@hapi/joi');

const BodyDto = Joi.object({
name: Joi.string()
.required(),
});

const QueryDto = Joi.object({
token: Joi.string(),
});

const CreateSubsystemDto = Joi.object({
query: QueryDto,
body: BodyDto,
params: Joi.object({}),
});

module.exports = CreateSubsystemDto;
2 changes: 2 additions & 0 deletions lib/domain/dtos/index.js
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
*/

const CreateLogDto = require('./CreateLogDto');
const CreateSubsystemDto = require('./CreateSubsystemDto');
const CreateTagDto = require('./CreateTagDto');
const EntityIdDto = require('./EntityIdDto');
const GetAllLogsDto = require('./GetAllLogsDto');
@@ -24,6 +25,7 @@ const PaginationDto = require('./PaginationDto');

module.exports = {
CreateLogDto,
CreateSubsystemDto,
CreateTagDto,
EntityIdDto,
GetAllLogsDto,
28 changes: 28 additions & 0 deletions lib/server/controllers/subsystems.controller.js
Original file line number Diff line number Diff line change
@@ -13,12 +13,14 @@

const {
subsystem: {
CreateSubsystemUseCase,
GetAllSubsystemsUseCase,
GetSubsystemUseCase,
},
} = require('../../usecases');
const {
dtos: {
CreateSubsystemDto,
GetAllSubsystemsDto,
GetSubsystemDto,
},
@@ -84,7 +86,33 @@ const read = async (request, response, next) => {
});
};

/**
* Create subsystem.
*
* @param {Object} request The *request* object represents the HTTP request and has properties for the request query
* string, parameters, body, HTTP headers, and so on.
* @param {Object} response The *response* object represents the HTTP response that an Express app sends when it gets an
* HTTP request.
* @param {Function} next The *next* object represents the next middleware function which is used to pass control to the
* next middleware function.
* @returns {undefined}
*/
const create = async (request, response, next) => {
const value = await dtoValidator(CreateSubsystemDto, request, response);
if (!value) {
return;
}

const subsystem = await new CreateSubsystemUseCase()
.execute(value);

response.status(301).json({
data: subsystem,
});
};

module.exports = {
create,
index,
read,
};
4 changes: 4 additions & 0 deletions lib/server/routers/subsystems.router.js
Original file line number Diff line number Diff line change
@@ -21,6 +21,10 @@ module.exports = {
method: 'get',
controller: SubsystemsController.index,
},
{
method: 'post',
controller: SubsystemsController.create,
},
{
method: 'get',
path: ':subsystemId',
39 changes: 39 additions & 0 deletions lib/usecases/subsystem/CreateSubsystemUseCase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @license
* Copyright CERN and copyright holders of ALICE O2. This software is
* distributed under the terms of the GNU General Public License v3 (GPL
* Version 3), copied verbatim in the file "COPYING".
*
* See http://alice-o2.web.cern.ch/license for full licensing information.
*
* In applying this license CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

const {
repositories: {
SubsystemRepository,
},
utilities: {
TransactionHelper,
},
} = require('../../database');

/**
* CreateSubsystemUseCase
*/
class CreateSubsystemUseCase {
/**
* Executes this use case.
*
* @param {Object} dto The CreateSubsystemDto containing all data.
* @returns {Promise} Promise object represents the result of this use case.
*/
async execute(dto) {
const { body } = dto;
return TransactionHelper.provide(() => SubsystemRepository.insert(body));
}
}

module.exports = CreateSubsystemUseCase;
2 changes: 2 additions & 0 deletions lib/usecases/subsystem/index.js
Original file line number Diff line number Diff line change
@@ -10,10 +10,12 @@
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/
const CreateSubsystemUseCase = require('./CreateSubsystemUseCase');
const GetAllSubsystemsUseCase = require('./GetAllSubsystemsUseCase');
const GetSubsystemUseCase = require('./GetSubsystemUseCase');

module.exports = {
CreateSubsystemUseCase,
GetAllSubsystemsUseCase,
GetSubsystemUseCase,
};
30 changes: 30 additions & 0 deletions spec/openapi-source.yaml
Original file line number Diff line number Diff line change
@@ -115,6 +115,20 @@ paths:
$ref: '#/components/responses/BadRequest'
tags:
- subsystem
post:
operationId: createSubsystem
summary: Adds a new subsystem
requestBody:
$ref: '#/components/requestBodies/CreateSubsystem'
responses:
'201':
$ref: '#/components/responses/Subsystem'
'400':
$ref: '#/components/responses/BadRequest'
'409':
$ref: '#/components/responses/Conflict'
tags:
- subsystem
'/subsystems/{subsystemId}':
parameters:
- $ref: '#/components/parameters/SubsystemId'
@@ -251,6 +265,12 @@ components:
application/json:
schema:
$ref: '#/components/schemas/CreateLog'
CreateSubsystem:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateSubsystem'
CreateTag:
required: true
content:
@@ -440,6 +460,16 @@ components:
- title
- text
additionalProperties: false
CreateSubsystem:
description: A label attached to something for the purpose of identification.
type: object
properties:
text:
description: The label value of the subsystem.
type: string
required:
- text
additionalProperties: false
CreateTag:
description: A label attached to something for the purpose of identification.
type: object
32 changes: 32 additions & 0 deletions spec/openapi.yaml
Original file line number Diff line number Diff line change
@@ -133,6 +133,22 @@ paths:
$ref: '#/components/responses/UnexpectedError'
tags:
- subsystem
post:
operationId: createSubsystem
summary: Adds a new subsystem
requestBody:
$ref: '#/components/requestBodies/CreateSubsystem'
responses:
'201':
$ref: '#/components/responses/Subsystem'
'400':
$ref: '#/components/responses/BadRequest'
'409':
$ref: '#/components/responses/Conflict'
default:
$ref: '#/components/responses/UnexpectedError'
tags:
- subsystem
'/subsystems/{subsystemId}':
parameters:
- $ref: '#/components/parameters/SubsystemId'
@@ -281,6 +297,12 @@ components:
application/json:
schema:
$ref: '#/components/schemas/CreateLog'
CreateSubsystem:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateSubsystem'
CreateTag:
required: true
content:
@@ -470,6 +492,16 @@ components:
- title
- text
additionalProperties: false
CreateSubsystem:
description: A label attached to something for the purpose of identification.
type: object
properties:
text:
description: The label value of the subsystem.
type: string
required:
- text
additionalProperties: false
CreateTag:
description: A label attached to something for the purpose of identification.
type: object
92 changes: 92 additions & 0 deletions test/e2e/subsystems.test.js
Original file line number Diff line number Diff line change
@@ -105,6 +105,98 @@ module.exports = () => {
});
});

describe('POST /api/subsystems', () => {
it('should return 400 if no text is provided', (done) => {
request(server)
.post('/api/subsystems')
.expect(400)
.end((err, res) => {
if (err) {
done(err);
return;
}

// Response must satisfy the OpenAPI specification
expect(res).to.satisfyApiSpec;

const { errors } = res.body;
const titleError = errors.find((err) => err.source.pointer === '/data/attributes/body/text');
expect(titleError.detail).to.equal('"body.text" is required');

done();
});
});

it('should return 400 if the title is too short', (done) => {
request(server)
.post('/api/subsystems')
.send({
text: 'A',
})
.expect(400)
.end((err, res) => {
if (err) {
done(err);
return;
}

// Response must satisfy the OpenAPI specification
expect(res).to.satisfyApiSpec;

const { errors } = res.body;
const titleError = errors.find((err) => err.source.pointer === '/data/attributes/body/text');
expect(titleError.detail).to.equal('"body.text" length must be at least 3 characters long');

done();
});
});

it('should return 201 if a proper body was sent', (done) => {
const expectedText = `UNIX:${new Date().getTime()}`;
request(server)
.post('/api/subsystems')
.send({
text: expectedText,
})
.expect(201)
.end((err, res) => {
if (err) {
done(err);
return;
}

// Response must satisfy the OpenAPI specification
expect(res).to.satisfyApiSpec;

expect(res.body.data.text).to.equal(expectedText);

done();
});
});

it('should return 409 if we are creating the same subsystem again', (done) => {
request(server)
.post('/api/subsystems')
.send({
text: 'FOOD',
})
.expect(409)
.end((err, res) => {
if (err) {
done(err);
return;
}

// Response must satisfy the OpenAPI specification
expect(res).to.satisfyApiSpec;

expect(res.body.errors[0].detail).to.equal('The provided entity already exist');

done();
});
});
});

describe('GET /api/subsystems/:subsystemId', () => {
it('should return 400 if the subsystem id is not a number', (done) => {
request(server)
Loading

0 comments on commit ec08049

Please sign in to comment.