-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from Kalkuli/develop
Release 0.1
- Loading branch information
Showing
18 changed files
with
770 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,4 +2,5 @@ env | |
.dockerignore | ||
Dockerfile-dev | ||
Dockerfile-prod | ||
htmlcov/ | ||
htmlcov/ | ||
migrations |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
web: gunicorn -b 0.0.0.0:$PORT manage:app | ||
release: python manage.py recreatedb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,29 @@ | ||
from flask.cli import FlaskGroup | ||
from project import app, db | ||
from project.api.models import Company, User | ||
import unittest | ||
import coverage | ||
|
||
|
||
# Config coverage report | ||
COV = coverage.coverage( | ||
branch=True, | ||
include='project/*', | ||
omit=[ | ||
'project/tests/*', | ||
'project/config.py', | ||
'project/config.py' | ||
] | ||
) | ||
COV.start() | ||
from flask.cli import FlaskGroup | ||
from project import create_app, db | ||
from project.api.models import Company, User | ||
from project.tests.utils import add_company | ||
import unittest | ||
|
||
|
||
# Config coverage report | ||
|
||
|
||
cli = FlaskGroup(app) | ||
cli = FlaskGroup(create_app) | ||
|
||
|
||
# Registers comand to recreate database | ||
@cli.command() | ||
def recreate_db(): | ||
def recreatedb(): | ||
db.drop_all() | ||
db.create_all() | ||
db.session.commit() | ||
|
@@ -53,7 +54,23 @@ def cov(): | |
return 0 | ||
return 1 | ||
|
||
|
||
@cli.command() | ||
def seeduserdb(): | ||
company = add_company('Kalkuli', '00.000.000/0000-00', '[email protected]', 'kaliu', '789548546', 'ceilandia', 'df', '40028922') | ||
db.session.add(User( | ||
username='michael', | ||
email='[email protected]', | ||
password='greaterthaneight', | ||
company_id=company.id | ||
)) | ||
company_two = add_company('Kalkuli', '00.000.000/0000-00', '[email protected]', 'kaliu', '789548546', 'ceilandia', 'df', '40028922') | ||
db.session.add(User( | ||
username='michaelherman', | ||
email='[email protected]', | ||
password='greaterthaneight', | ||
company_id=company_two.id | ||
)) | ||
db.session.commit() | ||
|
||
if __name__ == '__main__': | ||
cli() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,28 @@ | ||
import os | ||
from flask import Flask, jsonify | ||
from flask_sqlalchemy import SQLAlchemy | ||
from flask_bcrypt import Bcrypt | ||
from flask_migrate import Migrate | ||
|
||
# Instantiate the app | ||
app = Flask(__name__) | ||
# instantiate the extensions | ||
db = SQLAlchemy() | ||
migrate = Migrate() | ||
bcrypt = Bcrypt() | ||
|
||
def create_app(script_info=None): | ||
#Instantiate the app | ||
app = Flask(__name__) | ||
|
||
# Set Configuration | ||
app_settings = os.getenv('APP_SETTINGS') | ||
app.config.from_object(app_settings) | ||
# Set Configuration | ||
app_settings = os.getenv('APP_SETTINGS') | ||
app.config.from_object(app_settings) | ||
|
||
# Instanciate Database | ||
db = SQLAlchemy(app) | ||
# set up extensions | ||
db.init_app(app) | ||
migrate.init_app(app, db) | ||
bcrypt.init_app(app) | ||
|
||
from project.api.views import user_blueprint | ||
app.register_blueprint(user_blueprint) | ||
|
||
@app.route('/', methods=['GET']) | ||
def ping_pong(): | ||
return jsonify({ | ||
'data': 'Welcome to Kalkuli Users Service!!' | ||
}) | ||
return app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,102 @@ | ||
from project import db | ||
from sqlalchemy_utils import PasswordType, EmailType, force_auto_coercion | ||
import datetime | ||
import jwt | ||
from project import create_app | ||
from sqlalchemy_utils import PasswordType, EmailType | ||
from project import bcrypt | ||
from flask import current_app | ||
|
||
force_auto_coercion() | ||
|
||
class Company(db.Model): | ||
__tablename__ = 'company' | ||
id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
company_name = db.Column(db.String(128), nullable=False) | ||
cnpj = db.Column(db.Integer, nullable=False) | ||
users = db.relationship('User', backref='company', lazy=True) | ||
id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
company_name = db.Column(db.String(128), nullable=False) | ||
cnpj = db.Column(db.String, nullable=True) | ||
user = db.relationship('User', uselist=False, back_populates='company') | ||
company_email = db.Column(db.String(128), nullable=False, unique=True) | ||
fantasy_name = db.Column(db.String(128), nullable=True) | ||
cep = db.Column(db.String(128), nullable=True) | ||
city = db.Column(db.String(128), nullable=True) | ||
state = db.Column(db.String(128), nullable=True) | ||
company_phone = db.Column(db.String(128), nullable=True) | ||
|
||
def __init__(self, company_name, cnpj): | ||
self.company_name = company_name | ||
self.cnpj = cnpj | ||
def __init__(self, company_name, cnpj, company_email, fantasy_name, cep, city, state, company_phone): | ||
self.company_name = company_name | ||
self.cnpj = cnpj | ||
self.company_email = company_email | ||
self.fantasy_name = fantasy_name | ||
self.cep = cep | ||
self.city = city | ||
self.state = state | ||
self.company_phone = company_phone | ||
|
||
def to_json(self): | ||
return { | ||
'id': self.id, | ||
'company_name': self.company_name, | ||
'cnpj': self.cnpj, | ||
'company_email': self.company_email, | ||
'fantasy_name': self.fantasy_name, | ||
'cep': self.cep, | ||
'city': self.city, | ||
'state': self.state, | ||
'company_phone': self.company_phone | ||
} | ||
|
||
|
||
class User(db.Model): | ||
__tablename__ = 'user' | ||
id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
name = db.Column(db.String(128), nullable=False) | ||
email = db.Column(EmailType, nullable=False) | ||
is_admin = db.Column(db.Boolean(), default=False, nullable=False) | ||
company_id = db.Column(db.Integer, db.ForeignKey('company.id'), nullable=False) | ||
password = db.Column(PasswordType(schemes=[ 'pbkdf2_sha512' ]), unique=False,nullable=False) | ||
|
||
id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
username = db.Column(db.String(128), nullable=False) | ||
email = db.Column(EmailType, nullable=False, unique=True) | ||
registered_on = db.Column(db.DateTime, nullable=False) | ||
company_id = db.Column(db.Integer, db.ForeignKey('company.id'), nullable=False) | ||
company = db.relationship('Company', back_populates='user') | ||
active = db.Column(db.Boolean(), default=True, nullable=False) | ||
password = db.Column(db.String(255), unique=False,nullable=False) | ||
|
||
def __init__(self, name, email, is_admin, company_id, password): | ||
self.name = name | ||
self.email = email | ||
self.is_admin = is_admin | ||
self.company_id = company_id | ||
self.password = password | ||
def __init__(self, username, email, company_id, password): | ||
self.username = username | ||
self.email = email | ||
self.company_id = company_id | ||
self.password = bcrypt.generate_password_hash(password, current_app.config.get('BCRYPT_LOG_ROUNDS')).decode() | ||
self.registered_on = datetime.datetime.now() | ||
|
||
def to_json(self): | ||
return { | ||
'username': self.username, | ||
'email': self.email, | ||
'company_id': self.company_id, | ||
'password': self.password, | ||
'active': self.active | ||
} | ||
|
||
def encode_auth_token(self, user_id): | ||
try: | ||
payload = { | ||
'exp': datetime.datetime.utcnow() + datetime.timedelta( | ||
days=current_app.config.get('TOKEN_EXPIRATION_DAYS'), | ||
seconds=current_app.config.get('TOKEN_EXPIRATION_SECONDS') | ||
), | ||
'iat': datetime.datetime.utcnow(), | ||
'sub': user_id | ||
} | ||
return jwt.encode( | ||
payload, | ||
current_app.config.get('SECRET_KEY'), | ||
algorithm='HS256' | ||
) | ||
except Exception as e: | ||
return e | ||
|
||
|
||
|
||
|
||
@staticmethod | ||
def decode_auth_token(auth_token): | ||
try: | ||
payload = jwt.decode( | ||
auth_token, current_app.config.get('SECRET_KEY')) | ||
return payload['sub'] | ||
except jwt.ExpiredSignatureError: | ||
return 'Signature expired. Please log in again.' | ||
except jwt.InvalidTokenError: | ||
return 'Invalid token. Please log in again.' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from functools import wraps | ||
from flask import request, jsonify | ||
from project.api.models import User | ||
|
||
|
||
def authenticate(f): | ||
@wraps(f) | ||
def decorated_function(*args, **kwargs): | ||
response_object = { | ||
'status': 'fail', | ||
'message': 'Provide a valid auth token.' | ||
} | ||
auth_header = request.headers.get('Authorization') | ||
|
||
if not auth_header: | ||
return jsonify(response_object), 403 | ||
auth_token = auth_header.split(" ")[1] | ||
resp = User.decode_auth_token(auth_token) | ||
|
||
if isinstance(resp, str): | ||
response_object['message'] = resp | ||
return jsonify(response_object), 401 | ||
user = User.query.filter_by(id=resp).first() | ||
|
||
if not user or not user.active: | ||
return jsonify(response_object), 401 | ||
return f(resp, *args, **kwargs) | ||
|
||
return decorated_function |
Oops, something went wrong.