Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/backend create #3

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
9 changes: 9 additions & 0 deletions backend/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
1 change: 1 addition & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
40 changes: 40 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# API Imóveis

Aqui você terá todos os passos necessários para que possa executar a API.

## 1 - Instalar o Docker

Caso ainda não possua o Docker instalado em sua maquina, poderá esta fazendo o download do mesmo nesse link (https://www.docker.com/products/docker-desktop) selecionando o sistema operacional da sua maquina.

## 2 - Criando o Banco de Dados

Após a instalação do Docker (caso não tivesse em sua maquina), irá executar o seguinte comando a baixo para a criação do Banco de Dados Mongo utilizado no projeto.

-> docker run --name imoveisDB -p 27017:27017 -d mongo:latest

## 3 - Clonar o projeto

Após criar o Banco de Dados Mongo no Docker, você irá clonar o projeto do repositorio.

## 4 - Instalar os pacotes

Após ter clonado o projeto, basta acessar a pasta do mesmo pelo terminal e executar o comando: yarn, para que todos os pacotes sejam instalados.

## 5 - Executar Mongo no Docker

Para executar o Mongo dentro do Docker basta executar o seguinte comando no terminal, sempre dentro da pasta do projeto.

-> yarn mongo:start

## 6 - Executando o projeto

Para rodar o projeto basta executar o seguinte comando no terminal dentro da pasta do projeto.

-> yarn dev:server

## OBS:
Caso você por algum motivo venha a reinicia a sua maquina, o container do Mongo no docker vai ser parado, para executar ele pode fazer de duas formas:

-> A primeira forma e acessar o aplicativo do Docker e starta o container.

-> A segunda maneira, basta acessar a pasta do projeto pelo terminal e executar o seguinte comando no terminal: yarn docker:start
35 changes: 35 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "backend",
"version": "1.0.0",
"main": "src/index.js",
"license": "MIT",
"scripts": {
"build": "tsc",
"dev:server": "node src/index.js",
"start": "node src/index.ts",
"mongo:start": "docker exec -it imoveisDB mongo",
"docker:start": "docker start imoveisDB"
},
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"fs": "^0.0.1-security",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.13.2",
"nodemailer": "^6.6.3",
"nodemailer-express-handlebars": "^4.0.0",
"path": "^0.12.7",
"pg": "^8.6.0",
"typeorm": "^0.2.34",
"uuidv4": "^6.2.11"
},
"devDependencies": {
"@types/bcryptjs": "^2.4.2",
"@types/express": "^4.17.13",
"nodemon": "^2.0.11",
"ts-node-dev": "^1.1.8",
"typescript": "^4.3.5"
}
}
130 changes: 130 additions & 0 deletions backend/src/app/controllers/authController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const crypto = require('crypto');
const mailer = require('../../modules/mailer');
const path = require('path');

const authConfig = require('../../config/auth');

const User = require('../models/user');

const router = express.Router();

function generateToken(params = {}) {
return jwt.sign(params, authConfig.secret, {
expiresIn: 86400,
});
}

router.post('/register', async (req, res) => {
const { email } = req.body;

try {
if (await User.findOne({ email }))
return res.status(400).send({ error: 'User already exists' });

const user = await User.create(req.body);

user.password = undefined;

return res.send({
user,
token: generateToken({ id: user.id }),
});
} catch (err) {
return res.status(400).send({ error: 'Registration failed' });
}
});

router.post('/authenticate', async (req, res) => {
const { email, password } = req.body;

const user = await User.findOne({ email }).select('+password');

if (!user)
return res.status(400).send({ error: 'User not found!' });

if (!await bcrypt.compare(password, user.password))
return res.status(400).send({ error: 'Invalid password' });

user.password = undefined;

return res.send({
user,
token: generateToken({ id: user.id }),
});
});

router.post('/forgot_password', async (req, res) => {
const { email } = req.body;

try {
const user = await User.findOne({ email });

if (!user)
return res.status(400).send({ error: 'User not found' });

const token = crypto.randomBytes(20).toString('hex');

const now = new Date();
now.setHours(now.getHours() + 1);

await User.findByIdAndUpdate(user.id, {
'$set': {
passwordResetToken: token,
passwordResetExpires: now,
}
});

const emailUser = user.email;

res.send({ token, emailUser });

mailer.sendMail({
to: email, // list of receivers
from: '"Pedro Souza 👻" <[email protected]>', // sender address
subject: "Recuperação de senha", // Subject line
// text: "Hello world?", // plain text body
html: `<p>Você esqueceu sua senha? Não tem problema, utilize esse token: ${token}</p>`, // html body

}, (err) => {
if (err)
return res.status(400).send({ error: 'Cannot send forgot password email' });

return res.send();
});
} catch (err) {
return res.status(400).send({ error: 'Erro on forgot password, try again'});
}
})

router.post('/reset_password', async (req, res) => {
const { email, password, token } = req.body;

try {
const user = await User.findOne({ email })
.select('+passwordResetToken passwordResetExpires');

if (!user)
return res.status(400).send({ error: 'User not found' });

if (token !== user.passwordResetToken)
return res.status(400).send({ error: 'Token invalid' });

const now = new Date();

if (now > user.passwordResetExpires)
return res.status(400).send({ error: 'Token expired, generate a new one' });

user.password = password;

await user.save();
res.send();

} catch (err) {
return res.status(400).send({ error: 'Cannot reset password, try again!' });
}
})

module.exports = app => app.use('/auth', router);
8 changes: 8 additions & 0 deletions backend/src/app/controllers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const fs = require("fs");
const path = require("path");

module.exports = app => {
fs.readdirSync(__dirname)
.filter(file => file.indexOf(".") !== 0 && file !== "index.js")
.forEach(file => require(path.resolve(__dirname, file))(app));
};
63 changes: 63 additions & 0 deletions backend/src/app/controllers/propertieController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const express = require('express');

const Propertie = require('../models/propertie');

const router = express.Router();


router.post('/', async (req, res) => {
try {
const propertie = await Propertie.create(req.body);

return res.send({ propertie });

} catch (err) {
return res.status(400).send({ error: 'It was not possible to register the property'})
}
});

router.get('/', async (req, res) => {
try {
const propertie = await Propertie.find();

return res.send({ propertie });

} catch (err) {
return res.status(400).send({ error: 'It was not possible to recover the properties' });
}
});

router.get('/:propertiesId', async (req, res) => {
try {
const propertie = await Propertie.findById(req.params.propertiesId);

return res.send({ propertie });
} catch (err) {
return res.status(400).send({ error: 'Error loading propertie' });
}
});

router.put('/:propertiesId', async (req, res) => {
try {
const propertie = await Propertie.findByIdAndUpdate(req.params.propertiesId, req.body, { new: true });

await propertie.save();

return res.send({ propertie });

} catch (err) {
return res.status(400).send({ error: 'Error updating propertie' });
}
});

router.delete('/:propertieId', async (req, res) => {
try {
await Propertie.findByIdAndRemove(req.params.propertieId);

return res.send();
} catch (err) {
return res.status(400).send({ error: 'Error deleting propertie' });
}
});

module.exports = app => app.use('/propertie', router);
29 changes: 29 additions & 0 deletions backend/src/app/middlewares/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const jwt = require('jsonwebtoken');
const authConfig = require('../../config/auth.json');


module.exports = (req, res, next) => {
const authHeader = req.headers.authorization;

if (!authHeader)
return res.status(401).send({ error: 'No token provided' });

const parts = authHeader.split(' ');

if (!parts.length === 2)
return res.status(401).send({ error: 'Token error' });

const [ scheme, token ] = parts;

if (!/^Bearer$/i.test(scheme)) {
return res.status(401).send({ error: 'Token malformatted' });
}

jwt.verify(token, authConfig.secret, (err, decoded) => {
if (err) return res.status(401).send({ error: 'Token invalid' });

req.userId = decoded.id;

return next();
});
};
58 changes: 58 additions & 0 deletions backend/src/app/models/propertie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const mongoose = require('../../database');

const PropertieSchema = new mongoose.Schema({
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
amount: {
type: Number,
required: true,
},
size: {
type: Number,
required: true,
},
street: {
type: String,
required: true,
},
number: {
type: Number,
required: true,
},
complement: {
type: String,
},
district: {
type: String,
required: true,
},
zipe_code: {
type: Number,
required: true,
},
city: {
type: String,
required: true,
},
state: {
type: String,
required: true,
},
createdAt: {
type: Date,
default: Date.now,
},
updatedAt: {
type: Date,
default: Date.now,
}
});

const Propertie = mongoose.model('Propertie', PropertieSchema);
module.exports = Propertie;
Loading