Skip to content

Commit

Permalink
replaced flask in favor of django
Browse files Browse the repository at this point in the history
  • Loading branch information
kwahome committed Oct 8, 2018
1 parent 58a0c15 commit da917f1
Show file tree
Hide file tree
Showing 33 changed files with 444 additions and 539 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,6 @@ logs
.idea/*
.idea/
.vscode/

# static files
static/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pip install flake8 && cp devops/scripts/commit-checks.sh .git/hooks/pre-commit

Run `docker-compose up` to fire up the notification service app & critical dependencies (database, rabbitmq)

Hit this url http://localhost:80/ to access the app.
Hit this url http://localhost:80/ to access the app. This will send a request to the nginx LB that in turn proxies it to the web server backends.

- Run `docker ps -a` to see all docker containers running on your development machine:

Expand Down
20 changes: 0 additions & 20 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,21 +1 @@
from flask import Flask
from config import config_by_name
from flask_bcrypt import Bcrypt
from flask_restful import Api

flask_bcrypt = Bcrypt()


def create_app(environment):
app = Flask(__name__, instance_relative_config=True)
app.config.from_object(config_by_name[environment])
flask_bcrypt.init_app(app)

from app.api.model import db
db.init_app(app)

from app.api.views import SendMessageView
api = Api(app)
api.add_resource(SendMessageView, '/api/v1.0/sendMessage')

return app, db
49 changes: 0 additions & 49 deletions app/api/model.py

This file was deleted.

10 changes: 9 additions & 1 deletion app/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
from flask_restless import DefaultSerializer
from rest_framework import serializers


class SendMessageRequestSerializer(serializers.Serializer):
"""
Serialize class for a send message request
"""
messageId = serializers.CharField(max_length=64)
messageType = serializers.CharField(max_length=16)
87 changes: 80 additions & 7 deletions app/api/views.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,84 @@
from flask_restful import Resource, reqparse
from rest_framework import status, views
from rest_framework.response import Response
from app.auth.authentication import APIKeyAuth
from app.auth.permissions import APIPermission
from app.api.serializers import SendMessageRequestSerializer

DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT = \
'delete', 'get', 'head', 'options', 'patch', 'post', 'put'


class BaseAPIView(views.APIView):
"""
Base API View class
"""
authentication_classes = (APIKeyAuth, )
permission_classes = (APIPermission,)
allowed_methods = (GET, HEAD, OPTIONS, PATCH, POST, PUT)

class SendMessageView(Resource):
def __init__(self):
self.parser = reqparse.RequestParser()
self.req_data = None

def handler(self, request, *args, **kwargs):
allowed, response = self.is_allowed(request=request)
valid, self.req_data = self.validate(request.data)
if allowed and not valid:
response = self.bad_request()
if allowed and valid:
response = self.handle(request, *args, **kwargs)
return response

def post(self, request):
return self.handler(request, self.post.__name__)

def get(self, request, *args, **kwargs):
return self.handler(request, *args, **kwargs)

def validate(self, data):
valid = True
if hasattr(self, 'serializer'):
serialized = self.serializer(data=data)
valid = serialized.is_valid()
if not valid:
data = serialized.errors
else:
data.update(serialized.validated_data)
return valid, data

def is_allowed(self, request):
res = True, None
if request.method.lower() not in self.allowed_methods:
res = False, Response(
status=status.HTTP_405_METHOD_NOT_ALLOWED,
data={
'detail': 'Method "{}" not allowed.'.format(
request.method)
},
content_type="application/json"
)
return res

def bad_request(self):
return Response(
status=status.HTTP_400_BAD_REQUEST,
data=self.req_data,
content_type="application/json"
)

def handle(self, request, *args, **kwargs):
raise NotImplementedError(
"`handle` method has not been implemented"
)


class HealthCheckView(BaseAPIView):
"""
View that monitoring services can use to check on the 'aliveness' of a
running messaging service.
"""
allowed_methods = (GET,)

def post(self):
self.parser.add_argument('messageId', type=str)
args = self.parser.parse_args()
return args, 201
def handle(self, request, *args, **kwargs):
return Response(
status=status.HTTP_200_OK, content_type="application/json"
)
File renamed without changes.
37 changes: 37 additions & 0 deletions app/auth/authentication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from django.conf import settings
from rest_framework import HTTP_HEADER_ENCODING, authentication, exceptions


class BaseCustomAPIkeyAuth(authentication.BaseAuthentication):
"""
This creates a custom authentication class that grants access to clients
that have the right Authorization header value set.
"""
api_key = ('',)

def authenticate(self, request):
"""
Authenticate the request and returns a tuple of (None, auth) for
successful api_key authentication, otherwise return None.
"""
try:
incoming_api_key = request.META['HTTP_AUTHORIZATION']
except (AttributeError, KeyError):
return None
else:
if incoming_api_key not in self.api_keys:
raise exceptions.AuthenticationFailed()
else:
return None, incoming_api_key

@staticmethod
def authenticate_header(request):
"""
Returns value for the WWW-Authenticate header in 401 response.
Otherwise a 403 forbidden response would be generated
"""
return 'api-key'


class APIKeyAuth(BaseCustomAPIkeyAuth):
api_keys = (settings.API_KEY, )
24 changes: 24 additions & 0 deletions app/auth/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from django.conf import settings
from rest_framework import permissions


class BaseAPIPermission(permissions.BasePermission):
"""
Custom permission to only allow requests bearing appropriate api key.
"""
api_keys = ('',)

def has_permission(self, request, view):
"""
returns True if permission is granted, False otherwise.
"""
permitted = False
if request.user and request.user.is_authenticated:
permitted = True
elif request.auth and request.auth in self.api_keys:
permitted = True
return permitted


class APIPermission(BaseAPIPermission):
api_keys = (settings.API_KEY,)
63 changes: 0 additions & 63 deletions config.py

This file was deleted.

Empty file added configuration/__init__.py
Empty file.
Loading

0 comments on commit da917f1

Please sign in to comment.