mgdis: add initial connector (#88018)
gitea/passerelle/pipeline/head This commit looks good Details

This commit is contained in:
Serghei Mihai 2024-03-07 12:36:35 +01:00
parent 5d26332646
commit 6b8cdd952b
6 changed files with 312 additions and 0 deletions

View File

View File

@ -0,0 +1,86 @@
# Generated by Django 3.2.18 on 2024-03-11 09:20
from django.db import migrations, models
import passerelle.utils.templates
class Migration(migrations.Migration):
initial = True
dependencies = [
('base', '0030_resourcelog_base_resour_appname_298cbc_idx'),
]
operations = [
migrations.CreateModel(
name='Mgdis',
fields=[
(
'id',
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
('title', models.CharField(max_length=50, verbose_name='Title')),
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
('description', models.TextField(verbose_name='Description')),
(
'basic_auth_username',
models.CharField(
blank=True, max_length=128, verbose_name='Basic authentication username'
),
),
(
'basic_auth_password',
models.CharField(
blank=True, max_length=128, verbose_name='Basic authentication password'
),
),
(
'client_certificate',
models.FileField(
blank=True, null=True, upload_to='', verbose_name='TLS client certificate'
),
),
(
'trusted_certificate_authorities',
models.FileField(blank=True, null=True, upload_to='', verbose_name='TLS trusted CAs'),
),
(
'verify_cert',
models.BooleanField(blank=True, default=True, verbose_name='TLS verify certificates'),
),
(
'http_proxy',
models.CharField(blank=True, max_length=128, verbose_name='HTTP and HTTPS proxy'),
),
(
'base_url',
models.URLField(
help_text='Example: https://test.mgcloud.fr/', verbose_name='Webservice Base URL'
),
),
('tenant_id', models.CharField(max_length=128, verbose_name='Tenant identifier')),
(
'demand_name_template',
models.CharField(
default='{{ text }}',
max_length=128,
validators=[passerelle.utils.templates.validate_template],
verbose_name='Demand name template',
),
),
(
'users',
models.ManyToManyField(
blank=True,
related_name='_mgdis_mgdis_users_+',
related_query_name='+',
to='base.ApiUser',
),
),
],
options={
'verbose_name': 'MGDIS',
},
),
]

View File

@ -0,0 +1,81 @@
# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2024 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/>.
from urllib.parse import urljoin
from django.db import models
from django.utils.translation import gettext_lazy as _
from passerelle.base.models import BaseResource, HTTPResource
from passerelle.utils.api import endpoint
from passerelle.utils.jsonresponse import APIError
from passerelle.utils.templates import evaluate_template, validate_template
class Mgdis(BaseResource, HTTPResource):
base_url = models.URLField(_('Webservice Base URL'), help_text=_('Example: https://test.mgcloud.fr/'))
tenant_id = models.CharField(_('Tenant identifier'), max_length=128)
demand_name_template = models.CharField(
_('Demand name template'), max_length=128, default='{{ text }}', validators=[validate_template]
)
category = _('Business Process Connectors')
class Meta:
verbose_name = _('MGDIS')
@endpoint(
description=_('Returns user forms'),
parameters={
'NameID': {'description': _('Publik NameID'), 'example_value': 'xyz'},
'status': {'description': _('Demands status'), 'example_value': 'all'},
'tiers_id': {'description': _('Tiers identifier')},
},
)
def demands(self, request, NameID, status='all', tiers_id=None):
url = urljoin(
self.base_url, 'pda-semi-public-api/api/tenants/%s/gru-publik/mes-demandes' % self.tenant_id
)
response = self.requests.get(url, params={'suboidc': NameID, 'size': 50})
demands = []
try:
json_response = response.json()
if json_response['err']:
raise APIError('MGDIS error: %s' % json_response['err_desc'])
data = json_response.get('data', {})
for tiers in data['tiers']:
for demand in tiers.pop('demandes', []):
if tiers_id is not None and tiers['id'] != tiers_id:
continue
if status == 'draft' and not demand['draft']:
continue
if status == 'done' and not demand['form_status_is_endpoint']:
continue
if status == 'pending' and demand['draft'] and demand['form_status_is_endpoint']:
continue
demand['tiers'] = tiers
demand['status'] = demand['status']['text']
demand['name'] = evaluate_template(self.demand_name_template, demand)
demands.append(demand)
except ValueError:
raise APIError(
'MGDIS error: unparsable response', data={'content': repr(response.content[:1024])}
)
return {'data': demands}

View File

@ -168,6 +168,7 @@ INSTALLED_APPS = (
'passerelle.apps.matrix42',
'passerelle.apps.mdel',
'passerelle.apps.mdel_ddpacs',
'passerelle.apps.mgdis',
'passerelle.apps.mobyt',
'passerelle.apps.okina',
'passerelle.apps.opendatasoft',

144
tests/test_mgdis.py Normal file
View File

@ -0,0 +1,144 @@
import os
import pytest
import responses
from django.contrib.contenttypes.models import ContentType
import tests.utils
from passerelle.apps.mgdis.models import Mgdis
from passerelle.base.models import AccessRight, ApiUser
pytestmark = pytest.mark.django_db
base_dir = os.path.dirname(__file__)
MGDIS_RESPONSE = {
'data': {
'tiers': [
{
'id': 'cOy8DSnSH',
'referenceAdministrative': '00000180',
'status': {'id': 'TEMPORARY', 'text': 'En cours de cr\u00e9ation'},
'famille': {'id': ''},
'demandes': [
{
'id': 'pFuGTUYDQ',
'text': 'Demande de financement - Associations',
'datetime': '2024-01-18T10:37:33.896Z',
'status': {'id': 'REQUESTED', 'text': 'En cours de saisie'},
'teleservice': {'text': 'Demande de financement - Associations', 'id': 'F_FINASSO'},
'form_status_is_endpoint': False,
'draft': True,
'url': 'https://mgdis.example.net/aides/#/mgdis-tenant/connecte/dashboard/pFuGTUYDQ/recapitulatif',
'action_usager': False,
'compte_demandeur': True,
'tiers_beneficiaire': True,
}
],
},
{
'id': 'L7dYZD1_o',
'text': 'Monsieur Foo Bar',
'referenceAdministrative': '00000181',
'status': {'id': 'TEMPORARY', 'text': 'En cours de cr\u00e9ation'},
'famille': {'text': 'Particulier', 'id': '01'},
'mail': 'foot@example.net',
'telephone': '06 07 08 09 00',
'demandes': [
{
'id': 'BgpRIrS0X',
'text': 'Transport - Allocation individuelle de transport - Monsieur Foo Bar',
'datetime': '2024-01-18T10:37:58.355Z',
'status': {'id': 'REQUESTED', 'text': 'En cours de saisie'},
'teleservice': {
'text': 'Transport - Allocation individuelle de transport',
'id': 'F_TRANSPAIT',
},
'form_status_is_endpoint': False,
'draft': True,
'url': 'https://mdgis.example.net/aides/#/mdgis-tenant/connecte/dashboard/BgpRIrS0X/recapitulatif',
'action_usager': False,
'compte_demandeur': True,
'tiers_beneficiaire': True,
}
],
},
]
},
'err': 0,
}
MGDIS_ERROR_RESPONSE = {'data': {}, 'err': 500, 'err_desc': "Cet utilisateur n'est pas connu"}
@pytest.fixture
def mgdis():
conn = Mgdis.objects.create(slug='test', base_url='https://mgdis.example.net/', tenant_id='mgdis-tenant')
api = ApiUser.objects.create(username='all', keytype='', key='')
obj_type = ContentType.objects.get_for_model(conn)
AccessRight.objects.create(
codename='can_access', apiuser=api, resource_type=obj_type, resource_pk=conn.pk
)
return conn
@responses.activate
def test_get_user_demands(app, mgdis):
endpoint = tests.utils.generic_endpoint_url('mgdis', 'demands', slug=mgdis.slug)
assert endpoint == '/mgdis/test/demands'
responses.add(
responses.GET,
f'{mgdis.base_url}pda-semi-public-api/api/tenants/{mgdis.tenant_id}/gru-publik/mes-demandes',
json=MGDIS_RESPONSE,
status=200,
)
resp = app.get(endpoint, params={'NameID': 'xyz'})
assert len(responses.calls) == 1
assert resp.json['err'] == 0
assert len(resp.json['data']) == 2
for item in resp.json['data']:
assert 'name' in item
assert 'url' in item
assert 'draft' in item
assert 'datetime' in item
assert 'status' in item
assert 'form_status_is_endpoint' in item
resp = app.get(endpoint, params={'NameID': 'xyz', 'status': 'done'})
assert len(resp.json['data']) == 0
resp = app.get(endpoint, params={'NameID': 'xyz', 'tiers_id': 'L7dYZD1_o'})
assert len(resp.json['data']) == 1
@responses.activate
def test_mgdis_invalid_response(app, mgdis):
endpoint = tests.utils.generic_endpoint_url('mgdis', 'demands', slug=mgdis.slug)
responses.add(
responses.GET,
f'{mgdis.base_url}pda-semi-public-api/api/tenants/{mgdis.tenant_id}/gru-publik/mes-demandes',
body='<h2>Error 500</h2>',
status=200,
)
resp = app.get(endpoint, params={'NameID': 'xyz'})
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'MGDIS error: unparsable response'
@responses.activate
def test_mgdis_error_response(app, mgdis):
endpoint = tests.utils.generic_endpoint_url('mgdis', 'demands', slug=mgdis.slug)
responses.add(
responses.GET,
f'{mgdis.base_url}pda-semi-public-api/api/tenants/{mgdis.tenant_id}/gru-publik/mes-demandes',
json=MGDIS_ERROR_RESPONSE,
status=200,
)
resp = app.get(endpoint, params={'NameID': 'xyz'})
assert resp.json['err'] != 0
assert not resp.json['data']