Skip to content
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.pyc
*__pycache__
/env
.coverage
.env
13 changes: 13 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
language: python
python:
- "3.6"
cache: pip
install:
- pip install -r requirements.txt
before_script:
- export SECRET_KEY="secret"
script:
- pytest
- pytest --cov=app
after_success:
- coveralls
15 changes: 15 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from flask import Flask, Blueprint
from flask_restful import Api
from instance.config import app_config
from .api.v1 import myblue

def create_app(config_name):
app = Flask(__name__, instance_relative_config=True)
app.config.from_object(app_config["development"])
app.config.from_pyfile('config.py')
app.register_blueprint(myblue)

app.config["TESTING"] = True


return app
Empty file added app/api/__init__.py
Empty file.
8 changes: 8 additions & 0 deletions app/api/v1/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from flask import Flask, Blueprint
from flask_restful import Api, Resource
from .views import SignUp, Login
myblue = Blueprint("api", __name__, url_prefix="/storemanager/api/v1")

api = Api(myblue)
api.add_resource(SignUp, '/auth/signup')
api.add_resource(Login, '/auth/login')
23 changes: 23 additions & 0 deletions app/api/v1/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
users = []


class UserAuth():
def __init__(self, name, email, password, role):
self.name = username
self.email = email
self.password = password
self.role = role

def save_user(self):
id = len(users) + 1
user = {
'id' : self.id,
'name' : self.name,
'email': self.email,
'password' : self.password,
'role' : self.role
}
users.append(user)

def collapse():
users = []
Empty file added app/api/v1/utils.py
Empty file.
83 changes: 83 additions & 0 deletions app/api/v1/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from flask import jsonify, make_response, request
from flask_restful import Resource
from functools import wraps
from instance.config import Config
import datetime
import jwt
import json

from .models import *

def token_required(func):
@wraps(func)
def decorated(*args, **kwargs):
token = None
if 'x-access-token' in request.headers:
token = request.headers['x-access-token']
if not token:
return make_response(jsonify({
"Message": "the access token is missing, Login"}, 401))
try:
data = jwt.decode(token, Config.SECRET_KEY)
for user in users:
if user['email'] == data['email']:
current_user = user

except:

print(Config.SECRET_KEY)
return make_response(jsonify({
"Message": "This token is invalid"
}, 403))

return func(current_user, *args, **kwargs)
return decorated

class SignUp(Resource):
def post(self):
data = request.get_json()
id = len(users) + 1
name = data["name"]
email = data["email"]
password = data["password"]
role = data["role"]

user = {
"id": id,
"name": name,
"email": email,
"password": password,
"role": role
}
users.append(user)
return make_response(jsonify({
"Status": "ok",
"Message": "user successfully created",
"user": users
}
), 201)

class Login(Resource):
def post(self):
data = request.get_json()
if not data:
return make_response(jsonify({
"Message": "Ensure you have inserted your credentials"
}
), 401)
email = data["email"]
password = data["password"]

for user in users:
if email == user["email"] and password == user["password"]:
token = jwt.encode({
"email": email,
"exp": datetime.datetime.utcnow() + datetime.timedelta
(minutes=5)
}, Config.SECRET_KEY)
return make_response(jsonify({
"token": token.decode("UTF-8")}), 200)
return make_response(jsonify({
"Message": "Login failed, wrong entries"
}
), 401)
Empty file added app/tests/__init__.py
Empty file.
Empty file added app/tests/v1/__init__.py
Empty file.
94 changes: 94 additions & 0 deletions app/tests/v1/test_endpoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import unittest
import json
from app import create_app
from instance.config import app_config
from app.api.v1.models import collapse


class TestEndpoints(unittest.TestCase):
"""docstring for setting up testEndpoints."""
def setUp(self):
self.app = create_app(app_config['testing'])
self.test_client = self.app.test_client()
self.app_context = self.app.app_context()
self.user_admin_details = json.dumps({
"name": "kevin",
"email": "kevin@email.com",
"password": "kevin",
"role": "admin"
})
admin_signup = self.test_client.post(
"/storemanager/api/v1/auth/signup",
data=self.user_admin_details, headers={
'content-type': 'application/json'})
self.user_attendant_details = json.dumps({
"name": "brian",
"email": "brian@email.com",
"password": "brian",
"role": "attendant"
})
attendant_signup = self.test_client.post("/storemanager/api/v1/auth/signup",
data=self.user_attendant_details,
headers={
'content-type': 'application/json'
})
self.login_admin = json.dumps({
"email": "kevin@email.com",
"password": "kevin"
})
admin_login = self.test_client.post("/storemanager/api/v1/auth/login",
data=self.login_admin, headers={
'content-type': 'application/json'
})
self.token_for_admin = json.loads(admin_login.data.decode())["token"]
self.login_attendant = json.dumps({
"email": "brian@email.com",
"password": "brian"
})
attendant_login = self.test_client.post("/storemanager/api/v1/auth/login",
data=self.login_attendant,
headers={
'content-type': 'application/json'
})
self.token_for_attendant = json.loads(attendant_login.data.decode())["token"]

def tearDown(self):
"""removes all the context and dicts"""
collapse()
# self.app_context.pop()
def test_signup(self):
response = self.test_client.post("/storemanager/api/v1/auth/signup",
data=self.user_admin_details,
content_type='application/json')
self.assertEqual(response.status_code, 201)
def test_empty_login(self):
data = json.dumps(
{
"email": "",
"password": ""
}
)
response = self.test_client.post("storemanager/api/v1/auth/login",
data=data,
content_type='application/json')
self.assertEqual(response.status_code, 401)

def test_wrong_login(self):
data = json.dumps({
"email": "blah@email.com",
"password": "blahblah"
})
response = self.test_client.post("storemanager/api/v1/auth/login",
data=data,
content_type='application/json')

self.assertEqual(response.status_code, 401)

def test_login_granted(self):

response = self.test_client.post("/storemanager/api/v1/auth/login",
data=self.login_admin,
headers={
'content-type': 'application/json'
})
self.assertEqual(response.status_code, 200)
Empty file added instance/__init__.py
Empty file.
20 changes: 20 additions & 0 deletions instance/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Config():

debug = False
SECRET_KEY = "secretkey"

class Develop(Config):
"""Configuration for the development enviroment"""
debug = True


class Testing(Config):
"""Configuration for the testing enviroment"""
WTF_CSRF_ENABLED = False
debug = True


app_config={
"development": Develop,
"testing": Testing
}
Empty file added procfile
Empty file.
22 changes: 22 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
aniso8601==3.0.2
atomicwrites==1.2.1
attrs==18.2.0
Blueprints==2.3.0.2
Click==7.0
coverage==4.5.1
Flask==1.0.2
Flask-RESTful==0.3.6
funcsigs==1.0.2
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
more-itertools==4.3.0
pathlib2==2.3.2
pluggy==0.8.0
py==1.7.0
PyJWT==1.6.4
pytest==3.9.1
pytz==2018.5
scandir==1.9.0
six==1.11.0
Werkzeug==0.14.1
6 changes: 6 additions & 0 deletions run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from app import create_app

app = create_app("development")

if __name__ == '__main__':
app.run()