From 096e9a4c7111e19dc372cbdd1ba2cbe8751d2d91 Mon Sep 17 00:00:00 2001 From: Josue Kouka Date: Tue, 23 May 2017 00:40:18 +0200 Subject: [PATCH 1/6] cityweb: add city web data source endpoints (#15883) --- passerelle/contrib/cityweb/__init__.py | 0 passerelle/contrib/cityweb/models.py | 124 ++++++++++++++++++++++++ passerelle/contrib/cityweb/utils.py | 42 +++++++++ tests/settings.py | 2 + tests/test_cityweb.py | 168 +++++++++++++++++++++++++++++++++ 5 files changed, 336 insertions(+) create mode 100644 passerelle/contrib/cityweb/__init__.py create mode 100644 passerelle/contrib/cityweb/models.py create mode 100644 passerelle/contrib/cityweb/utils.py create mode 100644 tests/test_cityweb.py diff --git a/passerelle/contrib/cityweb/__init__.py b/passerelle/contrib/cityweb/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/passerelle/contrib/cityweb/models.py b/passerelle/contrib/cityweb/models.py new file mode 100644 index 0000000..2aea46b --- /dev/null +++ b/passerelle/contrib/cityweb/models.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2017 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 . + +import json + +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +from passerelle.base.models import BaseResource +from passerelle.utils.api import endpoint + + +EVENTS_KIND = [ + {"id": "NAI", "text": "Naissance"}, + {"id": "MAR", "text": "Mariage"}, + {"id": "REC", "text": "Reconnaissance"}, + {"id": "DEC", "text": "Décès"} +] + +GENDERS = [ + {"id": "M", "text": "Homme"}, + {"id": "F", "text": "Femme"}, + {"id": "NA", "text": "Autre"} +] + +TITLES = [ + {"id": "M", "text": "Monsieur"}, + {"id": "Mme", "text": "Madame"}, + {"id": "Mlle", "text": "Mademoiselle"} +] + +DOCUMENTS_KIND = [ + {"id": "CPI", "text": "Copie intégrale"}, + {"id": "EXTAF", "text": "Extrait avec filiation"}, + {"id": "EXTSF", "text": "Extrait sans filiation"}, + {"id": "EXTPL", "text": "Extrait plurilingue"} +] + +CONCERNED = [ + {"id": "reconnu", "text": "Reconnu"}, + {"id": "auteur", "text": "Auteur"} +] + +CANALS = [ + {"id": "internet", "text": "Internet"}, + {"id": "guichet", "text": "Guichet"}, + {"id": "courrier", "text": "Courrier"} +] + + +class CityWeb(BaseResource): + category = _('Business Process Connectors') + + class Meta: + verbose_name = "CityWeb - Demande d'acte d'etat civil" + + @classmethod + def get_verbose_name(cls): + return cls._meta.verbose_name + + @endpoint(serializer_type='json-api', perm='can_access', methods=['post']) + def create(self, request, *args, **kwargs): + formdata = json.loads(request.body) + demand, created = Demand.objects.get_or_create(resource=self, demand_id='demand_id', + kind='kind') + result = demand.create(formdata) + return {'demand_id': result} + + @endpoint(serializer_type='json-api', perm='can_access') + def titles(self, request, without=''): + return TITLES + + @endpoint(serializer_type='json-api', perm='can_access') + def genders(self, request, without=''): + return GENDERS + + @endpoint(serializer_type='json-api', perm='can_access') + def concerned(self, request, without=''): + return CONCERNED + + @endpoint(serializer_type='json-api', perm='can_access') + def canals(self, request, without=''): + return CANALS + + @endpoint(name='events-kind', serializer_type='json-api', perm='can_access') + def events_kind(self, request, without=''): + return [item for item in EVENTS_KIND + if item.get('id') not in without.split(',')] + + @endpoint(name='documents-kind', serializer_type='json-api', perm='can_access') + def documents_kind(self, request, without=''): + return [item for item in DOCUMENTS_KIND + if item.get('id') not in without.split(',')] + + +class Demand(models.Model): + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + resource = models.ForeignKey(CityWeb) + name = models.CharField(max_length=32) + kind = models.CharField(max_length=32) + + def __unicode__(self): + return '%s - %s - %s' % (self.resource.slug, self.name, self.kind) + + @property + def filename(self): + pass + + def create(self, data): + pass diff --git a/passerelle/contrib/cityweb/utils.py b/passerelle/contrib/cityweb/utils.py new file mode 100644 index 0000000..4c8c209 --- /dev/null +++ b/passerelle/contrib/cityweb/utils.py @@ -0,0 +1,42 @@ +# Copyright (C) 2017 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 . + +import os +import zipfile + +from django.core.files.storage import default_storage + + +def flatten_payload(*subs): + result = {} + for sub in subs: + result.update(sub) # priority on last sub dict + return result + + +def get_resource_base_dir(): + return default_storage.path('cityweb') + + +def zipdir(path): + """Zip directory + """ + archname = path + '.zip' + with zipfile.ZipFile(archname, 'w', zipfile.ZIP_DEFLATED) as zipf: + for root, dirs, files in os.walk(path): + for f in files: + fpath = os.path.join(root, f) + zipf.write(fpath, os.path.basename(fpath)) + return archname diff --git a/tests/settings.py b/tests/settings.py index 0dc081e..a29d6cd 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -28,6 +28,7 @@ INSTALLED_APPS += ( 'passerelle.contrib.stub_invoices', 'passerelle.contrib.teamnet_axel', 'passerelle.contrib.tlmcom', + 'passerelle.contrib.cityweb', ) PASSERELLE_APP_FAKE_FAMILY_ENABLED = True @@ -39,3 +40,4 @@ PASSERELLE_APP_ARCGIS_ENABLED = True PASSERELLE_APP_SOLIS_APA_ENABLED = True PASSERELLE_APP_MDEL_ENABLED = True PASSERELLE_APP_GRANDLYON_STREETSECTIONS_ENABLED = True +PASSERELLE_APP_CITYWEB_ENABLED = True diff --git a/tests/test_cityweb.py b/tests/test_cityweb.py new file mode 100644 index 0000000..1480a03 --- /dev/null +++ b/tests/test_cityweb.py @@ -0,0 +1,168 @@ +# -*- coding: utf-8 -*- +# Passerelle - uniform access to data and services +# Copyright (C) 2017 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.deepcopy of the GNU Affero General Public License +# along with this program. If not, see . +from __future__ import unicode_literals + +import os +import json +import shutil + +import pytest +import mock + +import utils + +from passerelle.contrib.cityweb.models import CityWeb + + +CITYWEB_TEST_BASE_DIR = os.path.join(os.path.dirname(__file__), 'data', 'cityweb') + + +def get_file_from_test_base_dir(filename): + path = os.path.join(CITYWEB_TEST_BASE_DIR, filename) + with open(path, 'rb') as fd: + return fd.read() + + +@pytest.fixture +def setup(db): + return utils.setup_access_rights(CityWeb.objects.create(slug='test')) + + +PAYLOAD = [ + { + 'naissance': json.loads(get_file_from_test_base_dir('formdata_nais.json')) + }, + { + 'mariage': json.loads(get_file_from_test_base_dir('formdata_mar.json')) + }, + { + 'deces': json.loads(get_file_from_test_base_dir('formdata_dec.json')) + } +] + + +@pytest.fixture(params=PAYLOAD) +def payload(request): + return request.param + + +@mock.patch('passerelle.contrib.cityweb.utils.get_resource_base_dir', CITYWEB_TEST_BASE_DIR) +def test_demand_creation(app, setup, payload): + if 'naissance' in payload: + pass + elif 'mariage' in payload: + pass + else: + pass + + +def test_datasource_titles(app, setup): + response = app.get('/cityweb/test/titles/') + data = response.json['data'] + assert len(data) == 3 + for datum in data: + if datum['id'] == 'M': + assert datum['text'] == 'Monsieur' + elif datum['id'] == 'Mme': + assert datum['text'] == 'Madame' + else: + assert datum['id'] == 'Mlle' + assert datum['text'] == 'Mademoiselle' + + +def test_datasource_genders(app, setup): + response = app.get('/cityweb/test/genders/') + data = response.json['data'] + assert len(data) == 3 + for datum in data: + if datum['id'] == 'M': + assert datum['text'] + elif datum['id'] == 'F': + assert datum['text'] == 'Femme' + else: + assert datum['id'] == 'NA' + assert datum['text'] == 'Autre' + + +def test_datasource_concerned(app, setup): + response = app.get('/cityweb/test/concerned/') + data = response.json['data'] + assert len(data) == 2 + for datum in data: + if datum['id'] == 'reconnu': + assert datum['text'] == 'Reconnu' + else: + assert datum['id'] == 'auteur' + assert datum['text'] == 'Auteur' + + +def test_datasource_canals(app, setup): + response = app.get('/cityweb/test/canals/') + data = response.json['data'] + assert len(data) == 3 + for datum in data: + if datum['id'] == 'internet': + assert datum['text'] == 'Internet' + elif datum['id'] == 'guichet': + assert datum['text'] == 'Guichet' + else: + assert datum['id'] == 'courrier' + assert datum['text'] == 'Courrier' + + +def test_datasource_documents_kind(app, setup): + response = app.get('/cityweb/test/documents-kind/') + data = response.json['data'] + assert len(data) == 4 + for datum in data: + if datum['id'] == 'CPI': + assert datum['text'] == 'Copie intégrale' + elif datum['id'] == 'EXTAF': + assert datum['text'] == 'Extrait avec filiation' + elif datum['id'] == 'EXTSF': + assert datum['text'] == 'Extrait sans filiation' + else: + datum['id'] == 'EXTPL' + datum['text'] == 'Extrait plurilingue' + + params = {'without': 'EXTAF,EXTSF,EXTPL'} + response = app.get('/cityweb/test/documents-kind/', params=params) + data = response.json['data'] + assert len(data) == 1 + assert data[0]['id'] == 'CPI' + assert data[0]['text'] == 'Copie intégrale' + + +def test_datasource_events_kind(app, setup): + response = app.get('/cityweb/test/events-kind/') + data = response.json['data'] + assert len(data) == 4 + for datum in data: + if datum['id'] == 'NAI': + assert datum['text'] == 'Naissance' + elif datum['id'] == 'MAR': + assert datum['text'] == 'Mariage' + elif datum['id'] == 'REC': + assert datum['text'] == 'Reconnaissance' + else: + assert datum['id'] == 'DEC' + assert datum['text'] == 'Décès' + + +def teardown_module(module): + # remove test/inputs from fs + shutil.rmtree(os.path.join(CITYWEB_TEST_BASE_DIR, 'test', 'inputs'), ignore_errors=True) -- 2.11.0