From 4caebeb6be0740f3308a69404ee83a5c512ad77e Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Wed, 29 May 2019 01:15:24 +0200
Subject: [PATCH] WIP ASGI

---
 config/asgi.py                     |  9 +++++++
 config/routing.py                  | 15 ++++++++++--
 config/settings/base.py            | 22 ++++++++---------
 config/wsgi.py                     | 39 ------------------------------
 retribute_api/search/consumers.py  |  7 +++++-
 retribute_api/search/exceptions.py | 10 +++++---
 retribute_api/search/webfinger.py  |  8 +++++-
 7 files changed, 52 insertions(+), 58 deletions(-)
 create mode 100644 config/asgi.py
 delete mode 100644 config/wsgi.py

diff --git a/config/asgi.py b/config/asgi.py
new file mode 100644
index 0000000..a2b51e7
--- /dev/null
+++ b/config/asgi.py
@@ -0,0 +1,9 @@
+import os
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.base")
+
+import django  # noqa
+
+django.setup()
+
+from .routing import application  # noqa
diff --git a/config/routing.py b/config/routing.py
index 1175710..cfe3534 100644
--- a/config/routing.py
+++ b/config/routing.py
@@ -1,6 +1,16 @@
+import os
+import sys
+
+app_path = os.path.abspath(
+    os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)
+)
+sys.path.append(os.path.join(app_path, "retribute_api"))
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.base")
+
+
 from django.conf.urls import url
 
-from channels.routing import ProtocolTypeRouter, URLRouter
+from channels.routing import ProtocolTypeRouter, URLRouter, AsgiHandler
 
 from retribute_api.search import consumers
 
@@ -11,7 +21,8 @@ application = ProtocolTypeRouter(
                 url(
                     r"^api/v1/search/(?P<lookup_type>.+):(?P<lookup>.+)$",
                     consumers.SearchSingleConsumer,
-                )
+                ),
+                url(r"", AsgiHandler),
             ]
         )
     }
diff --git a/config/settings/base.py b/config/settings/base.py
index 2aa5241..3c6f357 100644
--- a/config/settings/base.py
+++ b/config/settings/base.py
@@ -52,7 +52,7 @@ DATABASES["default"]["CONN_MAX_AGE"] = env.int("CONN_MAX_AGE", default=60)  # no
 ROOT_URLCONF = "config.urls"
 # https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application
 WSGI_APPLICATION = "config.wsgi.application"
-
+ASGI_APPLICATION = "config.routing.application"
 # APPS
 # ------------------------------------------------------------------------------
 DJANGO_APPS = [
@@ -63,7 +63,7 @@ DJANGO_APPS = [
     "django.contrib.staticfiles",
     "django.contrib.admin",
 ]
-THIRD_PARTY_APPS = ["rest_framework"]
+THIRD_PARTY_APPS = ["rest_framework", "channels"]
 LOCAL_APPS = [
     # Your stuff: custom apps go here
 ]
@@ -180,15 +180,6 @@ EMAIL_BACKEND = env(
     "DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend"
 )
 
-# ADMIN
-# ------------------------------------------------------------------------------
-# Django Admin URL.
-ADMIN_URL = "admin/"
-# https://docs.djangoproject.com/en/dev/ref/settings/#admins
-ADMINS = [("""Eliot Berriot""", "contact@eliotberriot.com")]
-# https://docs.djangoproject.com/en/dev/ref/settings/#managers
-MANAGERS = ADMINS
-
 # LOGGING
 # ------------------------------------------------------------------------------
 # https://docs.djangoproject.com/en/dev/ref/settings/#logging
@@ -228,6 +219,13 @@ ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=["retribute.me"])
 # ------------------------------------------------------------------------------
 CACHES = {"default": env.cache()}
 
+CHANNEL_LAYERS = {
+    "default": {
+        "BACKEND": "channels_redis.core.RedisChannelLayer",
+        "CONFIG": {"hosts": [CACHES["default"]["LOCATION"]]},
+    }
+}
+
 # SECURITY
 # ------------------------------------------------------------------------------
 # https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header
@@ -280,7 +278,7 @@ EMAIL_SUBJECT_PREFIX = env("DJANGO_EMAIL_SUBJECT_PREFIX", default="[Retribute AP
 # ADMIN
 # ------------------------------------------------------------------------------
 # Django Admin URL regex.
-ADMIN_URL = env("DJANGO_ADMIN_URL", default="^api/admin/")
+ADMIN_URL = env("DJANGO_ADMIN_URL", default="admin/")
 
 # ------------------------------------------------------------------------------
 # http://whitenoise.evans.io/en/latest/django.html#enable-whitenoise
diff --git a/config/wsgi.py b/config/wsgi.py
deleted file mode 100644
index 44972ce..0000000
--- a/config/wsgi.py
+++ /dev/null
@@ -1,39 +0,0 @@
-"""
-WSGI config for Retribute API project.
-
-This module contains the WSGI application used by Django's development server
-and any production WSGI deployments. It should expose a module-level variable
-named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
-this application via the ``WSGI_APPLICATION`` setting.
-
-Usually you will have the standard Django WSGI application here, but it also
-might make sense to replace the whole Django WSGI application with a custom one
-that later delegates to the Django one. For example, you could introduce WSGI
-middleware here, or combine a Django application with an application of another
-framework.
-
-"""
-import os
-import sys
-
-from django.core.wsgi import get_wsgi_application
-
-# This allows easy placement of apps within the interior
-# retribute_api directory.
-app_path = os.path.abspath(
-    os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)
-)
-sys.path.append(os.path.join(app_path, "retribute_api"))
-# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
-# if running multiple sites in the same mod_wsgi process. To fix this, use
-# mod_wsgi daemon mode with each site in its own daemon process, or use
-# os.environ["DJANGO_SETTINGS_MODULE"] = "config.settings.production"
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
-
-# This application object is used by any WSGI server configured to use this
-# file. This includes Django's development server, if the WSGI_APPLICATION
-# setting points here.
-application = get_wsgi_application()
-# Apply WSGI middleware here.
-# from helloworld.wsgi import HelloWorldApplication
-# application = HelloWorldApplication(application)
diff --git a/retribute_api/search/consumers.py b/retribute_api/search/consumers.py
index 2cc4e2a..01a53ef 100644
--- a/retribute_api/search/consumers.py
+++ b/retribute_api/search/consumers.py
@@ -3,6 +3,7 @@ import json
 
 from channels.generic.http import AsyncHttpConsumer
 
+from . import exceptions
 from . import sources
 
 
@@ -23,9 +24,13 @@ class SearchSingleConsumer(AsyncHttpConsumer):
         except KeyError:
             await json_response(self, 400, {"detail": "Invalid lookup"})
         try:
+            import ipdb
+
+            ipdb.set_trace()
             async with aiohttp.client.ClientSession() as session:
                 data = await source.get(lookup, session)
-        except Exception:
+        except exceptions.SearchError as e:
+            await json_response(self, 400, {"detail": e.message})
             raise
         try:
             profile = sources.result_to_retribute_profile(lookup_type, lookup, data)
diff --git a/retribute_api/search/exceptions.py b/retribute_api/search/exceptions.py
index 19836fb..7c0f7a7 100644
--- a/retribute_api/search/exceptions.py
+++ b/retribute_api/search/exceptions.py
@@ -1,10 +1,14 @@
 class SearchError(ValueError):
-    pass
+    message = "Error while retrieving remote profile"
+
+
+class InvalidLookup(SearchError):
+    message = "Invalid lookup"
 
 
 class MeansNotFound(SearchError):
-    pass
+    message = "No payment means found on remote profile"
 
 
 class SkippedProfile(SearchError):
-    pass
+    message = "Profile skipped"
diff --git a/retribute_api/search/webfinger.py b/retribute_api/search/webfinger.py
index 84ed55f..9e8cc44 100644
--- a/retribute_api/search/webfinger.py
+++ b/retribute_api/search/webfinger.py
@@ -1,8 +1,14 @@
 from rest_framework import serializers
 
+from . import exceptions
+
 
 async def lookup(name, session):
-    username, domain = name.split("@")
+    try:
+        username, domain = name.split("@")
+    except ValueError:
+        raise exceptions.InvalidLookup()
+
     async with session.get(
         "https://{}/.well-known/webfinger".format(domain),
         params={"resource": "acct:{}".format(name)},
-- 
GitLab