From 2a72f1a8adb4ae54bba77eb8fff6a6c4e4e9d256 Mon Sep 17 00:00:00 2001
From: Andrew Buss <abuss@ucsd.edu>
Date: Sat, 9 May 2015 12:27:43 -0700
Subject: [PATCH] Development server now serves the frontend too

---
 README.md                |  4 +++-
 flashcards/views.py      | 10 ++++++++--
 flashy/frontend_serve.py | 15 +++++++++++++++
 flashy/urls.py           | 17 +++++++++++------
 scripts/run_local.sh     |  7 +++++++
 5 files changed, 44 insertions(+), 9 deletions(-)
 create mode 100644 flashy/frontend_serve.py
 create mode 100755 scripts/run_local.sh

diff --git a/README.md b/README.md
index 4163994..4087d22 100644
--- a/README.md
+++ b/README.md
@@ -16,4 +16,6 @@ Run tests:
 
 Run development server (local):
 
-    python manage.py runserver
\ No newline at end of file
+    scripts/run_local.sh
+
+This requires that flashy-backend be in the directory as flashy-frontend.
\ No newline at end of file
diff --git a/flashcards/views.py b/flashcards/views.py
index c23c487..16b5129 100644
--- a/flashcards/views.py
+++ b/flashcards/views.py
@@ -13,21 +13,24 @@ from rest_framework.response import Response
 from rest_framework.generics import RetrieveAPIView
 from rest_framework.exceptions import AuthenticationFailed, NotAuthenticated, ValidationError
 from simple_email_confirmation import EmailAddress
-from rest_framework import filters
+
 
 class SectionViewSet(ReadOnlyModelViewSet):
     queryset = Section.objects.all()
     serializer_class = SectionSerializer
     pagination_class = StandardResultsSetPagination
 
+
 class UserSectionViewSet(ModelViewSet):
     serializer_class = SectionSerializer
     permission_classes = [IsAuthenticated]
+
     def get_queryset(self):
         return self.request.user.sections.all()
-    
+
     def paginate_queryset(self, queryset): return None
 
+
 class UserDetail(APIView):
     def patch(self, request, format=None):
         """
@@ -127,6 +130,7 @@ class UserLogin(APIView):
 
 class UserLogout(APIView):
     permission_classes = (IsAuthenticated,)
+
     def post(self, request, format=None):
         """
         Logs the authenticated user out.
@@ -184,9 +188,11 @@ class PasswordReset(APIView):
             raise ValidationError('Could not verify reset token')
         return Response(status=HTTP_204_NO_CONTENT)
 
+
 class FlashcardDetail(RetrieveAPIView):
     queryset = Flashcard.objects.all()
     serializer_class = FlashcardSerializer
+
 ##    def get(self, request):
 
 
diff --git a/flashy/frontend_serve.py b/flashy/frontend_serve.py
new file mode 100644
index 0000000..ae7728c
--- /dev/null
+++ b/flashy/frontend_serve.py
@@ -0,0 +1,15 @@
+from django.http import Http404
+from django.views.static import serve
+
+
+def serve_with_default(*args, **kwargs):
+    """
+    Wrap Django's static file serving view. If 404, return a default file
+    """
+    default_file = kwargs.get('default_file', 'index.html')
+    del kwargs['default_file']
+    try:
+        return serve(*args, **kwargs)
+    except Http404:
+        kwargs['path'] = default_file
+        return serve(*args, **kwargs)
\ No newline at end of file
diff --git a/flashy/urls.py b/flashy/urls.py
index ccebb82..592f38d 100644
--- a/flashy/urls.py
+++ b/flashy/urls.py
@@ -1,13 +1,16 @@
 from django.conf.urls import include, url
 from django.contrib import admin
-from flashcards.views import SectionViewSet, UserDetail, UserLogin, UserLogout, PasswordReset, UserSectionViewSet, FlashcardDetail
+from flashcards.views import SectionViewSet, UserDetail, UserLogin, UserLogout, PasswordReset, UserSectionViewSet, \
+    FlashcardDetail
+from flashy.frontend_serve import serve_with_default
+from flashy.settings import DEBUG
 from rest_framework.routers import DefaultRouter
 from flashcards.api import *
 
 router = DefaultRouter()
 router.register(r'sections', SectionViewSet)
 
-router.register(r'users/me/sections', UserSectionViewSet, base_name = 'usersection')
+router.register(r'users/me/sections', UserSectionViewSet, base_name='usersection')
 
 urlpatterns = [
     url(r'^api/docs/', include('rest_framework_swagger.urls')),
@@ -18,10 +21,12 @@ urlpatterns = [
     url(r'^api/', include(router.urls)),
     url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
     url(r'^admin/', include(admin.site.urls)),
-    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'
-)),
-    url(r'^api/flashcards/(?P<pk>[0-9]+)$', FlashcardDetail.as_view(), name   \
-            ="flashcard-detail"),
+    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
+    url(r'^api/flashcards/(?P<pk>[0-9]+)$', FlashcardDetail.as_view(), name="flashcard-detail"),
 ]
 
 urlpatterns += (url(r'^admin/django-ses/', include('django_ses.urls')),)
+
+if DEBUG: urlpatterns += [url(r'^app/(?P<path>.*)$', serve_with_default,
+                              {'document_root': '../flashy-frontend', 'default_file': 'home.html'})]
+
diff --git a/scripts/run_local.sh b/scripts/run_local.sh
new file mode 100755
index 0000000..bc00c51
--- /dev/null
+++ b/scripts/run_local.sh
@@ -0,0 +1,7 @@
+#!/bin/bash -xe
+if [ ! -d "../flashy-frontend/" ]; then
+   echo "In order to serve the frontend, flashy-frontend must be in the parent dir"
+   exit 1
+fi
+source venv/bin/activate
+python manage.py runserver 127.0.0.1:8080
-- 
1.9.1