From 36aa1d99dab287f03d664f344216de35fe0f91a5 Mon Sep 17 00:00:00 2001 From: Emmanuel Cazenave Date: Thu, 27 May 2021 17:57:32 +0200 Subject: [PATCH] venissieux-technocarte: use wcs HTTP API to import data --- venissieux-technocarte/run.py | 195 +++++++++++++++++++++------------- 1 file changed, 121 insertions(+), 74 deletions(-) diff --git a/venissieux-technocarte/run.py b/venissieux-technocarte/run.py index a72392b..0bdd076 100644 --- a/venissieux-technocarte/run.py +++ b/venissieux-technocarte/run.py @@ -1,10 +1,26 @@ -import collections +import base64 import csv + +import datetime +import hashlib +import hmac +import random import sys import time +import urllib.parse +import requests from wcs.carddef import CardDef +CARD_ENFANT_SLUG = 'enfants' +CARD_ADULTE_SLUG = 'adultes' +CARD_FAMILLE_SLUG = 'familles' + +USER = 'admin' +WCS_BASE_URL = 'https://@wcs.dev.publik.love/api/' +EMAIL = 'admin@localhost' +WCS_ORIG = 'wcs.dev.publik.love' +WCS_KEY = 'c25fc1f82bd56b01e7cf62d785ae4410b0f7fdbebfb92a986d3fd6a150f3ba0e' FILEPATH = None ACTION = sys.argv[1] @@ -14,18 +30,47 @@ if ACTION == 'import': FILEPATH = sys.argv[2] -AdulteCardDef = CardDef.select(clause=lambda x: x.url_name == 'adultes')[0] -EnfantCardDef = CardDef.select(clause=lambda x: x.url_name == 'enfants')[0] -FamilleCardDef = CardDef.select(clause=lambda x: x.url_name == 'familles')[0] +def sign_url(url, key, algo='sha256', orig=None, timestamp=None, nonce=None): + parsed = urllib.parse.urlparse(url) + new_query = sign_query(parsed.query, key, algo, orig, timestamp, nonce) + return urllib.parse.urlunparse(parsed[:4] + (new_query,) + parsed[5:]) -def set_field(carddata, varname, value): - field = None - for field in carddata.formdef.get_all_fields(): - if field.varname == varname: - break - assert field is not None - carddata.data[field.id] = value +def sign_query(query, key, algo='sha256', orig=None, timestamp=None, nonce=None): + if timestamp is None: + timestamp = datetime.datetime.utcnow() + timestamp = timestamp.strftime('%Y-%m-%dT%H:%M:%SZ') + if nonce is None: + nonce = hex(random.getrandbits(128))[2:].rstrip('L') + new_query = query + if new_query: + new_query += '&' + new_query += urllib.parse.urlencode((('algo', algo), ('timestamp', timestamp), ('nonce', nonce))) + if orig is not None: + new_query += '&' + urllib.parse.urlencode({'orig': orig}) + signature = base64.b64encode(sign_string(new_query, key, algo=algo)) + new_query += '&' + urllib.parse.urlencode({'signature': signature}) + return new_query + + +def sign_string(s, key, algo='sha256', timedelta=30): + if not isinstance(key, bytes): + key = key.encode('utf-8') + if not isinstance(s, bytes): + s = s.encode('utf-8') + digestmod = getattr(hashlib, algo) + hash = hmac.HMAC(key, digestmod=digestmod, msg=s) + return hash.digest() + + +def api_call(url, data=None, method='post'): + url = sign_url(url + '?email=%s' % EMAIL, WCS_KEY, orig=WCS_ORIG) + if method == 'post': + resp = requests.post(url, json={'data': data}) + elif method == 'get': + resp = requests.get(url) + resp.raise_for_status() + return resp def get_field_value(carddata, varname): @@ -46,42 +91,47 @@ def get_rows(): yield row +def init_human_data(row): + data = { + 'nom': row['NOMENF'], + 'prenom': row['PREENF'] + } + codsex = row['CODSEX'] + genre = '' + if codsex == 'M': + genre = 'Homme' + elif codsex == 'F': + genre = 'Femme' + data['genre'] = genre + + if row['DATNAI']: + data['date_naissance'] = time.strftime( + '%Y-%m-%d', + time.strptime(row['DATNAI'][:10], '%d/%m/%Y') + ) + return data + + def create_adultes(): adultes = {} - + url = WCS_BASE_URL + 'cards/adultes/submit' for row in get_rows(): if row['ADULTE'] != '1': continue - adulte = AdulteCardDef.data_class()() - set_field(adulte, 'nom', row['NOMENF']) - set_field(adulte, 'prenom', row['PREENF']) - codsex = row['CODSEX'] - genre = '' - if codsex == 'M': - genre = 'Homme' - elif codsex == 'F': - genre = 'Femme' - set_field(adulte, 'genre', genre) - - if row['DATNAI']: - set_field(adulte, 'date_naissance', time.strptime(row['DATNAI'][:10], '%d/%m/%Y')) - - set_field(adulte, 'telephone', row['NUMTEL']) - set_field(adulte, 'courriel', row['MAIL']) - set_field(adulte, 'numero_voie', "%s %s" % (row['NUMVOI'], row['ADRENF1'])) - set_field(adulte, 'code_postal', row['CODPOSENF']) - set_field(adulte, 'commune', row['COMMUNE']) - adulte.store() - adulte.just_created() - adulte.store() - adulte.perform_workflow() - adulte.store() + data = init_human_data(row) + data['telephone'] = row['NUMTEL'] + data['courriel'] = row['MAIL'] + data['numero_voie'] = "%s %s" % (row['NUMVOI'], row['ADRENF1']) + data['code_postal'] = row['CODPOSENF'] + data['commune'] = row['COMMUNE'] + resp = api_call(url, data) adultes[row['CODENF']] = { 'technocarte_id': row['CODENF'], - 'publik_id': adulte.id, - 'technocarte_famille_id': row['CODFAM'] + 'publik_id': str(resp.json()['data']['id']), + 'technocarte_famille_id': row['CODFAM'], + 'nom': row['NOMENF'] } return adultes @@ -89,36 +139,18 @@ def create_adultes(): def create_enfants(): enfants = {} + url = WCS_BASE_URL + 'cards/%s/submit' % CARD_ENFANT_SLUG for row in get_rows(): if row['ADULTE'] == '1': continue - enfant = EnfantCardDef.data_class()() - set_field(enfant, 'nom', row['NOMENF']) - set_field(enfant, 'prenom', row['PREENF']) - - codsex = row['PREENF'] - genre = '' - if codsex == 'M': - genre = 'Homme' - elif codsex == 'F': - genre = 'Femme' - set_field(enfant, 'genre', genre) - - if row['DATNAI']: - set_field(enfant, 'date_naissance', time.strptime(row['DATNAI'][:10], '%d/%m/%Y')) - - enfant.store() - enfant.just_created() - enfant.store() - enfant.perform_workflow() - enfant.store() - + data = init_human_data(row) + resp = api_call(url, data) enfant = { 'technocarte_id': row['CODENF'], - 'publik_id': enfant.id, - 'technocarte_famille': row['CODFAM'] + 'publik_id': str(resp.json()['data']['id']), + 'technocarte_famille_id': row['CODFAM'] } if row['CODPEREBIO']: enfant['pere_technocarte_id'] = row['CODPEREBIO'] @@ -131,18 +163,33 @@ def create_enfants(): def create_familles(adultes, enfants): + familles_map = {} + url = WCS_BASE_URL + 'cards/%s/submit' % CARD_FAMILLE_SLUG for adulte_technocarte_id, adulte in adultes.items(): - if 'publik_famille_id' in adulte: - # ajouter comme deuxième adulte - pass + technocarte_famille_id = adulte['technocarte_famille_id'] + if technocarte_famille_id not in familles_map: + # création famille + data = { + 'famille': adulte['nom'], + 'adulte1': adulte['publik_id'] + } + url = WCS_BASE_URL + 'cards/%s/submit' % CARD_FAMILLE_SLUG + resp = api_call(url, data) + familles_map[technocarte_famille_id] = str(resp.json()['data']['id']) else: - publik_adulte = AdulteCardDef.data_class().select( - clause=lambda x: x.id == adulte['publik_id'] - )[0] - famille = FamilleCardDef.data_class()() - set_field(famille, 'famille', get_field_value(publik_adulte, 'nom')) - famille.store() - adulte['publik_famille_id'] = famille.id + # ajouter comme deuxième adulte à la famille existante + url = WCS_BASE_URL + 'cards/%s/%s/' % ( + CARD_FAMILLE_SLUG, familles_map[technocarte_famille_id] + ) + data = { + 'adulte2': adulte['publik_id'] + } + nom_famille = api_call(url, method='get').json()['fields']['famille'] + if nom_famille != adulte['nom']: + # les gens ne se marient plus + data['famille'] = "%s %s" % (nom_famille, adulte['nom']) + + api_call(url, data) def import_data(): @@ -152,9 +199,9 @@ def import_data(): def reset(): - AdulteCardDef.data_class().wipe() - EnfantCardDef.data_class().wipe() - FamilleCardDef.data_class().wipe() + CardDef.get_by_urlname(CARD_ENFANT_SLUG).data_class().wipe() + CardDef.get_by_urlname(CARD_ADULTE_SLUG).data_class().wipe() + CardDef.get_by_urlname(CARD_FAMILLE_SLUG).data_class().wipe() if ACTION == 'import':