diff --git a/apimanager/apicollections/__init__.py b/apimanager/apicollections/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apimanager/apicollections/apps.py b/apimanager/apicollections/apps.py new file mode 100644 index 0000000..c4ab07c --- /dev/null +++ b/apimanager/apicollections/apps.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +""" +App config for config app +""" + +from django.apps import AppConfig + +class ApiCollectionsConfig(AppConfig): + """Config for apicollections""" + name = 'apicollections' diff --git a/apimanager/apicollections/forms.py b/apimanager/apicollections/forms.py new file mode 100644 index 0000000..936c630 --- /dev/null +++ b/apimanager/apicollections/forms.py @@ -0,0 +1,24 @@ +from django import forms + + +class ApiCollectionsForm(forms.Form): + api_collections_body = forms.CharField( + label='API Collections Body', + widget=forms.Textarea( + attrs={ + 'class': 'form-control', + } + ), + required=False + ) + +class ApiCollectionEndpointsForm(forms.Form): + operation_id = forms.CharField( + label='Operation Id', + widget=forms.TextInput( + attrs={ + 'class': 'form-control', + } + ), + required=True + ) \ No newline at end of file diff --git a/apimanager/apicollections/static/apicollections/js/apicollections.js b/apimanager/apicollections/static/apicollections/js/apicollections.js new file mode 100644 index 0000000..d0d9d94 --- /dev/null +++ b/apimanager/apicollections/static/apicollections/js/apicollections.js @@ -0,0 +1,34 @@ +$(document).ready(function($) { + $('.runner button.forSave').click(function(e) { + e.preventDefault(); + var t = $(this); + var runner = t.parent().parent().parent(); + var api_collection_name = $(runner).find('.api_collection_name').val(); + var api_collection_is_sharable = $(runner).find('.api_collection_is_sharable').val(); + var api_collection_description = $(runner).find('.api_collection_description').val(); + + $('.runner button.forSave').attr("disabled","disabled"); + $('.runner button.forDelete').attr("disabled","disabled"); + $.post('save/apicollection', { + 'api_collection_name': api_collection_name, + 'api_collection_is_sharable': api_collection_is_sharable, + 'api_collection_description': api_collection_description, + }, function (response) { + location.reload(); + }); + }); + + $('.runner button.forDelete').click(function(e) { + e.preventDefault(); + var t = $(this); + var runner = t.parent().parent().parent(); + var api_collection_id = $(runner).find('.api_collection_id').html(); + $('.runner button.forSave').attr("disabled","disabled"); + $('.runner button.forDelete').attr("disabled","disabled"); + $.post('delete/apicollection', { + 'api_collection_id': api_collection_id + }, function (response) { + location.reload(); + }); + }); +}); diff --git a/apimanager/apicollections/templates/apicollections/detail.html b/apimanager/apicollections/templates/apicollections/detail.html new file mode 100644 index 0000000..fe7bcd7 --- /dev/null +++ b/apimanager/apicollections/templates/apicollections/detail.html @@ -0,0 +1,43 @@ +{% extends 'base.html' %} +{% load static %} +{% block content %} +
+

Add Endpoint to API Collection

+
+ {% csrf_token %} +
+
+
+ {{ form.operation_id.label_tag}} + {{ form.operation_id }} +
+ + +
+
+
+ +

Endpoints

+
+ + + + + + {% for api_collection_endpoint in api_collection_endpoints %} + + + + + {% endfor %} + +
Operation Ids
{{ api_collection_endpoint.operation_id }} +
+ {% csrf_token %} + +
+
+
+
+{% endblock %} diff --git a/apimanager/apicollections/templates/apicollections/index.html b/apimanager/apicollections/templates/apicollections/index.html new file mode 100644 index 0000000..ae552b5 --- /dev/null +++ b/apimanager/apicollections/templates/apicollections/index.html @@ -0,0 +1,85 @@ +{% extends 'base.html' %} +{% load static %} +{% block page_title %}{{ block.super }} / API Collections{% endblock page_title %} + +{% block content %} +

API Collections

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% csrf_token %} + {% for api_collection in api_collections %} + {% url 'my-api-collection-detail' api_collection.api_collection_id as url_collection_detail %} +
+
+ + {% if api_collection.api_collection_id %} +
+
+
{{ api_collection.api_collection_name }}
+
+
+
+
{{ api_collection.is_sharable }}
+
+
+
+
{{api_collection.description}}
+
+ {% else %} +
+
+ +
+
+
+
+ +
+
+
+ +
+ {% endif %} + {% if forloop.counter0 == 0 %} +
+
+ +
+
+ {% endif %} + {% if forloop.counter0 > 0 %} +
+
+ +
+
+ {% endif %} +
+
+ {% endfor %} +
+{% endblock %} + + +{% block extrajs %} + +{% endblock extrajs %} diff --git a/apimanager/apicollections/urls.py b/apimanager/apicollections/urls.py new file mode 100644 index 0000000..84fbe65 --- /dev/null +++ b/apimanager/apicollections/urls.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +""" +URLs for config app +""" + +from django.conf.urls import url + +from apicollections.views import IndexView, apicollections_save, \ + apicollections_delete, DetailView, DeleteCollectionEndpointView + +urlpatterns = [ + url(r'^$', + IndexView.as_view(), + name='apicollections-index'), + url(r'save/apicollection', apicollections_save, + name='apicollection-save'), + url(r'delete/apicollection', apicollections_delete, + name='apicollection-delete'), + url(r'^my-api-collection-ids/(?P[\w\@\.\+-]+)$', + DetailView.as_view(), + name='my-api-collection-detail'), + url(r'^delete/api-collections/(?P[\w-]+)/api-collection-endpoint/(?P[\w\@\.\+-]+)$', + DeleteCollectionEndpointView.as_view(), + name='delete-api-collection-endpoint'), + # url(r'^add/api-collections/(?P[\w-]+)/api-collection-endpoints/(?P[\w\@\.\+-]+)$', + # AddCollectionEndpointView.as_view(), + # name='add-api-collection-endpoint'), +] diff --git a/apimanager/apicollections/views.py b/apimanager/apicollections/views.py new file mode 100644 index 0000000..743a857 --- /dev/null +++ b/apimanager/apicollections/views.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +""" +Views of config app +""" + +import json +from django.contrib import messages +from django.contrib.auth.mixins import LoginRequiredMixin +from django.http import HttpResponseRedirect +from django.views.generic import FormView +from obp.api import API, APIError +from django.urls import reverse, reverse_lazy +from base.utils import exception_handle, error_once_only +from .forms import ApiCollectionsForm, ApiCollectionEndpointsForm +from django.views.decorators.csrf import csrf_exempt + + +class IndexView(LoginRequiredMixin, FormView): + """Index view for config""" + template_name = "apicollections/index.html" + form_class = ApiCollectionsForm + success_url = reverse_lazy('apicollections-index') + + def get_context_data(self, **kwargs): + context = super(IndexView, self).get_context_data(**kwargs) + api = API(self.request.session.get('obp')) + urlpath = '/my/api-collections' + api_collections =[] + try: + response = api.get(urlpath) + if 'code' in response and response['code'] >= 400: + error_once_only(self.request, response['message']) + else: + api_collections=response['api_collections'] + except APIError as err: + error_once_only(self.request, Exception("OBP-API server is not running or do not response properly. " + "Please check OBP-API server. " + "Details: " + str(err))) + except BaseException as err: + error_once_only(self.request, (Exception("Unknown Error. Details:" + str(err)))) + else: + # set the default endpoint there, the first item will be the new endpoint. + default_api_endpoint = { + "api_collection_name": "Customer", + "is_sharable": True, + "description":"Describe the purpose of the collection" + } + api_collections.insert(0,json.dumps(default_api_endpoint)) + + context.update({ + 'api_collections': api_collections + }) + return context + +class DetailView(LoginRequiredMixin, FormView): + """Index view for config""" + template_name = "apicollections/detail.html" + form_class = ApiCollectionEndpointsForm + success_url = reverse_lazy('my-api-collection-detail') + + def form_valid(self, form): + """Posts api collection endpoint data to API""" + try: + data = form.cleaned_data + api = API(self.request.session.get('obp')) + api_collection_id = super(DetailView, self).get_context_data()['view'].kwargs['api_collection_id'] + + urlpath = '/my/api-collection-ids/{}/api-collection-endpoints'.format(api_collection_id) + payload = { + 'operation_id': data['operation_id'] + } + api_collection_endpoint = api.post(urlpath, payload=payload) + except APIError as err: + messages.error(self.request, err) + return super(DetailView, self).form_invalid(form) + except: + messages.error(self.request, 'Unknown Error') + return super(DetailView, self).form_invalid(form) + if 'code' in api_collection_endpoint and api_collection_endpoint['code']>=400: + messages.error(self.request, api_collection_endpoint['message']) + return super(DetailView, self).form_invalid(form) + else: + msg = 'Operation Id {} has been added.'.format(data['operation_id']) + messages.success(self.request, msg) + self.success_url = self.request.path + return super(DetailView, self).form_valid(form) + + def get_context_data(self, **kwargs): + context = super(DetailView, self).get_context_data(**kwargs) + api_collection_id = context['view'].kwargs['api_collection_id'] + + api = API(self.request.session.get('obp')) + urlpath = '/my/api-collection-ids/{}/api-collection-endpoints'.format(api_collection_id) + api_collection_endpoints =[] + try: + response = api.get(urlpath) + if 'code' in response and response['code'] >= 400: + error_once_only(self.request, response['message']) + else: + api_collection_endpoints=response['api_collection_endpoints'] + except APIError as err: + error_once_only(self.request, Exception("OBP-API server is not running or do not response properly. " + "Please check OBP-API server. " + "Details: " + str(err))) + except BaseException as err: + error_once_only(self.request, (Exception("Unknown Error. Details:" + str(err)))) + else: + context.update({ + 'api_collection_endpoints': api_collection_endpoints, + 'api_collection_id': api_collection_id + }) + return context + +class DeleteCollectionEndpointView(LoginRequiredMixin, FormView): + """View to delete an api collection endpoint""" + def post(self, request, *args, **kwargs): + """Deletes api collection endpoint from API""" + api = API(self.request.session.get('obp')) + try: + urlpath = '/my/api-collections-ids/{}/api-collection-endpoints/{}'\ + .format(kwargs['api_collection_id'],kwargs['operation_id']) + result = api.delete(urlpath) + if result is not None and 'code' in result and result['code']>=400: + messages.error(request, result['message']) + else: + msg = 'Operation Id {} has been deleted.'.format(kwargs['operation_id']) + messages.success(request, msg) + except APIError as err: + messages.error(request, err) + except: + messages.error(self.request, 'Unknown Error') + + redirect_url = reverse('my-api-collection-detail',kwargs={"api_collection_id":kwargs['api_collection_id']}) + return HttpResponseRedirect(redirect_url) + +@exception_handle +@csrf_exempt +def apicollections_save(request): + api = API(request.session.get('obp')) + urlpath = '/my/api-collections' + payload = { + 'api_collection_name': request.POST.get('api_collection_name').strip(), + 'is_sharable': bool(request.POST.get('api_collection_is_sharable')), + 'description': request.POST.get('api_collection_description').strip() + } + result = api.post(urlpath, payload = payload) + return result + + +@exception_handle +@csrf_exempt +def apicollections_delete(request): + api_collection_id = request.POST.get('api_collection_id').strip() + + api = API(request.session.get('obp')) + urlpath = '/my/api-collections/{}'.format(api_collection_id) + result = api.delete(urlpath) + return result diff --git a/apimanager/apimanager/settings.py b/apimanager/apimanager/settings.py index 632903d..abdcb1e 100644 --- a/apimanager/apimanager/settings.py +++ b/apimanager/apimanager/settings.py @@ -58,7 +58,8 @@ INSTALLED_APPS = [ 'config', 'webui', 'methodrouting', - 'dynamicendpoints' + 'dynamicendpoints', + 'apicollections' ] MIDDLEWARE = [ diff --git a/apimanager/apimanager/urls.py b/apimanager/apimanager/urls.py index 01e4db3..3fba52b 100644 --- a/apimanager/apimanager/urls.py +++ b/apimanager/apimanager/urls.py @@ -40,4 +40,5 @@ urlpatterns = [ url(r'^webui/', include('webui.urls')), url(r'^methodrouting/', include('methodrouting.urls')), url(r'^dynamicendpoints/', include('dynamicendpoints.urls')), + url(r'^apicollections/', include('apicollections.urls')), ] diff --git a/apimanager/base/templates/base.html b/apimanager/base/templates/base.html index 7533831..c28ea9e 100644 --- a/apimanager/base/templates/base.html +++ b/apimanager/base/templates/base.html @@ -70,13 +70,15 @@ {% url "webui-index" as webui_props_index_url %} {% url "methodrouting-index" as methodrouting_index_url %} {% url "dynamicendpoints-index" as dynamic_endpoints_index_url %} + {% url "apicollections-index" as api_collections_index_url %}