diff --git a/Pokemon Go.xlsx b/Pokemon Go.xlsx deleted file mode 100644 index c991e83e..00000000 Binary files a/Pokemon Go.xlsx and /dev/null differ diff --git a/README.md b/README.md deleted file mode 100644 index 1c684b2a..00000000 --- a/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Teste de Backend - -Olá Dev! Tudo bem? - -Nós estamos sempre em busca de profissionais interessantes e interessados, com boa capacidade de aprendizado, adaptação e principalmente bom senso! - -Este teste tem como objetivo avaliar e desafiar você. Não é obrigatório realizá-lo completamente, queremos apenas reconhecer seu esforço e potencial para aprender, se adaptar e tomar decisões. - -Vamos ao teste! - -## Desafio Pokémon Go! - -Sua missão é importar os dados do Pokemon Go, que estão no excel, e criar uma API usando NodeJS para que possamos consumir estes dados de maneira prática, rápida e automatizada. - -Esta API deverá seguir o mínimo de práticas RESTful e conter listagens, busca, paginação e filtros. Fique à vontade para decidir quais filtros são mais interessantes. - -## Consigo fazer? - -Consegue sim! Só precisa saber (ou aprender agora) um pouco sobre as seguintes tecnologias: -- Conceitos de API RESTful -- Modelagem de dados -- NodeJS -- Algum banco de dados, por exemplo, MySQL, SQL Server, MongoDB, etc... -- Git - -## Por onde começo? - -Primeiramente, você pode fazer um fork desse repositório aqui, para sua conta do Github, depois disso crie uma branch nova com o seu nome (ex: nome_sobrenome), para podermos indentificá-lo. - -Após terminar o desafio, você pode solicitar um pull request para a branch master do nosso repositório. Vamos receber e fazer a avaliação de todos. - -## Só isso? - -Só! Mas se quiser fazer a diferença, tente implementar um pouco de TDD e utilizar docker para execução do projeto. - -Boa sorte! :) diff --git a/pokemongo/.babelrc b/pokemongo/.babelrc new file mode 100644 index 00000000..3c078e9f --- /dev/null +++ b/pokemongo/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "es2015" + ] +} diff --git a/pokemongo/.docker/node/Dockerfile b/pokemongo/.docker/node/Dockerfile new file mode 100644 index 00000000..19812606 --- /dev/null +++ b/pokemongo/.docker/node/Dockerfile @@ -0,0 +1,18 @@ +FROM node:10.16.3 + +# Atualizando / Instalando pacotes +RUN apt-get update && apt-get install apt-utils nano vim libcups2-dev -y + +RUN mkdir -p /app/home +WORKDIR /app/home + +# Copiando aplicacao pro lado do volume +COPY . . + +# Clonando env +COPY .env.example .env + +# Instalando dependencias +RUN npm install + +EXPOSE 3333 diff --git a/pokemongo/.editorconfig b/pokemongo/.editorconfig new file mode 100644 index 00000000..91422397 --- /dev/null +++ b/pokemongo/.editorconfig @@ -0,0 +1,13 @@ +# editorconfig.org +root = true + +[*] +indent_size = 2 +indent_style = space +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/pokemongo/.env.example b/pokemongo/.env.example new file mode 100644 index 00000000..2aaf625f --- /dev/null +++ b/pokemongo/.env.example @@ -0,0 +1,8 @@ +NODE_ENV=development +APP_NAME=pokemongo +APP_PORT=3333 +MONGO_HOST=mongo +MONGO_PORT=27017 +MONGO_USER= +MONGO_PASSWORD= +MONGO_COLLECTION=pokemongo diff --git a/pokemongo/.eslintrc.js b/pokemongo/.eslintrc.js new file mode 100644 index 00000000..8b21db46 --- /dev/null +++ b/pokemongo/.eslintrc.js @@ -0,0 +1,24 @@ +module.exports = { + env: { + commonjs: true, + es6: true, + node: true + }, + extends: 'standard', + globals: { + Atomics: 'readonly', + SharedArrayBuffer: 'readonly', + use: 'readonly' + }, + parserOptions: { + ecmaVersion: 2018 + }, + rules: { + camelcase: [ + 'error', { + properties: 'never', + ignoreDestructuring: true + } + ] + } +} diff --git a/pokemongo/.gitignore b/pokemongo/.gitignore new file mode 100644 index 00000000..a59ce735 --- /dev/null +++ b/pokemongo/.gitignore @@ -0,0 +1,11 @@ +# Node modules +/node_modules +package-lock.json +npm-debug.log* +yarn-debug.log* +yarn-error.log* +yarn.lock +/.idea +.env + +/uploads/* diff --git a/pokemongo/README.md b/pokemongo/README.md new file mode 100644 index 00000000..23b56922 --- /dev/null +++ b/pokemongo/README.md @@ -0,0 +1,13 @@ +# poke-mongo + +Docker + + docker-compose up --build + +Mongoosejs + + https://mongoosejs.com/docs/api.html + +Carga excel API + + route: /api/carga diff --git a/pokemongo/app/Controllers/CargaController.js b/pokemongo/app/Controllers/CargaController.js new file mode 100644 index 00000000..43fcfef8 --- /dev/null +++ b/pokemongo/app/Controllers/CargaController.js @@ -0,0 +1,64 @@ +'use strict' + +const Pokemon = require('../Models/Pokemon') +const fs = require('fs') +const excelToJson = require('convert-excel-to-json') + +class CargaController { + async store (req, res, next) { + const file = req.file + + try { + const arr = excelToJson({ + source: fs.readFileSync(file.path), // fs.readFileSync return a Buffer + header: { + rows: 1 + }, + columnToKey: { + A: 'row', + B: 'name', + C: 'pokedex_number', + D: 'img_name', + E: 'generation', + F: 'evolution_stage', + G: 'evolved', + H: 'family_id', + I: 'cross_gen', + J: 'type_1', + K: 'type_2', + L: 'wheather_1', + M: 'wheather_2', + N: 'stat_total', + O: 'atk', + P: 'def', + Q: 'sta', + R: 'legendary', + S: 'aquireable', + T: 'spawns', + U: 'regional', + V: 'raidable', + W: 'hatchable', + X: 'shiny', + Y: 'nest', + Z: 'new', + AA: 'not_Gettable', + AB: 'futute_evolve', + AC: 'forty', + AD: 'thirty_nine' + } + }) + + for (const i of arr.Sheet1) { + await Pokemon.create(i) + } + + return res.json({ + success: true + }) + } catch (err) { + return next(err) + } + } +} + +module.exports = new CargaController() \ No newline at end of file diff --git a/pokemongo/app/Controllers/PokemonController.js b/pokemongo/app/Controllers/PokemonController.js new file mode 100644 index 00000000..673b06d6 --- /dev/null +++ b/pokemongo/app/Controllers/PokemonController.js @@ -0,0 +1,74 @@ +'use strict' + +const Pokemon = require('../Models/Pokemon') +const fs = require('fs') +const excelToJson = require('convert-excel-to-json') + +class PokemonController { + async index (req, res) { + const perPage = 10 + const page = req.params.page || 1 + + const pokemons = await Pokemon.find() + .where(req.body) + .skip((perPage * page) - perPage) + .limit(perPage) + + return res.json(pokemons) + } + + async store (req, res, next){ + try { + const pokemon = await Pokemon.create(req.body) + + return res.json(pokemon) + } catch (err) { + return next(err) + } + } + + async show (req, res) { + try { + const pokemon = await Pokemon.findOne({ + _id: req.params.id + }) + + res.send({ pokemon }) + } catch (err) { + return next(err) + } + } + + async update (req, res) { + try { + const pokemon = await Pokemon.findOne({ + _id: req.params.id + }) + + await pokemon.update(req.body) + + return res.json({ + success: true + }) + } catch (err) { + return next(err) + } + } + + async destroy (req, res) { + try { + await Pokemon.findOneAndDelete({ + _id: req.params.id + }) + + return res.json({ + success: true + }) + } catch (err) { + return next(err) + } + + } +} + +module.exports = new PokemonController() diff --git a/pokemongo/app/Exceptions/ApiException.js b/pokemongo/app/Exceptions/ApiException.js new file mode 100644 index 00000000..f091f940 --- /dev/null +++ b/pokemongo/app/Exceptions/ApiException.js @@ -0,0 +1,22 @@ +'use strict' + +class ApiException extends Error { + constructor (status, message) { + super() + this.status = status + this.message = message + } +} + +const handleError = (err, res) => { + const { status, message } = err + res.status(status || 400).json({ + status, + message + }) +} + +module.exports = { + ApiException, + handleError +} diff --git a/pokemongo/app/Models/Pokemon.js b/pokemongo/app/Models/Pokemon.js new file mode 100644 index 00000000..853e9a10 --- /dev/null +++ b/pokemongo/app/Models/Pokemon.js @@ -0,0 +1,130 @@ +'use strict' + +const mongoose = require('../../database/mongo') + +const PokemonSchema = new mongoose.Schema({ + row: { + type: Number, + require: true + }, + name: { + type: String, + require: true + }, + pokedex_number: { + type: Number, + require: true + }, + img_name: { + type: String, + require: true + }, + generation: { + type: Number, + require: true + }, + evolution_stage: { + type: String, + require: true + }, + evolved: { + type: Number, + require: true + }, + family_id: { + type: Number, + require: false + }, + cross_gen: { + type: Number, + require: true + }, + type_1: { + type: String, + require: true + }, + type_2: { + type: String, + require: false + }, + wheather_1: { + type: String, + require: true + }, + wheather_2: { + type: String, + require: false + }, + stat_total: { + type: Number, + require: true + }, + atk: { + type: Number, + require: true + }, + def: { + type: Number, + require: true + }, + sta: { + type: Number, + require: true + }, + legendary: { + type: Number, + require: true + }, + aquireable: { + type: Number, + require: true + }, + spawns: { + type: Number, + require: true + }, + regional: { + type: Number, + require: true + }, + raidable: { + type: Number, + require: true + }, + hatchable: { + type: Number, + require: true + }, + shiny: { + type: Number, + require: true + }, + nest: { + type: Number, + require: true + }, + new: { + type: Number, + require: true + }, + not_Gettable: { + type: Number, + require: true + }, + futute_evolve: { + type: Number, + require: true + }, + forty: { + type: Number, + require: true + }, + thirty_nine: { + type: Number, + require: true + } +}) + +const Pokemon = mongoose.model('Pokemon', PokemonSchema) + +module.exports = Pokemon diff --git a/pokemongo/app/Validators/BaseValidator.js b/pokemongo/app/Validators/BaseValidator.js new file mode 100644 index 00000000..cbedebeb --- /dev/null +++ b/pokemongo/app/Validators/BaseValidator.js @@ -0,0 +1,16 @@ +'use strict' + +const { validationResult } = require('express-validator') + +const validation = (req, res, next) => { + const errors = validationResult(req) + if (!errors.isEmpty()) { + return res.status(422).json({ errors: errors.array() }) + } + + return next() +} + +module.exports = { + validation +} diff --git a/pokemongo/app/Validators/PokemonStore.js b/pokemongo/app/Validators/PokemonStore.js new file mode 100644 index 00000000..68de231d --- /dev/null +++ b/pokemongo/app/Validators/PokemonStore.js @@ -0,0 +1,40 @@ +'use strict' + +const { check, body } = require('express-validator') + +const PokemonStore = [ + check('row').isNumeric(), + check('name').isString(), + check('pokedex_number').isNumeric(), + check('img_name').isString(), + check('generation').isNumeric(), + check('evolution_stage').isString(), + check('evolved').isNumeric(), + check('family_id').isNumeric(), + check('cross_gen').isNumeric(), + check('type_1').isString(), + check('type_2').isString(), + check('wheather_1').isString(), + check('wheather_2').isString(), + check('stat_total').isNumeric(), + check('atk').isNumeric(), + check('def').isNumeric(), + check('sta' ).isNumeric(), + check('legendary').isNumeric(), + check('aquireable').isNumeric(), + check('spawns').isNumeric(), + check('regional').isNumeric(), + check('raidable').isNumeric(), + check('hatchable').isNumeric(), + check('shiny').isNumeric(), + check('nest').isNumeric(), + check('new').isNumeric(), + check('not_Gettable').isNumeric(), + check('futute_evolve').isNumeric(), + check('forty').isNumeric(), + check('thirty_nine').isNumeric(), +] + +module.exports = { + PokemonStore +} diff --git a/pokemongo/config/index.js b/pokemongo/config/index.js new file mode 100644 index 00000000..d13d6e61 --- /dev/null +++ b/pokemongo/config/index.js @@ -0,0 +1,5 @@ +'use strict' + +var requireDir = require('require-dir') + +module.exports = requireDir('./') diff --git a/pokemongo/config/mongo.js b/pokemongo/config/mongo.js new file mode 100644 index 00000000..055bb135 --- /dev/null +++ b/pokemongo/config/mongo.js @@ -0,0 +1,13 @@ +'use strict' + +module.exports = { + host: process.env.MONGO_HOST, + port: process.env.MONGO_HOST, + user: process.env.MONGO_HOST, + password: process.env.MONGO_HOST, + collection: process.env.MONGO_COLLECTION, + options: { + useUnifiedTopology: true, + useNewUrlParser: true + } +} diff --git a/pokemongo/database/mongo.js b/pokemongo/database/mongo.js new file mode 100644 index 00000000..b0665ada --- /dev/null +++ b/pokemongo/database/mongo.js @@ -0,0 +1,9 @@ +'use strict' + +const mongoose = require('mongoose') +const { mongo } = require('../config') + +mongoose.connect(`mongodb://${mongo.host}:${mongo.port}/${mongo.collection}`, mongo.options) +mongoose.Promise = global.Promise + +module.exports = mongoose diff --git a/pokemongo/docker-compose.yml b/pokemongo/docker-compose.yml new file mode 100644 index 00000000..94a80cda --- /dev/null +++ b/pokemongo/docker-compose.yml @@ -0,0 +1,30 @@ +version: "3.3" + +services: + web: + container_name: pokemongo + restart: unless-stopped + build: + context: ./ + dockerfile: .docker/node/Dockerfile + command: ["node", "server"] + ports: + - "3333:3333" + networks: + - proxy + depends_on: + - mongo + + mongo: + container_name: mongo + image: "mongo" + ports: + - "27017:27017" + networks: + - proxy + +networks: + proxy: + driver: bridge + + \ No newline at end of file diff --git a/pokemongo/package.json b/pokemongo/package.json new file mode 100644 index 00000000..58629610 --- /dev/null +++ b/pokemongo/package.json @@ -0,0 +1,38 @@ +{ + "name": "pokemongo", + "version": "1.0.0", + "description": "", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "dev": "nodemon babel-node server.js", + "lint": "eslint .", + "lint-fix": "eslint . --fix" + }, + "author": "", + "license": "ISC", + "dependencies": { + "body-parser": "^1.19.0", + "convert-excel-to-json": "^1.6.1", + "cors": "^2.8.5", + "dotenv": "^8.2.0", + "express": "^4.17.1", + "express-validator": "^6.3.0", + "mongodb": "^3.4.1", + "mongoose": "^5.8.2", + "multer": "^1.4.2", + "require-dir": "^1.2.0", + "xlsx-to-json": "^0.3.0" + }, + "devDependencies": { + "babel-cli": "^6.26.0", + "babel-preset-es2015": "^6.24.1", + "eslint": "^6.1.0", + "eslint-config-standard": "^13.0.1", + "eslint-plugin-import": "^2.18.2", + "eslint-plugin-node": "^9.1.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.0", + "nodemon": "^2.0.1" + } +} diff --git a/pokemongo/routes.js b/pokemongo/routes.js new file mode 100644 index 00000000..df394dec --- /dev/null +++ b/pokemongo/routes.js @@ -0,0 +1,22 @@ +'use strict' + +const express = require('express') +const routes = express.Router() +const multer = require('multer') +const upload = multer({ dest: 'uploads/' }) +const { validation } = require('./app/Validators/BaseValidator') +const { PokemonStore } = require('./app/Validators/PokemonStore') + +const PokemonController = require('./app/Controllers/PokemonController.js') +const CargaController = require('./app/Controllers/CargaController.js') + +//Carga +routes.post('/carga', upload.single('pokemons'), CargaController.store) + +routes.post('/pokemon',[PokemonStore, validation], PokemonController.store) +routes.get('/pokemon/index/:page', PokemonController.index) +routes.get('/pokemon/:id', PokemonController.show) +routes.put('/pokemon/:id',PokemonController.update) +routes.delete('/pokemon/:id', PokemonController.destroy) + +module.exports = routes diff --git a/pokemongo/server.js b/pokemongo/server.js new file mode 100644 index 00000000..5aae82d1 --- /dev/null +++ b/pokemongo/server.js @@ -0,0 +1,28 @@ +'use strict' + +const express = require('express') +const cors = require('cors') +const dotenv = require('dotenv') +const bodyParser = require('body-parser') +const { handleError } = require('./app/Exceptions/ApiException') +require('babel-core') + +dotenv.config() + +const app = express() + +app.use(bodyParser.json()) +app.use(bodyParser.urlencoded({ extended: false })) +app.use(cors()) + +app.use('/api', require('./routes')) + +app.use((err, req, res, next) => { + handleError(err, res) +}) + +var server = app.listen(process.env.APP_PORT || 3333, function () { + var host = server.address().address + var port = server.address().port + console.info(`server start successfully on http://${host}:${port}`) +})