transform and push form data to wcs (#9296)

This commit is contained in:
Serghei Mihai 2016-02-24 15:47:17 +01:00
parent e150ca6d12
commit 775a1f59b1
3 changed files with 233 additions and 6 deletions

View File

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('passerelle_paris_poc_gru', '0002_auto_20160225_0743'),
]
operations = [
migrations.AddField(
model_name='parispocgru',
name='authentic_password',
field=models.CharField(default='', max_length=64, verbose_name='Authentic password'),
preserve_default=False,
),
migrations.AddField(
model_name='parispocgru',
name='authentic_username',
field=models.CharField(default='', max_length=64, verbose_name='Authentic username'),
preserve_default=False,
),
migrations.AddField(
model_name='parispocgru',
name='wcs_user_email',
field=models.EmailField(default='', help_text='to authenticate against wcs', max_length=75, verbose_name='WCS user email'),
preserve_default=False,
),
migrations.AlterField(
model_name='parispocgru',
name='consumer_key',
field=models.CharField(default=None, max_length=128, verbose_name='Consumer Key'),
preserve_default=True,
),
migrations.AlterField(
model_name='parispocgru',
name='consumer_secret',
field=models.CharField(default=None, max_length=128, verbose_name='Consumer Secret'),
preserve_default=True,
),
migrations.AlterField(
model_name='parispocgru',
name='url',
field=models.CharField(default=None, max_length=128, verbose_name='WebService Base Url'),
preserve_default=True,
),
]

View File

@ -19,6 +19,7 @@ import requests
from django.db import models
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.db import models
from passerelle.base.models import BaseResource
@ -27,15 +28,16 @@ class ParisPocGru(BaseResource):
url = models.CharField(max_length=128, blank=False,
default="not provided", verbose_name=_('WebService Base Url')
)
consumer_key = models.CharField(max_length=128, blank=False,
default="not provided", verbose_name=_('Consumer Key')
)
consumer_secret = models.CharField(max_length=128, blank=False,
default="not provided", verbose_name=_('Consumer Secret')
)
authentic_username = models.CharField(_('Authentic username'), max_length=64)
authentic_password = models.CharField(_('Authentic password'), max_length=64)
wcs_user_email = models.EmailField(_('WCS user email'),
help_text=_('to authenticate against wcs'))
category = _('Business Process Connectors')
class Meta:
@ -71,4 +73,3 @@ class ParisPocGru(BaseResource):
self.headers = {'Authorization': 'Bearer %s' %(self.access_token)}
return self.access_token

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2015-2016 Entr'ouvert
#
@ -16,20 +17,90 @@
import datetime
import json
import unicodedata
import re
import random
import requests
import time
import logging
from django.core.files.storage import default_storage
from django.conf import settings
from django.core.urlresolvers import reverse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.generic.detail import SingleObjectMixin, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.views.generic.base import View
from django.core.files.storage import default_storage
from django.utils.http import urlencode
from django.http import HttpResponse
from passerelle.base.signature import sign_url
from passerelle import utils
from .models import ParisPocGru
from .forms import ParisPocGruForm
demand_types = {
1: u"demande d'information",
2: u"reclamation"
}
domains = {
110: u"mairie",
120: u"stationnement",
100: u"autre",
200: u"autre",
210: u"Facil'familles"
}
categories = {
2: u"reservation de salle",
3: u"autre",
4: u"horaire de stationnement",
5: u"autre",
6: u"autre",
7: u"problème tarifaire périscolaire",
8: u"problème tarifaire petite enfance",
9: u"autres"
}
titles = {
'1': u'Monsieur',
'2': u'Madame'
}
contact_mode = {
1: u"mail",
2: u"phone",
3: u"mobile"
}
fields_mapping = {
'title': 'title',
'last_name': 'last_name',
'first_name': 'first_name',
'email': 'email',
'fixed_phone_number': 'fixed_phone_number',
'mobile_phone_number': 'mobile_phone_number',
'contact_mode': 'contact_mode',
'comment': 'comment',
'FFAccountNumber': 'family_number',
'IncomeRevenue-Year-2': 'tax_bill',
}
def get_authentic_site_url():
return settings.KNOWN_SERVICES.get('authentic').items()[0][1]['url']
def simplify(s, space='-'):
if s is None:
return ''
s = unicodedata.normalize('NFKD', s).encode('ascii', 'ignore')
s = re.sub(r'[^\w\s\'%s]' % space, '', s).strip().lower()
s = re.sub(r'[\s\'%s]+' % space, space, s)
return s
class ParisPocGruCreateView(CreateView):
model = ParisPocGru
form_class = ParisPocGruForm
@ -55,7 +126,112 @@ class ParisPocGruDetailView(DetailView):
class EndpointView(View, SingleObjectMixin):
model = ParisPocGru
def get_user(self, data):
logger = logging.getLogger(__name__)
a2_url = get_authentic_site_url() + 'api/users/'
headers={'Content-type': 'application/json'}
auth = (self.object.authentic_username, self.object.authentic_password)
kwargs = {'headers': headers, 'auth': auth}
uid = data['guid'].replace('-', '')
r = requests.get(a2_url + uid, **kwargs)
result = r.json()
if 'email' in result:
logger.debug('user %r found', result['email'])
return result
data = {'password': str(random.SystemRandom().random()),
'first_name': data['first_name'],
'last_name': data['last_name'],
'email': data['email'],
'username': uid,
'uuid': uid,
'title': data['title'],
'phone': data.get('fixed_phone_number'),
'mobile': data.get('mobile_phone_number')
}
r = requests.post(a2_url, data=json.dumps(data),
**kwargs)
logger.debug('user %r created', result['email'])
return r.json()
def sign_wcs_url(self, endpoint):
wcs_site = settings.KNOWN_SERVICES.get('wcs').items()[0][1]
params = {'orig': wcs_site['orig'], 'email': self.object.wcs_user_email}
url = wcs_site['url'] + endpoint
url += '?' + urlencode(params)
return sign_url(url, wcs_site.get('secret'))
def create_demand(self, data):
logger = logging.getLogger(__name__)
self.object = self.get_object()
data = data['ticket']
user = self.get_user(data.pop('user'))
extra_fields = data.pop('extra_fields')
demand_type = data.get('type')
domain = data.get('domain')
category = data.get('category')
# compute form slug from input data
assert demand_type in demand_types
form_slug = demand_types[demand_type]
assert domain in domains
form_slug += ' ' + domains[domain]
assert category in categories
form_slug += ' ' + categories[category]
logger.debug('posting to form "%r"', simplify(form_slug))
extra_fields = dict([(item['field'], {'metadata': item.get('metadata'),
'value': item['value']}) for item in extra_fields])
data.update(extra_fields)
user_uuid = user.get('uuid')
for i in xrange(50):
try:
r = requests.get(self.sign_wcs_url('api/users/%s/' % user_uuid))
user_data = r.json()
r.raise_for_status()
break
except requests.HTTPError as e:
if e.response.status_code != 404:
raise
time.sleep(0.1)
else:
# return gateway timeout if no user provisionned
return HttpResponse(status=504)
formdata = {}
for f, k in fields_mapping.iteritems():
if f == 'title':
d = titles[user.get(f)]
formdata['%s_raw' % k] = user.get(f)
elif f == 'contact_mode':
d = contact_mode[data.get(f)]
formdata['%s_raw' % k] = data.get(f)
elif f == 'IncomeRevenue-Year-2' and data.get(f):
metadata = dict([(item['name'], item['value']) for item in data.get(f, {}).get('metadata', [])])
if metadata:
d = {'filename': metadata['filename'],
'content': data.get(f, {}).get('value'),
'content_type': metadata['mimetype']}
else:
d = data.get(f, user.get(f))
if not d:
continue
if 'value' in d:
d = d['value']
formdata[str(k)] = d
data = {
'data': formdata,
'context': {'user_id': user_data['id']}
}
url = self.sign_wcs_url('api/formdefs/%s/submit' % simplify(form_slug))
response = requests.post(url, data=json.dumps(data),
headers={'Content-type': 'application/json'})
if response.json().get('err') != 0:
raise Exception('error %r' % response.content)
return response.json()['data']['id']
@method_decorator(csrf_exempt)
@utils.to_json('api')
def dispatch(self, request, *args, **kwargs):
filename = 'paris-poc-gru-dump-%s.txt' % self.get_object().slug
with default_storage.open(filename, mode='a') as fp:
@ -65,4 +241,4 @@ class EndpointView(View, SingleObjectMixin):
'qs': request.environ.get('QUERY_STRING'),
'body': request.body,
})
return utils.response_for_json(request, {})
return self.create_demand(json.loads(request.body))