Skip to content

Commit

Permalink
Merge pull request #1 from postech-5soat-grupo-25/alanmmolina/fase-5/…
Browse files Browse the repository at this point in the history
…adicionando-microservico-para-lgpd

adicionando microservico lgpd
  • Loading branch information
alanmmolina authored Sep 8, 2024
2 parents 3cd923d + 8394b49 commit 003226a
Show file tree
Hide file tree
Showing 29 changed files with 375 additions and 1 deletion.
6 changes: 6 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM python:3.11-slim-buster

RUN apt-get update && apt-get install -y curl build-essential libpq-dev
RUN curl -sSL https://install.python-poetry.org | python3 -

RUN poetry install --no-root
15 changes: 15 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "tech-challenge-lgpd `devcontainer`",
"dockerFile": "Dockerfile",
"context": "..",
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"charliermarsh.ruff",
"mtxr.sqltools",
"mtxr.sqltools-driver-pg"
]
}
}
}
33 changes: 33 additions & 0 deletions .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Code Coverage

on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened]

jobs:
test:
name: Run tests and collect coverage
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v4

- name: Install dependencies
run: pip install pytest pytest-cov

- name: Run tests
run: pytest --cov

- name: Upload results to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: postech-5soat-grupo-25/tech-challenge-lgpd
19 changes: 19 additions & 0 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Build
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened]
jobs:
sonarcloud:
name: SonarCloud
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
SONAR_TOKEN: ${{ secrets.SONARCLOUD_TOKEN }}
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ ipython_config.py
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
Expand Down
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.11.9
14 changes: 14 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"sqltools.connections": [
{
"previewLimit": 50,
"server": "localhost",
"port": 5432,
"askForPassword": true,
"driver": "PostgreSQL",
"name": "tech-challenge-lgpd-db",
"username": "postgres",
"database": "lgpd"
}
]
}
16 changes: 16 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM python:3.11-slim-buster

WORKDIR /app

RUN apt-get update && apt-get install -y curl build-essential libpq-dev
RUN curl -sSL https://install.python-poetry.org | python3 -

ENV PATH="/root/.local/bin:$PATH"

COPY pyproject.toml poetry.lock* /app/
RUN poetry install --no-root
COPY source /app

EXPOSE 8000

CMD ["poetry", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
20 changes: 20 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Precisa ter o .env com as variaveis corretas
include .env
export

.PHONY: build
build:
docker compose up db -d
sleep 5
docker cp ./database/01_create_table.sql tech-challenge-lgpd-db-1:/01_create_table.sql
docker compose exec db psql -U ${POSTGRES_USER} -d ${POSTGRES_DB} -a -f 01_create_table.sql
sleep 2
docker compose up app --build

.PHONY: run
run:
docker compose up --remove-orphans

.PHONY: down
down:
docker compose down
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# `Tech Challenge` | PosTech 5SOAT • Grupo 25

![microservice](https://img.shields.io/badge/lgpd-blue?label=microsservi%C3%A7o&labelColor=%23505050&color=%23d63865)
[![sonarcloud](https://sonarcloud.io/api/project_badges/measure?project=postech-5soat-grupo-25_tech-challenge-lgpd&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=postech-5soat-grupo-25_tech-challenge-lgpd) [![codecov](https://codecov.io/gh/postech-5soat-grupo-25/tech-challenge-lgpd/graph/badge.svg?token=O85UX0WQ43)](https://codecov.io/gh/postech-5soat-grupo-25/tech-challenge-lgpd)

## Sobre o Projeto

Este projeto é desenvolvido como parte do Tech Challenge, um requisito para a conclusão do curso de Pós-Graduação em Software Architecture da FIAP. O desafio proposto visa solucionar problemas reais enfrentados por uma lanchonete em expansão, através do desenvolvimento de um sistema de autoatendimento eficiente. A ausência de um sistema de controle de pedidos pode tornar o atendimento caótico, afetando a satisfação dos clientes. Nosso sistema busca otimizar o processo de pedidos, pagamento, acompanhamento e entrega, garantindo uma experiência fluida e satisfatória para os clientes e uma gestão eficaz para o estabelecimento.

---

### Equipe

| Membro | RM |
|-------------------------------------------------------------------------------|----------|
| [Alan Marques Molina](https://www.linkedin.com/in/alanmmolina/) | `353062` |
| [Albert Dias Moreira](https://www.linkedin.com/in/albert-moreira-62b9272b/) | `352569` |
| [Bruno Mafra Pelence](https://www.linkedin.com/in/bruno-mafra-pelence/) | `352939` |
| [Lucas Felipe Rebello](https://www.linkedin.com/in/lucas-rebello-b01849112/) | `352982` |
| [Matheus Bachiste Lopes](https://www.linkedin.com/in/matheus-bachiste-lopes/) | `352783` |

---

### Documentação

Este projeto está em constante evolução ao longo do curso, e para acompanhar essas mudanças, estamos centralizando todas as documentações em um único lugar. Para informações detalhadas sobre o projeto, incluindo aspectos técnicos e guias de uso, acesse nossa **documentação completa** em:

[postech-5soat-grupo-25.github.io](https://postech-5soat-grupo-25.github.io/)

### Executar

Para iniciar esse serviço localmente em ambiente de desenvolvimento, basta executar:

```sh
make build
```
7 changes: 7 additions & 0 deletions database/01_create_table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE TABLE IF NOT EXISTS solicitacoes (
id SERIAL PRIMARY KEY,
nome VARCHAR(255) NOT NULL,
endereco VARCHAR(255) NOT NULL,
telefone VARCHAR(20) NOT NULL,
tipo VARCHAR(255) NOT NULL
);
22 changes: 22 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
restart: always
ports:
- 8080:8000
depends_on:
- db
env_file:
- .env
db:
image: postgres:15.2-alpine
restart: always
environment:
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
POSTGRES_USER: "${POSTGRES_USER}"
POSTGRES_DB: "${POSTGRES_DB}"
ports:
- 5432:5432
25 changes: 25 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[tool.poetry]
name = "tech-challenge-lgpd"
version = "1.0.0"
description = "Microserviço para gerenciar conformidade com a Lei Geral de Proteção de Dados (LGPD)"
authors = ["PosTech 5SOAT GRUPO 25 <postech-5soat-grupo-25@googlegroups.com>"]

[tool.poetry.dependencies]
python = "^3.11"
python-dotenv = "^1.0.1"
fastapi = "^0.114.0"
httpx = "^0.27.2"
uvicorn = "^0.30.6"
pydantic = "^2.9.0"
databases = "^0.9.0"
asyncpg = "^0.29.0"
psycopg2-binary = "^2.9.9"

[tool.poetry.group.dev.dependencies]
pytest = "^8.3.2"
pytest-mock = "^3.14.0"
pytest-asyncio = "^0.24.0"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
3 changes: 3 additions & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
sonar.projectKey=postech-5soat-grupo-25_tech-challenge-lgpd
sonar.organization=postech-5soat-grupo-25
sonar.sources=source
Empty file added source/adapters/__init__.py
Empty file.
20 changes: 20 additions & 0 deletions source/adapters/api_adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel

from use_cases.exclusao_dados_pessoais_use_case import ExclusaoDadosPessoaisUseCase

routes = APIRouter()

class SolicitacaoInput(BaseModel):
nome: str
endereco: str
telefone: str

@routes.post("/solicitacao/exclusao/")
async def criar_solicitacao_exclusao(solicitacao: SolicitacaoInput):
use_case = ExclusaoDadosPessoaisUseCase()
try:
await use_case.executar(solicitacao.nome, solicitacao.endereco, solicitacao.telefone)
return {"message": "Solicitação de exclusão de dados pessoais criada com sucesso!"}
except Exception as error:
raise HTTPException(status_code=400, detail=str(error))
31 changes: 31 additions & 0 deletions source/adapters/postgresql_adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from databases import Database
import sqlalchemy
from dotenv import load_dotenv
import os

load_dotenv()

POSTGRES_DB=os.getenv("POSTGRES_DB")
POSTGRES_USER=os.getenv("POSTGRES_USER")
POSTGRES_PASSWORD=os.getenv("POSTGRES_PASSWORD")
DATABASE_URL = f"postgresql+psycopg2://{POSTGRES_USER}:{POSTGRES_PASSWORD}@db:5432/{POSTGRES_DB}"

database = Database(DATABASE_URL)
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata = sqlalchemy.MetaData()

solicitacoes = sqlalchemy.Table(
"solicitacoes",
metadata,
sqlalchemy.Column("id", sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column("nome", sqlalchemy.String, nullable=False),
sqlalchemy.Column("endereco", sqlalchemy.String, nullable=False),
sqlalchemy.Column("telefone", sqlalchemy.String, nullable=False),
sqlalchemy.Column("tipo", sqlalchemy.String, nullable=False)
)

async def inserir_solicitacao_exclusao(nome: str, endereco: str, telefone: str):
query = solicitacoes.insert().values(
nome=nome, endereco=endereco, telefone=telefone, tipo="Exclusão de Dados Pessoais"
)
await database.execute(query)
Empty file added source/entities/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions source/entities/solicitante.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Solicitante:
def __init__(self, nome: str, endereco: str, telefone: str):
self.nome = nome
self.endereco = endereco
self.telefone = telefone
Empty file added source/gateways/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions source/gateways/solicitacao_exclusao_gateway.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from adapters.postgresql_adapter import inserir_solicitacao_exclusao

class SolicitacaoExclusaoGateway:
async def salvar_solicitacao(self, nome: str, endereco: str, telefone: str):
await inserir_solicitacao_exclusao(nome, endereco, telefone)
18 changes: 18 additions & 0 deletions source/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from fastapi import FastAPI
from adapters.api_adapter import routes
from adapters.postgresql_adapter import database, solicitacoes
import sqlalchemy
from dotenv import load_dotenv


load_dotenv()

async def lifespan(app: FastAPI):
await database.connect()
engine = sqlalchemy.create_engine(str(database.url))
solicitacoes.create(engine, checkfirst=True)
yield
await database.disconnect()

app = FastAPI(lifespan=lifespan)
app.include_router(routes)
Empty file added source/use_cases/__init__.py
Empty file.
12 changes: 12 additions & 0 deletions source/use_cases/exclusao_dados_pessoais_use_case.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from entities.solicitante import Solicitante
from gateways.solicitacao_exclusao_gateway import SolicitacaoExclusaoGateway

class ExclusaoDadosPessoaisUseCase:
def __init__(self):
self.gateway = SolicitacaoExclusaoGateway()

async def executar(self, nome: str, endereco: str, telefone: str):
solicitante = Solicitante(nome, endereco, telefone)
await self.gateway.salvar_solicitacao(
solicitante.nome, solicitante.endereco, solicitante.telefone
)
Empty file added tests/__init__.py
Empty file.
10 changes: 10 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import pytest
from fastapi.testclient import TestClient
from fastapi import FastAPI
from source.adapters.api_adapter import routes

@pytest.fixture(scope="module")
def client():
app = FastAPI()
app.include_router(routes)
return TestClient(app)
32 changes: 32 additions & 0 deletions tests/test_adapters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import pytest
from fastapi.testclient import TestClient
from source.adapters.api_adapter import routes
from source.adapters.postgresql_adapter import inserir_solicitacao_exclusao


@pytest.fixture
def client():
from fastapi import FastAPI
app = FastAPI()
app.include_router(routes)
return TestClient(app)

def test_criar_solicitacao_exclusao(client):
response = client.post("/solicitacao/exclusao/", json={
"nome": "Fulano",
"endereco": "Rua A 123",
"telefone": "123456789"
})
assert response.status_code == 200
assert response.json() == {"message": "Solicitação de exclusão de dados pessoais criada com sucesso!"}


@pytest.mark.asyncio
async def test_inserir_solicitacao_exclusao(mocker):
mock_execute = mocker.patch("source.adapters.postgresql_adapter.database.execute", autospec=True)

await inserir_solicitacao_exclusao("Fulano", "Rua A 123", "123456789")

mock_execute.assert_called_once()
args, kwargs = mock_execute.call_args
assert args[0].startswith("INSERT INTO solicitacoes")
Loading

0 comments on commit 003226a

Please sign in to comment.