From 25df9db6ff21e3d0cd7165a081bed6c59aaa5156 Mon Sep 17 00:00:00 2001 From: Bill DeRusha Date: Tue, 19 Apr 2016 11:08:29 -0400 Subject: [PATCH] WIP django catalog admin --- .../admin/api_admin/catalog/change_form.html | 50 ++++++++++++ .../admin/api_admin/catalog/change_list.html | 27 +++++++ .../api_admin/catalog_changeform.html | 49 +++++++++++ .../api_admin/catalog_changelist.html | 60 ++++++++++++++ lms/urls.py | 3 + openedx/core/djangoapps/api_admin/admin.py | 5 +- openedx/core/djangoapps/api_admin/forms.py | 10 +++ openedx/core/djangoapps/api_admin/models.py | 21 +++++ openedx/core/djangoapps/api_admin/views.py | 81 ++++++++++++++++++- openedx/core/lib/token_utils.py | 3 +- 10 files changed, 305 insertions(+), 4 deletions(-) create mode 100644 lms/templates/admin/api_admin/catalog/change_form.html create mode 100644 lms/templates/admin/api_admin/catalog/change_list.html create mode 100644 lms/templates/api_admin/catalog_changeform.html create mode 100644 lms/templates/api_admin/catalog_changelist.html diff --git a/lms/templates/admin/api_admin/catalog/change_form.html b/lms/templates/admin/api_admin/catalog/change_form.html new file mode 100644 index 0000000000..b8db8593c5 --- /dev/null +++ b/lms/templates/admin/api_admin/catalog/change_form.html @@ -0,0 +1,50 @@ +{% extends "admin/base_site.html" %} +{% load admin_modify adminmedia %} + +{% block extrahead %} +{{ block.super }} +{{ media }} +{% endblock %} + +{% block extrastyle %}{{ block.super }}{% endblock %} + +{% block coltype %}colMS{% endblock %} + +{% block bodyclass %} change-form{% endblock %} + +{% block breadcrumbs %} + +{% endblock %} + +{% block content %} +
+ {% block object-tools %} + {% endblock %} +
+ +
+ {% for field in form.visible_fields %} +
+ {{ field.errors }} + {{ field.label_tag }}{{ field }} + {% if field.field.help_text %}

{{ field.field.help_text|safe }}

{% endif %} +
+ {% endfor %} + {% for field in form.hidden_fields %} + {{ field }} + {% endfor %} + +
+ +
+
+{% endblock %} diff --git a/lms/templates/admin/api_admin/catalog/change_list.html b/lms/templates/admin/api_admin/catalog/change_list.html new file mode 100644 index 0000000000..e6785a186c --- /dev/null +++ b/lms/templates/admin/api_admin/catalog/change_list.html @@ -0,0 +1,27 @@ +{% extends "admin/base_site.html" %} +{% block extrahead %} + {{ block.super }} +{% endblock %} +{% block innercontent %} + + + + + + + + + {% for catalog in catalogs %} + + + + + {% endfor %} +
Name
  + {{catalog.name}} +
+{% endblock %} diff --git a/lms/templates/api_admin/catalog_changeform.html b/lms/templates/api_admin/catalog_changeform.html new file mode 100644 index 0000000000..de7e4b0eac --- /dev/null +++ b/lms/templates/api_admin/catalog_changeform.html @@ -0,0 +1,49 @@ +{% extends "admin/base_site.html" %} +{% load admin_modify staticfiles %} + +{% block extrahead %} +{{ block.super }} +{{ media }} +{% endblock %} + +{% block extrastyle %}{{ block.super }}{% endblock %} + +{% block coltype %}colMS{% endblock %} + +{% block bodyclass %} change-form{% endblock %} + +{% block breadcrumbs %} + +{% endblock %} + +{% block content %} +
+ {% block object-tools %} + {% endblock %} +
{% csrf_token %} +
+ {% for field in form.visible_fields %} +
+ {{ field.errors }} + {{ field.label_tag }}{{ field }} + {% if field.field.help_text %}

{{ field.field.help_text|safe }}

{% endif %} +
+ {% endfor %} + {% for field in form.hidden_fields %} + {{ field }} + {% endfor %} + +
+ +
+
+{% endblock %} diff --git a/lms/templates/api_admin/catalog_changelist.html b/lms/templates/api_admin/catalog_changelist.html new file mode 100644 index 0000000000..264580b542 --- /dev/null +++ b/lms/templates/api_admin/catalog_changelist.html @@ -0,0 +1,60 @@ +{% extends "admin/base_site.html" %} +{% load i18n admin_urls static admin_list %} + +{% block extrastyle %} + {{ block.super }} + + {% if cl.formset %} + + {% endif %} + {% if cl.formset or action_form %} + + {% endif %} + {{ media.css }} + {% if not actions_on_top and not actions_on_bottom %} + + {% endif %} +{% endblock %} + +{% block extrahead %} +{{ block.super }} +{{ media.js }} +{% endblock %} + +{% block breadcrumbs %} + +{% endblock %} + +{% block coltype %}flex{% endblock %} + +{% block content %} + {% block innercontent %} + + + + + + + + + {% for catalog in catalogs %} + + + + + {% endfor %} +
Name
  + {{catalog.name}} +
+ {% endblock %} +{% endblock %} diff --git a/lms/urls.py b/lms/urls.py index f3db4952ce..7fa30a78e0 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -113,6 +113,9 @@ urlpatterns = ( # URLs for API access management url(r'^api-admin/', include('openedx.core.djangoapps.api_admin.urls', namespace='api_admin')), + url(r'^admin/api_admin/catalog/add/$', 'openedx.core.djangoapps.api_admin.views.catalog_changeform'), + url(r'^admin/api_admin/catalog/(?P\d+)/$', 'openedx.core.djangoapps.api_admin.views.catalog_changeform'), + url(r'^admin/api_admin/catalog/$', 'openedx.core.djangoapps.api_admin.views.catalog_changelist'), ) urlpatterns += ( diff --git a/openedx/core/djangoapps/api_admin/admin.py b/openedx/core/djangoapps/api_admin/admin.py index d6018f7bd8..c3e9952442 100644 --- a/openedx/core/djangoapps/api_admin/admin.py +++ b/openedx/core/djangoapps/api_admin/admin.py @@ -2,7 +2,7 @@ from django.contrib import admin from config_models.admin import ConfigurationModelAdmin -from openedx.core.djangoapps.api_admin.models import ApiAccessRequest, ApiAccessConfig +from openedx.core.djangoapps.api_admin.models import ApiAccessRequest, ApiAccessConfig, Catalog @admin.register(ApiAccessRequest) @@ -15,5 +15,8 @@ class ApiAccessRequestAdmin(admin.ModelAdmin): readonly_fields = ('user', 'website', 'reason', 'company_name', 'company_address', 'contacted', ) exclude = ('site',) +@admin.register(Catalog) +class CatalogAdmin (admin.ModelAdmin): + name="Catalog" admin.site.register(ApiAccessConfig, ConfigurationModelAdmin) diff --git a/openedx/core/djangoapps/api_admin/forms.py b/openedx/core/djangoapps/api_admin/forms.py index 037e40d0a4..3d40d96008 100644 --- a/openedx/core/djangoapps/api_admin/forms.py +++ b/openedx/core/djangoapps/api_admin/forms.py @@ -32,3 +32,13 @@ class ApiAccessRequestForm(forms.ModelForm): # Get rid of the colons at the end of the field labels. kwargs.setdefault('label_suffix', '') super(ApiAccessRequestForm, self).__init__(*args, **kwargs) + + +class CatalogForm(forms.Form): + id = forms.IntegerField(required=False, widget=forms.HiddenInput) + name = forms.CharField(required=True, help_text="The name of this catalog") + query = forms.CharField( + required=True, + help_text="The query for courses to be returned by catalog", + widget=forms.Textarea + ) diff --git a/openedx/core/djangoapps/api_admin/models.py b/openedx/core/djangoapps/api_admin/models.py index 57ed3f6178..feca3bd469 100644 --- a/openedx/core/djangoapps/api_admin/models.py +++ b/openedx/core/djangoapps/api_admin/models.py @@ -179,3 +179,24 @@ def _send_decision_email(instance): instance.contacted = True except SMTPException: log.exception('Error sending API user notification email for request [%s].', instance.id) + + +class CatalogManager(object): + def get(self, key): + log.info("GET api call: %s", key) + return None + + def all(self): + log.info("ALL api call") + return [] + + def filter(self, **kwargs): + log.info("FILTER api call: %s", kwargs) + return [] + + +class Catalog(models.Model): + objects = CatalogManager() + + class Meta: + managed = False diff --git a/openedx/core/djangoapps/api_admin/views.py b/openedx/core/djangoapps/api_admin/views.py index 55343e6d2d..bb6c54dedb 100644 --- a/openedx/core/djangoapps/api_admin/views.py +++ b/openedx/core/djangoapps/api_admin/views.py @@ -2,10 +2,14 @@ import logging from django.conf import settings +from django.contrib.admin.views.decorators import staff_member_required from django.contrib.sites.shortcuts import get_current_site from django.core.urlresolvers import reverse_lazy, reverse -from django.shortcuts import redirect +from django.http import HttpResponseRedirect +from django.shortcuts import redirect, render +from django.template import RequestContext from django.utils.translation import ugettext as _ +from django.views.decorators.cache import never_cache from django.views.generic import View from django.views.generic.base import TemplateView from django.views.generic.edit import CreateView @@ -14,9 +18,11 @@ from oauth2_provider.models import get_application_model from oauth2_provider.views import ApplicationRegistration from edxmako.shortcuts import render_to_response +from edx_rest_api_client.client import EdxRestApiClient from openedx.core.djangoapps.api_admin.decorators import require_api_access -from openedx.core.djangoapps.api_admin.forms import ApiAccessRequestForm +from openedx.core.djangoapps.api_admin.forms import ApiAccessRequestForm, CatalogForm from openedx.core.djangoapps.api_admin.models import ApiAccessRequest +from openedx.core.lib.token_utils import get_asymmetric_token log = logging.getLogger(__name__) @@ -115,3 +121,74 @@ class ApiTosView(TemplateView): """View to show the API Terms of Service.""" template_name = 'api_admin/terms_of_service.html' + + +@never_cache +@staff_member_required +def catalog_changelist(request): + # TODO: get catalogs + catalogs = [ + { + 'id': '1', + 'name': 'test1', + 'query': '*' + } + ] + return render( + RequestContext(request), + 'api_admin/catalog_changelist.html', + { + 'catalogs': catalogs, + } + ) + + +@never_cache +@staff_member_required +def catalog_changeform(request, id=None): + # import pdb; pdb.set_trace() + if request.method == 'POST': + form = CatalogForm(request.POST) + change = False + if form.is_valid(): + if id is None: + log.info("CREATE NEW CATALOGUE") # create new catalog + else: + change = True + log.info("UPDATE CATALOGUE") # update catalog + return HttpResponseRedirect('..') + else: + if id is None: # Create new catalog + change = False + form = CatalogForm() + else: # Update existing catalog + change = True + catalog = { + 'id': '2', + 'name': 'test2', + 'query': 'test*' + } # Get catalogs + + form = CatalogForm(catalog) + # del form.fields['hidden_field'] + return render( + request, + 'api_admin/catalog_changeform.html', + { + 'change': change, + 'form': form, + } + ) + + +def catalog_client(user): + token = get_asymmetric_token(user, 'course-discovery') + return EdxRestApiClient( + "http://18.111.106.34:8008/api/v1/", + jwt=token + ) + +# from openedx.core.djangoapps.api_admin.views import catalog_client +# from django.contrib.auth.models import User +# user = User.objects.all()[1] +# c = catalog_client(user) diff --git a/openedx/core/lib/token_utils.py b/openedx/core/lib/token_utils.py index 9b5401d240..13aca508b5 100644 --- a/openedx/core/lib/token_utils.py +++ b/openedx/core/lib/token_utils.py @@ -67,7 +67,7 @@ def get_id_token(user, client_name): return jwt.encode(payload, client.client_secret) -def get_asymmetric_token(user): +def get_asymmetric_token(user, client_id): """Construct a JWT signed with this app's private key. The JWT includes the following claims: @@ -108,6 +108,7 @@ def get_asymmetric_token(user): 'iss': settings.OAUTH_OIDC_ISSUER, 'exp': now + datetime.timedelta(seconds=expires_in), 'iat': now, + 'aud': client_id, 'sub': anonymous_id_for_user(user, None), }