bdp connector (#5777)

This commit is contained in:
Thomas NOËL 2014-10-22 01:04:00 +02:00
parent 1b603959fa
commit 7c4557a623
14 changed files with 349 additions and 0 deletions

View File

View File

@ -0,0 +1,9 @@
from django.contrib import admin
from models import Bdp
class BdpAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('title',)}
admin.site.register(Bdp, BdpAdmin)

View File

@ -0,0 +1,20 @@
from django.utils.text import slugify
from django import forms
from .models import Bdp
class BdpForm(forms.ModelForm):
class Meta:
model = Bdp
exclude = ('slug', 'users')
def save(self, commit=True):
if not self.instance.slug:
self.instance.slug = slugify(self.instance.title)
return super(BdpForm, self).save(commit=commit)
class BdpUpdateForm(BdpForm):
class Meta:
model = Bdp
exclude = ('users',)

View File

@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Bdp'
db.create_table(u'bdp_bdp', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('title', self.gf('django.db.models.fields.CharField')(max_length=50)),
('slug', self.gf('django.db.models.fields.SlugField')(max_length=50)),
('description', self.gf('django.db.models.fields.TextField')()),
('service_url', self.gf('django.db.models.fields.CharField')(max_length=128)),
('username', self.gf('django.db.models.fields.CharField')(max_length=128, blank=True)),
('password', self.gf('django.db.models.fields.CharField')(max_length=128, blank=True)),
('verify_cert', self.gf('django.db.models.fields.BooleanField')(default=True)),
('keystore', self.gf('django.db.models.fields.files.FileField')(max_length=100, null=True, blank=True)),
))
db.send_create_signal(u'bdp', ['Bdp'])
# Adding M2M table for field users on 'Bdp'
m2m_table_name = db.shorten_name(u'bdp_bdp_users')
db.create_table(m2m_table_name, (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('bdp', models.ForeignKey(orm[u'bdp.bdp'], null=False)),
('apiuser', models.ForeignKey(orm[u'base.apiuser'], null=False))
))
db.create_unique(m2m_table_name, ['bdp_id', 'apiuser_id'])
def backwards(self, orm):
# Deleting model 'Bdp'
db.delete_table(u'bdp_bdp')
# Removing M2M table for field users on 'Bdp'
db.delete_table(db.shorten_name(u'bdp_bdp_users'))
models = {
u'base.apiuser': {
'Meta': {'object_name': 'ApiUser'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'fullname': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ipsource': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39', 'null': 'True', 'blank': 'True'}),
'key': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'keytype': ('django.db.models.fields.CharField', [], {'max_length': '4', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'bdp.bdp': {
'Meta': {'object_name': 'Bdp'},
'description': ('django.db.models.fields.TextField', [], {}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'keystore': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'service_url': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['base.ApiUser']", 'symmetrical': 'False', 'blank': 'True'}),
'verify_cert': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
}
}
complete_apps = ['bdp']

View File

@ -0,0 +1,66 @@
import json
import requests
from requests.auth import HTTPBasicAuth
from django.core.urlresolvers import reverse
from django.db import models
from django.utils.translation import ugettext_lazy as _
from passerelle.base.models import BaseResource
class Bdp(BaseResource):
service_url = models.CharField(max_length=128, blank=False,
verbose_name=_('Service URL'),
help_text=_('BDP Web Service URL'))
username = models.CharField(max_length=128, blank=True,
verbose_name=_('Username'))
password = models.CharField(max_length=128, blank=True,
verbose_name=_('Password'))
verify_cert = models.BooleanField(default=True,
verbose_name=_('Check HTTPS Certificate validity'))
keystore = models.FileField(upload_to='pastell',
blank=True, null=True,
verbose_name=_('Keystore'),
help_text=_('Certificate and private key in PEM format'))
category = _('Business Process Connectors')
class Meta:
verbose_name = _('BDP Web Service')
def get_absolute_url(self):
return reverse('bdp-view', kwargs={'slug': self.slug})
@classmethod
def get_add_url(cls):
return reverse('bdp-add')
@classmethod
def get_verbose_name(cls):
return cls._meta.verbose_name
@classmethod
def get_icon_class(cls):
return 'bdp'
def requests_options(self):
options = {}
if self.keystore:
options['cert'] = (self.keystore.path, self.keystore.path)
if not self.verify_cert:
options['verify'] = False
if self.username:
options['auth'] = HTTPBasicAuth(self.username, self.password)
return options
def get_api(self, endpoint, **params):
options = self.requests_options()
return requests.get(self.service_url + '/api/' + endpoint,
params=params, **options).json()
def post_api(self, endpoint, obj):
data = json.dumps(obj)
headers = {'Content-Type': 'application/json'}
options = self.requests_options()
return requests.post(self.service_url + '/api/' + endpoint,
data=data, headers=headers, **options).json()

View File

@ -0,0 +1,8 @@
{% extends "passerelle/manage.html" %}
{% block more-user-links %}
{{ block.super }}
{% if object.id %}
<a href="{% url 'bdp-view' slug=object.slug %}">{{ object.title }}</a>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,65 @@
{% extends "bdp/base.html" %}
{% load i18n passerelle %}
{% block appbar %}
<h2>BDP - {{ object.title }}</h2>
{% if perms.bdp.change_bdp %}
<a rel="popup" class="button" href="{% url 'bdp-edit' slug=object.slug %}">{% trans 'edit' %}</a>
{% endif %}
{% if perms.bdp.delete_bdp %}
<a rel="popup" class="button" href="{% url 'bdp-delete' slug=object.slug %}">{% trans 'delete' %}</a>
{% endif %}
{% endblock %}
{% block content %}
<p>
Service URL : {{ object.service_url }}
</p>
<div>
<h3>{% trans 'Endpoints' %}</h3>
<ul>
<li>{% trans 'Listing ressources:' %} <a
>{{ site_base_uri }}{% url 'bdp-ressources' slug=object.slug ressources='ressources' %}</a> (GET)</li>
<li>{% trans 'Create a new user:' %} <a
>{{ site_base_uri }}{% url 'bdp-post-adherent' slug=object.slug %}</a> (POST)</li>
</ul>
</div>
<div>
<h3>{% trans 'Examples' %}</h3>
<ul>
<li>{% trans 'Libraries:' %} <a
href="{{ site_base_uri }}{% url 'bdp-ressources' slug=object.slug ressources='bibliotheques' %}"
>{{ site_base_uri }}{% url 'bdp-ressources' slug=object.slug ressources='bibliotheques' %}</a>
</li>
<li>{% trans 'Libraries with a text label:' %} <a
href="{{ site_base_uri }}{% url 'bdp-ressources' slug=object.slug ressources='bibliotheques' %}?text_key=nom"
>{{ site_base_uri }}{% url 'bdp-ressources' slug=object.slug ressources='bibliotheques' %}?text_key=nom</a>
</li>
<li>{% trans 'Members:' %} <a
href="{{ site_base_uri }}{% url 'bdp-ressources' slug=object.slug ressources='adherents' %}"
>{{ site_base_uri }}{% url 'bdp-ressources' slug=object.slug ressources='adherents' %}</a>
</li>
<li>{% trans 'Filtered Members:' %} <a
href="{{ site_base_uri }}{% url 'bdp-ressources' slug=object.slug ressources='adherents' %}?filter[0][field]=email&filter[0][operator]=eq&filter[0][value]=login@example.net"
>{{ site_base_uri }}{% url 'bdp-ressources' slug=object.slug ressources='adherents' %}?filter[0][field]=email&filter[0][operator]=eq&filter[0][value]=login@example.net</a>
</li>
</ul>
</div>
{% if perms.base.view_accessright %}
<div>
<h3>{% trans "Security" %}</h3>
<p>
{% trans 'Accessing is limited to the following API users:' %}
</p>
{% access_rights_table resource=object permission='can_access' %}
{% endif %}
</div>
{% endblock %}

View File

@ -0,0 +1,16 @@
from django.views.decorators.csrf import csrf_exempt
from django.conf.urls import patterns, url
from django.contrib.auth.decorators import login_required
from views import *
urlpatterns = patterns('',
url(r'^(?P<slug>[\w,-]+)/$', BdpDetailView.as_view(), name='bdp-view'),
url(r'^(?P<slug>[\w,-]+)/(?P<ressources>[\w,-]+)/$', RessourcesView.as_view(), name='bdp-ressources'),
url(r'^(?P<slug>[\w,-]+)/post/adherent/$', csrf_exempt(PostAdherentView.as_view()), name='bdp-post-adherent'),
)
management_urlpatterns = patterns('',
url(r'^add$', BdpCreateView.as_view(), name='bdp-add'),
url(r'^(?P<slug>[\w,-]+)/edit$', BdpUpdateView.as_view(), name='bdp-edit'),
url(r'^(?P<slug>[\w,-]+)/delete$', BdpDeleteView.as_view(), name='bdp-delete'),
)

View File

@ -0,0 +1,88 @@
import json
from django.core.urlresolvers import reverse
from django.http import Http404
from django.views.generic.base import View
from django.views.generic.detail import SingleObjectMixin, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from jsonresponse import to_json
from passerelle import utils
from .models import Bdp
from .forms import BdpForm, BdpUpdateForm
# See documentation:
# https://dev.entrouvert.org/projects/bdp/wiki/WebServices
class RessourcesView(View, SingleObjectMixin):
model = Bdp
@utils.protected_api('can_access')
@to_json('api')
def get(self, request, *args, **kwargs):
text_key = request.GET.get('text_key')
id_key = request.GET.get('id_key')
ressources = self.get_object().get_api(kwargs['ressources'], **(request.GET))
for r in ressources:
if id_key:
r['id'] = r[id_key]
r['id'] = '%s' % r['id']
if text_key:
r['text'] = r[text_key]
elif 'text' not in r:
r['text'] = r['id']
return ressources
class PostAdherentView(View, SingleObjectMixin):
model = Bdp
def get(self, request, *args, **kwargs):
raise Http404
@utils.protected_api('can_access')
@to_json('api')
def post(self, request, *args, **kwargs):
data = json.loads(request.body) # JSON w.c.s. formdata
date_de_naissance = data['fields'].get('date_de_naissance')
if len(date_de_naissance) == 19: # 1973-04-18T00:00:00 without timezone
date_de_naissance += 'Z'
adherent = {
'nom': data['fields'].get('nom'),
'prenom': data['fields'].get('prenom'),
'email': data['fields'].get('courriel'),
'hashpass': data['fields'].get('mot_de_passe'),
'dateNaissance': date_de_naissance,
'actif': 'on',
'bibliotheque': {'id': data['fields'].get('bibliotheque_raw')},
'abonnements': '15',
}
return self.get_object().post_api('adherents', adherent)
class BdpDetailView(DetailView):
model = Bdp
template_name = 'bdp/bdp_detail.html'
class BdpCreateView(CreateView):
model = Bdp
form_class = BdpForm
template_name = 'passerelle/manage/service_form.html'
class BdpUpdateView(UpdateView):
model = Bdp
form_class = BdpUpdateForm
template_name = 'passerelle/manage/service_form.html'
class BdpDeleteView(DeleteView):
model = Bdp
template_name = 'passerelle/manage/service_confirm_delete.html'
def get_success_url(self):
return reverse('manage-home')

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -26,3 +26,6 @@ li.pastell a:hover { background-image: url(icons/icon-pastell-hover.png); }
li.concerto a { background-image: url(icons/icon-concerto.png); }
li.concerto a:hover { background-image: url(icons/icon-concerto-hover.png); }
li.bdp a { background-image: url(icons/icon-bdp.png); }
li.bdp a:hover { background-image: url(icons/icon-bdp-hover.png); }

View File

@ -18,6 +18,7 @@ import ovh.urls
import oxyd.urls
import pastell.urls
import concerto.urls
import bdp.urls
admin.autodiscover()
@ -69,6 +70,10 @@ urlpatterns = patterns('',
url(r'^manage/concerto/',
decorated_includes(login_required, include(concerto.urls.management_urlpatterns))),
url(r'^bdp/', include(bdp.urls.urlpatterns)),
url(r'^manage/bdp/',
decorated_includes(login_required, include(bdp.urls.management_urlpatterns))),
)
# activate URL for installed apps only