Compare commits
No commits in common. "main" and "main" have entirely different histories.
@ -1,31 +1,8 @@
|
|||||||
from flask import Flask
|
from flask import Flask
|
||||||
from app.database import db
|
|
||||||
# Importação dos blueprints
|
|
||||||
from app.routes.usuario import usuarios_bp
|
|
||||||
from app.routes.organizacao import organizacoes_bp
|
|
||||||
from app.routes.documentos import documentos_bp
|
|
||||||
|
|
||||||
|
|
||||||
def create_app():
|
|
||||||
app = Flask(__name__)
|
|
||||||
app.config.from_object("config")
|
|
||||||
|
|
||||||
# Inicializa a extensão SQLAlchemy
|
|
||||||
db.init_app(app)
|
|
||||||
|
|
||||||
# Registra os blueprints
|
|
||||||
app.register_blueprint(usuarios_bp)
|
|
||||||
app.register_blueprint(organizacoes_bp)
|
|
||||||
app.register_blueprint(documentos_bp)
|
|
||||||
|
|
||||||
return app
|
|
||||||
from flask import Flask
|
|
||||||
from flasgger import Swagger
|
from flasgger import Swagger
|
||||||
from app.database import db
|
from app.database import db
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.routes.user_routes import user_bp
|
from app.routes.user_routes import user_bp
|
||||||
from app.routes.login_form import login_bp
|
|
||||||
from app.routes.dashboard import dashboard_bp
|
|
||||||
from app.routes.invoice_routes import invoice_bp
|
from app.routes.invoice_routes import invoice_bp
|
||||||
from werkzeug.security import generate_password_hash
|
from werkzeug.security import generate_password_hash
|
||||||
|
|
||||||
@ -77,7 +54,5 @@ def create_app():
|
|||||||
# Registrar Blueprints
|
# Registrar Blueprints
|
||||||
app.register_blueprint(user_bp, url_prefix="/users")
|
app.register_blueprint(user_bp, url_prefix="/users")
|
||||||
app.register_blueprint(invoice_bp, url_prefix="/invoices")
|
app.register_blueprint(invoice_bp, url_prefix="/invoices")
|
||||||
app.register_blueprint(login_bp, url_prefix="/login_bp")
|
|
||||||
app.register_blueprint(dashboard_bp, url_prefix="/dashboard")
|
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
from app.auth import generate_token
|
|
||||||
from app.models.user import User
|
|
||||||
from werkzeug.security import check_password_hash
|
|
||||||
from flask import jsonify
|
|
||||||
|
|
||||||
def authenticate_user(email, password):
|
|
||||||
user = User.query.filter_by(email=email).first()
|
|
||||||
|
|
||||||
if not user or not check_password_hash(user.password, password):
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
token = generate_token(user)
|
|
||||||
return user, token
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
# documento.py
|
|
||||||
from app.database import db
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
|
|
||||||
class Documento(db.Model): #
|
|
||||||
__tablename__ = 'documentos'
|
|
||||||
|
|
||||||
id = db.Column(db.UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, unique=True, nullable=False)
|
|
||||||
nome_arquivo = db.Column(db.String, nullable=False)
|
|
||||||
caminho_arquivo = db.Column(db.String, nullable=False)
|
|
||||||
usuario_id = db.Column(db.Integer, db.ForeignKey('usuario.id'), nullable=False)
|
|
||||||
criado_em = db.Column(db.DateTime(timezone=True), server_default=db.func.now(), nullable=False)
|
|
||||||
|
|
||||||
usuario = db.relationship('Usuario', back_populates='documentos')
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
from app.database import db
|
|
||||||
|
|
||||||
|
|
||||||
class Organizacao(db.Model):
|
|
||||||
__tablename__ = 'organizacao'
|
|
||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True,
|
|
||||||
autoincrement=True, unique=True)
|
|
||||||
nome = db.Column(db.String, nullable=False, unique=True)
|
|
||||||
criado_em = db.Column(db.DateTime(timezone=True),
|
|
||||||
server_default=db.func.now(), nullable=False)
|
|
||||||
|
|
||||||
usuarios = db.relationship('Usuario', back_populates='organizacao')
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
# usuario.py
|
|
||||||
from app.database import db
|
|
||||||
|
|
||||||
|
|
||||||
class Usuario(db.Model):
|
|
||||||
__tablename__ = 'usuario'
|
|
||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True,
|
|
||||||
autoincrement=True, unique=True)
|
|
||||||
nome = db.Column(db.String, nullable=False)
|
|
||||||
email = db.Column(db.String, nullable=False, unique=True)
|
|
||||||
senha_hash = db.Column(db.String, nullable=False)
|
|
||||||
organizacao_id = db.Column(db.Integer, db.ForeignKey(
|
|
||||||
'organizacao.id'), nullable=False)
|
|
||||||
criado_em = db.Column(db.DateTime(timezone=True),
|
|
||||||
server_default=db.func.now(), nullable=False)
|
|
||||||
atualizado_em = db.Column(db.DateTime(
|
|
||||||
timezone=True), onupdate=db.func.now())
|
|
||||||
|
|
||||||
organizacao = db.relationship('Organizacao', back_populates='usuarios')
|
|
||||||
documentos = db.relationship('Documento', back_populates='usuario')
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f'<Usuario {self.nome}>'
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
from flask import Blueprint, render_template, session, redirect, url_for, flash
|
|
||||||
|
|
||||||
dashboard_bp = Blueprint("dashboard", __name__, template_folder="templates")
|
|
||||||
|
|
||||||
@dashboard_bp.route("/")
|
|
||||||
def dashboard():
|
|
||||||
"""Protege a rota do dashboard"""
|
|
||||||
if "user_id" not in session:
|
|
||||||
flash("Faça login para acessar o dashboard.", "warning")
|
|
||||||
return redirect(url_for("login_form.login"))
|
|
||||||
|
|
||||||
return render_template("dashboard.html", user_email=session.get("user_email"))
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
from flask import Blueprint, request, jsonify
|
|
||||||
from app.database import db
|
|
||||||
from app.models import Documento
|
|
||||||
|
|
||||||
|
|
||||||
documentos_bp = Blueprint('documentos', __name__, url_prefix='/documentos')
|
|
||||||
|
|
||||||
@documentos_bp.route('/', methods=['GET'])
|
|
||||||
def get_documentos():
|
|
||||||
documentos = Documento.query.all()
|
|
||||||
documentos_data = [
|
|
||||||
{
|
|
||||||
'id': str(doc.id),
|
|
||||||
'nome_arquivo': doc.nome_arquivo,
|
|
||||||
'caminho_arquivo': doc.caminho_arquivo,
|
|
||||||
'usuario_id': doc.usuario_id,
|
|
||||||
'criado_em': doc.criado_em
|
|
||||||
}
|
|
||||||
for doc in documentos
|
|
||||||
]
|
|
||||||
return jsonify(documentos_data), 200
|
|
||||||
|
|
||||||
@documentos_bp.route('/', methods=['POST'])
|
|
||||||
def create_documento():
|
|
||||||
data = request.get_json()
|
|
||||||
if not all(k in data for k in ('nome_arquivo', 'caminho_arquivo', 'usuario_id')):
|
|
||||||
return jsonify({'error': 'Campos obrigatórios ausentes'}), 400
|
|
||||||
|
|
||||||
try:
|
|
||||||
novo_documento = Documento(
|
|
||||||
nome_arquivo=data['nome_arquivo'],
|
|
||||||
caminho_arquivo=data['caminho_arquivo'],
|
|
||||||
usuario_id=data['usuario_id']
|
|
||||||
)
|
|
||||||
db.session.add(novo_documento)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
return jsonify({
|
|
||||||
'message': 'documento criado com sucesso',
|
|
||||||
'id': str(novo_documento.id)
|
|
||||||
}), 201
|
|
||||||
except Exception as e:
|
|
||||||
db.session.rollback()
|
|
||||||
return jsonify({'error': str(e)}), 500
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
from flask import Blueprint, render_template, request, redirect, url_for, flash, session
|
|
||||||
from app.controllers.auth_controller import authenticate_user
|
|
||||||
|
|
||||||
login_bp = Blueprint("login_form", __name__, template_folder="templates")
|
|
||||||
|
|
||||||
@login_bp.route("/", methods=["GET", "POST"])
|
|
||||||
def login():
|
|
||||||
"""Rota de login"""
|
|
||||||
if request.method == "POST":
|
|
||||||
email = request.form.get("email")
|
|
||||||
password = request.form.get("password")
|
|
||||||
|
|
||||||
user, token = authenticate_user(email, password)
|
|
||||||
|
|
||||||
if user:
|
|
||||||
session["user_id"] = user.id
|
|
||||||
session["user_email"] = user.email
|
|
||||||
flash("Login bem-sucedido!", "success")
|
|
||||||
return redirect(url_for("dashboard.dashboard"))
|
|
||||||
|
|
||||||
flash("Credenciais inválidas!", "danger")
|
|
||||||
|
|
||||||
return render_template("login.html")
|
|
||||||
|
|
||||||
@login_bp.route("/logout")
|
|
||||||
def logout():
|
|
||||||
"""Rota de logout"""
|
|
||||||
session.clear()
|
|
||||||
flash("Você saiu da conta.", "info")
|
|
||||||
return redirect(url_for("login_form.login"))
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
from flask import Blueprint, request, jsonify
|
|
||||||
from app.database import db
|
|
||||||
from app.models import Organizacao # ajuste conforme sua estrutura
|
|
||||||
|
|
||||||
organizacoes_bp = Blueprint(
|
|
||||||
'organizacoes', __name__, url_prefix='/organizacoes')
|
|
||||||
|
|
||||||
|
|
||||||
@organizacoes_bp.route('/', methods=['GET'])
|
|
||||||
def get_organizacoes():
|
|
||||||
organizacoes = Organizacao.query.all()
|
|
||||||
data = [
|
|
||||||
{
|
|
||||||
'id': org.id,
|
|
||||||
'nome': org.nome,
|
|
||||||
'criado_em': org.criado_em
|
|
||||||
}
|
|
||||||
for org in organizacoes
|
|
||||||
]
|
|
||||||
return jsonify(data), 200
|
|
||||||
|
|
||||||
|
|
||||||
@organizacoes_bp.route('/', methods=['POST'])
|
|
||||||
def create_organizacao():
|
|
||||||
data = request.get_json()
|
|
||||||
if not data or 'nome' not in data:
|
|
||||||
return jsonify({'error': 'O campo "nome" é obrigatório'}), 400
|
|
||||||
|
|
||||||
if Organizacao.query.filter_by(nome=data['nome']).first():
|
|
||||||
return jsonify({'error': 'Já existe uma organização com este nome'}), 409
|
|
||||||
|
|
||||||
try:
|
|
||||||
nova_org = Organizacao(nome=data['nome'])
|
|
||||||
db.session.add(nova_org)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
return jsonify({
|
|
||||||
'message': 'Organização criada com sucesso',
|
|
||||||
'id': nova_org.id
|
|
||||||
}), 201
|
|
||||||
except Exception as e:
|
|
||||||
db.session.rollback()
|
|
||||||
return jsonify({'error': str(e)}), 500
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
from flask import Blueprint, request, jsonify
|
|
||||||
from app.database import db
|
|
||||||
from app.models.usuario import Usuario # nome correto do modelo
|
|
||||||
|
|
||||||
usuarios_bp = Blueprint('usuarios', __name__, url_prefix='/usuarios')
|
|
||||||
|
|
||||||
|
|
||||||
@usuarios_bp.route('/', methods=['GET'])
|
|
||||||
def get_usuarios():
|
|
||||||
usuarios = Usuario.query.all()
|
|
||||||
usuarios_data = [
|
|
||||||
{
|
|
||||||
'id': usuario.id,
|
|
||||||
'nome': usuario.nome,
|
|
||||||
'email': usuario.email,
|
|
||||||
'organizacao_id': usuario.organizacao_id,
|
|
||||||
'criado_em': usuario.criado_em,
|
|
||||||
'atualizado_em': usuario.atualizado_em
|
|
||||||
}
|
|
||||||
for usuario in usuarios
|
|
||||||
]
|
|
||||||
return jsonify(usuarios_data), 200
|
|
||||||
|
|
||||||
|
|
||||||
@usuarios_bp.route('/', methods=['POST'])
|
|
||||||
def create_usuario():
|
|
||||||
data = request.get_json()
|
|
||||||
if not all(k in data for k in ('nome', 'email', 'senha_hash', 'organizacao_id')):
|
|
||||||
return jsonify({'error': 'Campos obrigatórios ausentes'}), 400
|
|
||||||
|
|
||||||
if Usuario.query.filter_by(email=data['email']).first():
|
|
||||||
return jsonify({'error': 'E-mail já está em uso'}), 409
|
|
||||||
|
|
||||||
novo_usuario = Usuario(
|
|
||||||
nome=data['nome'],
|
|
||||||
email=data['email'],
|
|
||||||
senha_hash=data['senha_hash'],
|
|
||||||
organizacao_id=data['organizacao_id']
|
|
||||||
)
|
|
||||||
|
|
||||||
db.session.add(novo_usuario)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
return jsonify({'message': 'Usuário criado com sucesso', 'id': novo_usuario.id}), 201
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="pt">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Dashboard</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Bem-vindo ao Dashboard!</h1>
|
|
||||||
<p>Usuário logado: {{ user_email }}</p>
|
|
||||||
<a href="{{ url_for('login_form.login') }}">Sair</a>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="pt">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Login</title>
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="login-container">
|
|
||||||
<h2>Login</h2>
|
|
||||||
|
|
||||||
{% with messages = get_flashed_messages(with_categories=True) %}
|
|
||||||
{% if messages %}
|
|
||||||
{% for category, message in messages %}
|
|
||||||
<div class="alert alert-{{ category }}">{{ message }}</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
|
|
||||||
<form method="POST">
|
|
||||||
<label for="email">E-mail:</label>
|
|
||||||
<input type="email" name="email" required>
|
|
||||||
|
|
||||||
<label for="password">Senha:</label>
|
|
||||||
<input type="password" name="password" required>
|
|
||||||
|
|
||||||
<button type="submit">Entrar</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,16 +1,13 @@
|
|||||||
attrs==25.1.0
|
attrs==25.1.0
|
||||||
blinker==1.9.0
|
blinker==1.9.0
|
||||||
click==8.1.8
|
click==8.1.8
|
||||||
exceptiongroup==1.2.2
|
|
||||||
factory_boy==3.3.3
|
factory_boy==3.3.3
|
||||||
Faker==36.2.2
|
Faker==36.2.2
|
||||||
flasgger==0.9.7.1
|
flasgger==0.9.7.1
|
||||||
Flask==3.1.0
|
Flask==3.1.0
|
||||||
Flask-JWT-Extended==4.7.1
|
|
||||||
Flask-SQLAlchemy==3.1.1
|
Flask-SQLAlchemy==3.1.1
|
||||||
Flask-Testing==0.8.1
|
Flask-Testing==0.8.1
|
||||||
greenlet==3.1.1
|
greenlet==3.1.1
|
||||||
importlib_metadata==8.6.1
|
|
||||||
iniconfig==2.0.0
|
iniconfig==2.0.0
|
||||||
itsdangerous==2.2.0
|
itsdangerous==2.2.0
|
||||||
Jinja2==3.1.6
|
Jinja2==3.1.6
|
||||||
@ -20,15 +17,12 @@ MarkupSafe==3.0.2
|
|||||||
mistune==3.1.2
|
mistune==3.1.2
|
||||||
packaging==24.2
|
packaging==24.2
|
||||||
pluggy==1.5.0
|
pluggy==1.5.0
|
||||||
PyJWT==2.10.1
|
|
||||||
pytest==8.3.5
|
pytest==8.3.5
|
||||||
PyYAML==6.0.2
|
PyYAML==6.0.2
|
||||||
referencing==0.36.2
|
referencing==0.36.2
|
||||||
rpds-py==0.23.1
|
rpds-py==0.23.1
|
||||||
six==1.17.0
|
six==1.17.0
|
||||||
SQLAlchemy==2.0.38
|
SQLAlchemy==2.0.38
|
||||||
tomli==2.2.1
|
|
||||||
typing_extensions==4.12.2
|
typing_extensions==4.12.2
|
||||||
tzdata==2025.1
|
tzdata==2025.1
|
||||||
Werkzeug==3.1.3
|
Werkzeug==3.1.3
|
||||||
zipp==3.21.0
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user