Skip to content
Snippets Groups Projects
Commit c71ae8c4 authored by Diego Giovane Pasqualin's avatar Diego Giovane Pasqualin
Browse files

Cobertura de código

parent 038d0a8a
No related branches found
No related tags found
No related merge requests found
Showing
with 1496 additions and 26 deletions
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.json]
indent_size = 2
# Limitando quais branches terão a build construída
image: node:4.2
# 'only' e 'except' permitem limitar quando builds são executadas a partir
# de nomes de branches ou tags. Eles são 'inclusivos', ou seja, se um branch
# aparece em 'only' ele será executado, independente de aparecer em 'except'
# ou não.
# Expressões regulares são aceitas.
services:
- mongo:latest
# Roda a build somente se o branch começar com issue-
job1:
script:
- echo "Building"
# Gera build para todos os branches que começam com issue-
only:
- /^issue-.*$/
# 'branches' é uma palavra-chave que significa 'todos os branches'
# Então essa linha garante que a build não será executada para nenhum
# branch que não casar com o 'only'
except:
- branches
before_script:
- npm config set cache /cache/npm
- npm install --silent -g gulp
- npm install --silent
- cp config/example.yaml config/test.yaml
- sed -i 's/database\x3a[ ]*\x27test\x27/database\x3a \x27simmc_test\x27/' config/test.yaml
- sed -i 's/host\x3a[ ]*\x27localhost\x27/host\x3a \x27mongo\x27/' config/test.yaml
# Roda a build em todos os branches menos no master
job2:
check:
type: test
script:
- echo "Building"
only:
- branches
except:
- master
- gulp lint
- gulp test
tags:
- node
- mongo
.jscsrc 0 → 100644
{
"preset": "airbnb",
"validateIndentation": 4,
"requireTrailingComma": false,
"disallowTrailingComma": true,
"requireCurlyBraces": [
"if",
"else",
"for",
"while",
"do",
"try",
"catch"
],
"requireCamelCaseOrUpperCaseIdentifiers": "ignoreProperties",
"disallowKeywordsOnNewLine": [],
"maximumLineLength": 80,
"requirePaddingNewLinesAfterBlocks": {
"allExcept": ["inCallExpressions", "inNewExpressions", "inArrayExpressions", "inProperties"]
}
}
{
/*
* ENVIRONMENTS
* =================
*/
// Define globals exposed by modern browsers.
"browser": false,
// Define globals exposed by Node.js.
"node": true,
// Allow ES6.
"esnext": true,
/*
* ENFORCING OPTIONS
* =================
*/
// Prohibit use of == and != in favor of === and !==.
"eqeqeq": true,
// Enforce tab width of 2 spaces.
"indent": 4,
// Prohibit use of a variable before it is defined.
"latedef": false,
// Require capitalized names for constructor functions.
"newcap": true,
// Enforce use of single quotation marks for strings.
"quotmark": "single",
// Prohibit use of explicitly undeclared variables.
"undef": true,
// Warn when variables are defined but never used.
"unused": "vars",
/*
* RELAXING OPTIONS
* =================
*/
// Suppress warnings about == null comparisons.
"eqnull": true,
// Add global variables for Mocha and Chai
"globals": {
"describe": false,
"xdescribe": false,
"ddescribe": false,
"it": false,
"xit": false,
"iit": false,
"beforeEach": false,
"afterEach": false,
"before": false,
"after": false
}
}
LICENSE 0 → 100644
This diff is collapsed.
/*
* Copyright (C) 2015 Centro de Computacao Cientifica e Software Livre
* Departamento de Informatica - Universidade Federal do Parana
*
* This file is part of simmc.
*
* simmc is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* simmc is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with simmc. If not, see <http://www.gnu.org/licenses/>.
*/
var FilterParser = require('filter-parser');
var createError = require('http-errors');
module.exports = {
list: list,
index: index,
read: read
};
var filterParser = new FilterParser({
identifierParser: function(ident) {
// convert the identifier id into _id
if (ident === 'id') {
ident = '_id';
}
// only accept a few valid identifiers
if ((ident !== '_id') &&
(ident !== 'name') &&
(ident !== 'adminLevel') &&
(ident !== 'extras.city_code')) {
throw new Error('Invalid identifier ' + ident);
}
return ident;
}
});
function mapLocation(doc) {
return {
id: parseInt(doc.id),
score: doc.score,
name: doc.name,
adminLevel: doc.adminLevel,
border: doc.border,
subDivisions: doc.subDivisions,
extras: doc.extras
};
}
function list(req, res, next) {
var Location = req.db.model('Location');
// retrieve query parameters
var perPage = req.query.per_page || 10;
var page = req.query.page || 1;
var search = req.query.query;
var filters = req.query.filters;
// build the query
var qQuery = {};
var qProjection = { _id: 1, name: 1, adminLevel: 1, extras: 1 };
var qSort = { _id: 1 };
if (filters) {
try {
qQuery = filterParser.parse(filters);
}
catch (err) {
next(createError.BadRequest(
'Invalid filter expression. Check your syntax and try again.'));
return;
}
}
if (search) {
qQuery.$text = { $search: search };
qProjection.score = { $meta: 'textScore' };
qSort = { score: { $meta: 'textScore' } };
}
var q = Location
.find(qQuery, qProjection)
.sort(qSort)
.skip((page - 1) * perPage)
.limit(perPage);
// execute the query
q.exec(function(err, docs) {
if (err) {
req.log.error(err);
next(createError.BadRequest(
'Unfortunately, the request you are making cannot be ' +
'fulfilled by the server.'));
return;
}
var locations = [];
docs.forEach(function(doc) {
locations.push(mapLocation(doc));
});
res.status(200).json(locations);
});
}
function index(req, res, next) {
var Location = req.db.model('Location');
var q = Location
.find({}, { _id: 1, adminLevel: 1, name: 1 })
.sort({ _id: 1 });
// execute the query
q.exec(function(err, docs) {
/* istanbul ignore if */
if (err) {
req.log.error(err);
next(createError.InternalServerError());
return;
}
var result = {
keys: ['adminLevel', 'id', 'name'],
index: {}
};
docs.forEach(function(doc) {
if (!result.index[doc.adminLevel]) {
result.index[doc.adminLevel] = {};
}
result.index[doc.adminLevel][doc.id] = doc.name;
});
res.status(200).json(result);
});
}
function read(req, res, next) {
var Location = req.db.model('Location');
var locationId = req.params.locationId;
var projection = {
_id: 1,
name: 1,
adminLevel: 1,
extras: 1
};
if (req.query.border) {
projection.border = 1;
}
if (req.query.sub_divisions) {
projection.subDivisions = 1;
}
Location.findOne({_id: locationId}, projection, function(err, doc) {
/* istanbul ignore if */
if (err) {
req.log.error(err);
next(createError.InternalServerError());
return;
}
if (!doc) {
next(createError.NotFound(
'Location \'' + locationId + '\' could not be found.'));
return;
}
res.status(200).json(mapLocation(doc));
});
}
/*
* Copyright (C) 2015 Centro de Computacao Cientifica e Software Livre
* Departamento de Informatica - Universidade Federal do Parana
*
* This file is part of simmc.
*
* simmc is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* simmc is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with simmc. If not, see <http://www.gnu.org/licenses/>.
*/
module.exports = {
list: list,
create: create,
read: read,
update: update,
delete: del
};
function mapUser(doc) {
var user = {
id: String(doc.id),
email: doc.email,
firstname: doc.firstname,
lastname: doc.lastname,
tags: doc.tags,
created_at: doc.created_at,
updated_at: doc.updated_at
};
return user;
}
function list(req, res) {
var User = req.db.model('User');
var perPage = req.query.per_page || 10;
var page = req.query.page || 1;
var offset = (page - 1) * perPage;
var q = User
.find()
.skip(offset)
.limit(perPage);
q.exec(function(err, docs) {
if (err) {
console.error(err);
res.status(500).json({ message: 'Database query failed.' });
return;
}
var users = [];
docs.forEach(function(doc) {
users.push(mapUser(doc));
});
res.json(users);
});
}
function create(req, res) {
var User = req.db.model('User');
var userEmail = req.body.email;
var userPassword = req.body.password;
var userFirstname = req.body.firstname;
var userLastname = req.body.lastname;
var userTags = req.body.tags;
// add comment
var doc = new User();
doc.email = userEmail;
doc.password = userPassword;
doc.firstname = userFirstname;
doc.lastname = userLastname;
doc.tags = userTags;
doc.save(function(err) {
if (err) {
console.error(err);
res.status(500).json({
message: 'Failed to save user to the database.'
});
return;
}
res.status(200).json(mapUser(doc));
});
}
function read(req, res) {
var User = req.db.model('User');
var userId = req.params.userId;
User.findOne({_id: userId}, function(err, doc) {
if (err) {
console.error(err);
res.status(500).json({ message: 'Database query failed.' });
return;
}
if (!doc) {
res.status(404).json({ message: 'User could not be found.' });
return;
}
res.status(200).json(mapUser(doc));
});
}
function update(req, res) {
var User = req.db.model('User');
var userId = req.params.userId;
var userEmail = req.body.email;
var userPassword = req.body.password;
var userFirstname = req.body.firstname;
var userLastname = req.body.lastname;
var userTags = req.body.tags;
User.findOne({_id: userId}, function(err, doc) {
if (err) {
console.error(err);
res.status(500).json({ message: 'Database query failed.' });
return;
}
if (!doc) {
res.status(404).json({ message: 'User could not be found.' });
return;
}
doc.email = userEmail || doc.email;
doc.password = userPassword || doc.password;
doc.firstname = userFirstname || doc.firstname;
doc.lastname = userLastname || doc.lastname;
doc.tags = userTags || doc.tags;
doc.save(function(err) {
if (err) {
console.error(err);
res.status(500).json({
message: 'Failed to save user to the database.'
});
return;
}
res.status(200).json(mapUser(doc));
});
});
}
function del(req, res) {
var User = req.db.model('User');
var userId = req.params.userId;
User.findOne({_id: userId}, function(err, doc) {
if (err) {
console.error(err);
res.status(500).json({ message: 'Database query failed.' });
return;
}
if (!doc) {
res.status(404).json({ message: 'User could not be found.' });
return;
}
doc.remove(function(err) {
if (err) {
console.error(err);
res.status(500).json({ message: 'Database query failed.' });
return;
}
res.status(200).json({ message: 'User sucessufully removed.' });
});
});
}
/*
* Copyright (C) 2015 Centro de Computacao Cientifica e Software Livre
* Departamento de Informatica - Universidade Federal do Parana
*
* This file is part of simmc.
*
* simmc is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* simmc is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with simmc. If not, see <http://www.gnu.org/licenses/>.
*/
var mongoose = require('mongoose');
var glob = require('glob');
var path = require('path');
module.exports = function(config) {
var connectString = 'mongodb://' + config.get('mongodb.host') + ':' +
config.get('mongodb.port') + '/' +
config.get('mongodb.database');
mongoose.connect(connectString);
mongoose.connection.on('error', function(err) {
throw err;
});
glob.sync(path.resolve(__dirname, '../models/*.js'))
.forEach(function(file) {
require(file)();
});
return function(req, res, next) {
req.db = mongoose;
next();
};
};
/*
* Copyright (C) 2015 Centro de Computacao Cientifica e Software Livre
* Departamento de Informatica - Universidade Federal do Parana
*
* This file is part of simmc.
*
* simmc is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* simmc is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with simmc. If not, see <http://www.gnu.org/licenses/>.
*/
var mongoose = require('mongoose');
module.exports = function() {
var locationSchema = mongoose.Schema({
_id: {type: Number, required: true},
name: {type: String, required: true},
adminLevel: {type: Number, required: true},
border: {type: Object, required: true},
subDivisions: {type: Object},
extras: {type: mongoose.Schema.Types.Mixed}
});
// Workaround Alert:
// The following virtual is only needed as a placeholder for the
// calculated score of a text search on this collection. If this virtual
// is ommited, mongoose hides the 'score' field on the final document
// returned on queries.
locationSchema.virtual('score');
locationSchema.index({ adminLevel: 1 });
locationSchema.index({ name: 'text', 'extras.city_code': 'text' },
{ default_language: 'portuguese' });
return mongoose.model('Location', locationSchema);
};
/*
* Copyright (C) 2015 Centro de Computacao Cientifica e Software Livre
* Departamento de Informatica - Universidade Federal do Parana
*
* This file is part of simmc.
*
* simmc is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* simmc is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with simmc. If not, see <http://www.gnu.org/licenses/>.
*/
var mongoose = require('mongoose');
var bcrypt = require('bcrypt');
var BCRYPT_SALT_WORK_FACTOR = 10;
var MAX_NUMBER_OF_TAGS = 256;
module.exports = function() {
var userSchema = mongoose.Schema({
email: {type: String, required: true, unique: true },
password: {type: String, required: true },
firstname: {type: String},
lastname: {type: String},
tags: [String],
created_at: {type: Date },
updated_at: {type: Date }
});
userSchema.pre('save', function(next) {
var _this = this;
var now = new Date();
// set/update the created_at and updated_at fields
_this.updated_at = now;
if (!_this.created_at) {
_this.created_at = now;
}
// hash the password (only if has been modified or is new)
if (!_this.isModified('password')) {
next();
} else {
// generate a salt
bcrypt.genSalt(BCRYPT_SALT_WORK_FACTOR, function(err, salt) {
if (err) {
return next(err);
}
// hash the password along with our new salt
bcrypt.hash(_this.password, salt, function(err, hash) {
if (err) {
return next(err);
}
// override the cleartext password with the hashed one
_this.password = hash;
next();
});
});
}
});
function validateEmail(value) {
if ((value.length < 4) || (value.length > 255)) {
return false;
}
if (!value.match(/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/)) {
return false;
}
return true;
}
function validatePassword(value) {
if ((value.length < 8) || (value.length > 256)) {
return false;
}
if (!value.match(/^[a-zA-Z0-9$-\/:-?{-~!\"^_`\[\]]*$/)) {
return false;
}
return true;
}
function validateTags(value) {
if (value.length > MAX_NUMBER_OF_TAGS) {
return false;
}
for (var i = 0; i < value.length; i++) {
if (!value[i].match(/^[A-Za-z]+[A-Za-z0-9.-_]+$/)) {
return false;
}
if (value[i].length > 28) {
return false;
}
}
return true;
}
function validateName(value) {
if ((value.length < 3) || (value.length > 28)) {
return false;
}
return true;
}
userSchema.path('email').validate(validateEmail);
userSchema.path('password').validate(validatePassword);
userSchema.path('tags').validate(validateTags);
userSchema.path('firstname').validate(validateName);
userSchema.path('lastname').validate(validateName);
return mongoose.model('User', userSchema);
};
/*
* Copyright (C) 2015 Centro de Computacao Cientifica e Software Livre
* Departamento de Informatica - Universidade Federal do Parana
*
* This file is part of simmc.
*
* simmc is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* simmc is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with simmc. If not, see <http://www.gnu.org/licenses/>.
*/
var osprey = require('osprey');
// import controllers
var users = require('./controllers/users');
var locations = require('./controllers/locations');
var router = module.exports = osprey.Router();
router.get('/users', users.list);
router.post('/users', users.create);
router.get('/users/{userId}', { userId: { type: 'string' } }, users.read);
router.put('/users/{userId}', { userId: { type: 'string' } }, users.update);
router.delete('/users/{userId}', { userId: { type: 'string' } }, users.delete);
router.get('/locations', locations.list);
router.get('/locations/_index', locations.index);
router.get('/locations/{locationId}',
{ locationId: { type: 'integer' } }, locations.read);
{
"email": "email@something.com",
"password": "somerandompassword",
"firstname": "Name",
"tags": ["SomeProject", "AnotherProject"]
}
[
{
"id": "11",
"name": "RONDÔNIA",
"adminLevel": 4,
"extras": {}
},
{
"id": "14",
"name": "RORAIMA",
"adminLevel": 4,
"extras": {}
},
{
"id": "13",
"name": "AMAZONAS",
"adminLevel": 4,
"extras": {}
},
{
"id": "16",
"name": "AMAPÁ",
"adminLevel": 4,
"extras": {}
}
]
[
{
"id": "5639ff8eeca3b4f8334e9917",
"email": "email@something.com",
"firstname": "Name",
"tags": [
"SomeProject",
"AnotherProject"
],
"created_at": "2015-11-04T12:52:30.781Z",
"updated_at": "2015-11-04T12:52:30.781Z"
},
{
"id": "558acc151806abf713891b6c",
"email": "another@user.me",
"tags": [],
"created_at": "2015-06-24T15:26:13.281Z",
"updated_at": "2015-06-24T15:26:13.281Z"
},
{
"id": "5638a4c39517775d37a506b1",
"email": "yet@another.biz",
"firstname": "John",
"lastname": "Doe",
"tags": [
"SomeProject"
],
"created_at": "2015-11-03T12:12:51.855Z",
"updated_at": "2015-11-03T12:12:51.855Z"
}
]
{
"id": "3528858",
"name": "MARAPOAMA",
"adminLevel": 8,
"extras": {
"city_code": "MARP"
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment