246 lines
8.1 KiB
Python
246 lines
8.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
# passerelle - uniform access to multiple data sources and services
|
|
# Copyright (C) 2015-2016 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import datetime
|
|
import json
|
|
import unicodedata
|
|
import re
|
|
import random
|
|
import requests
|
|
import time
|
|
import logging
|
|
|
|
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 = {
|
|
1: u"autre",
|
|
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
|
|
template_name = 'passerelle/manage/service_form.html'
|
|
|
|
|
|
class ParisPocGruUpdateView(UpdateView):
|
|
model = ParisPocGru
|
|
form_class = ParisPocGruForm
|
|
|
|
|
|
class ParisPocGruDeleteView(DeleteView):
|
|
model = ParisPocGru
|
|
|
|
def get_success_url(self):
|
|
return reverse('manage-home')
|
|
|
|
|
|
class ParisPocGruDetailView(DetailView):
|
|
model = ParisPocGru
|
|
|
|
|
|
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': titles.get(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 = user.get(f)
|
|
formdata['%s_raw' % k] = user.get(f)
|
|
elif f == 'contact_mode':
|
|
d = contact_mode[data.get(f)]
|
|
formdata['%s_raw' % k] = str(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:
|
|
fp.write('%(datetime)s %(method)s %(qs)s\n%(body)s\n\n' % {
|
|
'datetime': datetime.datetime.now(),
|
|
'method': request.method,
|
|
'qs': request.environ.get('QUERY_STRING'),
|
|
'body': request.body,
|
|
})
|
|
return self.create_demand(json.loads(request.body))
|