Merge branch 'api' into filmowa
authorJan Szejko <jan.szejko@gmail.com>
Mon, 20 Jun 2016 12:43:04 +0000 (14:43 +0200)
committerJan Szejko <jan.szejko@gmail.com>
Mon, 20 Jun 2016 12:43:04 +0000 (14:43 +0200)
12 files changed:
api/handlers.py [new file with mode: 0644]
api/helpers.py [new file with mode: 0644]
api/templates/oauth/challenge.html [new file with mode: 0644]
api/templates/piston/authorize_token.html [new file with mode: 0644]
api/urls.py [new file with mode: 0644]
catalogue/forms.py [new file with mode: 0644]
contact/templates/contact/form.html
contact/views.py
edumed/settings/apps.py
edumed/settings/middleware.py
edumed/urls.py
requirements.txt

diff --git a/api/handlers.py b/api/handlers.py
new file mode 100644 (file)
index 0000000..5746b0c
--- /dev/null
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+import json
+
+from django.contrib.sites.models import Site
+from django.core.urlresolvers import reverse
+from django.utils.functional import lazy
+from piston.handler import BaseHandler
+from piston.utils import rc
+
+from catalogue.forms import LessonImportForm
+from catalogue.models import Lesson
+
+API_BASE = EDUMED_BASE = MEDIA_BASE = lazy(
+    lambda: u'https://' + Site.objects.get_current().domain, unicode)()
+
+
+class LessonDetails(object):
+    """Custom fields used for representing Lessons."""
+
+    @classmethod
+    def href(cls, lesson):
+        """ Returns an URI for a Lesson in the API. """
+        return API_BASE + reverse("api_lesson", args=[lesson.slug])
+
+    @classmethod
+    def url(cls, lesson):
+        """ Returns Lesson's URL on the site. """
+        return EDUMED_BASE + lesson.get_absolute_url()
+
+
+class LessonDetailHandler(BaseHandler, LessonDetails):
+    """ Main handler for Lesson objects.
+
+    Responsible for single Lesson details.
+    """
+    allowed_methods = ['GET']
+    fields = ['title', 'url']
+
+    def read(self, request, lesson):
+        """ Returns details of a lesson, identified by a slug. """
+        try:
+            return Lesson.objects.get(slug=lesson)
+        except Lesson.DoesNotExist:
+            return rc.NOT_FOUND
+
+
+class LessonsHandler(LessonDetailHandler):
+    allowed_methods = ('GET', 'POST')
+    model = Lesson
+    fields = ['href', 'title', 'url']
+
+    def create(self, request, *args, **kwargs):
+        if not request.user.has_perm('catalogue.add_lesson'):
+            return rc.FORBIDDEN
+
+        data = json.loads(request.POST.get('data'))
+        form = LessonImportForm(data)
+        if form.is_valid():
+            form.save()
+            return rc.CREATED
+        else:
+            return rc.NOT_FOUND
diff --git a/api/helpers.py b/api/helpers.py
new file mode 100644 (file)
index 0000000..a40373a
--- /dev/null
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+from piston.resource import Resource
+
+
+class CsrfExemptResource(Resource):
+    """A Custom Resource that is csrf exempt"""
+    def __init__(self, handler, authentication=None):
+        super(CsrfExemptResource, self).__init__(handler, authentication)
+        self.csrf_exempt = getattr(self.handler, 'csrf_exempt', True)
\ No newline at end of file
diff --git a/api/templates/oauth/challenge.html b/api/templates/oauth/challenge.html
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/api/templates/piston/authorize_token.html b/api/templates/piston/authorize_token.html
new file mode 100644 (file)
index 0000000..0151b58
--- /dev/null
@@ -0,0 +1,20 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block titleextra %}Zezwól na dostęp do Edukacji Medialnej{% endblock %}
+
+{% block body %}
+  <h1>Zezwól na dostęp do Edukacji Medialnej</h1>
+
+  <div class="normal-text">
+    <p>
+      Potwierdź dostęp do Edukacji Medialnej jako użytkownik <strong>{{ user }}</strong>.
+    </p>
+
+    <form action="{% url 'piston.authentication.oauth_user_auth' %}" method="POST">
+      {% csrf_token %}
+      {{ form.as_p }}
+      <button type="submit">Potwierdź</button>
+    </form>
+  </div>
+{% endblock %}
diff --git a/api/urls.py b/api/urls.py
new file mode 100644 (file)
index 0000000..a111872
--- /dev/null
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+from django.conf.urls import patterns, url
+from django.views.decorators.csrf import csrf_exempt
+from piston.authentication import OAuthAuthentication, oauth_access_token
+from piston.resource import Resource
+
+from api import handlers
+from api.helpers import CsrfExemptResource
+
+auth = OAuthAuthentication(realm="Edukacja Medialna")
+
+lesson_list_resource = CsrfExemptResource(handler=handlers.LessonsHandler, authentication=auth)
+lesson_resource = Resource(handler=handlers.LessonDetailHandler)
+
+urlpatterns = patterns(
+    'piston.authentication',
+    url(r'^oauth/request_token/$', 'oauth_request_token'),
+    url(r'^oauth/authorize/$', 'oauth_user_auth'),
+    url(r'^oauth/access_token/$', csrf_exempt(oauth_access_token)),
+)
+
+urlpatterns += patterns(
+    '',
+    # url(r'^$', TemplateView.as_view(template_name='api/main.html'), name='api'),
+
+    # objects details
+    url(r'^lessons/(?P<lesson>[a-z0-9-]+)/$', lesson_resource, name="api_lesson"),
+
+    # lessons
+    url(r'^lessons/$', lesson_list_resource, name='api_lesson_list'),
+)
diff --git a/catalogue/forms.py b/catalogue/forms.py
new file mode 100644 (file)
index 0000000..84f2e43
--- /dev/null
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+from django.forms import Form, CharField
+
+from librarian import IOFile
+from catalogue.models import Lesson
+
+
+class LessonImportForm(Form):
+    lesson_xml = CharField()
+
+    def save(self, commit=True, **kwargs):
+        return Lesson.publish(IOFile.from_string(self.cleaned_data['lesson_xml']))
index a9741f1..584629a 100644 (file)
@@ -1,5 +1,6 @@
 {% extends form.base_template|default:"base.html" %}
 {% load chunks %}
+{% load honeypot %}
 
 {% block title %}{{ form.form_title }}{% endblock %}
 
@@ -15,6 +16,7 @@
 
     <form method="POST" action="." enctype="multipart/form-data" class="submit-form">
     {% csrf_token %}
+    {% render_honeypot_field %}
     <table>
         {{ form.as_table }}
         <tr><td></td><td><button>{% block contact_form_submit %}{{ form.submit_label }}{% endblock %}</button></td></tr>
index e52b6b2..b9a411f 100644 (file)
@@ -5,10 +5,13 @@ from django.contrib.auth.decorators import permission_required
 from django.http import Http404
 from django.shortcuts import get_object_or_404, redirect, render
 from fnpdjango.utils.views import serve_file
+from honeypot.decorators import check_honeypot
+
 from .forms import contact_forms
 from .models import Attachment
 
 
+@check_honeypot
 def form(request, form_tag, force_enabled=False):
     try:
         form_class = contact_forms[form_tag]
index ca243c9..04835b5 100644 (file)
@@ -27,6 +27,7 @@ INSTALLED_APPS = (
     'django_libravatar',
     'sorl.thumbnail',
     'subdomains',
+    'piston',
 
     'django.contrib.auth',
     'django.contrib.contenttypes',
index 15ab189..3dc3278 100644 (file)
@@ -10,7 +10,6 @@ MIDDLEWARE_CLASSES = process_app_deps((
 
     'django.middleware.common.CommonMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
-    'honeypot.middleware.HoneypotMiddleware',
     ('django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth'),
     ('django_cas.middleware.CASMiddleware', 'django_cas'),
     ('django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages'),
index a62aee3..a06a2e9 100644 (file)
@@ -24,6 +24,7 @@ urlpatterns = patterns(
     url(r'^forum/', include('pybb.urls', namespace='pybb')),
     url(r'^kompetencje/', include('curriculum.urls')),
     url(r'^wtem/', include('wtem.urls')),
+    url(r'^api/', include('api.urls')),
 )
 
 
index e75d0eb..1daff32 100644 (file)
@@ -6,6 +6,7 @@ django-pipeline>=1.3,<1.4
 python-memcached
 django-piwik
 django-extensions
+django-piston==0.2.2.1.2
 #pyScss
 #git+git://github.com/Kronuz/pyScss.git@d8f4da23a3c87696a75b3830ed4ab49b75550a93#egg=pyScss
 #TODO: pyScss support, for now just install sass