trivial: apply black (#49820)
This commit is contained in:
parent
4540043a25
commit
3d9df1e526
|
@ -9,6 +9,6 @@ STATIC_ROOT = 'collected-static'
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||||
'NAME': 'passerelle.sqlite3',
|
'NAME': 'passerelle.sqlite3',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,12 @@
|
||||||
# This file is sourced by "execfile" from /usr/lib/passerelle/debian_config.py
|
# This file is sourced by "execfile" from /usr/lib/passerelle/debian_config.py
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
#DEBUG = False
|
# DEBUG = False
|
||||||
|
|
||||||
#ADMINS = (
|
# ADMINS = (
|
||||||
# ('User 1', 'poulpe@example.org'),
|
# ('User 1', 'poulpe@example.org'),
|
||||||
# ('User 2', 'janitor@example.net'),
|
# ('User 2', 'janitor@example.net'),
|
||||||
#)
|
# )
|
||||||
|
|
||||||
# ALLOWED_HOSTS must be correct in production!
|
# ALLOWED_HOSTS must be correct in production!
|
||||||
# See https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
|
# See https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
|
||||||
|
@ -29,26 +29,26 @@ ALLOWED_HOSTS = ['*']
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
# Warning: don't change ENGINE, it must be 'tenant_schemas.postgresql_backend'
|
# Warning: don't change ENGINE, it must be 'tenant_schemas.postgresql_backend'
|
||||||
#DATABASES['default']['NAME'] = 'passerelle'
|
# DATABASES['default']['NAME'] = 'passerelle'
|
||||||
#DATABASES['default']['USER'] = 'passerelle'
|
# DATABASES['default']['USER'] = 'passerelle'
|
||||||
#DATABASES['default']['PASSWORD'] = '******'
|
# DATABASES['default']['PASSWORD'] = '******'
|
||||||
#DATABASES['default']['HOST'] = 'localhost'
|
# DATABASES['default']['HOST'] = 'localhost'
|
||||||
#DATABASES['default']['PORT'] = '5432'
|
# DATABASES['default']['PORT'] = '5432'
|
||||||
|
|
||||||
LANGUAGE_CODE = 'fr-fr'
|
LANGUAGE_CODE = 'fr-fr'
|
||||||
TIME_ZONE = 'Europe/Paris'
|
TIME_ZONE = 'Europe/Paris'
|
||||||
|
|
||||||
# Email configuration
|
# Email configuration
|
||||||
#EMAIL_SUBJECT_PREFIX = '[passerelle] '
|
# EMAIL_SUBJECT_PREFIX = '[passerelle] '
|
||||||
#SERVER_EMAIL = 'root@passerelle.example.org'
|
# SERVER_EMAIL = 'root@passerelle.example.org'
|
||||||
#DEFAULT_FROM_EMAIL = 'webmaster@passerelle.example.org'
|
# DEFAULT_FROM_EMAIL = 'webmaster@passerelle.example.org'
|
||||||
|
|
||||||
# SMTP configuration
|
# SMTP configuration
|
||||||
#EMAIL_HOST = 'localhost'
|
# EMAIL_HOST = 'localhost'
|
||||||
#EMAIL_HOST_USER = ''
|
# EMAIL_HOST_USER = ''
|
||||||
#EMAIL_HOST_PASSWORD = ''
|
# EMAIL_HOST_PASSWORD = ''
|
||||||
#EMAIL_PORT = 25
|
# EMAIL_PORT = 25
|
||||||
|
|
||||||
# HTTPS
|
# HTTPS
|
||||||
#CSRF_COOKIE_SECURE = True
|
# CSRF_COOKIE_SECURE = True
|
||||||
#SESSION_COOKIE_SECURE = True
|
# SESSION_COOKIE_SECURE = True
|
||||||
|
|
|
@ -9,15 +9,16 @@ def pytest_addoption(parser):
|
||||||
parser.addoption("--cmis-endpoint", help="Url of a passerelle CMIS endpoint")
|
parser.addoption("--cmis-endpoint", help="Url of a passerelle CMIS endpoint")
|
||||||
parser.addoption("--cmis-username", help="Username for the CMIS endpoint")
|
parser.addoption("--cmis-username", help="Username for the CMIS endpoint")
|
||||||
parser.addoption("--cmis-password", help="Password for the CMIS endpoint")
|
parser.addoption("--cmis-password", help="Password for the CMIS endpoint")
|
||||||
parser.addoption(
|
parser.addoption("--preserve-tree", action="store_true", default=False, help="Preserve test directory")
|
||||||
"--preserve-tree", action="store_true", default=False, help="Preserve test directory")
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def cmisclient(request):
|
def cmisclient(request):
|
||||||
return cmislib.CmisClient(
|
return cmislib.CmisClient(
|
||||||
request.config.getoption("--cmis-endpoint"), request.config.getoption("--cmis-username"),
|
request.config.getoption("--cmis-endpoint"),
|
||||||
request.config.getoption("--cmis-password"))
|
request.config.getoption("--cmis-username"),
|
||||||
|
request.config.getoption("--cmis-password"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
|
|
|
@ -10,11 +10,16 @@ import requests
|
||||||
SPECIAL_CHARS = '!#$%&+-^_`;[]{}+='
|
SPECIAL_CHARS = '!#$%&+-^_`;[]{}+='
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("path,file_name", [
|
@pytest.mark.parametrize(
|
||||||
('', 'some.file'), ('/toto', 'some.file'), ('/toto/tata', 'some.file'),
|
"path,file_name",
|
||||||
('/toto', 'some.other'),
|
[
|
||||||
('/%s' % SPECIAL_CHARS, '%(spe)s.%(spe)s' % {'spe': SPECIAL_CHARS})
|
('', 'some.file'),
|
||||||
])
|
('/toto', 'some.file'),
|
||||||
|
('/toto/tata', 'some.file'),
|
||||||
|
('/toto', 'some.other'),
|
||||||
|
('/%s' % SPECIAL_CHARS, '%(spe)s.%(spe)s' % {'spe': SPECIAL_CHARS}),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_uploadfile(cmisclient, cmis_connector, cmis_tmpdir, tmpdir, monkeypatch, path, file_name):
|
def test_uploadfile(cmisclient, cmis_connector, cmis_tmpdir, tmpdir, monkeypatch, path, file_name):
|
||||||
result_filename = 'result.file'
|
result_filename = 'result.file'
|
||||||
monkeypatch.chdir(tmpdir)
|
monkeypatch.chdir(tmpdir)
|
||||||
|
@ -25,9 +30,12 @@ def test_uploadfile(cmisclient, cmis_connector, cmis_tmpdir, tmpdir, monkeypatch
|
||||||
with orig_file.open('rb') as f:
|
with orig_file.open('rb') as f:
|
||||||
file_b64_content = base64.b64encode(f.read())
|
file_b64_content = base64.b64encode(f.read())
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
url, json={"path": cmis_tmpdir + path,
|
url,
|
||||||
"file": {"content": file_b64_content, "filename": file_name,
|
json={
|
||||||
"content_type": "image/jpeg"}})
|
"path": cmis_tmpdir + path,
|
||||||
|
"file": {"content": file_b64_content, "filename": file_name, "content_type": "image/jpeg"},
|
||||||
|
},
|
||||||
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
resp_data = response.json()
|
resp_data = response.json()
|
||||||
assert resp_data['err'] == 0
|
assert resp_data['err'] == 0
|
||||||
|
@ -50,17 +58,23 @@ def test_uploadfile_conflict(cmisclient, cmis_connector, cmis_tmpdir, tmpdir, mo
|
||||||
url = urlparse.urljoin(cmis_connector, 'uploadfile')
|
url = urlparse.urljoin(cmis_connector, 'uploadfile')
|
||||||
file_b64_content = base64.b64encode('file_content')
|
file_b64_content = base64.b64encode('file_content')
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
url, json={"path": cmis_tmpdir + '/uploadconflict',
|
url,
|
||||||
"file": {"content": file_b64_content, "filename": 'some.file',
|
json={
|
||||||
"content_type": "image/jpeg"}})
|
"path": cmis_tmpdir + '/uploadconflict',
|
||||||
|
"file": {"content": file_b64_content, "filename": 'some.file', "content_type": "image/jpeg"},
|
||||||
|
},
|
||||||
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
resp_data = response.json()
|
resp_data = response.json()
|
||||||
assert resp_data['err'] == 0
|
assert resp_data['err'] == 0
|
||||||
file_b64_content = base64.b64encode('other_file_content')
|
file_b64_content = base64.b64encode('other_file_content')
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
url, json={"path": cmis_tmpdir + '/uploadconflict',
|
url,
|
||||||
"file": {"content": file_b64_content, "filename": 'some.file',
|
json={
|
||||||
"content_type": "image/jpeg"}})
|
"path": cmis_tmpdir + '/uploadconflict',
|
||||||
|
"file": {"content": file_b64_content, "filename": 'some.file', "content_type": "image/jpeg"},
|
||||||
|
},
|
||||||
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
resp_data = response.json()
|
resp_data = response.json()
|
||||||
assert resp_data['err'] == 1
|
assert resp_data['err'] == 1
|
||||||
|
|
|
@ -2,8 +2,7 @@ import pytest
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
parser.addoption(
|
parser.addoption("--url", help="Url of a passerelle Planitech connector instance")
|
||||||
"--url", help="Url of a passerelle Planitech connector instance")
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
|
|
|
@ -7,10 +7,9 @@ import requests
|
||||||
|
|
||||||
def test_main(conn):
|
def test_main(conn):
|
||||||
# get days
|
# get days
|
||||||
query_string = parse.urlencode({
|
query_string = parse.urlencode(
|
||||||
'start_days': 1, 'end_days': 90, 'start_time': '10:00', 'end_time': '11:00',
|
{'start_days': 1, 'end_days': 90, 'start_time': '10:00', 'end_time': '11:00', 'display': 'date'}
|
||||||
'display': 'date'
|
)
|
||||||
})
|
|
||||||
url = conn + '/getfreegaps?%s' % query_string
|
url = conn + '/getfreegaps?%s' % query_string
|
||||||
resp = requests.get(url)
|
resp = requests.get(url)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
|
@ -20,10 +19,9 @@ def test_main(conn):
|
||||||
assert data
|
assert data
|
||||||
|
|
||||||
# get places
|
# get places
|
||||||
query_string = parse.urlencode({
|
query_string = parse.urlencode(
|
||||||
'start_days': 1, 'end_days': 90, 'start_time': '10:00', 'end_time': '11:00',
|
{'start_days': 1, 'end_days': 90, 'start_time': '10:00', 'end_time': '11:00', 'display': 'place'}
|
||||||
'display': 'place'
|
)
|
||||||
})
|
|
||||||
url = conn + '/getfreegaps?%s' % query_string
|
url = conn + '/getfreegaps?%s' % query_string
|
||||||
resp = requests.get(url)
|
resp = requests.get(url)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
|
@ -34,10 +32,16 @@ def test_main(conn):
|
||||||
place = data[random.randint(0, len(data) - 1)]['id']
|
place = data[random.randint(0, len(data) - 1)]['id']
|
||||||
|
|
||||||
# get days on one place
|
# get days on one place
|
||||||
query_string = parse.urlencode({
|
query_string = parse.urlencode(
|
||||||
'start_days': 1, 'end_days': 90, 'start_time': '10:00', 'end_time': '11:00',
|
{
|
||||||
'place_id': place, 'display': 'date'
|
'start_days': 1,
|
||||||
})
|
'end_days': 90,
|
||||||
|
'start_time': '10:00',
|
||||||
|
'end_time': '11:00',
|
||||||
|
'place_id': place,
|
||||||
|
'display': 'date',
|
||||||
|
}
|
||||||
|
)
|
||||||
url = conn + '/getfreegaps?%s' % query_string
|
url = conn + '/getfreegaps?%s' % query_string
|
||||||
resp = requests.get(url)
|
resp = requests.get(url)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
|
@ -55,10 +59,19 @@ def test_main(conn):
|
||||||
chosen_date = data[0]['id']
|
chosen_date = data[0]['id']
|
||||||
# create reservation
|
# create reservation
|
||||||
params = {
|
params = {
|
||||||
'date': chosen_date, 'start_time': '10:00', 'end_time': '11:00',
|
'date': chosen_date,
|
||||||
'place_id': place, 'price': 200, 'name_id': 'john-doe', 'type_id': resa_type_id,
|
'start_time': '10:00',
|
||||||
'first_name': 'jon', 'last_name': 'doe', 'activity_id': activity_id,
|
'end_time': '11:00',
|
||||||
'email': 'jon.doe@localhost', 'object': 'reservation object', 'vat_rate': 200
|
'place_id': place,
|
||||||
|
'price': 200,
|
||||||
|
'name_id': 'john-doe',
|
||||||
|
'type_id': resa_type_id,
|
||||||
|
'first_name': 'jon',
|
||||||
|
'last_name': 'doe',
|
||||||
|
'activity_id': activity_id,
|
||||||
|
'email': 'jon.doe@localhost',
|
||||||
|
'object': 'reservation object',
|
||||||
|
'vat_rate': 200,
|
||||||
}
|
}
|
||||||
print('Create reservation parameters \n')
|
print('Create reservation parameters \n')
|
||||||
pprint.pprint(params)
|
pprint.pprint(params)
|
||||||
|
@ -76,9 +89,7 @@ def test_main(conn):
|
||||||
reservation_id = data['reservation_id']
|
reservation_id = data['reservation_id']
|
||||||
|
|
||||||
# confirm reservation
|
# confirm reservation
|
||||||
params = {
|
params = {'reservation_id': reservation_id, 'status': 'standard'}
|
||||||
'reservation_id': reservation_id, 'status': 'standard'
|
|
||||||
}
|
|
||||||
url = conn + '/updatereservation'
|
url = conn + '/updatereservation'
|
||||||
resp = requests.post(url, json=params)
|
resp = requests.post(url, json=params)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
|
|
|
@ -2,8 +2,7 @@ import pytest
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
parser.addoption(
|
parser.addoption("--url", help="Url of a passerelle Toulouse Axel connector instance")
|
||||||
"--url", help="Url of a passerelle Toulouse Axel connector instance")
|
|
||||||
parser.addoption("--nameid", help="Publik Name ID")
|
parser.addoption("--nameid", help="Publik Name ID")
|
||||||
parser.addoption("--firstname", help="first name of a user")
|
parser.addoption("--firstname", help="first name of a user")
|
||||||
parser.addoption("--lastname", help="Last name of a user")
|
parser.addoption("--lastname", help="Last name of a user")
|
||||||
|
|
|
@ -45,19 +45,58 @@ def test_link(conn, user):
|
||||||
payload['DROITALIMAGE'] = 'NON'
|
payload['DROITALIMAGE'] = 'NON'
|
||||||
payload['REVENUS']['CHOIXREVENU'] = ''
|
payload['REVENUS']['CHOIXREVENU'] = ''
|
||||||
# remove non editable fields
|
# remove non editable fields
|
||||||
for key in ['SITUATIONFAMILIALE', 'SITUATIONFAMILIALE_label', 'NBENFANTACTIF', 'NBRLACTIF', 'IDDUI', 'CODEMISEAJOUR',
|
for key in [
|
||||||
'management_dates', 'annee_reference', 'annee_reference_label', 'annee_reference_short']:
|
'SITUATIONFAMILIALE',
|
||||||
|
'SITUATIONFAMILIALE_label',
|
||||||
|
'NBENFANTACTIF',
|
||||||
|
'NBRLACTIF',
|
||||||
|
'IDDUI',
|
||||||
|
'CODEMISEAJOUR',
|
||||||
|
'management_dates',
|
||||||
|
'annee_reference',
|
||||||
|
'annee_reference_label',
|
||||||
|
'annee_reference_short',
|
||||||
|
]:
|
||||||
payload.pop(key)
|
payload.pop(key)
|
||||||
for key in ['IDPERSONNE', 'NOM', 'PRENOM', 'NOMJEUNEFILLE', 'DATENAISSANCE', 'CIVILITE', 'INDICATEURRL', 'CSP_label']:
|
for key in [
|
||||||
|
'IDPERSONNE',
|
||||||
|
'NOM',
|
||||||
|
'PRENOM',
|
||||||
|
'NOMJEUNEFILLE',
|
||||||
|
'DATENAISSANCE',
|
||||||
|
'CIVILITE',
|
||||||
|
'INDICATEURRL',
|
||||||
|
'CSP_label',
|
||||||
|
]:
|
||||||
if 'RL1' in payload:
|
if 'RL1' in payload:
|
||||||
payload['RL1'].pop(key)
|
payload['RL1'].pop(key)
|
||||||
if 'RL2' in payload:
|
if 'RL2' in payload:
|
||||||
payload['RL2'].pop(key)
|
payload['RL2'].pop(key)
|
||||||
for key in ['MONTANTTOTAL', 'DATEVALIDITE', 'SFI', 'IREVENUS', 'RNF', 'NBENFANTSACHARGE', 'TYPEREGIME_label']:
|
for key in [
|
||||||
|
'MONTANTTOTAL',
|
||||||
|
'DATEVALIDITE',
|
||||||
|
'SFI',
|
||||||
|
'IREVENUS',
|
||||||
|
'RNF',
|
||||||
|
'NBENFANTSACHARGE',
|
||||||
|
'TYPEREGIME_label',
|
||||||
|
]:
|
||||||
payload['REVENUS'].pop(key, None)
|
payload['REVENUS'].pop(key, None)
|
||||||
for enfant in payload['ENFANT']:
|
for enfant in payload['ENFANT']:
|
||||||
for key in ['id', 'text', 'NOM', 'DATENAISSANCE', 'SEXE', 'PRENOMPERE', 'PRENOMMERE', 'NOMPERE', 'NOMMERE', 'RATTACHEAUTREDUI', 'PRENOM',
|
for key in [
|
||||||
'clae_cantine_current']:
|
'id',
|
||||||
|
'text',
|
||||||
|
'NOM',
|
||||||
|
'DATENAISSANCE',
|
||||||
|
'SEXE',
|
||||||
|
'PRENOMPERE',
|
||||||
|
'PRENOMMERE',
|
||||||
|
'NOMPERE',
|
||||||
|
'NOMMERE',
|
||||||
|
'RATTACHEAUTREDUI',
|
||||||
|
'PRENOM',
|
||||||
|
'clae_cantine_current',
|
||||||
|
]:
|
||||||
enfant.pop(key)
|
enfant.pop(key)
|
||||||
enfant['AUTORISATIONURGENCEMEDICALE'] = 'OUI'
|
enfant['AUTORISATIONURGENCEMEDICALE'] = 'OUI'
|
||||||
# manage contact fields
|
# manage contact fields
|
||||||
|
@ -98,8 +137,10 @@ def test_link(conn, user):
|
||||||
# add partial update flags
|
# add partial update flags
|
||||||
flags = [
|
flags = [
|
||||||
'maj:adresse',
|
'maj:adresse',
|
||||||
'maj:rl1', 'maj:rl1_adresse_employeur',
|
'maj:rl1',
|
||||||
'maj:rl2', 'maj:rl2_adresse_employeur',
|
'maj:rl1_adresse_employeur',
|
||||||
|
'maj:rl2',
|
||||||
|
'maj:rl2_adresse_employeur',
|
||||||
'maj:revenus',
|
'maj:revenus',
|
||||||
]
|
]
|
||||||
for i in range(0, 6):
|
for i in range(0, 6):
|
||||||
|
|
|
@ -2,8 +2,7 @@ import pytest
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
parser.addoption(
|
parser.addoption("--url", help="Url of a passerelle Vivaticket connector instance")
|
||||||
"--url", help="Url of a passerelle Vivaticket connector instance")
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
|
|
|
@ -4,6 +4,7 @@ import datetime
|
||||||
import requests
|
import requests
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
|
||||||
def call_generic(conn, endpoint):
|
def call_generic(conn, endpoint):
|
||||||
print("%s \n" % endpoint)
|
print("%s \n" % endpoint)
|
||||||
url = conn + '/%s' % endpoint
|
url = conn + '/%s' % endpoint
|
||||||
|
@ -21,17 +22,24 @@ def call_generic(conn, endpoint):
|
||||||
def test_get_events(conn):
|
def test_get_events(conn):
|
||||||
call_generic(conn, 'events')
|
call_generic(conn, 'events')
|
||||||
|
|
||||||
|
|
||||||
def test_get_rooms(conn):
|
def test_get_rooms(conn):
|
||||||
call_generic(conn, 'rooms')
|
call_generic(conn, 'rooms')
|
||||||
|
|
||||||
|
|
||||||
def test_get_themes(conn):
|
def test_get_themes(conn):
|
||||||
call_generic(conn, 'themes')
|
call_generic(conn, 'themes')
|
||||||
|
|
||||||
|
|
||||||
def test_book_event(conn):
|
def test_book_event(conn):
|
||||||
url = conn + '/book'
|
url = conn + '/book'
|
||||||
payload = {'id': 'formid', 'email': 'foo@example.com',
|
payload = {
|
||||||
'datetime': datetime.datetime.now().strftime('%Y-%m-%dT%H:%M'),
|
'id': 'formid',
|
||||||
'room': '001', 'theme': 'A0001', 'quantity': 1
|
'email': 'foo@example.com',
|
||||||
|
'datetime': datetime.datetime.now().strftime('%Y-%m-%dT%H:%M'),
|
||||||
|
'room': '001',
|
||||||
|
'theme': 'A0001',
|
||||||
|
'quantity': 1,
|
||||||
}
|
}
|
||||||
events = call_generic(conn, 'events')
|
events = call_generic(conn, 'events')
|
||||||
random.shuffle(events)
|
random.shuffle(events)
|
||||||
|
@ -42,7 +50,7 @@ def test_book_event(conn):
|
||||||
themes = call_generic(conn, 'themes')
|
themes = call_generic(conn, 'themes')
|
||||||
random.shuffle(themes)
|
random.shuffle(themes)
|
||||||
payload['theme'] = themes[0]['id']
|
payload['theme'] = themes[0]['id']
|
||||||
print("Creating booking with the following payload:\n%s" % payload)
|
print("Creating booking with the following payload:\n%s" % payload)
|
||||||
resp = requests.post(url, json=payload)
|
resp = requests.post(url, json=payload)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
res = resp.json()
|
res = resp.json()
|
||||||
|
|
|
@ -14,12 +14,38 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ActesWeb',
|
name='ActesWeb',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(max_length=50, verbose_name='Title')),
|
('title', models.CharField(max_length=50, verbose_name='Title')),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('log_level', models.CharField(default=b'INFO', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')])),
|
(
|
||||||
('users', models.ManyToManyField(to='base.ApiUser', related_name='_actesweb_users_+', related_query_name='+', blank=True)),
|
'log_level',
|
||||||
|
models.CharField(
|
||||||
|
default=b'INFO',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='base.ApiUser',
|
||||||
|
related_name='_actesweb_users_+',
|
||||||
|
related_query_name='+',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': "ActesWeb - Demande d'acte d'\xe9tat civil",
|
'verbose_name': "ActesWeb - Demande d'acte d'\xe9tat civil",
|
||||||
|
|
|
@ -32,6 +32,8 @@ from passerelle.compat import json_loads
|
||||||
from passerelle.utils.api import endpoint
|
from passerelle.utils.api import endpoint
|
||||||
from passerelle.utils.jsonresponse import APIError
|
from passerelle.utils.jsonresponse import APIError
|
||||||
from passerelle.utils.conversion import ensure_encoding
|
from passerelle.utils.conversion import ensure_encoding
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def named_tempfile(*args, **kwargs):
|
def named_tempfile(*args, **kwargs):
|
||||||
with tempfile.NamedTemporaryFile(*args, **kwargs) as fp:
|
with tempfile.NamedTemporaryFile(*args, **kwargs) as fp:
|
||||||
|
@ -46,8 +48,7 @@ class ActesWeb(BaseResource):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def basepath(self):
|
def basepath(self):
|
||||||
return os.path.join(
|
return os.path.join(default_storage.path('actesweb'), self.slug)
|
||||||
default_storage.path('actesweb'), self.slug)
|
|
||||||
|
|
||||||
@endpoint(perm='can_access', methods=['post'], description=_('Create demand'))
|
@endpoint(perm='can_access', methods=['post'], description=_('Create demand'))
|
||||||
def create(self, request, *args, **kwargs):
|
def create(self, request, *args, **kwargs):
|
||||||
|
@ -88,6 +89,6 @@ class ActesWeb(BaseResource):
|
||||||
tempfile_name = tpf.name
|
tempfile_name = tpf.name
|
||||||
os.rename(tempfile_name, filepath)
|
os.rename(tempfile_name, filepath)
|
||||||
# set read only permission for owner and group
|
# set read only permission for owner and group
|
||||||
os.chmod(filepath, stat.S_IRUSR|stat.S_IRGRP|stat.S_IWGRP)
|
os.chmod(filepath, stat.S_IRUSR | stat.S_IRGRP | stat.S_IWGRP)
|
||||||
demand_id = '%s_%s' % (application_id, os.path.basename(filepath))
|
demand_id = '%s_%s' % (application_id, os.path.basename(filepath))
|
||||||
return {'data': {'demand_id': demand_id}}
|
return {'data': {'demand_id': demand_id}}
|
||||||
|
|
|
@ -14,12 +14,38 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='AirQuality',
|
name='AirQuality',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(verbose_name='Title', max_length=50)),
|
('title', models.CharField(verbose_name='Title', max_length=50)),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('log_level', models.CharField(default=b'INFO', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')])),
|
(
|
||||||
('users', models.ManyToManyField(to='base.ApiUser', related_name='_airquality_users_+', related_query_name='+', blank=True)),
|
'log_level',
|
||||||
|
models.CharField(
|
||||||
|
default=b'INFO',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='base.ApiUser',
|
||||||
|
related_name='_airquality_users_+',
|
||||||
|
related_query_name='+',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Air Quality',
|
'verbose_name': 'Air Quality',
|
||||||
|
|
|
@ -28,24 +28,28 @@ from passerelle.utils.jsonresponse import APIError
|
||||||
|
|
||||||
class AirQuality(BaseResource):
|
class AirQuality(BaseResource):
|
||||||
category = _('Misc')
|
category = _('Misc')
|
||||||
api_description = _(u'''
|
api_description = _(
|
||||||
|
u'''
|
||||||
This API provides a unique format for the air quality data of various places.
|
This API provides a unique format for the air quality data of various places.
|
||||||
(But only supports the Rhône-Alpes region for now).
|
(But only supports the Rhône-Alpes region for now).
|
||||||
''')
|
'''
|
||||||
|
)
|
||||||
|
|
||||||
atmo_aura_api_token = models.CharField(max_length=100,
|
atmo_aura_api_token = models.CharField(
|
||||||
verbose_name=_('ATMO AURA API token'),
|
max_length=100, verbose_name=_('ATMO AURA API token'), blank=True, null=True
|
||||||
blank=True, null=True)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Air Quality')
|
verbose_name = _('Air Quality')
|
||||||
|
|
||||||
@endpoint(pattern='^(?P<country>\w+)/(?P<city>\w+)/$',
|
@endpoint(
|
||||||
example_pattern='{country}/{city}/',
|
pattern='^(?P<country>\w+)/(?P<city>\w+)/$',
|
||||||
parameters={
|
example_pattern='{country}/{city}/',
|
||||||
'country': {'description': _('Country Code'), 'example_value': 'fr'},
|
parameters={
|
||||||
'city': {'description': _('City Name'), 'example_value': 'lyon'},
|
'country': {'description': _('Country Code'), 'example_value': 'fr'},
|
||||||
})
|
'city': {'description': _('City Name'), 'example_value': 'lyon'},
|
||||||
|
},
|
||||||
|
)
|
||||||
def details(self, request, country, city, **kwargs):
|
def details(self, request, country, city, **kwargs):
|
||||||
methods = {
|
methods = {
|
||||||
('fr', 'albertville'): 'air_rhonealpes',
|
('fr', 'albertville'): 'air_rhonealpes',
|
||||||
|
@ -82,7 +86,8 @@ class AirQuality(BaseResource):
|
||||||
'vienne': '38544',
|
'vienne': '38544',
|
||||||
}
|
}
|
||||||
insee_code = insee_codes.get(city.lower())
|
insee_code = insee_codes.get(city.lower())
|
||||||
response = self.requests.get('https://api.atmo-aura.fr/communes/%s/indices' % insee_code,
|
response = self.requests.get(
|
||||||
|
'https://api.atmo-aura.fr/communes/%s/indices' % insee_code,
|
||||||
params={'api_token': self.atmo_aura_api_token},
|
params={'api_token': self.atmo_aura_api_token},
|
||||||
)
|
)
|
||||||
json_response = response.json()
|
json_response = response.json()
|
||||||
|
@ -106,12 +111,13 @@ class AirQuality(BaseResource):
|
||||||
break
|
break
|
||||||
|
|
||||||
if 'latest' in response_data:
|
if 'latest' in response_data:
|
||||||
comment_response = self.requests.get('https://api.atmo-aura.fr/commentaire',
|
comment_response = self.requests.get(
|
||||||
params={
|
'https://api.atmo-aura.fr/commentaire',
|
||||||
'date': response_data['latest']['date'],
|
params={
|
||||||
'api_token': self.atmo_aura_api_token,
|
'date': response_data['latest']['date'],
|
||||||
}
|
'api_token': self.atmo_aura_api_token,
|
||||||
)
|
},
|
||||||
|
)
|
||||||
if comment_response.ok:
|
if comment_response.ok:
|
||||||
response_data['comment'] = comment_response.json().get('commentaire')
|
response_data['comment'] = comment_response.json().get('commentaire')
|
||||||
|
|
||||||
|
|
|
@ -17,13 +17,29 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='APIEntreprise',
|
name='APIEntreprise',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('title', models.CharField(max_length=50, verbose_name='Title')),
|
('title', models.CharField(max_length=50, verbose_name='Title')),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
|
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
|
||||||
('url', models.URLField(default=b'https://entreprise.api.gouv.fr/v2/', max_length=256, verbose_name='API URL')),
|
(
|
||||||
|
'url',
|
||||||
|
models.URLField(
|
||||||
|
default=b'https://entreprise.api.gouv.fr/v2/', max_length=256, verbose_name='API URL'
|
||||||
|
),
|
||||||
|
),
|
||||||
('token', models.CharField(max_length=1024, verbose_name='API token')),
|
('token', models.CharField(max_length=1024, verbose_name='API token')),
|
||||||
('users', models.ManyToManyField(blank=True, related_name='_apientreprise_users_+', related_query_name='+', to='base.ApiUser')),
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
related_name='_apientreprise_users_+',
|
||||||
|
related_query_name='+',
|
||||||
|
to='base.ApiUser',
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'API Entreprise',
|
'verbose_name': 'API Entreprise',
|
||||||
|
|
|
@ -15,8 +15,8 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='apientreprise',
|
model_name='apientreprise',
|
||||||
name='recipient',
|
name='recipient',
|
||||||
field=models.CharField(default='', max_length=1024, verbose_name='Recipient',
|
field=models.CharField(
|
||||||
help_text='default value'
|
default='', max_length=1024, verbose_name='Recipient', help_text='default value'
|
||||||
),
|
),
|
||||||
preserve_default=False,
|
preserve_default=False,
|
||||||
),
|
),
|
||||||
|
|
|
@ -69,7 +69,7 @@ def normalize_results(data):
|
||||||
if tstamp > 0:
|
if tstamp > 0:
|
||||||
try:
|
try:
|
||||||
aware_date = make_aware(datetime.fromtimestamp(int(data[key])))
|
aware_date = make_aware(datetime.fromtimestamp(int(data[key])))
|
||||||
timestamp_to_datetime[key[:-len('timestamp')] + 'datetime'] = aware_date
|
timestamp_to_datetime[key[: -len('timestamp')] + 'datetime'] = aware_date
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
# add converted timestamps to initial data
|
# add converted timestamps to initial data
|
||||||
|
@ -81,8 +81,9 @@ class APIEntreprise(BaseResource):
|
||||||
|
|
||||||
url = models.URLField(_('API URL'), max_length=256, default='https://entreprise.api.gouv.fr/v2/')
|
url = models.URLField(_('API URL'), max_length=256, default='https://entreprise.api.gouv.fr/v2/')
|
||||||
token = models.CharField(max_length=1024, verbose_name=_('API token'))
|
token = models.CharField(max_length=1024, verbose_name=_('API token'))
|
||||||
recipient = models.CharField(max_length=1024, verbose_name=_('Recipient'), blank=False,
|
recipient = models.CharField(
|
||||||
help_text=_('default value'))
|
max_length=1024, verbose_name=_('Recipient'), blank=False, help_text=_('default value')
|
||||||
|
)
|
||||||
|
|
||||||
category = _('Business Process Connectors')
|
category = _('Business Process Connectors')
|
||||||
|
|
||||||
|
@ -102,20 +103,20 @@ class APIEntreprise(BaseResource):
|
||||||
try:
|
try:
|
||||||
response = self.requests.get(url, data=params, cache_duration=300)
|
response = self.requests.get(url, data=params, cache_duration=300)
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
raise APIError(u'API-entreprise connection error: %s' %
|
raise APIError(u'API-entreprise connection error: %s' % exception_to_text(e), data=[])
|
||||||
exception_to_text(e), data=[])
|
|
||||||
try:
|
try:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
content = response.text[:1000]
|
content = response.text[:1000]
|
||||||
raise APIError(
|
raise APIError(
|
||||||
u'API-entreprise returned non-JSON content with status %s: %s' %
|
u'API-entreprise returned non-JSON content with status %s: %s'
|
||||||
(response.status_code, content),
|
% (response.status_code, content),
|
||||||
data={
|
data={
|
||||||
'status_code': response.status_code,
|
'status_code': response.status_code,
|
||||||
'exception': exception_to_text(e),
|
'exception': exception_to_text(e),
|
||||||
'content': content,
|
'content': content,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
if data.get('error') == 'not_found':
|
if data.get('error') == 'not_found':
|
||||||
return {
|
return {
|
||||||
|
@ -123,12 +124,12 @@ class APIEntreprise(BaseResource):
|
||||||
'err_desc': data.get('message', 'not-found'),
|
'err_desc': data.get('message', 'not-found'),
|
||||||
}
|
}
|
||||||
raise APIError(
|
raise APIError(
|
||||||
u'API-entreprise returned a non 200 status %s: %s' %
|
u'API-entreprise returned a non 200 status %s: %s' % (response.status_code, data),
|
||||||
(response.status_code, data),
|
|
||||||
data={
|
data={
|
||||||
'status_code': response.status_code,
|
'status_code': response.status_code,
|
||||||
'content': data,
|
'content': data,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
normalize_results(data)
|
normalize_results(data)
|
||||||
return {
|
return {
|
||||||
'err': 0,
|
'err': 0,
|
||||||
|
@ -138,13 +139,10 @@ class APIEntreprise(BaseResource):
|
||||||
# description of common endpoint parameters
|
# description of common endpoint parameters
|
||||||
ASSOCIATION_PARAM = {
|
ASSOCIATION_PARAM = {
|
||||||
'description': _('association SIREN or RNA/WALDEC number'),
|
'description': _('association SIREN or RNA/WALDEC number'),
|
||||||
'example_value': '44317013900036'
|
'example_value': '44317013900036',
|
||||||
}
|
}
|
||||||
|
|
||||||
CONTEXT_PARAM = {
|
CONTEXT_PARAM = {'description': _('request context: MPS, APS...'), 'example_value': 'APS'}
|
||||||
'description': _('request context: MPS, APS...'),
|
|
||||||
'example_value': 'APS'
|
|
||||||
}
|
|
||||||
|
|
||||||
MONTH_PARAM = {
|
MONTH_PARAM = {
|
||||||
'description': _('requested month'),
|
'description': _('requested month'),
|
||||||
|
@ -153,12 +151,12 @@ class APIEntreprise(BaseResource):
|
||||||
|
|
||||||
OBJECT_PARAM = {
|
OBJECT_PARAM = {
|
||||||
'description': _('request object: form number, file identifier...'),
|
'description': _('request object: form number, file identifier...'),
|
||||||
'example_value': '42'
|
'example_value': '42',
|
||||||
}
|
}
|
||||||
|
|
||||||
RECIPIENT_PARAM = {
|
RECIPIENT_PARAM = {
|
||||||
'description': _('request recipient: usually customer number'),
|
'description': _('request recipient: usually customer number'),
|
||||||
'example_value': '44317013900036'
|
'example_value': '44317013900036',
|
||||||
}
|
}
|
||||||
|
|
||||||
SIREN_PARAM = {
|
SIREN_PARAM = {
|
||||||
|
@ -166,26 +164,25 @@ class APIEntreprise(BaseResource):
|
||||||
'example_value': '443170139',
|
'example_value': '443170139',
|
||||||
}
|
}
|
||||||
|
|
||||||
SIRET_PARAM = {
|
SIRET_PARAM = {'description': _('firms SIRET number'), 'example_value': '44317013900036'}
|
||||||
'description': _('firms SIRET number'),
|
|
||||||
'example_value': '44317013900036'
|
|
||||||
}
|
|
||||||
|
|
||||||
YEAR_PARAM = {
|
YEAR_PARAM = {
|
||||||
'description': _('requested year'),
|
'description': _('requested year'),
|
||||||
'example_value': '2019',
|
'example_value': '2019',
|
||||||
}
|
}
|
||||||
|
|
||||||
@endpoint(perm='can_access',
|
@endpoint(
|
||||||
pattern=r'(?P<association_id>\w+)/$',
|
perm='can_access',
|
||||||
example_pattern='{association_id}/',
|
pattern=r'(?P<association_id>\w+)/$',
|
||||||
description=_('Get association\'s documents'),
|
example_pattern='{association_id}/',
|
||||||
parameters={
|
description=_('Get association\'s documents'),
|
||||||
'association_id': ASSOCIATION_PARAM,
|
parameters={
|
||||||
'object': OBJECT_PARAM,
|
'association_id': ASSOCIATION_PARAM,
|
||||||
'context': CONTEXT_PARAM,
|
'object': OBJECT_PARAM,
|
||||||
'recipient': RECIPIENT_PARAM
|
'context': CONTEXT_PARAM,
|
||||||
})
|
'recipient': RECIPIENT_PARAM,
|
||||||
|
},
|
||||||
|
)
|
||||||
def documents_associations(self, request, association_id, **kwargs):
|
def documents_associations(self, request, association_id, **kwargs):
|
||||||
data = []
|
data = []
|
||||||
resp = self.get('documents_associations/%s/' % association_id, **kwargs)
|
resp = self.get('documents_associations/%s/' % association_id, **kwargs)
|
||||||
|
@ -193,19 +190,24 @@ class APIEntreprise(BaseResource):
|
||||||
# ignore documents with no type
|
# ignore documents with no type
|
||||||
if not item.get('type'):
|
if not item.get('type'):
|
||||||
continue
|
continue
|
||||||
signature_elements = {'url': item['url'],
|
signature_elements = {
|
||||||
'context': kwargs['context'],
|
'url': item['url'],
|
||||||
'object': kwargs['object'],
|
'context': kwargs['context'],
|
||||||
'recipient': kwargs['recipient']}
|
'object': kwargs['object'],
|
||||||
|
'recipient': kwargs['recipient'],
|
||||||
|
}
|
||||||
signature = signing.dumps(signature_elements)
|
signature = signing.dumps(signature_elements)
|
||||||
document_url = request.build_absolute_uri(
|
document_url = request.build_absolute_uri(
|
||||||
reverse('generic-endpoint',
|
reverse(
|
||||||
kwargs={
|
'generic-endpoint',
|
||||||
'connector': self.get_connector_slug(),
|
kwargs={
|
||||||
'slug': self.slug,
|
'connector': self.get_connector_slug(),
|
||||||
'endpoint': 'document',
|
'slug': self.slug,
|
||||||
'rest': '%s/%s/' % (association_id, signature),
|
'endpoint': 'document',
|
||||||
}))
|
'rest': '%s/%s/' % (association_id, signature),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
item['id'] = item['timestamp']
|
item['id'] = item['timestamp']
|
||||||
item['text'] = item['type']
|
item['text'] = item['type']
|
||||||
item['url'] = document_url
|
item['url'] = document_url
|
||||||
|
@ -214,19 +216,21 @@ class APIEntreprise(BaseResource):
|
||||||
data.sort(key=lambda i: i['id'])
|
data.sort(key=lambda i: i['id'])
|
||||||
return {'err': 0, 'data': data}
|
return {'err': 0, 'data': data}
|
||||||
|
|
||||||
@endpoint(pattern=r'(?P<association_id>\w+)/(?P<document_id>[\:\w-]+)/$',
|
@endpoint(
|
||||||
example_pattern='{association_id}/{document_id}/',
|
pattern=r'(?P<association_id>\w+)/(?P<document_id>[\:\w-]+)/$',
|
||||||
description=_('Get association\'s document'),
|
example_pattern='{association_id}/{document_id}/',
|
||||||
parameters={
|
description=_('Get association\'s document'),
|
||||||
'association_id': ASSOCIATION_PARAM,
|
parameters={
|
||||||
'document_id': {
|
'association_id': ASSOCIATION_PARAM,
|
||||||
'description': _('document id'),
|
'document_id': {
|
||||||
'example_value': 'A1500660325',
|
'description': _('document id'),
|
||||||
},
|
'example_value': 'A1500660325',
|
||||||
'object': OBJECT_PARAM,
|
},
|
||||||
'context': CONTEXT_PARAM,
|
'object': OBJECT_PARAM,
|
||||||
'recipient': RECIPIENT_PARAM,
|
'context': CONTEXT_PARAM,
|
||||||
})
|
'recipient': RECIPIENT_PARAM,
|
||||||
|
},
|
||||||
|
)
|
||||||
def document(self, request, association_id, document_id, **kwargs):
|
def document(self, request, association_id, document_id, **kwargs):
|
||||||
try:
|
try:
|
||||||
params = signing.loads(document_id, max_age=DOCUMENT_SIGNATURE_MAX_AGE)
|
params = signing.loads(document_id, max_age=DOCUMENT_SIGNATURE_MAX_AGE)
|
||||||
|
@ -237,20 +241,22 @@ class APIEntreprise(BaseResource):
|
||||||
return HttpResponse(response, content_type='application/pdf')
|
return HttpResponse(response, content_type='application/pdf')
|
||||||
raise Http404('document not found')
|
raise Http404('document not found')
|
||||||
|
|
||||||
@endpoint(name='document_association',
|
@endpoint(
|
||||||
pattern=r'(?P<association_id>\w+)/get-last/$',
|
name='document_association',
|
||||||
example_pattern='{association_id}/get-last/',
|
pattern=r'(?P<association_id>\w+)/get-last/$',
|
||||||
description=_('Get association\'s last document of type'),
|
example_pattern='{association_id}/get-last/',
|
||||||
parameters={
|
description=_('Get association\'s last document of type'),
|
||||||
'association_id': ASSOCIATION_PARAM,
|
parameters={
|
||||||
'document_type': {
|
'association_id': ASSOCIATION_PARAM,
|
||||||
'description': _('document type'),
|
'document_type': {
|
||||||
'example_value': 'Statuts',
|
'description': _('document type'),
|
||||||
},
|
'example_value': 'Statuts',
|
||||||
'object': OBJECT_PARAM,
|
},
|
||||||
'context': CONTEXT_PARAM,
|
'object': OBJECT_PARAM,
|
||||||
'recipient': RECIPIENT_PARAM,
|
'context': CONTEXT_PARAM,
|
||||||
})
|
'recipient': RECIPIENT_PARAM,
|
||||||
|
},
|
||||||
|
)
|
||||||
def get_last_document_of_type(self, request, association_id, document_type, **kwargs):
|
def get_last_document_of_type(self, request, association_id, document_type, **kwargs):
|
||||||
document = None
|
document = None
|
||||||
resp = self.get('documents_associations/%s/' % association_id, **kwargs)
|
resp = self.get('documents_associations/%s/' % association_id, **kwargs)
|
||||||
|
@ -260,46 +266,49 @@ class APIEntreprise(BaseResource):
|
||||||
document = documents[-1]
|
document = documents[-1]
|
||||||
return {'data': document}
|
return {'data': document}
|
||||||
|
|
||||||
@endpoint(perm='can_access',
|
@endpoint(
|
||||||
pattern=r'(?P<siren>\w+)/$',
|
perm='can_access',
|
||||||
example_pattern='{siren}/',
|
pattern=r'(?P<siren>\w+)/$',
|
||||||
description=_('Get firm\'s data from Infogreffe'),
|
example_pattern='{siren}/',
|
||||||
parameters={
|
description=_('Get firm\'s data from Infogreffe'),
|
||||||
'siren': SIREN_PARAM,
|
parameters={
|
||||||
'object': OBJECT_PARAM,
|
'siren': SIREN_PARAM,
|
||||||
'context': CONTEXT_PARAM,
|
'object': OBJECT_PARAM,
|
||||||
'recipient': RECIPIENT_PARAM,
|
'context': CONTEXT_PARAM,
|
||||||
})
|
'recipient': RECIPIENT_PARAM,
|
||||||
|
},
|
||||||
|
)
|
||||||
def extraits_rcs(self, request, siren, **kwargs):
|
def extraits_rcs(self, request, siren, **kwargs):
|
||||||
return self.get('extraits_rcs_infogreffe/%s/' % siren, **kwargs)
|
return self.get('extraits_rcs_infogreffe/%s/' % siren, **kwargs)
|
||||||
|
|
||||||
@endpoint(perm='can_access',
|
@endpoint(
|
||||||
pattern=r'(?P<association_id>\w+)/$',
|
perm='can_access',
|
||||||
example_pattern='{association_id}/',
|
pattern=r'(?P<association_id>\w+)/$',
|
||||||
description=_('Get association\'s related informations'),
|
example_pattern='{association_id}/',
|
||||||
parameters={
|
description=_('Get association\'s related informations'),
|
||||||
'association_id': ASSOCIATION_PARAM,
|
parameters={
|
||||||
'object': OBJECT_PARAM,
|
'association_id': ASSOCIATION_PARAM,
|
||||||
'context': CONTEXT_PARAM,
|
'object': OBJECT_PARAM,
|
||||||
'recipient': RECIPIENT_PARAM,
|
'context': CONTEXT_PARAM,
|
||||||
})
|
'recipient': RECIPIENT_PARAM,
|
||||||
|
},
|
||||||
|
)
|
||||||
def associations(self, request, association_id, **kwargs):
|
def associations(self, request, association_id, **kwargs):
|
||||||
return self.get('associations/%s/' % association_id, **kwargs)
|
return self.get('associations/%s/' % association_id, **kwargs)
|
||||||
|
|
||||||
@endpoint(perm='can_access',
|
@endpoint(
|
||||||
pattern=r'(?P<siren>\w+)/$',
|
perm='can_access',
|
||||||
example_pattern='{siren}/',
|
pattern=r'(?P<siren>\w+)/$',
|
||||||
description=_('Get firm\'s related informations'),
|
example_pattern='{siren}/',
|
||||||
parameters={
|
description=_('Get firm\'s related informations'),
|
||||||
'siren': SIREN_PARAM,
|
parameters={
|
||||||
'object': OBJECT_PARAM,
|
'siren': SIREN_PARAM,
|
||||||
'context': CONTEXT_PARAM,
|
'object': OBJECT_PARAM,
|
||||||
'recipient': RECIPIENT_PARAM,
|
'context': CONTEXT_PARAM,
|
||||||
'include_private': {
|
'recipient': RECIPIENT_PARAM,
|
||||||
'description': _('Include private informations'),
|
'include_private': {'description': _('Include private informations'), 'example_value': 'true'},
|
||||||
'example_value': 'true'
|
},
|
||||||
}
|
)
|
||||||
})
|
|
||||||
def entreprises(self, request, siren, include_private=False, **kwargs):
|
def entreprises(self, request, siren, include_private=False, **kwargs):
|
||||||
if len(siren) != 9:
|
if len(siren) != 9:
|
||||||
raise APIError(_('invalid SIREN length (must be 9 characters)'))
|
raise APIError(_('invalid SIREN length (must be 9 characters)'))
|
||||||
|
@ -307,60 +316,68 @@ class APIEntreprise(BaseResource):
|
||||||
kwargs['non_diffusables'] = True
|
kwargs['non_diffusables'] = True
|
||||||
return self.get('entreprises/%s/' % siren, **kwargs)
|
return self.get('entreprises/%s/' % siren, **kwargs)
|
||||||
|
|
||||||
@endpoint(perm='can_access',
|
@endpoint(
|
||||||
methods=['get'],
|
perm='can_access',
|
||||||
pattern=r'(?P<siret>\w+)/$',
|
methods=['get'],
|
||||||
example_pattern='{siret}/',
|
pattern=r'(?P<siret>\w+)/$',
|
||||||
description_get=_('Get firms\'s related informations'),
|
example_pattern='{siret}/',
|
||||||
parameters={
|
description_get=_('Get firms\'s related informations'),
|
||||||
'siret': SIRET_PARAM,
|
parameters={
|
||||||
'object': OBJECT_PARAM,
|
'siret': SIRET_PARAM,
|
||||||
'context': CONTEXT_PARAM,
|
'object': OBJECT_PARAM,
|
||||||
'recipient': RECIPIENT_PARAM,
|
'context': CONTEXT_PARAM,
|
||||||
})
|
'recipient': RECIPIENT_PARAM,
|
||||||
|
},
|
||||||
|
)
|
||||||
def etablissements(self, request, siret, **kwargs):
|
def etablissements(self, request, siret, **kwargs):
|
||||||
return self.get('etablissements/%s/' % siret, **kwargs)
|
return self.get('etablissements/%s/' % siret, **kwargs)
|
||||||
|
|
||||||
@endpoint(perm='can_access',
|
@endpoint(
|
||||||
methods=['get'],
|
perm='can_access',
|
||||||
pattern=r'(?P<siret>\w+)/$',
|
methods=['get'],
|
||||||
example_pattern='{siret}/',
|
pattern=r'(?P<siret>\w+)/$',
|
||||||
description_get=_('Get firms\'s financial year informations'),
|
example_pattern='{siret}/',
|
||||||
parameters={
|
description_get=_('Get firms\'s financial year informations'),
|
||||||
'siret': SIRET_PARAM,
|
parameters={
|
||||||
'object': OBJECT_PARAM,
|
'siret': SIRET_PARAM,
|
||||||
'context': CONTEXT_PARAM,
|
'object': OBJECT_PARAM,
|
||||||
'recipient': RECIPIENT_PARAM,
|
'context': CONTEXT_PARAM,
|
||||||
})
|
'recipient': RECIPIENT_PARAM,
|
||||||
|
},
|
||||||
|
)
|
||||||
def exercices(self, request, siret, **kwargs):
|
def exercices(self, request, siret, **kwargs):
|
||||||
return self.get('exercices/%s/' % siret, **kwargs)
|
return self.get('exercices/%s/' % siret, **kwargs)
|
||||||
|
|
||||||
@endpoint(perm='can_access',
|
@endpoint(
|
||||||
pattern=r'(?P<siren>\w+)/$',
|
perm='can_access',
|
||||||
example_pattern='{siren}/',
|
pattern=r'(?P<siren>\w+)/$',
|
||||||
description=_('Get firm\'s annual workforce data'),
|
example_pattern='{siren}/',
|
||||||
parameters={
|
description=_('Get firm\'s annual workforce data'),
|
||||||
'siren': SIREN_PARAM,
|
parameters={
|
||||||
'object': OBJECT_PARAM,
|
'siren': SIREN_PARAM,
|
||||||
'context': CONTEXT_PARAM,
|
'object': OBJECT_PARAM,
|
||||||
'recipient': RECIPIENT_PARAM,
|
'context': CONTEXT_PARAM,
|
||||||
})
|
'recipient': RECIPIENT_PARAM,
|
||||||
|
},
|
||||||
|
)
|
||||||
def effectifs_annuels_acoss_covid(self, request, siren, **kwargs):
|
def effectifs_annuels_acoss_covid(self, request, siren, **kwargs):
|
||||||
if len(siren) != 9:
|
if len(siren) != 9:
|
||||||
raise APIError(_('invalid SIREN length (must be 9 characters)'))
|
raise APIError(_('invalid SIREN length (must be 9 characters)'))
|
||||||
return self.get('effectifs_annuels_acoss_covid/%s/' % siren, **kwargs)
|
return self.get('effectifs_annuels_acoss_covid/%s/' % siren, **kwargs)
|
||||||
|
|
||||||
@endpoint(perm='can_access',
|
@endpoint(
|
||||||
pattern=r'(?P<year>\w+)/(?P<month>\w+)/(?P<siren>\w+)/$',
|
perm='can_access',
|
||||||
description=_('Get firm\'s monthly workforce data, by SIREN'),
|
pattern=r'(?P<year>\w+)/(?P<month>\w+)/(?P<siren>\w+)/$',
|
||||||
parameters={
|
description=_('Get firm\'s monthly workforce data, by SIREN'),
|
||||||
'year': YEAR_PARAM,
|
parameters={
|
||||||
'month': MONTH_PARAM,
|
'year': YEAR_PARAM,
|
||||||
'siren': SIREN_PARAM,
|
'month': MONTH_PARAM,
|
||||||
'object': OBJECT_PARAM,
|
'siren': SIREN_PARAM,
|
||||||
'context': CONTEXT_PARAM,
|
'object': OBJECT_PARAM,
|
||||||
'recipient': RECIPIENT_PARAM,
|
'context': CONTEXT_PARAM,
|
||||||
})
|
'recipient': RECIPIENT_PARAM,
|
||||||
|
},
|
||||||
|
)
|
||||||
def entreprise_effectifs_mensuels_acoss_covid(self, request, year, month, siren, **kwargs):
|
def entreprise_effectifs_mensuels_acoss_covid(self, request, year, month, siren, **kwargs):
|
||||||
if len(siren) != 9:
|
if len(siren) != 9:
|
||||||
raise APIError(_('invalid SIREN length (must be 9 characters)'))
|
raise APIError(_('invalid SIREN length (must be 9 characters)'))
|
||||||
|
@ -369,17 +386,19 @@ class APIEntreprise(BaseResource):
|
||||||
'effectifs_mensuels_acoss_covid/%s/%s/entreprise/%s/' % (year, month, siren), **kwargs
|
'effectifs_mensuels_acoss_covid/%s/%s/entreprise/%s/' % (year, month, siren), **kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
@endpoint(perm='can_access',
|
@endpoint(
|
||||||
pattern=r'(?P<year>\w+)/(?P<month>\w+)/(?P<siret>\w+)/$',
|
perm='can_access',
|
||||||
description=_('Get firm\'s monthly workforce data, by SIRET'),
|
pattern=r'(?P<year>\w+)/(?P<month>\w+)/(?P<siret>\w+)/$',
|
||||||
parameters={
|
description=_('Get firm\'s monthly workforce data, by SIRET'),
|
||||||
'year': YEAR_PARAM,
|
parameters={
|
||||||
'month': MONTH_PARAM,
|
'year': YEAR_PARAM,
|
||||||
'siret': SIRET_PARAM,
|
'month': MONTH_PARAM,
|
||||||
'object': OBJECT_PARAM,
|
'siret': SIRET_PARAM,
|
||||||
'context': CONTEXT_PARAM,
|
'object': OBJECT_PARAM,
|
||||||
'recipient': RECIPIENT_PARAM,
|
'context': CONTEXT_PARAM,
|
||||||
})
|
'recipient': RECIPIENT_PARAM,
|
||||||
|
},
|
||||||
|
)
|
||||||
def etablissement_effectifs_mensuels_acoss_covid(self, request, year, month, siret, **kwargs):
|
def etablissement_effectifs_mensuels_acoss_covid(self, request, year, month, siret, **kwargs):
|
||||||
month = month.zfill(2)
|
month = month.zfill(2)
|
||||||
return self.get(
|
return self.get(
|
||||||
|
|
|
@ -29,7 +29,7 @@ KNOWN_ERRORS = {
|
||||||
'Il existe au moins un enfant pour lequel il existe un droit sur le dossier et/ou à la période demandée',
|
'Il existe au moins un enfant pour lequel il existe un droit sur le dossier et/ou à la période demandée',
|
||||||
'Il existe des droits pour la prestation sélectionnée sur le dossier et/ou la période demandée',
|
'Il existe des droits pour la prestation sélectionnée sur le dossier et/ou la période demandée',
|
||||||
'Il existe des droits pour la prestation sélectionnée sur le dossier et/ou la période demandée (après date du jour)',
|
'Il existe des droits pour la prestation sélectionnée sur le dossier et/ou la période demandée (après date du jour)',
|
||||||
'L’opérateurs téléphonique» ne propose pas de raccordement SMS avec un prestataire externe (raccordement avec un numéro court). '
|
'L’opérateurs téléphonique» ne propose pas de raccordement SMS avec un prestataire externe (raccordement avec un numéro court). ',
|
||||||
},
|
},
|
||||||
500: {
|
500: {
|
||||||
'Les informations souhaitées sont momentanément indisponibles. Merci de renouveler votre demande ultérieurement.',
|
'Les informations souhaitées sont momentanément indisponibles. Merci de renouveler votre demande ultérieurement.',
|
||||||
|
@ -42,6 +42,6 @@ KNOWN_ERRORS = {
|
||||||
"Votre demande n'a pu aboutir en raison d'un incident technique momentané. Merci de renouveler votre demande ultérieurement.",
|
"Votre demande n'a pu aboutir en raison d'un incident technique momentané. Merci de renouveler votre demande ultérieurement.",
|
||||||
"Votre demande n'a pu aboutir en raison d'une erreur fonctionnelle lié à l'appel au service IMC.",
|
"Votre demande n'a pu aboutir en raison d'une erreur fonctionnelle lié à l'appel au service IMC.",
|
||||||
"Votre demande n'a pu aboutir en raison d'une erreur technique lié à l'appel au service IMC.",
|
"Votre demande n'a pu aboutir en raison d'une erreur technique lié à l'appel au service IMC.",
|
||||||
"Votre demande n’a pu aboutir en raison d'un problème technique lié aux données entrantes du webservice. Merci de renouveler votre demande ultérieurement."
|
"Votre demande n’a pu aboutir en raison d'un problème technique lié aux données entrantes du webservice. Merci de renouveler votre demande ultérieurement.",
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,50 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='APIParticulier',
|
name='APIParticulier',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(max_length=50, verbose_name='Title')),
|
('title', models.CharField(max_length=50, verbose_name='Title')),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('log_level', models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')])),
|
(
|
||||||
('_platform', models.CharField(choices=[(b'prod', 'Production'), (b'test', 'Test')], max_length=8, verbose_name='Platform')),
|
'log_level',
|
||||||
('_api_key', models.CharField(default=b'', max_length=64, verbose_name='API key', blank=True)),
|
models.CharField(
|
||||||
('users', models.ManyToManyField(to='base.ApiUser', related_name='_apiparticulier_users_+', related_query_name='+', blank=True)),
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'_platform',
|
||||||
|
models.CharField(
|
||||||
|
choices=[(b'prod', 'Production'), (b'test', 'Test')],
|
||||||
|
max_length=8,
|
||||||
|
verbose_name='Platform',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'_api_key',
|
||||||
|
models.CharField(default=b'', max_length=64, verbose_name='API key', blank=True),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='base.ApiUser',
|
||||||
|
related_name='_apiparticulier_users_+',
|
||||||
|
related_query_name='+',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'abstract': False,
|
'abstract': False,
|
||||||
|
|
|
@ -42,11 +42,7 @@ from .known_errors import KNOWN_ERRORS
|
||||||
|
|
||||||
class APIParticulier(BaseResource):
|
class APIParticulier(BaseResource):
|
||||||
PLATFORMS = [
|
PLATFORMS = [
|
||||||
{
|
{'name': 'prod', 'label': _('Production'), 'url': 'https://particulier.api.gouv.fr/api/'},
|
||||||
'name': 'prod',
|
|
||||||
'label': _('Production'),
|
|
||||||
'url': 'https://particulier.api.gouv.fr/api/'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
'name': 'test',
|
'name': 'test',
|
||||||
'label': _('Test'),
|
'label': _('Test'),
|
||||||
|
@ -58,13 +54,10 @@ class APIParticulier(BaseResource):
|
||||||
platform = models.CharField(
|
platform = models.CharField(
|
||||||
verbose_name=_('Platform'),
|
verbose_name=_('Platform'),
|
||||||
max_length=8,
|
max_length=8,
|
||||||
choices=[(key, platform['label']) for key, platform in PLATFORMS.items()])
|
choices=[(key, platform['label']) for key, platform in PLATFORMS.items()],
|
||||||
|
)
|
||||||
|
|
||||||
api_key = models.CharField(
|
api_key = models.CharField(max_length=256, default='', blank=True, verbose_name=_('API key'))
|
||||||
max_length=256,
|
|
||||||
default='',
|
|
||||||
blank=True,
|
|
||||||
verbose_name=_('API key'))
|
|
||||||
|
|
||||||
log_requests_errors = False
|
log_requests_errors = False
|
||||||
|
|
||||||
|
@ -79,28 +72,24 @@ class APIParticulier(BaseResource):
|
||||||
if user:
|
if user:
|
||||||
headers['X-User'] = user
|
headers['X-User'] = user
|
||||||
try:
|
try:
|
||||||
response = self.requests.get(
|
response = self.requests.get(url, headers=headers, timeout=5, **kwargs)
|
||||||
url,
|
|
||||||
headers=headers,
|
|
||||||
timeout=5,
|
|
||||||
**kwargs)
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
u'API-particulier platform "%s" connection error: %s' %
|
u'API-particulier platform "%s" connection error: %s' % (self.platform, exception_to_text(e)),
|
||||||
(self.platform, exception_to_text(e)),
|
|
||||||
log_error=True,
|
log_error=True,
|
||||||
data={
|
data={
|
||||||
'code': 'connection-error',
|
'code': 'connection-error',
|
||||||
'platform': self.platform,
|
'platform': self.platform,
|
||||||
'error': six.text_type(e),
|
'error': six.text_type(e),
|
||||||
})
|
},
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
except JSONDecodeError as e:
|
except JSONDecodeError as e:
|
||||||
content = repr(response.content[:1000])
|
content = repr(response.content[:1000])
|
||||||
raise APIError(
|
raise APIError(
|
||||||
u'API-particulier platform "%s" returned non-JSON content with status %s: %s' %
|
u'API-particulier platform "%s" returned non-JSON content with status %s: %s'
|
||||||
(self.platform, response.status_code, content),
|
% (self.platform, response.status_code, content),
|
||||||
log_error=True,
|
log_error=True,
|
||||||
data={
|
data={
|
||||||
'code': 'non-json',
|
'code': 'non-json',
|
||||||
|
@ -108,7 +97,8 @@ class APIParticulier(BaseResource):
|
||||||
'exception': six.text_type(e),
|
'exception': six.text_type(e),
|
||||||
'platform': self.platform,
|
'platform': self.platform,
|
||||||
'content': content,
|
'content': content,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
# avoid logging http errors about non-transport failure
|
# avoid logging http errors about non-transport failure
|
||||||
message = data.get('message', '')
|
message = data.get('message', '')
|
||||||
|
@ -120,162 +110,180 @@ class APIParticulier(BaseResource):
|
||||||
'status_code': response.status_code,
|
'status_code': response.status_code,
|
||||||
'platform': self.platform,
|
'platform': self.platform,
|
||||||
'content': data,
|
'content': data,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
raise APIError(
|
raise APIError(
|
||||||
u'API-particulier platform "%s" returned a non 200 status %s: %s' %
|
u'API-particulier platform "%s" returned a non 200 status %s: %s'
|
||||||
(self.platform, response.status_code, data),
|
% (self.platform, response.status_code, data),
|
||||||
log_error=True,
|
log_error=True,
|
||||||
data={
|
data={
|
||||||
'code': 'non-200',
|
'code': 'non-200',
|
||||||
'status_code': response.status_code,
|
'status_code': response.status_code,
|
||||||
'platform': self.platform,
|
'platform': self.platform,
|
||||||
'content': data,
|
'content': data,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
'err': 0,
|
'err': 0,
|
||||||
'data': data,
|
'data': data,
|
||||||
}
|
}
|
||||||
|
|
||||||
@endpoint(perm='can_access',
|
@endpoint(
|
||||||
show=False,
|
perm='can_access',
|
||||||
description=_('Get citizen\'s fiscal informations'),
|
show=False,
|
||||||
parameters={
|
description=_('Get citizen\'s fiscal informations'),
|
||||||
'numero_fiscal': {
|
parameters={
|
||||||
'description': _('fiscal identifier'),
|
'numero_fiscal': {
|
||||||
'example_value': '1562456789521',
|
'description': _('fiscal identifier'),
|
||||||
},
|
'example_value': '1562456789521',
|
||||||
'reference_avis': {
|
},
|
||||||
'description': _('tax notice number'),
|
'reference_avis': {
|
||||||
'example_value': '1512456789521',
|
'description': _('tax notice number'),
|
||||||
},
|
'example_value': '1512456789521',
|
||||||
'user': {
|
},
|
||||||
'description': _('requesting user'),
|
'user': {
|
||||||
'example_value': 'John Doe (agent)',
|
'description': _('requesting user'),
|
||||||
},
|
'example_value': 'John Doe (agent)',
|
||||||
})
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
def impots_svair(self, request, numero_fiscal, reference_avis, user=None):
|
def impots_svair(self, request, numero_fiscal, reference_avis, user=None):
|
||||||
# deprecated endpoint
|
# deprecated endpoint
|
||||||
return self.v2_avis_imposition(request, numero_fiscal, reference_avis, user=user)
|
return self.v2_avis_imposition(request, numero_fiscal, reference_avis, user=user)
|
||||||
|
|
||||||
@endpoint(name='avis-imposition',
|
@endpoint(
|
||||||
perm='can_access',
|
name='avis-imposition',
|
||||||
description=_('Get citizen\'s fiscal informations'),
|
perm='can_access',
|
||||||
parameters={
|
description=_('Get citizen\'s fiscal informations'),
|
||||||
'numero_fiscal': {
|
parameters={
|
||||||
'description': _('fiscal identifier'),
|
'numero_fiscal': {
|
||||||
'example_value': '1562456789521',
|
'description': _('fiscal identifier'),
|
||||||
},
|
'example_value': '1562456789521',
|
||||||
'reference_avis': {
|
},
|
||||||
'description': _('tax notice number'),
|
'reference_avis': {
|
||||||
'example_value': '1512456789521',
|
'description': _('tax notice number'),
|
||||||
},
|
'example_value': '1512456789521',
|
||||||
'user': {
|
},
|
||||||
'description': _('requesting user'),
|
'user': {
|
||||||
'example_value': 'John Doe (agent)',
|
'description': _('requesting user'),
|
||||||
},
|
'example_value': 'John Doe (agent)',
|
||||||
},
|
},
|
||||||
json_schema_response={
|
},
|
||||||
'type': 'object',
|
json_schema_response={
|
||||||
'required': ['err'],
|
'type': 'object',
|
||||||
'properties': {
|
'required': ['err'],
|
||||||
'err': {'enum': [0, 1]},
|
'properties': {
|
||||||
'declarant1': {
|
'err': {'enum': [0, 1]},
|
||||||
'type': 'object',
|
'declarant1': {
|
||||||
'properties': {
|
'type': 'object',
|
||||||
'nom': {'type': 'string'},
|
'properties': {
|
||||||
'nomNaissance': {'type': 'string'},
|
'nom': {'type': 'string'},
|
||||||
'prenoms': {'type': 'string'},
|
'nomNaissance': {'type': 'string'},
|
||||||
'dateNaissance': {'type': 'string'}
|
'prenoms': {'type': 'string'},
|
||||||
},
|
'dateNaissance': {'type': 'string'},
|
||||||
},
|
},
|
||||||
'declarant2': {
|
},
|
||||||
'type': 'object',
|
'declarant2': {
|
||||||
'properties': {
|
'type': 'object',
|
||||||
'nom': {'type': 'string'},
|
'properties': {
|
||||||
'nomNaissance': {'type': 'string'},
|
'nom': {'type': 'string'},
|
||||||
'prenoms': {'type': 'string'},
|
'nomNaissance': {'type': 'string'},
|
||||||
'dateNaissance': {'type': 'string'}
|
'prenoms': {'type': 'string'},
|
||||||
}
|
'dateNaissance': {'type': 'string'},
|
||||||
},
|
},
|
||||||
'foyerFiscal': {
|
},
|
||||||
'type': 'object',
|
'foyerFiscal': {
|
||||||
'properties': {
|
'type': 'object',
|
||||||
'annee': {'type': 'integer'},
|
'properties': {
|
||||||
'adresse': {'type': 'string'},
|
'annee': {'type': 'integer'},
|
||||||
}
|
'adresse': {'type': 'string'},
|
||||||
},
|
},
|
||||||
'dateRecouvrement': {'type': 'string', 'pattern': r'^\d{1,2}/\d{1,2}/\d{4}$'},
|
},
|
||||||
'dateEtablissement': {'type': 'string', 'pattern': r'^\d{1,2}/\d{1,2}/\d{4}$'},
|
'dateRecouvrement': {'type': 'string', 'pattern': r'^\d{1,2}/\d{1,2}/\d{4}$'},
|
||||||
'nombreParts': {'type': 'integer'},
|
'dateEtablissement': {'type': 'string', 'pattern': r'^\d{1,2}/\d{1,2}/\d{4}$'},
|
||||||
'situationFamille': {'type': 'string'},
|
'nombreParts': {'type': 'integer'},
|
||||||
'nombrePersonnesCharge': {'type': 'integer'},
|
'situationFamille': {'type': 'string'},
|
||||||
'revenuBrutGlobal': {'type': 'integer'},
|
'nombrePersonnesCharge': {'type': 'integer'},
|
||||||
'revenuImposable': {'type': 'integer'},
|
'revenuBrutGlobal': {'type': 'integer'},
|
||||||
'impotRevenuNetAvantCorrections': {'type': 'integer'},
|
'revenuImposable': {'type': 'integer'},
|
||||||
'montantImpot': {'type': 'integer'},
|
'impotRevenuNetAvantCorrections': {'type': 'integer'},
|
||||||
'revenuFiscalReference': {'type': 'integer'},
|
'montantImpot': {'type': 'integer'},
|
||||||
'anneeImpots': {'type': 'string', 'pattern': r'^[0-9]{4}$'},
|
'revenuFiscalReference': {'type': 'integer'},
|
||||||
'anneeRevenus': {'type': 'string', 'pattern': r'^[0-9]{4}$'},
|
'anneeImpots': {'type': 'string', 'pattern': r'^[0-9]{4}$'},
|
||||||
'erreurCorrectif': {'type': 'string'},
|
'anneeRevenus': {'type': 'string', 'pattern': r'^[0-9]{4}$'},
|
||||||
'situationPartielle': {'type': 'string'}
|
'erreurCorrectif': {'type': 'string'},
|
||||||
}
|
'situationPartielle': {'type': 'string'},
|
||||||
})
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
def v2_avis_imposition(self, request, numero_fiscal, reference_avis, user=None):
|
def v2_avis_imposition(self, request, numero_fiscal, reference_avis, user=None):
|
||||||
numero_fiscal = numero_fiscal.strip()[:13]
|
numero_fiscal = numero_fiscal.strip()[:13]
|
||||||
reference_avis = reference_avis.strip()[:13]
|
reference_avis = reference_avis.strip()[:13]
|
||||||
if len(numero_fiscal) < 13 or len(reference_avis) < 13:
|
if len(numero_fiscal) < 13 or len(reference_avis) < 13:
|
||||||
raise APIError('bad numero_fiscal or reference_avis, must be 13 chars long', status_code=400)
|
raise APIError('bad numero_fiscal or reference_avis, must be 13 chars long', status_code=400)
|
||||||
return self.get('v2/avis-imposition', params={
|
return self.get(
|
||||||
'numeroFiscal': numero_fiscal,
|
'v2/avis-imposition',
|
||||||
'referenceAvis': reference_avis,
|
params={
|
||||||
}, user=user)
|
'numeroFiscal': numero_fiscal,
|
||||||
|
'referenceAvis': reference_avis,
|
||||||
|
},
|
||||||
|
user=user,
|
||||||
|
)
|
||||||
|
|
||||||
@endpoint(perm='can_access',
|
@endpoint(
|
||||||
show=False,
|
perm='can_access',
|
||||||
description=_('Get family allowances recipient informations'),
|
show=False,
|
||||||
parameters={
|
description=_('Get family allowances recipient informations'),
|
||||||
'code_postal': {
|
parameters={
|
||||||
'description': _('postal code'),
|
'code_postal': {
|
||||||
'example_value': '99148',
|
'description': _('postal code'),
|
||||||
},
|
'example_value': '99148',
|
||||||
'numero_allocataire': {
|
},
|
||||||
'description': _('recipient identifier'),
|
'numero_allocataire': {
|
||||||
'example_value': '0000354',
|
'description': _('recipient identifier'),
|
||||||
},
|
'example_value': '0000354',
|
||||||
'user': {
|
},
|
||||||
'description': _('requesting user'),
|
'user': {
|
||||||
'example_value': 'John Doe (agent)',
|
'description': _('requesting user'),
|
||||||
},
|
'example_value': 'John Doe (agent)',
|
||||||
})
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
def caf_famille(self, request, code_postal, numero_allocataire, user=None):
|
def caf_famille(self, request, code_postal, numero_allocataire, user=None):
|
||||||
# deprecated endpoint
|
# deprecated endpoint
|
||||||
return self.v2_situation_familiale(request, code_postal, numero_allocataire, user=user)
|
return self.v2_situation_familiale(request, code_postal, numero_allocataire, user=user)
|
||||||
|
|
||||||
@endpoint(name='situation-familiale',
|
@endpoint(
|
||||||
perm='can_access',
|
name='situation-familiale',
|
||||||
description=_('Get family allowances recipient informations'),
|
perm='can_access',
|
||||||
parameters={
|
description=_('Get family allowances recipient informations'),
|
||||||
'code_postal': {
|
parameters={
|
||||||
'description': _('postal code'),
|
'code_postal': {
|
||||||
'example_value': '99148',
|
'description': _('postal code'),
|
||||||
},
|
'example_value': '99148',
|
||||||
'numero_allocataire': {
|
},
|
||||||
'description': _('recipient identifier'),
|
'numero_allocataire': {
|
||||||
'example_value': '0000354',
|
'description': _('recipient identifier'),
|
||||||
},
|
'example_value': '0000354',
|
||||||
'user': {
|
},
|
||||||
'description': _('requesting user'),
|
'user': {
|
||||||
'example_value': 'John Doe (agent)',
|
'description': _('requesting user'),
|
||||||
},
|
'example_value': 'John Doe (agent)',
|
||||||
})
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
def v2_situation_familiale(self, request, code_postal, numero_allocataire, user=None):
|
def v2_situation_familiale(self, request, code_postal, numero_allocataire, user=None):
|
||||||
if not code_postal.strip() or not numero_allocataire.strip():
|
if not code_postal.strip() or not numero_allocataire.strip():
|
||||||
raise APIError('missing code_postal or numero_allocataire', status_code=400)
|
raise APIError('missing code_postal or numero_allocataire', status_code=400)
|
||||||
return self.get('v2/composition-familiale', params={
|
return self.get(
|
||||||
'codePostal': code_postal,
|
'v2/composition-familiale',
|
||||||
'numeroAllocataire': numero_allocataire,
|
params={
|
||||||
}, user=user)
|
'codePostal': code_postal,
|
||||||
|
'numeroAllocataire': numero_allocataire,
|
||||||
|
},
|
||||||
|
user=user,
|
||||||
|
)
|
||||||
|
|
||||||
category = _('Business Process Connectors')
|
category = _('Business Process Connectors')
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,36 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Arcgis',
|
name='Arcgis',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(verbose_name='Title', max_length=50)),
|
('title', models.CharField(verbose_name='Title', max_length=50)),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('log_level', models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')])),
|
(
|
||||||
|
'log_level',
|
||||||
|
models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
('base_url', models.CharField(max_length=256, verbose_name='SIG Url')),
|
('base_url', models.CharField(max_length=256, verbose_name='SIG Url')),
|
||||||
('users', models.ManyToManyField(to='base.ApiUser', related_name='_arcgis_users_+', related_query_name='+', blank=True)),
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='base.ApiUser', related_name='_arcgis_users_+', related_query_name='+', blank=True
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Arcgis Webservice',
|
'verbose_name': 'Arcgis Webservice',
|
||||||
|
|
|
@ -29,7 +29,9 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='arcgis',
|
model_name='arcgis',
|
||||||
name='client_certificate',
|
name='client_certificate',
|
||||||
field=models.FileField(blank=True, null=True, upload_to=b'', verbose_name='TLS client certificate'),
|
field=models.FileField(
|
||||||
|
blank=True, null=True, upload_to=b'', verbose_name='TLS client certificate'
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='arcgis',
|
model_name='arcgis',
|
||||||
|
@ -54,6 +56,18 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='arcgis',
|
model_name='arcgis',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')], default=b'INFO', max_length=10, verbose_name='Log Level'),
|
field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
default=b'INFO',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -18,17 +18,51 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Query',
|
name='Query',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('name', models.CharField(max_length=128, verbose_name='Name')),
|
('name', models.CharField(max_length=128, verbose_name='Name')),
|
||||||
('slug', models.SlugField(max_length=128, verbose_name='Slug')),
|
('slug', models.SlugField(max_length=128, verbose_name='Slug')),
|
||||||
('description', models.TextField(blank=True, verbose_name='Description')),
|
('description', models.TextField(blank=True, verbose_name='Description')),
|
||||||
('folder', models.CharField(blank=True, max_length=64, verbose_name='ArcGis Folder')),
|
('folder', models.CharField(blank=True, max_length=64, verbose_name='ArcGis Folder')),
|
||||||
('service', models.CharField(max_length=64, verbose_name='ArcGis Service')),
|
('service', models.CharField(max_length=64, verbose_name='ArcGis Service')),
|
||||||
('layer', models.CharField(blank=True, max_length=8, verbose_name='ArcGis Layer')),
|
('layer', models.CharField(blank=True, max_length=8, verbose_name='ArcGis Layer')),
|
||||||
('where', models.TextField(blank=True, help_text="<span>Use syntax <tt>{name}</tt> to introduce a string parameter and <tt>{name:d}</tt> for a decimal parameter. ex.:<br/><tt>adress LIKE ('%' || UPPER({adress}) || '%')</tt><br/><tt>population < {population:d}</tt></span>", validators=[passerelle.apps.arcgis.models.validate_where], verbose_name='ArcGis Where Clause')),
|
(
|
||||||
('id_template', models.TextField(blank=True, help_text="Use Django's template syntax. Attributes can be accessed through {{ attributes.name }}", validators=[passerelle.utils.templates.validate_template], verbose_name='Id template')),
|
'where',
|
||||||
('text_template', models.TextField(blank=True, help_text="Use Django's template syntax. Attributes can be accessed through {{ attributes.name }}", validators=[passerelle.utils.templates.validate_template], verbose_name='Text template')),
|
models.TextField(
|
||||||
('resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='arcgis.ArcGIS', verbose_name='Resource')),
|
blank=True,
|
||||||
|
help_text="<span>Use syntax <tt>{name}</tt> to introduce a string parameter and <tt>{name:d}</tt> for a decimal parameter. ex.:<br/><tt>adress LIKE ('%' || UPPER({adress}) || '%')</tt><br/><tt>population < {population:d}</tt></span>",
|
||||||
|
validators=[passerelle.apps.arcgis.models.validate_where],
|
||||||
|
verbose_name='ArcGis Where Clause',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'id_template',
|
||||||
|
models.TextField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Use Django's template syntax. Attributes can be accessed through {{ attributes.name }}",
|
||||||
|
validators=[passerelle.utils.templates.validate_template],
|
||||||
|
verbose_name='Id template',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'text_template',
|
||||||
|
models.TextField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Use Django's template syntax. Attributes can be accessed through {{ attributes.name }}",
|
||||||
|
validators=[passerelle.utils.templates.validate_template],
|
||||||
|
verbose_name='Text template',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'resource',
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
to='arcgis.ArcGIS',
|
||||||
|
verbose_name='Resource',
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['name'],
|
'ordering': ['name'],
|
||||||
|
|
|
@ -16,7 +16,9 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='arcgis',
|
model_name='arcgis',
|
||||||
name='client_certificate',
|
name='client_certificate',
|
||||||
field=models.FileField(blank=True, null=True, upload_to='', verbose_name='TLS client certificate'),
|
field=models.FileField(
|
||||||
|
blank=True, null=True, upload_to='', verbose_name='TLS client certificate'
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='arcgis',
|
model_name='arcgis',
|
||||||
|
@ -26,6 +28,11 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='query',
|
model_name='query',
|
||||||
name='resource',
|
name='resource',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='queries', to='arcgis.ArcGIS', verbose_name='Resource'),
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name='queries',
|
||||||
|
to='arcgis.ArcGIS',
|
||||||
|
verbose_name='Resource',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -46,44 +46,61 @@ class ArcGIS(BaseResource, HTTPResource):
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('ArcGIS REST API')
|
verbose_name = _('ArcGIS REST API')
|
||||||
|
|
||||||
@endpoint(name='mapservice-query',
|
@endpoint(
|
||||||
description=_('Map Service Query'),
|
name='mapservice-query',
|
||||||
perm='can_access',
|
description=_('Map Service Query'),
|
||||||
parameters={
|
perm='can_access',
|
||||||
'folder': {
|
parameters={
|
||||||
'description': _('Folder name'),
|
'folder': {
|
||||||
'example_value': 'Specialty',
|
'description': _('Folder name'),
|
||||||
},
|
'example_value': 'Specialty',
|
||||||
'service': {
|
},
|
||||||
'description': _('Service name'),
|
'service': {
|
||||||
'example_value': 'ESRI_StateCityHighway_USA',
|
'description': _('Service name'),
|
||||||
},
|
'example_value': 'ESRI_StateCityHighway_USA',
|
||||||
'layer': {
|
},
|
||||||
'description': _('Layer or table name'),
|
'layer': {
|
||||||
'example_value': '1',
|
'description': _('Layer or table name'),
|
||||||
},
|
'example_value': '1',
|
||||||
'lat': {'description': _('Latitude')},
|
},
|
||||||
'lon': {'description': _('Longitude')},
|
'lat': {'description': _('Latitude')},
|
||||||
'latmin': {'description': _('Minimal latitude (envelope)')},
|
'lon': {'description': _('Longitude')},
|
||||||
'lonmin': {'description': _('Minimal longitude (envelope)')},
|
'latmin': {'description': _('Minimal latitude (envelope)')},
|
||||||
'latmax': {'description': _('Maximal latitude (envelope)')},
|
'lonmin': {'description': _('Minimal longitude (envelope)')},
|
||||||
'lonmax': {'description': _('Maximal longitude (envelope)')},
|
'latmax': {'description': _('Maximal latitude (envelope)')},
|
||||||
'q': {'description': _('Search text in display field')},
|
'lonmax': {'description': _('Maximal longitude (envelope)')},
|
||||||
'template': {
|
'q': {'description': _('Search text in display field')},
|
||||||
'description': _('Django template for text attribute'),
|
'template': {
|
||||||
'example_value': '{{ attributes.STATE_NAME }} ({{ attributes.STATE_ABBR }})',
|
'description': _('Django template for text attribute'),
|
||||||
},
|
'example_value': '{{ attributes.STATE_NAME }} ({{ attributes.STATE_ABBR }})',
|
||||||
'id_template': {
|
},
|
||||||
'description': _('Django template for id attribute'),
|
'id_template': {
|
||||||
},
|
'description': _('Django template for id attribute'),
|
||||||
'full': {
|
},
|
||||||
'description': _('Returns all ArcGIS informations (geometry, metadata)'),
|
'full': {
|
||||||
'type': 'bool',
|
'description': _('Returns all ArcGIS informations (geometry, metadata)'),
|
||||||
},
|
'type': 'bool',
|
||||||
})
|
},
|
||||||
def mapservice_query(self, request, service, layer='0', folder='', lat=None, lon=None,
|
},
|
||||||
latmin=None, lonmin=None, latmax=None, lonmax=None, q=None,
|
)
|
||||||
template=None, id_template=None, full=False, **kwargs):
|
def mapservice_query(
|
||||||
|
self,
|
||||||
|
request,
|
||||||
|
service,
|
||||||
|
layer='0',
|
||||||
|
folder='',
|
||||||
|
lat=None,
|
||||||
|
lon=None,
|
||||||
|
latmin=None,
|
||||||
|
lonmin=None,
|
||||||
|
latmax=None,
|
||||||
|
lonmax=None,
|
||||||
|
q=None,
|
||||||
|
template=None,
|
||||||
|
id_template=None,
|
||||||
|
full=False,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
url = urlparse.urljoin(self.base_url, 'services/')
|
url = urlparse.urljoin(self.base_url, 'services/')
|
||||||
if folder:
|
if folder:
|
||||||
url = urlparse.urljoin(url, folder + '/')
|
url = urlparse.urljoin(url, folder + '/')
|
||||||
|
@ -109,8 +126,7 @@ class ArcGIS(BaseResource, HTTPResource):
|
||||||
lonmin, latmin = float(lonmin), float(latmin)
|
lonmin, latmin = float(lonmin), float(latmin)
|
||||||
lonmax, latmax = float(lonmax), float(latmax)
|
lonmax, latmax = float(lonmax), float(latmax)
|
||||||
except (ValueError,):
|
except (ValueError,):
|
||||||
raise APIError('<lonmin> <latmin> <lonmax> and <latmax> must be floats',
|
raise APIError('<lonmin> <latmin> <lonmax> and <latmax> must be floats', http_status=400)
|
||||||
http_status=400)
|
|
||||||
params['geometry'] = '{},{},{},{}'.format(lonmin, latmin, lonmax, latmax)
|
params['geometry'] = '{},{},{},{}'.format(lonmin, latmin, lonmax, latmax)
|
||||||
params['geometryType'] = 'esriGeometryEnvelope'
|
params['geometryType'] = 'esriGeometryEnvelope'
|
||||||
if q is not None:
|
if q is not None:
|
||||||
|
@ -156,7 +172,7 @@ class ArcGIS(BaseResource, HTTPResource):
|
||||||
feature['id'] = '%s' % get_feature_attribute(feature, id_fieldname)
|
feature['id'] = '%s' % get_feature_attribute(feature, id_fieldname)
|
||||||
feature['text'] = '%s' % get_feature_attribute(feature, text_fieldname)
|
feature['text'] = '%s' % get_feature_attribute(feature, text_fieldname)
|
||||||
else:
|
else:
|
||||||
feature['id'] = feature['text'] = '%d' % (n+1)
|
feature['id'] = feature['text'] = '%d' % (n + 1)
|
||||||
if template:
|
if template:
|
||||||
feature['text'] = render_to_string(template, feature)
|
feature['text'] = render_to_string(template, feature)
|
||||||
if id_template:
|
if id_template:
|
||||||
|
@ -169,22 +185,30 @@ class ArcGIS(BaseResource, HTTPResource):
|
||||||
return {'data': data, 'metadata': infos}
|
return {'data': data, 'metadata': infos}
|
||||||
return {'data': data}
|
return {'data': data}
|
||||||
|
|
||||||
@endpoint(name='district',
|
@endpoint(
|
||||||
description=_('Districts in Nancy Town'),
|
name='district',
|
||||||
parameters={
|
description=_('Districts in Nancy Town'),
|
||||||
'lat': {'description': _('Latitude')},
|
parameters={
|
||||||
'lon': {'description': _('Longitude')},
|
'lat': {'description': _('Latitude')},
|
||||||
},
|
'lon': {'description': _('Longitude')},
|
||||||
show=False)
|
},
|
||||||
|
show=False,
|
||||||
|
)
|
||||||
def district(self, request, lon=None, lat=None):
|
def district(self, request, lon=None, lat=None):
|
||||||
# deprecated endpoint
|
# deprecated endpoint
|
||||||
if 'NANCY_Grc' in self.base_url:
|
if 'NANCY_Grc' in self.base_url:
|
||||||
# Nancy URL used to contains folder, service and layer, remove them
|
# Nancy URL used to contains folder, service and layer, remove them
|
||||||
self.base_url = 'https://geoservices.grand-nancy.org/arcgis/rest/'
|
self.base_url = 'https://geoservices.grand-nancy.org/arcgis/rest/'
|
||||||
features = self.mapservice_query(request, folder='public', service='NANCY_Grc', layer='0',
|
features = self.mapservice_query(
|
||||||
template='{{ attributes.NOM }}',
|
request,
|
||||||
id_template='{{ attributes.NUMERO }}',
|
folder='public',
|
||||||
lon=lon, lat=lat)['data']
|
service='NANCY_Grc',
|
||||||
|
layer='0',
|
||||||
|
template='{{ attributes.NOM }}',
|
||||||
|
id_template='{{ attributes.NUMERO }}',
|
||||||
|
lon=lon,
|
||||||
|
lat=lat,
|
||||||
|
)['data']
|
||||||
if not features:
|
if not features:
|
||||||
raise APIError('No features found.')
|
raise APIError('No features found.')
|
||||||
for feature in features:
|
for feature in features:
|
||||||
|
@ -197,15 +221,14 @@ class ArcGIS(BaseResource, HTTPResource):
|
||||||
@endpoint(
|
@endpoint(
|
||||||
name='tile',
|
name='tile',
|
||||||
description=_('Tiles layer'),
|
description=_('Tiles layer'),
|
||||||
pattern=r'^(?P<layer>[\w/]+)/(?P<zoom>\d+)/(?P<tile_x>\d+)/(?P<tile_y>\d+)\.png$')
|
pattern=r'^(?P<layer>[\w/]+)/(?P<zoom>\d+)/(?P<tile_x>\d+)/(?P<tile_y>\d+)\.png$',
|
||||||
|
)
|
||||||
def tile(self, request, layer, zoom, tile_x, tile_y):
|
def tile(self, request, layer, zoom, tile_x, tile_y):
|
||||||
zoom = int(zoom)
|
zoom = int(zoom)
|
||||||
tile_x = int(tile_x)
|
tile_x = int(tile_x)
|
||||||
tile_y = int(tile_y)
|
tile_y = int(tile_y)
|
||||||
|
|
||||||
bbox = '%.6f,%.6f,%.6f,%.6f' % (
|
bbox = '%.6f,%.6f,%.6f,%.6f' % (num2deg(tile_x, tile_y, zoom) + num2deg(tile_x + 1, tile_y + 1, zoom))
|
||||||
num2deg(tile_x, tile_y, zoom) +
|
|
||||||
num2deg(tile_x+1, tile_y+1, zoom))
|
|
||||||
|
|
||||||
# imageSR=3857: default projection for leaflet
|
# imageSR=3857: default projection for leaflet
|
||||||
base_url = self.base_url
|
base_url = self.base_url
|
||||||
|
@ -213,19 +236,22 @@ class ArcGIS(BaseResource, HTTPResource):
|
||||||
base_url += '/'
|
base_url += '/'
|
||||||
return HttpResponse(
|
return HttpResponse(
|
||||||
self.requests.get(
|
self.requests.get(
|
||||||
base_url +
|
base_url
|
||||||
'%s/MapServer/export' % layer +
|
+ '%s/MapServer/export' % layer
|
||||||
'?dpi=96&format=png24&bboxSR=4326&imageSR=3857&' +
|
+ '?dpi=96&format=png24&bboxSR=4326&imageSR=3857&'
|
||||||
'transparent=true&size=256,256&f=image&' +
|
+ 'transparent=true&size=256,256&f=image&'
|
||||||
'bbox=%s' % bbox
|
+ 'bbox=%s' % bbox
|
||||||
).content,
|
).content,
|
||||||
content_type='image/png')
|
content_type='image/png',
|
||||||
|
)
|
||||||
|
|
||||||
@endpoint(name='q',
|
@endpoint(
|
||||||
description=_('Query'),
|
name='q',
|
||||||
pattern=r'^(?P<query_slug>[\w:_-]+)/$',
|
description=_('Query'),
|
||||||
perm='can_access',
|
pattern=r'^(?P<query_slug>[\w:_-]+)/$',
|
||||||
show=False)
|
perm='can_access',
|
||||||
|
show=False,
|
||||||
|
)
|
||||||
def q(self, request, query_slug, q=None, full=False, **kwargs):
|
def q(self, request, query_slug, q=None, full=False, **kwargs):
|
||||||
query = get_object_or_404(Query, resource=self, slug=query_slug)
|
query = get_object_or_404(Query, resource=self, slug=query_slug)
|
||||||
refs = [ref for ref, _ in query.where_references]
|
refs = [ref for ref, _ in query.where_references]
|
||||||
|
@ -282,22 +308,12 @@ def validate_where(format_string):
|
||||||
|
|
||||||
class Query(BaseQuery):
|
class Query(BaseQuery):
|
||||||
resource = models.ForeignKey(
|
resource = models.ForeignKey(
|
||||||
to=ArcGIS,
|
to=ArcGIS, related_name='queries', verbose_name=_('Resource'), on_delete=models.CASCADE
|
||||||
related_name='queries',
|
)
|
||||||
verbose_name=_('Resource'),
|
|
||||||
on_delete=models.CASCADE)
|
|
||||||
|
|
||||||
folder = models.CharField(
|
folder = models.CharField(verbose_name=_('ArcGis Folder'), max_length=64, blank=True)
|
||||||
verbose_name=_('ArcGis Folder'),
|
service = models.CharField(verbose_name=_('ArcGis Service'), max_length=64)
|
||||||
max_length=64,
|
layer = models.CharField(verbose_name=_('ArcGis Layer'), max_length=8, blank=True)
|
||||||
blank=True)
|
|
||||||
service = models.CharField(
|
|
||||||
verbose_name=_('ArcGis Service'),
|
|
||||||
max_length=64)
|
|
||||||
layer = models.CharField(
|
|
||||||
verbose_name=_('ArcGis Layer'),
|
|
||||||
max_length=8,
|
|
||||||
blank=True)
|
|
||||||
|
|
||||||
where = models.TextField(
|
where = models.TextField(
|
||||||
verbose_name=_('ArcGis Where Clause'),
|
verbose_name=_('ArcGis Where Clause'),
|
||||||
|
@ -308,19 +324,28 @@ class Query(BaseQuery):
|
||||||
'<span>Use syntax <tt>{name}</tt> to introduce a string '
|
'<span>Use syntax <tt>{name}</tt> to introduce a string '
|
||||||
'parameter and <tt>{name:d}</tt> for a decimal parameter. ex.:<br/>'
|
'parameter and <tt>{name:d}</tt> for a decimal parameter. ex.:<br/>'
|
||||||
'<tt>adress LIKE (\'%\' || UPPER({adress}) || \'%\')</tt><br/>'
|
'<tt>adress LIKE (\'%\' || UPPER({adress}) || \'%\')</tt><br/>'
|
||||||
'<tt>population < {population:d}</tt></span>')))
|
'<tt>population < {population:d}</tt></span>'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
id_template = models.TextField(
|
id_template = models.TextField(
|
||||||
verbose_name=_('Id template'),
|
verbose_name=_('Id template'),
|
||||||
validators=[validate_template],
|
validators=[validate_template],
|
||||||
help_text=_('Use Django\'s template syntax. Attributes can be accessed through {{ attributes.name }}'),
|
help_text=_(
|
||||||
blank=True)
|
'Use Django\'s template syntax. Attributes can be accessed through {{ attributes.name }}'
|
||||||
|
),
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
|
||||||
text_template = models.TextField(
|
text_template = models.TextField(
|
||||||
verbose_name=_('Text template'),
|
verbose_name=_('Text template'),
|
||||||
help_text=_('Use Django\'s template syntax. Attributes can be accessed through {{ attributes.name }}'),
|
help_text=_(
|
||||||
|
'Use Django\'s template syntax. Attributes can be accessed through {{ attributes.name }}'
|
||||||
|
),
|
||||||
validators=[validate_template],
|
validators=[validate_template],
|
||||||
blank=True)
|
blank=True,
|
||||||
|
)
|
||||||
|
|
||||||
delete_view = 'arcgis-query-delete'
|
delete_view = 'arcgis-query-delete'
|
||||||
edit_view = 'arcgis-query-edit'
|
edit_view = 'arcgis-query-edit'
|
||||||
|
@ -328,15 +353,20 @@ class Query(BaseQuery):
|
||||||
@property
|
@property
|
||||||
def where_references(self):
|
def where_references(self):
|
||||||
if self.where:
|
if self.where:
|
||||||
return [(ref, int if spec and spec[-1] == 'd' else str)
|
return [
|
||||||
for _, ref, spec, _ in SqlFormatter().parse(self.where) if ref is not None]
|
(ref, int if spec and spec[-1] == 'd' else str)
|
||||||
|
for _, ref, spec, _ in SqlFormatter().parse(self.where)
|
||||||
|
if ref is not None
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def q(self, request, q=None, full=False, **kwargs):
|
def q(self, request, q=None, full=False, **kwargs):
|
||||||
kwargs.update({
|
kwargs.update(
|
||||||
'service': self.service,
|
{
|
||||||
})
|
'service': self.service,
|
||||||
|
}
|
||||||
|
)
|
||||||
if self.id_template:
|
if self.id_template:
|
||||||
kwargs['id_template'] = self.id_template
|
kwargs['id_template'] = self.id_template
|
||||||
if self.text_template:
|
if self.text_template:
|
||||||
|
|
|
@ -19,10 +19,11 @@ from django.conf.urls import url
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
management_urlpatterns = [
|
management_urlpatterns = [
|
||||||
url(r'^(?P<slug>[\w,-]+)/query/new/$',
|
url(r'^(?P<slug>[\w,-]+)/query/new/$', views.QueryNew.as_view(), name='arcgis-query-new'),
|
||||||
views.QueryNew.as_view(), name='arcgis-query-new'),
|
url(r'^(?P<slug>[\w,-]+)/query/(?P<pk>\d+)/$', views.QueryEdit.as_view(), name='arcgis-query-edit'),
|
||||||
url(r'^(?P<slug>[\w,-]+)/query/(?P<pk>\d+)/$',
|
url(
|
||||||
views.QueryEdit.as_view(), name='arcgis-query-edit'),
|
r'^(?P<slug>[\w,-]+)/query/(?P<pk>\d+)/delete/$',
|
||||||
url(r'^(?P<slug>[\w,-]+)/query/(?P<pk>\d+)/delete/$',
|
views.QueryDelete.as_view(),
|
||||||
views.QueryDelete.as_view(), name='arcgis-query-delete'),
|
name='arcgis-query-delete',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,15 +14,41 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ArpegeECP',
|
name='ArpegeECP',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(max_length=50, verbose_name='Title')),
|
('title', models.CharField(max_length=50, verbose_name='Title')),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('log_level', models.CharField(default=b'INFO', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')])),
|
(
|
||||||
|
'log_level',
|
||||||
|
models.CharField(
|
||||||
|
default=b'INFO',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
('webservice_base_url', models.URLField(verbose_name='Webservice Base URL')),
|
('webservice_base_url', models.URLField(verbose_name='Webservice Base URL')),
|
||||||
('hawk_auth_id', models.CharField(max_length=64, verbose_name='Hawk Authentication id')),
|
('hawk_auth_id', models.CharField(max_length=64, verbose_name='Hawk Authentication id')),
|
||||||
('hawk_auth_key', models.CharField(max_length=64, verbose_name='Hawk Authentication secret')),
|
('hawk_auth_key', models.CharField(max_length=64, verbose_name='Hawk Authentication secret')),
|
||||||
('users', models.ManyToManyField(to='base.ApiUser', related_name='_arpegeecp_users_+', related_query_name='+', blank=True)),
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='base.ApiUser',
|
||||||
|
related_name='_arpegeecp_users_+',
|
||||||
|
related_query_name='+',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Arpege ECP',
|
'verbose_name': 'Arpege ECP',
|
||||||
|
|
|
@ -56,8 +56,9 @@ class ArpegeECP(BaseResource):
|
||||||
def get_access_token(self, NameID):
|
def get_access_token(self, NameID):
|
||||||
url = urlparse.urljoin(self.webservice_base_url, 'LoginParSubOIDC')
|
url = urlparse.urljoin(self.webservice_base_url, 'LoginParSubOIDC')
|
||||||
try:
|
try:
|
||||||
response = self.requests.post(url, auth=HawkAuth(self.hawk_auth_id, self.hawk_auth_key),
|
response = self.requests.post(
|
||||||
json={'subOIDC': NameID})
|
url, auth=HawkAuth(self.hawk_auth_id, self.hawk_auth_key), json={'subOIDC': NameID}
|
||||||
|
)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
except RequestException as e:
|
except RequestException as e:
|
||||||
raise APIError(u'Arpege server is down: %s' % e)
|
raise APIError(u'Arpege server is down: %s' % e)
|
||||||
|
@ -73,7 +74,12 @@ class ArpegeECP(BaseResource):
|
||||||
return result['Data']['AccessToken']
|
return result['Data']['AccessToken']
|
||||||
raise APIError(u'%s (%s)' % (result.get('LibErreur'), result.get('CodErreur')))
|
raise APIError(u'%s (%s)' % (result.get('LibErreur'), result.get('CodErreur')))
|
||||||
|
|
||||||
@endpoint(name='api', pattern='^users/(?P<nameid>\w+)/forms$', perm='can_access', description='Returns user forms')
|
@endpoint(
|
||||||
|
name='api',
|
||||||
|
pattern='^users/(?P<nameid>\w+)/forms$',
|
||||||
|
perm='can_access',
|
||||||
|
description='Returns user forms',
|
||||||
|
)
|
||||||
def get_user_forms(self, request, nameid):
|
def get_user_forms(self, request, nameid):
|
||||||
access_token = self.get_access_token(nameid)
|
access_token = self.get_access_token(nameid)
|
||||||
url = urlparse.urljoin(self.webservice_base_url, 'DemandesUsager')
|
url = urlparse.urljoin(self.webservice_base_url, 'DemandesUsager')
|
||||||
|
@ -98,14 +104,15 @@ class ArpegeECP(BaseResource):
|
||||||
receipt_date = parse_date(data_administratives['date_depot'])
|
receipt_date = parse_date(data_administratives['date_depot'])
|
||||||
except (KeyError, TypeError) as e:
|
except (KeyError, TypeError) as e:
|
||||||
raise APIError(u'Arpege error: %s %r' % (e, json.dumps(demand)[:1000]))
|
raise APIError(u'Arpege error: %s %r' % (e, json.dumps(demand)[:1000]))
|
||||||
d = {'url': demand['url'],
|
d = {
|
||||||
'title': data_administratives.get('LibelleQualificationTypeDemande'),
|
'url': demand['url'],
|
||||||
'name': data_administratives.get('LibelleQualificationTypeDemande'),
|
'title': data_administratives.get('LibelleQualificationTypeDemande'),
|
||||||
'status': data_administratives.get('libelle_etat'),
|
'name': data_administratives.get('LibelleQualificationTypeDemande'),
|
||||||
'form_receipt_time': receipt_time,
|
'status': data_administratives.get('libelle_etat'),
|
||||||
'readable': True,
|
'form_receipt_time': receipt_time,
|
||||||
'form_receipt_datetime': timezone.datetime.combine(receipt_date, receipt_time),
|
'readable': True,
|
||||||
'form_status_is_endpoint': data_administratives.get('date_fin_instruction') is not None,
|
'form_receipt_datetime': timezone.datetime.combine(receipt_date, receipt_time),
|
||||||
|
'form_status_is_endpoint': data_administratives.get('date_fin_instruction') is not None,
|
||||||
}
|
}
|
||||||
data.append(d)
|
data.append(d)
|
||||||
return {'data': data}
|
return {'data': data}
|
||||||
|
|
|
@ -18,7 +18,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='AstreGS',
|
name='AstreGS',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('title', models.CharField(max_length=50, verbose_name='Title')),
|
('title', models.CharField(max_length=50, verbose_name='Title')),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
|
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
|
||||||
|
@ -28,7 +31,12 @@ class Migration(migrations.Migration):
|
||||||
('organism', models.CharField(max_length=32, verbose_name='Organisme')),
|
('organism', models.CharField(max_length=32, verbose_name='Organisme')),
|
||||||
('budget', models.CharField(max_length=32, verbose_name='Budget')),
|
('budget', models.CharField(max_length=32, verbose_name='Budget')),
|
||||||
('exercice', models.CharField(max_length=32, verbose_name='Exercice')),
|
('exercice', models.CharField(max_length=32, verbose_name='Exercice')),
|
||||||
('users', models.ManyToManyField(blank=True, related_name='_astregs_users_+', related_query_name='+', to='base.ApiUser')),
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True, related_name='_astregs_users_+', related_query_name='+', to='base.ApiUser'
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'AstresGS',
|
'verbose_name': 'AstresGS',
|
||||||
|
@ -37,11 +45,17 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Link',
|
name='Link',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('name_id', models.CharField(max_length=32)),
|
('name_id', models.CharField(max_length=32)),
|
||||||
('association_id', models.CharField(max_length=32)),
|
('association_id', models.CharField(max_length=32)),
|
||||||
('created', models.DateTimeField(auto_now_add=True)),
|
('created', models.DateTimeField(auto_now_add=True)),
|
||||||
('resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='astregs.AstreGS')),
|
(
|
||||||
|
'resource',
|
||||||
|
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='astregs.AstreGS'),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.AlterUniqueTogether(
|
migrations.AlterUniqueTogether(
|
||||||
|
|
|
@ -46,18 +46,35 @@ ASSOCIATION_SCHEMA = {
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Financier": {"description": "financial association", "type": "string", "enum": ["true", "false"]},
|
"Financier": {"description": "financial association", "type": "string", "enum": ["true", "false"]},
|
||||||
"CodeFamille": {"description": "association family code", "type": "string",},
|
"CodeFamille": {
|
||||||
"CatTiers": {"description": "association category", "type": "string",},
|
"description": "association family code",
|
||||||
"NomEnregistrement": {"description": "association name", "type": "string",},
|
"type": "string",
|
||||||
|
},
|
||||||
|
"CatTiers": {
|
||||||
|
"description": "association category",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"NomEnregistrement": {
|
||||||
|
"description": "association name",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
"StatutTiers": {
|
"StatutTiers": {
|
||||||
"description": "association status",
|
"description": "association status",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["PROPOSE", "VALIDE", "REFUSE", "BLOQUE", "A COMPLETER"],
|
"enum": ["PROPOSE", "VALIDE", "REFUSE", "BLOQUE", "A COMPLETER"],
|
||||||
},
|
},
|
||||||
"Type": {"description": "association type", "type": "string", "enum": ["D", "F", "*"]},
|
"Type": {"description": "association type", "type": "string", "enum": ["D", "F", "*"]},
|
||||||
"NumeroSiret": {"description": "SIREN number", "type": "string",},
|
"NumeroSiret": {
|
||||||
"NumeroSiretFin": {"description": "NIC number", "type": "string",},
|
"description": "SIREN number",
|
||||||
"AdresseTitre": {"type": "string",},
|
"type": "string",
|
||||||
|
},
|
||||||
|
"NumeroSiretFin": {
|
||||||
|
"description": "NIC number",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"AdresseTitre": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
"AdresseIsAdresseDeCommande": {"type": "string", "enum": ["true", "false"]},
|
"AdresseIsAdresseDeCommande": {"type": "string", "enum": ["true", "false"]},
|
||||||
"AdresseIsAdresseDeFacturation": {"type": "string", "enum": ["true", "false"]},
|
"AdresseIsAdresseDeFacturation": {"type": "string", "enum": ["true", "false"]},
|
||||||
},
|
},
|
||||||
|
@ -78,13 +95,27 @@ CONTACT_SCHEMA = {
|
||||||
"EncodeKeyStatut",
|
"EncodeKeyStatut",
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"CodeContact": {"type": "string",},
|
"CodeContact": {
|
||||||
"CodeTitreCivilite": {"type": "string",},
|
"type": "string",
|
||||||
"Nom": {"type": "string",},
|
},
|
||||||
"AdresseDestinataire": {"type": "string",},
|
"CodeTitreCivilite": {
|
||||||
"CodePostal": {"type": "string",},
|
"type": "string",
|
||||||
"Ville": {"type": "string",},
|
},
|
||||||
"EncodeKeyStatut": {"type": "string",},
|
"Nom": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"AdresseDestinataire": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"CodePostal": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"Ville": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"EncodeKeyStatut": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,21 +136,43 @@ DOCUMENT_SCHEMA = {
|
||||||
"document",
|
"document",
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Sujet": {"type": "string",},
|
"Sujet": {
|
||||||
"Entite": {"type": "string",},
|
"type": "string",
|
||||||
"CodType": {"type": "string",},
|
},
|
||||||
"Type": {"type": "string",},
|
"Entite": {
|
||||||
"hdnCodeTrt": {"type": "string",},
|
"type": "string",
|
||||||
"EncodeKeyEntite": {"type": "string",},
|
},
|
||||||
"CodeDomaine": {"type": "string",},
|
"CodType": {
|
||||||
"CodDom": {"type": "string",},
|
"type": "string",
|
||||||
|
},
|
||||||
|
"Type": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"hdnCodeTrt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"EncodeKeyEntite": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"CodeDomaine": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"CodDom": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
"document": {
|
"document": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ['filename', 'content_type', 'content'],
|
"required": ['filename', 'content_type', 'content'],
|
||||||
'properties': {
|
'properties': {
|
||||||
'filename': {'type': 'string',},
|
'filename': {
|
||||||
'content_type': {'type': 'string',},
|
'type': 'string',
|
||||||
'content': {'type': 'string',},
|
},
|
||||||
|
'content_type': {
|
||||||
|
'type': 'string',
|
||||||
|
},
|
||||||
|
'content': {
|
||||||
|
'type': 'string',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -141,14 +194,28 @@ GRANT_SCHEMA = {
|
||||||
"CodeServiceUtilisateur",
|
"CodeServiceUtilisateur",
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Libelle": {"type": "string",},
|
"Libelle": {
|
||||||
"LibelleCourt": {"type": "string",},
|
"type": "string",
|
||||||
|
},
|
||||||
|
"LibelleCourt": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
"ModGestion": {"type": "string", "enum": ["1", "2", "3", "4"]},
|
"ModGestion": {"type": "string", "enum": ["1", "2", "3", "4"]},
|
||||||
"TypeAide": {"type": "string",},
|
"TypeAide": {
|
||||||
"Sens": {"type": "string",},
|
"type": "string",
|
||||||
"CodeTiersDem": {"type": "string",},
|
},
|
||||||
"CodeServiceGestionnaire": {"type": "string",},
|
"Sens": {
|
||||||
"CodeServiceUtilisateur": {"type": "string",},
|
"type": "string",
|
||||||
|
},
|
||||||
|
"CodeTiersDem": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"CodeServiceGestionnaire": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"CodeServiceUtilisateur": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,11 +226,21 @@ INDANA_SCHEMA = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["CodeDossier", "CodeInd_1", "AnneeInd_1", "ValInd_1"],
|
"required": ["CodeDossier", "CodeInd_1", "AnneeInd_1", "ValInd_1"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"CodeDossier": {"type": "string",},
|
"CodeDossier": {
|
||||||
"CodeInd_1": {"type": "string",},
|
"type": "string",
|
||||||
"AnneeInd_1": {"type": "string",},
|
},
|
||||||
"ValInd_1": {"type": "string",},
|
"CodeInd_1": {
|
||||||
"IndAide": {"type": "string",},
|
"type": "string",
|
||||||
|
},
|
||||||
|
"AnneeInd_1": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"ValInd_1": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"IndAide": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,9 +251,15 @@ INDANA_KEY_SCHEMA = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["CodeDossier", "CodeInd_1", "AnneeInd_1"],
|
"required": ["CodeDossier", "CodeInd_1", "AnneeInd_1"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"CodeDossier": {"type": "string",},
|
"CodeDossier": {
|
||||||
"CodeInd_1": {"type": "string",},
|
"type": "string",
|
||||||
"AnneeInd_1": {"type": "string",},
|
},
|
||||||
|
"CodeInd_1": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"AnneeInd_1": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,51 +280,26 @@ TIERS_RIB_SCHEMA = {
|
||||||
"CodeStatut",
|
"CodeStatut",
|
||||||
"CodeDevise",
|
"CodeDevise",
|
||||||
"CodeIso2Pays",
|
"CodeIso2Pays",
|
||||||
"LibelleCompteEtranger"
|
"LibelleCompteEtranger",
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"CodeDevise": {
|
"CodeDevise": {"type": "string"},
|
||||||
"type": "string"
|
"CodeDomiciliation": {"type": "string"},
|
||||||
},
|
"CodeIso2Pays": {"type": "string"},
|
||||||
"CodeDomiciliation": {
|
"CodePaiement": {"type": "string"},
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"CodeIso2Pays": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"CodePaiement": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"CodeStatut": {
|
"CodeStatut": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["PROPOSE", "VALIDE", "REFUSE", "A COMPLETER",
|
"enum": ["PROPOSE", "VALIDE", "REFUSE", "A COMPLETER", "BLOQUE", "EN MODIFICATION"],
|
||||||
"BLOQUE", "EN MODIFICATION"]
|
|
||||||
},
|
},
|
||||||
"CodeTiers": {
|
"CodeTiers": {"type": "string"},
|
||||||
"type": "string"
|
"IndicateurRibDefaut": {"type": "string"},
|
||||||
},
|
"LibelleCompteEtranger": {"type": "string"},
|
||||||
"IndicateurRibDefaut": {
|
"LibelleCourt": {"type": "string"},
|
||||||
"type": "string"
|
"NumeroIban": {"type": "string"},
|
||||||
},
|
"CleIban": {"type": "string"},
|
||||||
"LibelleCompteEtranger": {
|
"CodeBic": {"type": "string"},
|
||||||
"type": "string"
|
"IdRib": {"type": "string"},
|
||||||
},
|
},
|
||||||
"LibelleCourt": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"NumeroIban": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"CleIban": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"CodeBic": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"IdRib": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TIERS_RIB_UPDATE_SCHEMA = {
|
TIERS_RIB_UPDATE_SCHEMA = {
|
||||||
|
@ -259,45 +317,24 @@ TIERS_RIB_UPDATE_SCHEMA = {
|
||||||
"CodeStatut",
|
"CodeStatut",
|
||||||
"CodeDevise",
|
"CodeDevise",
|
||||||
"CodeIso2Pays",
|
"CodeIso2Pays",
|
||||||
"LibelleCompteEtranger"
|
"LibelleCompteEtranger",
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"CodeDevise": {
|
"CodeDevise": {"type": "string"},
|
||||||
"type": "string"
|
"CodeDomiciliation": {"type": "string"},
|
||||||
},
|
"CodeIso2Pays": {"type": "string"},
|
||||||
"CodeDomiciliation": {
|
"CodePaiement": {"type": "string"},
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"CodeIso2Pays": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"CodePaiement": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"CodeStatut": {
|
"CodeStatut": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["PROPOSE", "VALIDE", "REFUSE", "A COMPLETER",
|
"enum": ["PROPOSE", "VALIDE", "REFUSE", "A COMPLETER", "BLOQUE", "EN MODIFICATION"],
|
||||||
"BLOQUE", "EN MODIFICATION"]
|
|
||||||
},
|
},
|
||||||
"IndicateurRibDefaut": {
|
"IndicateurRibDefaut": {"type": "string"},
|
||||||
"type": "string"
|
"LibelleCompteEtranger": {"type": "string"},
|
||||||
},
|
"LibelleCourt": {"type": "string"},
|
||||||
"LibelleCompteEtranger": {
|
"NumeroIban": {"type": "string"},
|
||||||
"type": "string"
|
"CleIban": {"type": "string"},
|
||||||
},
|
"CodeBic": {"type": "string"},
|
||||||
"LibelleCourt": {
|
},
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"NumeroIban": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"CleIban": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"CodeBic": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -434,8 +471,14 @@ class AstreGS(BaseResource):
|
||||||
description=_('Create link between user and association'),
|
description=_('Create link between user and association'),
|
||||||
perm='can_access',
|
perm='can_access',
|
||||||
parameters={
|
parameters={
|
||||||
'NameID': {'description': _('Publik NameID'), 'example_value': 'xyz24d934',},
|
'NameID': {
|
||||||
'association_id': {'description': _('Association ID'), 'example_value': '12345',},
|
'description': _('Publik NameID'),
|
||||||
|
'example_value': 'xyz24d934',
|
||||||
|
},
|
||||||
|
'association_id': {
|
||||||
|
'description': _('Association ID'),
|
||||||
|
'example_value': '12345',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
def link(self, request, NameID, association_id):
|
def link(self, request, NameID, association_id):
|
||||||
|
@ -464,7 +507,12 @@ class AstreGS(BaseResource):
|
||||||
@endpoint(
|
@endpoint(
|
||||||
description=_('List user links'),
|
description=_('List user links'),
|
||||||
perm='can_access',
|
perm='can_access',
|
||||||
parameters={'NameID': {'description': _('Publik NameID'), 'example_value': 'xyz24d934',}},
|
parameters={
|
||||||
|
'NameID': {
|
||||||
|
'description': _('Publik NameID'),
|
||||||
|
'example_value': 'xyz24d934',
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
def links(self, request, NameID):
|
def links(self, request, NameID):
|
||||||
if not Link.objects.filter(resource=self, name_id=NameID).exists():
|
if not Link.objects.filter(resource=self, name_id=NameID).exists():
|
||||||
|
@ -508,7 +556,12 @@ class AstreGS(BaseResource):
|
||||||
name='get-contact',
|
name='get-contact',
|
||||||
perm='can_access',
|
perm='can_access',
|
||||||
description=_('Get contact details'),
|
description=_('Get contact details'),
|
||||||
parameters={'contact_id': {'description': _('Contact identifier'), 'example_value': '1111',}},
|
parameters={
|
||||||
|
'contact_id': {
|
||||||
|
'description': _('Contact identifier'),
|
||||||
|
'example_value': '1111',
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
def get_contact(self, request, contact_id):
|
def get_contact(self, request, contact_id):
|
||||||
r = self.call('Contact', 'Chargement', ContactCle={'idContact': contact_id})
|
r = self.call('Contact', 'Chargement', ContactCle={'idContact': contact_id})
|
||||||
|
@ -533,7 +586,9 @@ class AstreGS(BaseResource):
|
||||||
description=_('Delete contact'),
|
description=_('Delete contact'),
|
||||||
name='delete-contact',
|
name='delete-contact',
|
||||||
perm='can_access',
|
perm='can_access',
|
||||||
parameters={'contact_id': {'description': _('Contact ID'), 'example_value': '4242'},},
|
parameters={
|
||||||
|
'contact_id': {'description': _('Contact ID'), 'example_value': '4242'},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
def delete_contact(self, request, contact_id):
|
def delete_contact(self, request, contact_id):
|
||||||
r = self.call('Contact', 'Suppression', ContactCle={'idContact': contact_id})
|
r = self.call('Contact', 'Suppression', ContactCle={'idContact': contact_id})
|
||||||
|
@ -615,31 +670,31 @@ class AstreGS(BaseResource):
|
||||||
r = self.call('TiersRib', 'Creation', TiersRib=post_data)
|
r = self.call('TiersRib', 'Creation', TiersRib=post_data)
|
||||||
return {'data': serialize_object(r)}
|
return {'data': serialize_object(r)}
|
||||||
|
|
||||||
|
|
||||||
@endpoint(
|
@endpoint(
|
||||||
name='get-tiers-rib', perm='can_access',
|
name='get-tiers-rib',
|
||||||
|
perm='can_access',
|
||||||
description=_('Get RIB'),
|
description=_('Get RIB'),
|
||||||
parameters={
|
parameters={
|
||||||
'CodeTiers': {'example_value': '42435'},
|
'CodeTiers': {'example_value': '42435'},
|
||||||
'IdRib': {'example_value': '4242'},
|
'IdRib': {'example_value': '4242'},
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
def get_tiers_rib(self, request, CodeTiers, IdRib):
|
def get_tiers_rib(self, request, CodeTiers, IdRib):
|
||||||
payload = {'CodeTiers': CodeTiers, 'IdRib': IdRib}
|
payload = {'CodeTiers': CodeTiers, 'IdRib': IdRib}
|
||||||
r = self.call('TiersRib', 'Chargement', TiersRibCle=payload)
|
r = self.call('TiersRib', 'Chargement', TiersRibCle=payload)
|
||||||
return {'data': serialize_object(r)}
|
return {'data': serialize_object(r)}
|
||||||
|
|
||||||
|
|
||||||
@endpoint(
|
@endpoint(
|
||||||
name='update-tiers-rib', perm='can_access',
|
name='update-tiers-rib',
|
||||||
|
perm='can_access',
|
||||||
post={
|
post={
|
||||||
'description': _('Update RIB'),
|
'description': _('Update RIB'),
|
||||||
'request_body': {'schema': {'application/json': TIERS_RIB_UPDATE_SCHEMA}}
|
'request_body': {'schema': {'application/json': TIERS_RIB_UPDATE_SCHEMA}},
|
||||||
},
|
},
|
||||||
parameters={
|
parameters={
|
||||||
'CodeTiers': {'example_value': '42435'},
|
'CodeTiers': {'example_value': '42435'},
|
||||||
'IdRib': {'example_value': '4242'},
|
'IdRib': {'example_value': '4242'},
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
def update_tiers_rib(self, request, CodeTiers, IdRib, post_data):
|
def update_tiers_rib(self, request, CodeTiers, IdRib, post_data):
|
||||||
post_data['CodeTiers'] = CodeTiers
|
post_data['CodeTiers'] = CodeTiers
|
||||||
|
@ -647,32 +702,33 @@ class AstreGS(BaseResource):
|
||||||
r = self.call('TiersRib', 'Modification', TiersRib=post_data)
|
r = self.call('TiersRib', 'Modification', TiersRib=post_data)
|
||||||
return {'data': serialize_object(r)}
|
return {'data': serialize_object(r)}
|
||||||
|
|
||||||
|
@endpoint(
|
||||||
@endpoint(name='delete-tiers-rib', perm='can_access',
|
name='delete-tiers-rib',
|
||||||
|
perm='can_access',
|
||||||
description=_('Delete RIB'),
|
description=_('Delete RIB'),
|
||||||
parameters={
|
parameters={
|
||||||
'CodeTiers': {'example_value': '42435'},
|
'CodeTiers': {'example_value': '42435'},
|
||||||
'IdRib': {'example_value': '4242'},
|
'IdRib': {'example_value': '4242'},
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
def delete_tiers_rib(self, request, CodeTiers, IdRib):
|
def delete_tiers_rib(self, request, CodeTiers, IdRib):
|
||||||
payload = {'CodeTiers': CodeTiers, 'IdRib': IdRib}
|
payload = {'CodeTiers': CodeTiers, 'IdRib': IdRib}
|
||||||
r = self.call('TiersRib', 'Suppression', TiersRibCle=payload)
|
r = self.call('TiersRib', 'Suppression', TiersRibCle=payload)
|
||||||
return {'data': serialize_object(r)}
|
return {'data': serialize_object(r)}
|
||||||
|
|
||||||
@endpoint(name='find-tiers-by-rib', perm='can_access',
|
@endpoint(
|
||||||
|
name='find-tiers-by-rib',
|
||||||
|
perm='can_access',
|
||||||
description=_('Find person by RIB'),
|
description=_('Find person by RIB'),
|
||||||
parameters={
|
parameters={
|
||||||
'banque': {'example_value': '30001'},
|
'banque': {'example_value': '30001'},
|
||||||
'guichet': {'example_value': '00794'},
|
'guichet': {'example_value': '00794'},
|
||||||
'numero_compte': {'example_value': '12345678901'},
|
'numero_compte': {'example_value': '12345678901'},
|
||||||
'cle': {'example_value': '85'},
|
'cle': {'example_value': '85'},
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
def find_tiers_by_rib(self, request, banque, guichet, numero_compte, cle, **kwargs):
|
def find_tiers_by_rib(self, request, banque, guichet, numero_compte, cle, **kwargs):
|
||||||
criteres = {'banque': banque, 'guichet': guichet,
|
criteres = {'banque': banque, 'guichet': guichet, 'numeroCompte': numero_compte, 'cleRIB': cle}
|
||||||
'numeroCompte': numero_compte,
|
|
||||||
'cleRIB': cle}
|
|
||||||
# add other params to search criterias
|
# add other params to search criterias
|
||||||
criteres.update(kwargs)
|
criteres.update(kwargs)
|
||||||
r = self.search_tiers(criteres)
|
r = self.search_tiers(criteres)
|
||||||
|
|
|
@ -17,12 +17,30 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ATALConnector',
|
name='ATALConnector',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('title', models.CharField(max_length=50, verbose_name='Title')),
|
('title', models.CharField(max_length=50, verbose_name='Title')),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
|
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
|
||||||
('base_soap_url', models.URLField(help_text='URL of the base SOAP endpoint', max_length=400, verbose_name='Base SOAP endpoint')),
|
(
|
||||||
('users', models.ManyToManyField(blank=True, related_name='_atalconnector_users_+', related_query_name='+', to='base.ApiUser')),
|
'base_soap_url',
|
||||||
|
models.URLField(
|
||||||
|
help_text='URL of the base SOAP endpoint',
|
||||||
|
max_length=400,
|
||||||
|
verbose_name='Base SOAP endpoint',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
related_name='_atalconnector_users_+',
|
||||||
|
related_query_name='+',
|
||||||
|
to='base.ApiUser',
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'ATAL connector',
|
'verbose_name': 'ATAL connector',
|
||||||
|
|
|
@ -43,17 +43,14 @@ def process_response(demande_number):
|
||||||
|
|
||||||
class ATALConnector(BaseResource):
|
class ATALConnector(BaseResource):
|
||||||
base_soap_url = models.URLField(
|
base_soap_url = models.URLField(
|
||||||
max_length=400, verbose_name=_('Base SOAP endpoint'),
|
max_length=400, verbose_name=_('Base SOAP endpoint'), help_text=_('URL of the base SOAP endpoint')
|
||||||
help_text=_('URL of the base SOAP endpoint'))
|
)
|
||||||
category = _('Business Process Connectors')
|
category = _('Business Process Connectors')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('ATAL connector')
|
verbose_name = _('ATAL connector')
|
||||||
|
|
||||||
DEMANDE_NUMBER_PARAM = {
|
DEMANDE_NUMBER_PARAM = {'description': _('Demande number'), 'example_value': 'DIT18050001'}
|
||||||
'description': _('Demande number'),
|
|
||||||
'example_value': 'DIT18050001'
|
|
||||||
}
|
|
||||||
|
|
||||||
def _soap_call(self, wsdl, method, **kwargs):
|
def _soap_call(self, wsdl, method, **kwargs):
|
||||||
wsdl_url = urllib.parse.urljoin(self.base_soap_url, '%s?wsdl' % wsdl)
|
wsdl_url = urllib.parse.urljoin(self.base_soap_url, '%s?wsdl' % wsdl)
|
||||||
|
@ -96,34 +93,29 @@ class ATALConnector(BaseResource):
|
||||||
return self._xml_ref('VilleAgileService', 'getTypesEquipement', 'types')
|
return self._xml_ref('VilleAgileService', 'getTypesEquipement', 'types')
|
||||||
|
|
||||||
@endpoint(
|
@endpoint(
|
||||||
perm='can_access', name='insert-action-comment',
|
perm='can_access',
|
||||||
|
name='insert-action-comment',
|
||||||
post={
|
post={
|
||||||
'description': _('Insert action comment'),
|
'description': _('Insert action comment'),
|
||||||
'request_body': {
|
'request_body': {'schema': {'application/json': schemas.INSERT_ACTION_COMMENT}},
|
||||||
'schema': {
|
},
|
||||||
'application/json': schemas.INSERT_ACTION_COMMENT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
def insert_action_comment(self, request, post_data):
|
def insert_action_comment(self, request, post_data):
|
||||||
demande_number = self._soap_call(
|
demande_number = self._soap_call(
|
||||||
wsdl='DemandeService', method='insertActionComment',
|
wsdl='DemandeService',
|
||||||
|
method='insertActionComment',
|
||||||
numeroDemande=post_data['numero_demande'],
|
numeroDemande=post_data['numero_demande'],
|
||||||
commentaire=post_data['commentaire']
|
commentaire=post_data['commentaire'],
|
||||||
)
|
)
|
||||||
return process_response(demande_number)
|
return process_response(demande_number)
|
||||||
|
|
||||||
@endpoint(
|
@endpoint(
|
||||||
perm='can_access', name='insert-demande-complet-by-type',
|
perm='can_access',
|
||||||
|
name='insert-demande-complet-by-type',
|
||||||
post={
|
post={
|
||||||
'description': _('Insert demande complet by type'),
|
'description': _('Insert demande complet by type'),
|
||||||
'request_body': {
|
'request_body': {'schema': {'application/json': schemas.INSERT_DEMANDE_COMPLET_BY_TYPE}},
|
||||||
'schema': {
|
},
|
||||||
'application/json': schemas.INSERT_DEMANDE_COMPLET_BY_TYPE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
def insert_demande_complet_by_type(self, request, post_data):
|
def insert_demande_complet_by_type(self, request, post_data):
|
||||||
data = {}
|
data = {}
|
||||||
|
@ -170,39 +162,39 @@ class ATALConnector(BaseResource):
|
||||||
if recv in post_data:
|
if recv in post_data:
|
||||||
data[send] = post_data[recv]
|
data[send] = post_data[recv]
|
||||||
|
|
||||||
demande_number = self._soap_call(
|
demande_number = self._soap_call(wsdl='DemandeService', method='insertDemandeCompletByType', **data)
|
||||||
wsdl='DemandeService', method='insertDemandeCompletByType', **data
|
|
||||||
)
|
|
||||||
return process_response(demande_number)
|
return process_response(demande_number)
|
||||||
|
|
||||||
@endpoint(
|
@endpoint(
|
||||||
methods=['get'], perm='can_access', example_pattern='{demande_number}/',
|
methods=['get'],
|
||||||
pattern='^(?P<demande_number>\w+)/$', name='retrieve-details-demande',
|
perm='can_access',
|
||||||
parameters={
|
example_pattern='{demande_number}/',
|
||||||
'demande_number': DEMANDE_NUMBER_PARAM
|
pattern='^(?P<demande_number>\w+)/$',
|
||||||
}
|
name='retrieve-details-demande',
|
||||||
|
parameters={'demande_number': DEMANDE_NUMBER_PARAM},
|
||||||
)
|
)
|
||||||
def retrieve_details_demande(self, request, demande_number):
|
def retrieve_details_demande(self, request, demande_number):
|
||||||
soap_res = self._soap_call(
|
soap_res = self._soap_call(
|
||||||
wsdl='DemandeService', method='retrieveDetailsDemande',
|
wsdl='DemandeService', method='retrieveDetailsDemande', demandeNumberParam=demande_number
|
||||||
demandeNumberParam=demande_number)
|
)
|
||||||
return {'data': helpers.serialize_object(soap_res)}
|
return {'data': helpers.serialize_object(soap_res)}
|
||||||
|
|
||||||
@endpoint(
|
@endpoint(
|
||||||
methods=['get'], perm='can_access', example_pattern='{demande_number}/',
|
methods=['get'],
|
||||||
pattern='^(?P<demande_number>\w+)/$', name='retrieve-etat-travaux',
|
perm='can_access',
|
||||||
parameters={
|
example_pattern='{demande_number}/',
|
||||||
'demande_number': DEMANDE_NUMBER_PARAM
|
pattern='^(?P<demande_number>\w+)/$',
|
||||||
}
|
name='retrieve-etat-travaux',
|
||||||
|
parameters={'demande_number': DEMANDE_NUMBER_PARAM},
|
||||||
)
|
)
|
||||||
def retrieve_etat_travaux(self, request, demande_number):
|
def retrieve_etat_travaux(self, request, demande_number):
|
||||||
soap_res = self._soap_call(
|
soap_res = self._soap_call(wsdl='DemandeService', method='retrieveEtatTravaux', numero=demande_number)
|
||||||
wsdl='DemandeService', method='retrieveEtatTravaux',
|
|
||||||
numero=demande_number)
|
|
||||||
return {'data': helpers.serialize_object(soap_res)}
|
return {'data': helpers.serialize_object(soap_res)}
|
||||||
|
|
||||||
@endpoint(
|
@endpoint(
|
||||||
methods=['get'], perm='can_access', example_pattern='{demande_number}/',
|
methods=['get'],
|
||||||
|
perm='can_access',
|
||||||
|
example_pattern='{demande_number}/',
|
||||||
pattern='^(?P<demande_number>\w+)/$',
|
pattern='^(?P<demande_number>\w+)/$',
|
||||||
parameters={
|
parameters={
|
||||||
'demande_number': DEMANDE_NUMBER_PARAM,
|
'demande_number': DEMANDE_NUMBER_PARAM,
|
||||||
|
@ -210,14 +202,14 @@ class ATALConnector(BaseResource):
|
||||||
'description': _('Full'),
|
'description': _('Full'),
|
||||||
'example_value': 'true',
|
'example_value': 'true',
|
||||||
'type': 'bool',
|
'type': 'bool',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
def infos(self, request, demande_number, full=False):
|
def infos(self, request, demande_number, full=False):
|
||||||
demand_details = helpers.serialize_object(
|
demand_details = helpers.serialize_object(
|
||||||
self._soap_call(
|
self._soap_call(
|
||||||
wsdl='DemandeService', method='retrieveDetailsDemande',
|
wsdl='DemandeService', method='retrieveDetailsDemande', demandeNumberParam=demande_number
|
||||||
demandeNumberParam=demande_number)
|
)
|
||||||
)
|
)
|
||||||
if not demand_details:
|
if not demand_details:
|
||||||
raise APIError('Could not get a status')
|
raise APIError('Could not get a status')
|
||||||
|
@ -230,18 +222,12 @@ class ATALConnector(BaseResource):
|
||||||
works_comments = []
|
works_comments = []
|
||||||
if responses:
|
if responses:
|
||||||
for response in responses:
|
for response in responses:
|
||||||
comment = {
|
comment = {'text': response.get('commentaires'), 'date': None}
|
||||||
'text': response.get('commentaires'),
|
|
||||||
'date': None
|
|
||||||
}
|
|
||||||
if 'dateReponse' in response:
|
if 'dateReponse' in response:
|
||||||
comment['date'] = dateformat.format(response['dateReponse'], DATE_FORMAT)
|
comment['date'] = dateformat.format(response['dateReponse'], DATE_FORMAT)
|
||||||
works_comments.append(comment)
|
works_comments.append(comment)
|
||||||
|
|
||||||
works_comment = {
|
works_comment = {'text': None, 'date': None}
|
||||||
'text': None,
|
|
||||||
'date': None
|
|
||||||
}
|
|
||||||
if works_comments:
|
if works_comments:
|
||||||
works_comment = works_comments[-1]
|
works_comment = works_comments[-1]
|
||||||
|
|
||||||
|
@ -249,22 +235,17 @@ class ATALConnector(BaseResource):
|
||||||
'status': status,
|
'status': status,
|
||||||
'works_comment': works_comment,
|
'works_comment': works_comment,
|
||||||
'demand_details': None,
|
'demand_details': None,
|
||||||
'works_comments': []
|
'works_comments': [],
|
||||||
}
|
}
|
||||||
if full:
|
if full:
|
||||||
data['demand_details'] = demand_details
|
data['demand_details'] = demand_details
|
||||||
data['works_comments'] = works_comments
|
data['works_comments'] = works_comments
|
||||||
|
|
||||||
if status not in ('PRISE EN COMPTE', 'ARCHIVEE'):
|
if status not in ('PRISE EN COMPTE', 'ARCHIVEE'):
|
||||||
return {
|
return {'data': data}
|
||||||
'data': data
|
|
||||||
}
|
|
||||||
|
|
||||||
works_status = helpers.serialize_object(
|
works_status = helpers.serialize_object(
|
||||||
self._soap_call(
|
self._soap_call(wsdl='DemandeService', method='retrieveEtatTravaux', numero=demande_number)
|
||||||
wsdl='DemandeService', method='retrieveEtatTravaux',
|
|
||||||
numero=demande_number
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
status = works_status.get('libelle')
|
status = works_status.get('libelle')
|
||||||
if not status:
|
if not status:
|
||||||
|
@ -277,20 +258,14 @@ class ATALConnector(BaseResource):
|
||||||
if full:
|
if full:
|
||||||
data['works_status'] = works_status
|
data['works_status'] = works_status
|
||||||
|
|
||||||
return {
|
return {'data': data}
|
||||||
'data': data
|
|
||||||
}
|
|
||||||
|
|
||||||
@endpoint(
|
@endpoint(
|
||||||
perm='can_access',
|
perm='can_access',
|
||||||
post={
|
post={
|
||||||
'description': _('Upload a file'),
|
'description': _('Upload a file'),
|
||||||
'request_body': {
|
'request_body': {'schema': {'application/json': schemas.UPLOAD}},
|
||||||
'schema': {
|
},
|
||||||
'application/json': schemas.UPLOAD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
def upload(self, request, post_data):
|
def upload(self, request, post_data):
|
||||||
try:
|
try:
|
||||||
|
@ -301,23 +276,22 @@ class ATALConnector(BaseResource):
|
||||||
data = {
|
data = {
|
||||||
'donneesFichier': content,
|
'donneesFichier': content,
|
||||||
'numeroDemande': post_data['numero_demande'],
|
'numeroDemande': post_data['numero_demande'],
|
||||||
'nomFichier': post_data['nom_fichier']
|
'nomFichier': post_data['nom_fichier'],
|
||||||
}
|
}
|
||||||
self._soap_call(
|
self._soap_call(wsdl='ChargementPiecesJointesService', method='upload', **data)
|
||||||
wsdl='ChargementPiecesJointesService', method='upload',
|
|
||||||
**data
|
|
||||||
)
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
@endpoint(
|
@endpoint(
|
||||||
methods=['get'], perm='can_access', example_pattern='{demande_number}/',
|
methods=['get'],
|
||||||
pattern='^(?P<demande_number>\w+)/$', name='new-comments',
|
perm='can_access',
|
||||||
|
example_pattern='{demande_number}/',
|
||||||
|
pattern='^(?P<demande_number>\w+)/$',
|
||||||
|
name='new-comments',
|
||||||
parameters={
|
parameters={
|
||||||
'demande_number': DEMANDE_NUMBER_PARAM,
|
'demande_number': DEMANDE_NUMBER_PARAM,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
def new_comments(self, request, demande_number, last_datetime=None):
|
def new_comments(self, request, demande_number, last_datetime=None):
|
||||||
|
|
||||||
def issup(datetime1, datetime2):
|
def issup(datetime1, datetime2):
|
||||||
if datetime1.tzinfo is None or datetime2.tzinfo is None:
|
if datetime1.tzinfo is None or datetime2.tzinfo is None:
|
||||||
datetime1 = datetime1.replace(tzinfo=None)
|
datetime1 = datetime1.replace(tzinfo=None)
|
||||||
|
@ -331,8 +305,8 @@ class ATALConnector(BaseResource):
|
||||||
|
|
||||||
demand_details = helpers.serialize_object(
|
demand_details = helpers.serialize_object(
|
||||||
self._soap_call(
|
self._soap_call(
|
||||||
wsdl='DemandeService', method='retrieveDetailsDemande',
|
wsdl='DemandeService', method='retrieveDetailsDemande', demandeNumberParam=demande_number
|
||||||
demandeNumberParam=demande_number)
|
)
|
||||||
)
|
)
|
||||||
if not demand_details:
|
if not demand_details:
|
||||||
raise APIError('Could not get comments')
|
raise APIError('Could not get comments')
|
||||||
|
@ -340,11 +314,7 @@ class ATALConnector(BaseResource):
|
||||||
new_comments, all_comments, last_date = [], [], None
|
new_comments, all_comments, last_date = [], [], None
|
||||||
responses = (demand_details.get('reponses') or {}).get('Reponse') or []
|
responses = (demand_details.get('reponses') or {}).get('Reponse') or []
|
||||||
for response in responses:
|
for response in responses:
|
||||||
comment = {
|
comment = {'text': response.get('commentaires'), 'date': None, 'date_raw': None}
|
||||||
'text': response.get('commentaires'),
|
|
||||||
'date': None,
|
|
||||||
'date_raw': None
|
|
||||||
}
|
|
||||||
dateobj = None
|
dateobj = None
|
||||||
if 'dateReponse' in response:
|
if 'dateReponse' in response:
|
||||||
dateobj = response['dateReponse']
|
dateobj = response['dateReponse']
|
||||||
|
@ -356,10 +326,4 @@ class ATALConnector(BaseResource):
|
||||||
if dateobj and issup(dateobj, last_datetime) or last_datetime is None:
|
if dateobj and issup(dateobj, last_datetime) or last_datetime is None:
|
||||||
if comment not in new_comments:
|
if comment not in new_comments:
|
||||||
new_comments.append(comment)
|
new_comments.append(comment)
|
||||||
return {
|
return {'data': {'new_comments': new_comments, 'all_comments': all_comments, 'last_date': last_date}}
|
||||||
'data': {
|
|
||||||
'new_comments': new_comments,
|
|
||||||
'all_comments': all_comments,
|
|
||||||
'last_date': last_date
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -122,25 +122,15 @@ INSERT_DEMANDE_COMPLET_BY_TYPE = {
|
||||||
'demande_commentaire': {
|
'demande_commentaire': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
},
|
},
|
||||||
'remote_adresse': {
|
'remote_adresse': {'type': 'string'},
|
||||||
'type': 'string'
|
'demande_mots_cles': {'type': 'string'},
|
||||||
},
|
|
||||||
'demande_mots_cles': {
|
|
||||||
'type': 'string'
|
|
||||||
},
|
|
||||||
'code_thematique': {
|
'code_thematique': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
},
|
},
|
||||||
'code_priorite': {
|
'code_priorite': {'type': 'string'},
|
||||||
'type': 'string'
|
'demande_thematique': {'type': 'string'},
|
||||||
},
|
'code_projet': {'type': 'string'},
|
||||||
'demande_thematique': {
|
},
|
||||||
'type': 'string'
|
|
||||||
},
|
|
||||||
'code_projet': {
|
|
||||||
'type': 'string'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
INSERT_ACTION_COMMENT = {
|
INSERT_ACTION_COMMENT = {
|
||||||
|
@ -153,8 +143,8 @@ INSERT_ACTION_COMMENT = {
|
||||||
},
|
},
|
||||||
'commentaire': {
|
'commentaire': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
UPLOAD = {
|
UPLOAD = {
|
||||||
|
@ -169,13 +159,13 @@ UPLOAD = {
|
||||||
'content': {
|
'content': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
'numero_demande': {
|
'numero_demande': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
},
|
},
|
||||||
'nom_fichier': {
|
'nom_fichier': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Link',
|
name='Link',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('name_id', models.CharField(max_length=256, verbose_name='NameID')),
|
('name_id', models.CharField(max_length=256, verbose_name='NameID')),
|
||||||
('id_per', models.CharField(max_length=64, verbose_name='ID Per')),
|
('id_per', models.CharField(max_length=64, verbose_name='ID Per')),
|
||||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='Creation date')),
|
('created', models.DateTimeField(auto_now_add=True, verbose_name='Creation date')),
|
||||||
|
@ -32,20 +35,65 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Resource',
|
name='Resource',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('title', models.CharField(max_length=50, verbose_name='Title')),
|
('title', models.CharField(max_length=50, verbose_name='Title')),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('log_level', models.CharField(choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL'), (b'FATAL', b'FATAL')], default=b'INFO', max_length=10, verbose_name='Log Level')),
|
(
|
||||||
('basic_auth_username', models.CharField(blank=True, max_length=128, verbose_name='Basic authentication username')),
|
'log_level',
|
||||||
('basic_auth_password', models.CharField(blank=True, max_length=128, verbose_name='Basic authentication password')),
|
models.CharField(
|
||||||
('client_certificate', models.FileField(blank=True, null=True, upload_to=b'', verbose_name='TLS client certificate')),
|
choices=[
|
||||||
('trusted_certificate_authorities', models.FileField(blank=True, null=True, upload_to=b'', verbose_name='TLS trusted CAs')),
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
(b'FATAL', b'FATAL'),
|
||||||
|
],
|
||||||
|
default=b'INFO',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'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=b'', verbose_name='TLS client certificate'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'trusted_certificate_authorities',
|
||||||
|
models.FileField(blank=True, null=True, upload_to=b'', verbose_name='TLS trusted CAs'),
|
||||||
|
),
|
||||||
('verify_cert', models.BooleanField(default=True, verbose_name='TLS verify certificates')),
|
('verify_cert', models.BooleanField(default=True, verbose_name='TLS verify certificates')),
|
||||||
('http_proxy', models.CharField(blank=True, max_length=128, verbose_name='HTTP and HTTPS proxy')),
|
(
|
||||||
|
'http_proxy',
|
||||||
|
models.CharField(blank=True, max_length=128, verbose_name='HTTP and HTTPS proxy'),
|
||||||
|
),
|
||||||
('webservice_base_url', models.URLField(verbose_name='Webservice Base URL')),
|
('webservice_base_url', models.URLField(verbose_name='Webservice Base URL')),
|
||||||
('cod_rgp', models.CharField(default=b'RGP_PUB', max_length=64, verbose_name='Code RGP')),
|
('cod_rgp', models.CharField(default=b'RGP_PUB', max_length=64, verbose_name='Code RGP')),
|
||||||
('users', models.ManyToManyField(blank=True, related_name='_link_users_+', related_query_name='+', to='base.ApiUser')),
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True, related_name='_link_users_+', related_query_name='+', to='base.ApiUser'
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'ATOS Genesys',
|
'verbose_name': 'ATOS Genesys',
|
||||||
|
|
|
@ -15,7 +15,9 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='resource',
|
model_name='resource',
|
||||||
name='client_certificate',
|
name='client_certificate',
|
||||||
field=models.FileField(blank=True, null=True, upload_to='', verbose_name='TLS client certificate'),
|
field=models.FileField(
|
||||||
|
blank=True, null=True, upload_to='', verbose_name='TLS client certificate'
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='resource',
|
model_name='resource',
|
||||||
|
|
|
@ -93,7 +93,7 @@ class Resource(BaseResource, HTTPResource):
|
||||||
continue
|
continue
|
||||||
categories[xmlutils.text_content(code)] = {
|
categories[xmlutils.text_content(code)] = {
|
||||||
'label': xmlutils.text_content(label),
|
'label': xmlutils.text_content(label),
|
||||||
'codifications': []
|
'codifications': [],
|
||||||
}
|
}
|
||||||
for codification in root.findall('CODIFICATIONS/CODIFICATIONS_ROW'):
|
for codification in root.findall('CODIFICATIONS/CODIFICATIONS_ROW'):
|
||||||
code = codification.find('CD_CODIF')
|
code = codification.find('CD_CODIF')
|
||||||
|
@ -107,11 +107,15 @@ class Resource(BaseResource, HTTPResource):
|
||||||
if category_cod not in categories:
|
if category_cod not in categories:
|
||||||
self.logger.warning('unknown category: %s', category_cod)
|
self.logger.warning('unknown category: %s', category_cod)
|
||||||
continue
|
continue
|
||||||
categories[category_cod]['codifications'].append({
|
categories[category_cod]['codifications'].append(
|
||||||
'code': xmlutils.text_content(code),
|
{
|
||||||
'label': xmlutils.text_content(label),
|
'code': xmlutils.text_content(code),
|
||||||
'enabled': xmlutils.text_content(in_val).strip().lower() == 'o' if in_val is not None else True,
|
'label': xmlutils.text_content(label),
|
||||||
})
|
'enabled': xmlutils.text_content(in_val).strip().lower() == 'o'
|
||||||
|
if in_val is not None
|
||||||
|
else True,
|
||||||
|
}
|
||||||
|
)
|
||||||
return categories
|
return categories
|
||||||
|
|
||||||
def get_codifications(self):
|
def get_codifications(self):
|
||||||
|
@ -119,40 +123,43 @@ class Resource(BaseResource, HTTPResource):
|
||||||
function=self.call_select_codifications,
|
function=self.call_select_codifications,
|
||||||
row=self,
|
row=self,
|
||||||
key_prefix='atos-genesys-codifications',
|
key_prefix='atos-genesys-codifications',
|
||||||
logger=self.logger)
|
logger=self.logger,
|
||||||
|
)
|
||||||
return cache()
|
return cache()
|
||||||
|
|
||||||
@endpoint(name='codifications',
|
@endpoint(name='codifications', description=_('List of codifications categories'))
|
||||||
description=_('List of codifications categories'))
|
|
||||||
def codifications(self, request):
|
def codifications(self, request):
|
||||||
codifications = self.get_codifications()
|
codifications = self.get_codifications()
|
||||||
|
|
||||||
items = []
|
items = []
|
||||||
for code, category in codifications.items():
|
for code, category in codifications.items():
|
||||||
items.append({
|
items.append(
|
||||||
'id': code,
|
{
|
||||||
'label': category['label'],
|
'id': code,
|
||||||
})
|
'label': category['label'],
|
||||||
|
}
|
||||||
|
)
|
||||||
items.sort(key=lambda c: c['label'])
|
items.sort(key=lambda c: c['label'])
|
||||||
return {'data': items}
|
return {'data': items}
|
||||||
|
|
||||||
@endpoint(name='codifications',
|
@endpoint(
|
||||||
pattern=r'^(?P<category>[\w-]+)/$',
|
name='codifications',
|
||||||
example_pattern='{category}/',
|
pattern=r'^(?P<category>[\w-]+)/$',
|
||||||
description=_('List of codifications'),
|
example_pattern='{category}/',
|
||||||
parameters={
|
description=_('List of codifications'),
|
||||||
'category': {
|
parameters={
|
||||||
'description': _('Category of codification'),
|
'category': {
|
||||||
'example_value': u'MOT_APA',
|
'description': _('Category of codification'),
|
||||||
}
|
'example_value': u'MOT_APA',
|
||||||
})
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
def codifications_list(self, request, category):
|
def codifications_list(self, request, category):
|
||||||
codifications = self.get_codifications().get(category, {}).get('codifications', [])
|
codifications = self.get_codifications().get(category, {}).get('codifications', [])
|
||||||
|
|
||||||
items = [{
|
items = [
|
||||||
'id': codification['code'],
|
{'id': codification['code'], 'text': codification['label']} for codification in codifications
|
||||||
'text': codification['label']
|
]
|
||||||
} for codification in codifications]
|
|
||||||
return {'data': items}
|
return {'data': items}
|
||||||
|
|
||||||
def check_status(self):
|
def check_status(self):
|
||||||
|
@ -163,11 +170,14 @@ class Resource(BaseResource, HTTPResource):
|
||||||
return urlparse.urljoin(self.base_url, 'WSUsagerPublik/services/PublikService/selectAppairage')
|
return urlparse.urljoin(self.base_url, 'WSUsagerPublik/services/PublikService/selectAppairage')
|
||||||
|
|
||||||
def call_select_appairage(self, login, password, email):
|
def call_select_appairage(self, login, password, email):
|
||||||
row = self.xml_request(self.select_appairage_url, params={
|
row = self.xml_request(
|
||||||
'login': login,
|
self.select_appairage_url,
|
||||||
'pwd': password,
|
params={
|
||||||
'email': email,
|
'login': login,
|
||||||
})
|
'pwd': password,
|
||||||
|
'email': email,
|
||||||
|
},
|
||||||
|
)
|
||||||
row_d = xmlutils.to_json(row)
|
row_d = xmlutils.to_json(row)
|
||||||
id_per = row_d.get('ID_PER', '').strip()
|
id_per = row_d.get('ID_PER', '').strip()
|
||||||
code = row_d.get('CD_RET', '').strip()
|
code = row_d.get('CD_RET', '').strip()
|
||||||
|
@ -175,72 +185,70 @@ class Resource(BaseResource, HTTPResource):
|
||||||
|
|
||||||
error = None
|
error = None
|
||||||
if code not in ['1', '2', '3', '4', '5', '6']:
|
if code not in ['1', '2', '3', '4', '5', '6']:
|
||||||
error = 'invalid CD_RET: %s' % code,
|
error = ('invalid CD_RET: %s' % code,)
|
||||||
if code in ['2', '3', '5'] and not id_per:
|
if code in ['2', '3', '5'] and not id_per:
|
||||||
error = 'missing ID_PER'
|
error = 'missing ID_PER'
|
||||||
if error:
|
if error:
|
||||||
raise APIError(error, data={'response': repr(ET.tostring(row))})
|
raise APIError(error, data={'response': repr(ET.tostring(row))})
|
||||||
return code, label, id_per
|
return code, label, id_per
|
||||||
|
|
||||||
@endpoint(name='link',
|
@endpoint(
|
||||||
methods=['post'],
|
name='link',
|
||||||
description=_('Create link with an extranet account'),
|
methods=['post'],
|
||||||
perm='can_access',
|
description=_('Create link with an extranet account'),
|
||||||
parameters={
|
perm='can_access',
|
||||||
'NameID':{
|
parameters={
|
||||||
'description': _('Publik NameID'),
|
'NameID': {
|
||||||
'example_value': 'xyz24d934',
|
'description': _('Publik NameID'),
|
||||||
},
|
'example_value': 'xyz24d934',
|
||||||
'email': {
|
},
|
||||||
'description': _('Publik known email'),
|
'email': {
|
||||||
'example_value': 'john.doe@example.com',
|
'description': _('Publik known email'),
|
||||||
},
|
'example_value': 'john.doe@example.com',
|
||||||
'login': {
|
},
|
||||||
'description': _('ATOS Genesys extranet login'),
|
'login': {
|
||||||
'example_value': '1234',
|
'description': _('ATOS Genesys extranet login'),
|
||||||
},
|
'example_value': '1234',
|
||||||
'password': {
|
},
|
||||||
'description': _('ATOS Genesys extranet password'),
|
'password': {
|
||||||
'example_value': 'password',
|
'description': _('ATOS Genesys extranet password'),
|
||||||
}
|
'example_value': 'password',
|
||||||
})
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
def link(self, request, NameID, email, login, password):
|
def link(self, request, NameID, email, login, password):
|
||||||
code, label, id_per = self.call_select_appairage(login, password, email)
|
code, label, id_per = self.call_select_appairage(login, password, email)
|
||||||
if code in ['2', '3', '5']:
|
if code in ['2', '3', '5']:
|
||||||
link, created = Link.objects.get_or_create(
|
link, created = Link.objects.get_or_create(resource=self, name_id=NameID, id_per=id_per)
|
||||||
resource=self,
|
|
||||||
name_id=NameID,
|
|
||||||
id_per=id_per)
|
|
||||||
return {'link_id': link.pk, 'new': created, 'code': code, 'label': label}
|
return {'link_id': link.pk, 'new': created, 'code': code, 'label': label}
|
||||||
elif code == '6':
|
elif code == '6':
|
||||||
raise APIError('unknown-login', data={'code': code, 'label': label})
|
raise APIError('unknown-login', data={'code': code, 'label': label})
|
||||||
elif code in ['4', '1']:
|
elif code in ['4', '1']:
|
||||||
raise APIError('invalid-password', data={'code': code, 'label': label})
|
raise APIError('invalid-password', data={'code': code, 'label': label})
|
||||||
|
|
||||||
@endpoint(name='unlink',
|
@endpoint(
|
||||||
methods=['post'],
|
name='unlink',
|
||||||
description=_('Delete link with an extranet account'),
|
methods=['post'],
|
||||||
perm='can_access',
|
description=_('Delete link with an extranet account'),
|
||||||
parameters={
|
perm='can_access',
|
||||||
'NameID':{
|
parameters={
|
||||||
'description': _('Publik NameID'),
|
'NameID': {
|
||||||
'example_value': 'xyz24d934',
|
'description': _('Publik NameID'),
|
||||||
},
|
'example_value': 'xyz24d934',
|
||||||
'link_id': {
|
},
|
||||||
'description': _('Identifier of the link'),
|
'link_id': {
|
||||||
'example_value': '1',
|
'description': _('Identifier of the link'),
|
||||||
},
|
'example_value': '1',
|
||||||
})
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
def unlink(self, request, NameID, link_id):
|
def unlink(self, request, NameID, link_id):
|
||||||
try:
|
try:
|
||||||
link_id = int(link_id.strip())
|
link_id = int(link_id.strip())
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise APIError('invalid link_id')
|
raise APIError('invalid link_id')
|
||||||
|
|
||||||
qs = Link.objects.filter(
|
qs = Link.objects.filter(resource=self, name_id=NameID, pk=link_id)
|
||||||
resource=self,
|
|
||||||
name_id=NameID,
|
|
||||||
pk=link_id)
|
|
||||||
count = qs.count()
|
count = qs.count()
|
||||||
qs.delete()
|
qs.delete()
|
||||||
return {'deleted': count}
|
return {'deleted': count}
|
||||||
|
@ -250,10 +258,13 @@ class Resource(BaseResource, HTTPResource):
|
||||||
return urlparse.urljoin(self.base_url, 'WSUsagerPublik/services/PublikService/selectUsager')
|
return urlparse.urljoin(self.base_url, 'WSUsagerPublik/services/PublikService/selectUsager')
|
||||||
|
|
||||||
def call_select_usager(self, id_per):
|
def call_select_usager(self, id_per):
|
||||||
row = self.xml_request(self.select_usager_url, params={
|
row = self.xml_request(
|
||||||
'idPer': id_per,
|
self.select_usager_url,
|
||||||
'codRgp': self.cod_rgp,
|
params={
|
||||||
})
|
'idPer': id_per,
|
||||||
|
'codRgp': self.cod_rgp,
|
||||||
|
},
|
||||||
|
)
|
||||||
return self._select_usager_row_to_json(row)
|
return self._select_usager_row_to_json(row)
|
||||||
|
|
||||||
def _select_usager_row_to_json(self, row):
|
def _select_usager_row_to_json(self, row):
|
||||||
|
@ -275,19 +286,19 @@ class Resource(BaseResource, HTTPResource):
|
||||||
identification['CIVILITE'] = {'M': u'Monsieur', 'F': u'Madame'}.get(sexe, '')
|
identification['CIVILITE'] = {'M': u'Monsieur', 'F': u'Madame'}.get(sexe, '')
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@endpoint(name='dossiers',
|
@endpoint(
|
||||||
description=_('Get datas for all links'),
|
name='dossiers',
|
||||||
perm='can_access',
|
description=_('Get datas for all links'),
|
||||||
parameters={
|
perm='can_access',
|
||||||
'NameID':{
|
parameters={
|
||||||
'description': _('Publik NameID'),
|
'NameID': {
|
||||||
'example_value': 'xyz24d934',
|
'description': _('Publik NameID'),
|
||||||
},
|
'example_value': 'xyz24d934',
|
||||||
})
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
def dossiers(self, request, NameID, link_id=None):
|
def dossiers(self, request, NameID, link_id=None):
|
||||||
qs = Link.objects.filter(
|
qs = Link.objects.filter(resource=self, name_id=NameID)
|
||||||
resource=self,
|
|
||||||
name_id=NameID)
|
|
||||||
if link_id:
|
if link_id:
|
||||||
try:
|
try:
|
||||||
link_id = int(link_id)
|
link_id = int(link_id)
|
||||||
|
@ -300,7 +311,8 @@ class Resource(BaseResource, HTTPResource):
|
||||||
function=self.call_select_usager,
|
function=self.call_select_usager,
|
||||||
row=link,
|
row=link,
|
||||||
key_prefix='atos-genesys-usager',
|
key_prefix='atos-genesys-usager',
|
||||||
logger=self.logger)
|
logger=self.logger,
|
||||||
|
)
|
||||||
dossier = cache(link.id_per)
|
dossier = cache(link.id_per)
|
||||||
# build text as "id_per - prenom - no
|
# build text as "id_per - prenom - no
|
||||||
text_parts = [str(link.id_per), '-']
|
text_parts = [str(link.id_per), '-']
|
||||||
|
@ -312,12 +324,14 @@ class Resource(BaseResource, HTTPResource):
|
||||||
text_parts.append(prenom.title())
|
text_parts.append(prenom.title())
|
||||||
if nom:
|
if nom:
|
||||||
text_parts.append(nom.upper())
|
text_parts.append(nom.upper())
|
||||||
data.append({
|
data.append(
|
||||||
'id': str(link.id),
|
{
|
||||||
'text': u' '.join(text_parts),
|
'id': str(link.id),
|
||||||
'id_per': link.id_per,
|
'text': u' '.join(text_parts),
|
||||||
'dossier': dossier,
|
'id_per': link.id_per,
|
||||||
})
|
'dossier': dossier,
|
||||||
|
}
|
||||||
|
)
|
||||||
if link_id:
|
if link_id:
|
||||||
return {'data': data[0] if data else None}
|
return {'data': data[0] if data else None}
|
||||||
return {'data': data}
|
return {'data': data}
|
||||||
|
@ -327,10 +341,13 @@ class Resource(BaseResource, HTTPResource):
|
||||||
return urlparse.urljoin(self.base_url, 'WSUsagerPublik/services/PublikService/selectUsagerByRef')
|
return urlparse.urljoin(self.base_url, 'WSUsagerPublik/services/PublikService/selectUsagerByRef')
|
||||||
|
|
||||||
def call_select_usager_by_ref(self, ref_per):
|
def call_select_usager_by_ref(self, ref_per):
|
||||||
row = self.xml_request(self.select_usager_by_ref_url, params={
|
row = self.xml_request(
|
||||||
'refPer': ref_per,
|
self.select_usager_by_ref_url,
|
||||||
'codRgp': self.cod_rgp,
|
params={
|
||||||
})
|
'refPer': ref_per,
|
||||||
|
'codRgp': self.cod_rgp,
|
||||||
|
},
|
||||||
|
)
|
||||||
return self._select_usager_row_to_json(row)
|
return self._select_usager_row_to_json(row)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -338,31 +355,36 @@ class Resource(BaseResource, HTTPResource):
|
||||||
return urlparse.urljoin(self.base_url, 'WSUsagerPublik/services/PublikService/chercheBeneficiaire')
|
return urlparse.urljoin(self.base_url, 'WSUsagerPublik/services/PublikService/chercheBeneficiaire')
|
||||||
|
|
||||||
def call_cherche_beneficiaire(self, prenom, nom, dob):
|
def call_cherche_beneficiaire(self, prenom, nom, dob):
|
||||||
rows = self.xml_request_multiple(self.cherche_beneficiaire_url, params={
|
rows = self.xml_request_multiple(
|
||||||
'nmPer': nom,
|
self.cherche_beneficiaire_url,
|
||||||
'prPer': prenom,
|
params={
|
||||||
'dtNaissance': dob.strftime('%d/%m/%Y'),
|
'nmPer': nom,
|
||||||
})
|
'prPer': prenom,
|
||||||
|
'dtNaissance': dob.strftime('%d/%m/%Y'),
|
||||||
|
},
|
||||||
|
)
|
||||||
beneficiaires = [xmlutils.to_json(row) for row in rows]
|
beneficiaires = [xmlutils.to_json(row) for row in rows]
|
||||||
return beneficiaires
|
return beneficiaires
|
||||||
|
|
||||||
@endpoint(name='search',
|
@endpoint(
|
||||||
description=_('Search for beneficiaries'),
|
name='search',
|
||||||
perm='can_access',
|
description=_('Search for beneficiaries'),
|
||||||
parameters={
|
perm='can_access',
|
||||||
'first_name': {
|
parameters={
|
||||||
'description': _('Beneficiary first name'),
|
'first_name': {
|
||||||
'example_value': 'John',
|
'description': _('Beneficiary first name'),
|
||||||
},
|
'example_value': 'John',
|
||||||
'last_name': {
|
},
|
||||||
'description': _('Beneficiary last name'),
|
'last_name': {
|
||||||
'example_value': 'Doe',
|
'description': _('Beneficiary last name'),
|
||||||
},
|
'example_value': 'Doe',
|
||||||
'date_of_birth': {
|
},
|
||||||
'description': _('Beneficiary date of birth'),
|
'date_of_birth': {
|
||||||
'example_value': '1987-10-23',
|
'description': _('Beneficiary date of birth'),
|
||||||
}
|
'example_value': '1987-10-23',
|
||||||
})
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
def search(self, request, first_name, last_name, date_of_birth, NameID=None, commune_naissance=None):
|
def search(self, request, first_name, last_name, date_of_birth, NameID=None, commune_naissance=None):
|
||||||
try:
|
try:
|
||||||
date_of_birth = datetime.datetime.strptime(date_of_birth, '%Y-%m-%d').date()
|
date_of_birth = datetime.datetime.strptime(date_of_birth, '%Y-%m-%d').date()
|
||||||
|
@ -373,10 +395,7 @@ class Resource(BaseResource, HTTPResource):
|
||||||
if commune_naissance:
|
if commune_naissance:
|
||||||
# convert commune_naissance to ASCII
|
# convert commune_naissance to ASCII
|
||||||
commune_naissance = to_ascii(commune_naissance).lower()
|
commune_naissance = to_ascii(commune_naissance).lower()
|
||||||
beneficiaires = self.call_cherche_beneficiaire(
|
beneficiaires = self.call_cherche_beneficiaire(prenom=first_name, nom=last_name, dob=date_of_birth)
|
||||||
prenom=first_name,
|
|
||||||
nom=last_name,
|
|
||||||
dob=date_of_birth)
|
|
||||||
data = []
|
data = []
|
||||||
dossiers = []
|
dossiers = []
|
||||||
# get dossiers of found beneficiaries
|
# get dossiers of found beneficiaries
|
||||||
|
@ -410,8 +429,12 @@ class Resource(BaseResource, HTTPResource):
|
||||||
if commune_naissance:
|
if commune_naissance:
|
||||||
cmu_nais = to_ascii(identification.get('CMU_NAIS', '')).lower()
|
cmu_nais = to_ascii(identification.get('CMU_NAIS', '')).lower()
|
||||||
if cmu_nais and commune_naissance != cmu_nais:
|
if cmu_nais and commune_naissance != cmu_nais:
|
||||||
self.logger.debug(u'id_per %s: CMU_NAIS(%s) does not match commune_naissance(%s)',
|
self.logger.debug(
|
||||||
id_per, cmu_nais, commune_naissance)
|
u'id_per %s: CMU_NAIS(%s) does not match commune_naissance(%s)',
|
||||||
|
id_per,
|
||||||
|
cmu_nais,
|
||||||
|
commune_naissance,
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
dossiers.append(dossier)
|
dossiers.append(dossier)
|
||||||
|
|
||||||
|
@ -431,38 +454,41 @@ class Resource(BaseResource, HTTPResource):
|
||||||
tel2 = ''.join(c for c in identification.get('TEL_FIXE', '') if is_number(c))
|
tel2 = ''.join(c for c in identification.get('TEL_FIXE', '') if is_number(c))
|
||||||
email = identification.get('MAIL', '').strip()
|
email = identification.get('MAIL', '').strip()
|
||||||
if tel1 and tel1[:2] in ('06', '07'):
|
if tel1 and tel1[:2] in ('06', '07'):
|
||||||
data.append({
|
data.append(
|
||||||
'id': 'tel1',
|
{
|
||||||
'text': 'par SMS vers ' + tel1[:2] + '*****' + tel1[-3:],
|
'id': 'tel1',
|
||||||
'phone': tel1,
|
'text': 'par SMS vers ' + tel1[:2] + '*****' + tel1[-3:],
|
||||||
|
'phone': tel1,
|
||||||
'id_per': id_per,
|
'id_per': id_per,
|
||||||
'nom': nom,
|
'nom': nom,
|
||||||
'prenom': prenom,
|
'prenom': prenom,
|
||||||
'nom_naissance': nom_naissance,
|
'nom_naissance': nom_naissance,
|
||||||
})
|
}
|
||||||
|
)
|
||||||
if tel2 and tel2[:2] in ('06', '07'):
|
if tel2 and tel2[:2] in ('06', '07'):
|
||||||
data.append({
|
data.append(
|
||||||
'id': 'tel2',
|
{
|
||||||
'text': 'par SMS vers ' + tel2[:2] + '*****' + tel2[-3:],
|
'id': 'tel2',
|
||||||
'phone': tel2,
|
'text': 'par SMS vers ' + tel2[:2] + '*****' + tel2[-3:],
|
||||||
|
'phone': tel2,
|
||||||
'id_per': id_per,
|
'id_per': id_per,
|
||||||
'nom': nom,
|
'nom': nom,
|
||||||
'prenom': prenom,
|
'prenom': prenom,
|
||||||
'nom_naissance': nom_naissance,
|
'nom_naissance': nom_naissance,
|
||||||
})
|
}
|
||||||
|
)
|
||||||
if email:
|
if email:
|
||||||
data.append({
|
data.append(
|
||||||
'id': 'email1',
|
{
|
||||||
'text': 'par courriel vers ' + email[:2] + '***@***' + email[-3:],
|
'id': 'email1',
|
||||||
'email': email,
|
'text': 'par courriel vers ' + email[:2] + '***@***' + email[-3:],
|
||||||
|
'email': email,
|
||||||
'id_per': id_per,
|
'id_per': id_per,
|
||||||
'nom': nom,
|
'nom': nom,
|
||||||
'prenom': prenom,
|
'prenom': prenom,
|
||||||
'nom_naissance': nom_naissance,
|
'nom_naissance': nom_naissance,
|
||||||
})
|
}
|
||||||
|
)
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
self.logger.debug('id_per %s: no contact information, ignored', id_per)
|
self.logger.debug('id_per %s: no contact information, ignored', id_per)
|
||||||
raise APIError('no-contacts')
|
raise APIError('no-contacts')
|
||||||
|
@ -476,50 +502,39 @@ class Resource(BaseResource, HTTPResource):
|
||||||
'link_id': link and link.id,
|
'link_id': link and link.id,
|
||||||
}
|
}
|
||||||
|
|
||||||
@endpoint(name='link-by-id-per',
|
@endpoint(
|
||||||
methods=['post'],
|
name='link-by-id-per',
|
||||||
description=_('Create link with an extranet account'),
|
methods=['post'],
|
||||||
perm='can_access',
|
description=_('Create link with an extranet account'),
|
||||||
parameters={
|
perm='can_access',
|
||||||
'NameID': {
|
parameters={
|
||||||
'description': _('Publik NameID'),
|
'NameID': {
|
||||||
'example_value': 'xyz24d934',
|
'description': _('Publik NameID'),
|
||||||
},
|
'example_value': 'xyz24d934',
|
||||||
'id_per': {
|
},
|
||||||
'description': _('ATOS Genesys ID_PER'),
|
'id_per': {
|
||||||
'example_value': '767676',
|
'description': _('ATOS Genesys ID_PER'),
|
||||||
}
|
'example_value': '767676',
|
||||||
})
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
def link_by_id_per(self, request, NameID, id_per):
|
def link_by_id_per(self, request, NameID, id_per):
|
||||||
dossier = self.call_select_usager(id_per)
|
dossier = self.call_select_usager(id_per)
|
||||||
link, created = Link.objects.get_or_create(
|
link, created = Link.objects.get_or_create(resource=self, name_id=NameID, id_per=id_per)
|
||||||
resource=self,
|
|
||||||
name_id=NameID,
|
|
||||||
id_per=id_per)
|
|
||||||
return {'link_id': link.pk, 'new': created}
|
return {'link_id': link.pk, 'new': created}
|
||||||
|
|
||||||
|
|
||||||
class Link(models.Model):
|
class Link(models.Model):
|
||||||
resource = models.ForeignKey(
|
resource = models.ForeignKey(Resource, on_delete=models.CASCADE)
|
||||||
Resource,
|
name_id = models.CharField(verbose_name=_('NameID'), blank=False, max_length=256)
|
||||||
on_delete=models.CASCADE)
|
id_per = models.CharField(verbose_name=_('ID Per'), blank=False, max_length=64)
|
||||||
name_id = models.CharField(
|
created = models.DateTimeField(verbose_name=_('Creation date'), auto_now_add=True)
|
||||||
verbose_name=_('NameID'),
|
extra = JSONField(verbose_name=_('Anything'), null=True)
|
||||||
blank=False,
|
|
||||||
max_length=256)
|
|
||||||
id_per = models.CharField(
|
|
||||||
verbose_name=_('ID Per'),
|
|
||||||
blank=False,
|
|
||||||
max_length=64)
|
|
||||||
created = models.DateTimeField(
|
|
||||||
verbose_name=_('Creation date'),
|
|
||||||
auto_now_add=True)
|
|
||||||
extra = JSONField(
|
|
||||||
verbose_name=_('Anything'),
|
|
||||||
null=True)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = (
|
unique_together = (
|
||||||
'resource', 'name_id', 'id_per',
|
'resource',
|
||||||
|
'name_id',
|
||||||
|
'id_per',
|
||||||
)
|
)
|
||||||
ordering = ['created']
|
ordering = ['created']
|
||||||
|
|
|
@ -25,11 +25,12 @@ def row_lock(row):
|
||||||
|
|
||||||
|
|
||||||
class RowLockedCache(object):
|
class RowLockedCache(object):
|
||||||
'''Cache return value of a function, always return the cached value for
|
"""Cache return value of a function, always return the cached value for
|
||||||
performance but if the cache is stale update it asynchronously using
|
performance but if the cache is stale update it asynchronously using
|
||||||
a thread, prevent multiple update using row locks on database models and
|
a thread, prevent multiple update using row locks on database models and
|
||||||
an update cache key.
|
an update cache key.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, function, logger=None, row=None, duration=DEFAULT_DURATION, key_prefix=None):
|
def __init__(self, function, logger=None, row=None, duration=DEFAULT_DURATION, key_prefix=None):
|
||||||
self.function = function
|
self.function = function
|
||||||
self.row = row
|
self.row = row
|
||||||
|
|
|
@ -14,12 +14,28 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='BaseAddresse',
|
name='BaseAddresse',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(verbose_name='Title', max_length=50)),
|
('title', models.CharField(verbose_name='Title', max_length=50)),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('service_url', models.CharField(help_text='Base Adresse Web Service URL', max_length=128, verbose_name='Service URL')),
|
(
|
||||||
('users', models.ManyToManyField(to='base.ApiUser', related_name='_baseaddresse_users_+', related_query_name='+', blank=True)),
|
'service_url',
|
||||||
|
models.CharField(
|
||||||
|
help_text='Base Adresse Web Service URL', max_length=128, verbose_name='Service URL'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='base.ApiUser',
|
||||||
|
related_name='_baseaddresse_users_+',
|
||||||
|
related_query_name='+',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Base Adresse Web Service',
|
'verbose_name': 'Base Adresse Web Service',
|
||||||
|
|
|
@ -14,7 +14,12 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='baseaddresse',
|
model_name='baseaddresse',
|
||||||
name='service_url',
|
name='service_url',
|
||||||
field=models.CharField(default=b'https://api-adresse.data.gouv.fr/', help_text='Base Adresse Web Service URL', max_length=128, verbose_name='Service URL'),
|
field=models.CharField(
|
||||||
|
default=b'https://api-adresse.data.gouv.fr/',
|
||||||
|
help_text='Base Adresse Web Service URL',
|
||||||
|
max_length=128,
|
||||||
|
verbose_name='Service URL',
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,7 +14,13 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='baseaddresse',
|
model_name='baseaddresse',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Debug Enabled', blank=True, choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Debug Enabled',
|
||||||
|
blank=True,
|
||||||
|
choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,7 +14,12 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='baseaddresse',
|
model_name='baseaddresse',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,7 +14,19 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='baseaddresse',
|
model_name='baseaddresse',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -10,6 +10,4 @@ class Migration(migrations.Migration):
|
||||||
('base_adresse', '0005_auto_20160407_0456'),
|
('base_adresse', '0005_auto_20160407_0456'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [migrations.RenameModel('BaseAddresse', 'BaseAdresse')]
|
||||||
migrations.RenameModel('BaseAddresse', 'BaseAdresse')
|
|
||||||
]
|
|
||||||
|
|
|
@ -14,7 +14,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='StreetModel',
|
name='StreetModel',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('city', models.CharField(max_length=100, verbose_name='City')),
|
('city', models.CharField(max_length=100, verbose_name='City')),
|
||||||
('name', models.CharField(max_length=150, verbose_name='Street name')),
|
('name', models.CharField(max_length=150, verbose_name='Street name')),
|
||||||
('zipcode', models.CharField(max_length=5, verbose_name='Postal code')),
|
('zipcode', models.CharField(max_length=5, verbose_name='Postal code')),
|
||||||
|
@ -26,7 +29,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='UpdateStreetModel',
|
name='UpdateStreetModel',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('zipcode', models.CharField(max_length=5, verbose_name='Postal code')),
|
('zipcode', models.CharField(max_length=5, verbose_name='Postal code')),
|
||||||
('start_time', models.DateTimeField(null=True, verbose_name='Start of update')),
|
('start_time', models.DateTimeField(null=True, verbose_name='Start of update')),
|
||||||
('end_time', models.DateTimeField(null=True, verbose_name='End of update')),
|
('end_time', models.DateTimeField(null=True, verbose_name='End of update')),
|
||||||
|
@ -35,6 +41,8 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='baseadresse',
|
model_name='baseadresse',
|
||||||
name='zipcode',
|
name='zipcode',
|
||||||
field=models.CharField(max_length=5, verbose_name='Postal codes to get streets, separated with commas', blank=True),
|
field=models.CharField(
|
||||||
|
max_length=5, verbose_name='Postal codes to get streets, separated with commas', blank=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -15,6 +15,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='baseadresse',
|
model_name='baseadresse',
|
||||||
name='zipcode',
|
name='zipcode',
|
||||||
field=models.CharField(blank=True, max_length=600, verbose_name='Postal codes or county number to get streets, separated with commas'),
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
max_length=600,
|
||||||
|
verbose_name='Postal codes or county number to get streets, separated with commas',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -17,9 +17,15 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CityModel',
|
name='CityModel',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('name', models.CharField(max_length=150, verbose_name='City name')),
|
('name', models.CharField(max_length=150, verbose_name='City name')),
|
||||||
('unaccent_name', models.CharField(max_length=150, null=True, verbose_name='City name ascii char')),
|
(
|
||||||
|
'unaccent_name',
|
||||||
|
models.CharField(max_length=150, null=True, verbose_name='City name ascii char'),
|
||||||
|
),
|
||||||
('code', models.CharField(max_length=5, verbose_name='INSEE code')),
|
('code', models.CharField(max_length=5, verbose_name='INSEE code')),
|
||||||
('zipcode', models.CharField(max_length=5, verbose_name='Postal code')),
|
('zipcode', models.CharField(max_length=5, verbose_name='Postal code')),
|
||||||
('population', models.PositiveIntegerField(verbose_name='Population')),
|
('population', models.PositiveIntegerField(verbose_name='Population')),
|
||||||
|
@ -33,9 +39,15 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='DepartmentModel',
|
name='DepartmentModel',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('name', models.CharField(max_length=100, verbose_name='Department name')),
|
('name', models.CharField(max_length=100, verbose_name='Department name')),
|
||||||
('unaccent_name', models.CharField(max_length=150, null=True, verbose_name='Department name ascii char')),
|
(
|
||||||
|
'unaccent_name',
|
||||||
|
models.CharField(max_length=150, null=True, verbose_name='Department name ascii char'),
|
||||||
|
),
|
||||||
('code', models.CharField(max_length=3, unique=True, verbose_name='Department code')),
|
('code', models.CharField(max_length=3, unique=True, verbose_name='Department code')),
|
||||||
('last_update', models.DateTimeField(auto_now=True, null=True, verbose_name='Last update')),
|
('last_update', models.DateTimeField(auto_now=True, null=True, verbose_name='Last update')),
|
||||||
],
|
],
|
||||||
|
@ -47,9 +59,15 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='RegionModel',
|
name='RegionModel',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('name', models.CharField(max_length=150, verbose_name='Region name')),
|
('name', models.CharField(max_length=150, verbose_name='Region name')),
|
||||||
('unaccent_name', models.CharField(max_length=150, null=True, verbose_name='Region name ascii char')),
|
(
|
||||||
|
'unaccent_name',
|
||||||
|
models.CharField(max_length=150, null=True, verbose_name='Region name ascii char'),
|
||||||
|
),
|
||||||
('code', models.CharField(max_length=2, unique=True, verbose_name='Region code')),
|
('code', models.CharField(max_length=2, unique=True, verbose_name='Region code')),
|
||||||
('last_update', models.DateTimeField(auto_now=True, null=True, verbose_name='Last update')),
|
('last_update', models.DateTimeField(auto_now=True, null=True, verbose_name='Last update')),
|
||||||
],
|
],
|
||||||
|
@ -61,12 +79,21 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='baseadresse',
|
model_name='baseadresse',
|
||||||
name='api_geo_url',
|
name='api_geo_url',
|
||||||
field=models.CharField(default=b'https://geo.api.gouv.fr/', help_text='Base Adresse API Geo URL', max_length=128, verbose_name='API Geo URL'),
|
field=models.CharField(
|
||||||
|
default=b'https://geo.api.gouv.fr/',
|
||||||
|
help_text='Base Adresse API Geo URL',
|
||||||
|
max_length=128,
|
||||||
|
verbose_name='API Geo URL',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='baseadresse',
|
model_name='baseadresse',
|
||||||
name='zipcode',
|
name='zipcode',
|
||||||
field=models.CharField(blank=True, max_length=600, verbose_name='Postal codes or department number to get streets, separated with commas'),
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
max_length=600,
|
||||||
|
verbose_name='Postal codes or department number to get streets, separated with commas',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='streetmodel',
|
model_name='streetmodel',
|
||||||
|
@ -76,17 +103,29 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='departmentmodel',
|
model_name='departmentmodel',
|
||||||
name='region',
|
name='region',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='base_adresse.RegionModel'),
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to='base_adresse.RegionModel'
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='citymodel',
|
model_name='citymodel',
|
||||||
name='department',
|
name='department',
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='base_adresse.DepartmentModel'),
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
to='base_adresse.DepartmentModel',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='citymodel',
|
model_name='citymodel',
|
||||||
name='region',
|
name='region',
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='base_adresse.RegionModel'),
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
to='base_adresse.RegionModel',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterUniqueTogether(
|
migrations.AlterUniqueTogether(
|
||||||
name='citymodel',
|
name='citymodel',
|
||||||
|
|
|
@ -16,7 +16,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='AddressCacheModel',
|
name='AddressCacheModel',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('api_id', models.CharField(max_length=30, unique=True)),
|
('api_id', models.CharField(max_length=30, unique=True)),
|
||||||
('data', django.contrib.postgres.fields.jsonb.JSONField(default=dict)),
|
('data', django.contrib.postgres.fields.jsonb.JSONField(default=dict)),
|
||||||
('timestamp', models.DateTimeField(auto_now=True)),
|
('timestamp', models.DateTimeField(auto_now=True)),
|
||||||
|
@ -25,11 +28,21 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='baseadresse',
|
model_name='baseadresse',
|
||||||
name='latitude',
|
name='latitude',
|
||||||
field=models.FloatField(blank=True, help_text='Geographic priority for /addresses/ endpoint.', null=True, verbose_name='Latitude'),
|
field=models.FloatField(
|
||||||
|
blank=True,
|
||||||
|
help_text='Geographic priority for /addresses/ endpoint.',
|
||||||
|
null=True,
|
||||||
|
verbose_name='Latitude',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='baseadresse',
|
model_name='baseadresse',
|
||||||
name='longitude',
|
name='longitude',
|
||||||
field=models.FloatField(blank=True, help_text='Geographic priority for /addresses/ endpoint.', null=True, verbose_name='Longitude'),
|
field=models.FloatField(
|
||||||
|
blank=True,
|
||||||
|
help_text='Geographic priority for /addresses/ endpoint.',
|
||||||
|
null=True,
|
||||||
|
verbose_name='Longitude',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -21,11 +21,21 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='baseadresse',
|
model_name='baseadresse',
|
||||||
name='api_geo_url',
|
name='api_geo_url',
|
||||||
field=models.CharField(default='https://geo.api.gouv.fr/', help_text='Base Adresse API Geo URL', max_length=128, verbose_name='API Geo URL'),
|
field=models.CharField(
|
||||||
|
default='https://geo.api.gouv.fr/',
|
||||||
|
help_text='Base Adresse API Geo URL',
|
||||||
|
max_length=128,
|
||||||
|
verbose_name='API Geo URL',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='baseadresse',
|
model_name='baseadresse',
|
||||||
name='service_url',
|
name='service_url',
|
||||||
field=models.CharField(default='https://api-adresse.data.gouv.fr/', help_text='Base Adresse Web Service URL', max_length=128, verbose_name='Service URL'),
|
field=models.CharField(
|
||||||
|
default='https://api-adresse.data.gouv.fr/',
|
||||||
|
help_text='Base Adresse Web Service URL',
|
||||||
|
max_length=128,
|
||||||
|
verbose_name='Service URL',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -22,16 +22,20 @@ from passerelle.utils.jsonresponse import APIError
|
||||||
|
|
||||||
class BaseAdresse(BaseResource):
|
class BaseAdresse(BaseResource):
|
||||||
service_url = models.CharField(
|
service_url = models.CharField(
|
||||||
max_length=128, blank=False,
|
max_length=128,
|
||||||
|
blank=False,
|
||||||
default='https://api-adresse.data.gouv.fr/',
|
default='https://api-adresse.data.gouv.fr/',
|
||||||
verbose_name=_('Service URL'),
|
verbose_name=_('Service URL'),
|
||||||
help_text=_('Base Adresse Web Service URL'))
|
help_text=_('Base Adresse Web Service URL'),
|
||||||
|
)
|
||||||
|
|
||||||
api_geo_url = models.CharField(
|
api_geo_url = models.CharField(
|
||||||
max_length=128, blank=False,
|
max_length=128,
|
||||||
|
blank=False,
|
||||||
default='https://geo.api.gouv.fr/',
|
default='https://geo.api.gouv.fr/',
|
||||||
verbose_name=_('API Geo URL'),
|
verbose_name=_('API Geo URL'),
|
||||||
help_text=_('Base Adresse API Geo URL'))
|
help_text=_('Base Adresse API Geo URL'),
|
||||||
|
)
|
||||||
|
|
||||||
category = _('Geographic information system')
|
category = _('Geographic information system')
|
||||||
|
|
||||||
|
@ -46,15 +50,18 @@ class BaseAdresse(BaseResource):
|
||||||
zipcode = models.CharField(
|
zipcode = models.CharField(
|
||||||
max_length=600,
|
max_length=600,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name=_('Postal codes or department number to get streets, separated with commas'))
|
verbose_name=_('Postal codes or department number to get streets, separated with commas'),
|
||||||
|
)
|
||||||
|
|
||||||
latitude = models.FloatField(
|
latitude = models.FloatField(
|
||||||
null=True, blank=True,
|
null=True,
|
||||||
|
blank=True,
|
||||||
verbose_name=_('Latitude'),
|
verbose_name=_('Latitude'),
|
||||||
help_text=_('Geographic priority for /addresses/ endpoint.'),
|
help_text=_('Geographic priority for /addresses/ endpoint.'),
|
||||||
)
|
)
|
||||||
longitude = models.FloatField(
|
longitude = models.FloatField(
|
||||||
null=True, blank=True,
|
null=True,
|
||||||
|
blank=True,
|
||||||
verbose_name=_('Longitude'),
|
verbose_name=_('Longitude'),
|
||||||
help_text=_('Geographic priority for /addresses/ endpoint.'),
|
help_text=_('Geographic priority for /addresses/ endpoint.'),
|
||||||
)
|
)
|
||||||
|
@ -78,29 +85,38 @@ class BaseAdresse(BaseResource):
|
||||||
elif prop == 'name':
|
elif prop == 'name':
|
||||||
house_number = data['properties'].get('housenumber')
|
house_number = data['properties'].get('housenumber')
|
||||||
if house_number and value.startswith(house_number):
|
if house_number and value.startswith(house_number):
|
||||||
value = value[len(house_number):].strip()
|
value = value[len(house_number) :].strip()
|
||||||
result['address']['road'] = value
|
result['address']['road'] = value
|
||||||
elif prop == 'id':
|
elif prop == 'id':
|
||||||
result['id'] = value
|
result['id'] = value
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@endpoint(pattern='(?P<q>.+)?$',
|
@endpoint(
|
||||||
description=_('Addresses list'),
|
pattern='(?P<q>.+)?$',
|
||||||
parameters={
|
description=_('Addresses list'),
|
||||||
'id': {'description': _('Address identifier')},
|
parameters={
|
||||||
'q': {'description': _('Address'), 'example_value': '169 rue du chateau, paris'},
|
'id': {'description': _('Address identifier')},
|
||||||
'page_limit': {'description': _('Maximum number of results to return. Must be '
|
'q': {'description': _('Address'), 'example_value': '169 rue du chateau, paris'},
|
||||||
'lower than 20.')},
|
'page_limit': {
|
||||||
'zipcode': {'description': _('Zipcode'), 'example_value': '75014'},
|
'description': _('Maximum number of results to return. Must be ' 'lower than 20.')
|
||||||
'citycode': {'description': _('INSEE City code')},
|
},
|
||||||
'lat': {'description': _('Prioritize results according to coordinates. "lon" '
|
'zipcode': {'description': _('Zipcode'), 'example_value': '75014'},
|
||||||
'parameter must also be present.')},
|
'citycode': {'description': _('INSEE City code')},
|
||||||
'lon': {'description': _('Prioritize results according to coordinates. "lat" '
|
'lat': {
|
||||||
'parameter must also be present.')},
|
'description': _(
|
||||||
})
|
'Prioritize results according to coordinates. "lon" ' 'parameter must also be present.'
|
||||||
def addresses(self, request, id=None, q=None,
|
)
|
||||||
zipcode='', citycode=None,
|
},
|
||||||
lat=None, lon=None, page_limit=5):
|
'lon': {
|
||||||
|
'description': _(
|
||||||
|
'Prioritize results according to coordinates. "lat" ' 'parameter must also be present.'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
def addresses(
|
||||||
|
self, request, id=None, q=None, zipcode='', citycode=None, lat=None, lon=None, page_limit=5
|
||||||
|
):
|
||||||
if id is not None:
|
if id is not None:
|
||||||
try:
|
try:
|
||||||
address = AddressCacheModel.objects.get(api_id=id)
|
address = AddressCacheModel.objects.get(api_id=id)
|
||||||
|
@ -145,34 +161,47 @@ class BaseAdresse(BaseResource):
|
||||||
data = self.format_address_data(feature)
|
data = self.format_address_data(feature)
|
||||||
result.append(data)
|
result.append(data)
|
||||||
address, created = AddressCacheModel.objects.get_or_create(
|
address, created = AddressCacheModel.objects.get_or_create(
|
||||||
api_id=data['id'], defaults={'data': data})
|
api_id=data['id'], defaults={'data': data}
|
||||||
|
)
|
||||||
if not created:
|
if not created:
|
||||||
address.update_timestamp()
|
address.update_timestamp()
|
||||||
|
|
||||||
return {'data': result}
|
return {'data': result}
|
||||||
|
|
||||||
@endpoint(pattern='(?P<q>.+)?$', description=_('Geocoding (Nominatim API)'),
|
@endpoint(
|
||||||
parameters={
|
pattern='(?P<q>.+)?$',
|
||||||
'q': {'description': _('Address'), 'example_value': '169 rue du chateau, paris'},
|
description=_('Geocoding (Nominatim API)'),
|
||||||
'zipcode': {'description': _('Zipcode')},
|
parameters={
|
||||||
'citycode': {'description': _('INSEE City code')},
|
'q': {'description': _('Address'), 'example_value': '169 rue du chateau, paris'},
|
||||||
'lat': {'description': _('Prioritize results according to coordinates. "lat" '
|
'zipcode': {'description': _('Zipcode')},
|
||||||
'parameter must be present.')},
|
'citycode': {'description': _('INSEE City code')},
|
||||||
'lon': {'description': _('Prioritize results according to coordinates. "lon" '
|
'lat': {
|
||||||
'parameter must be present.')},
|
'description': _(
|
||||||
})
|
'Prioritize results according to coordinates. "lat" ' 'parameter must be present.'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
'lon': {
|
||||||
|
'description': _(
|
||||||
|
'Prioritize results according to coordinates. "lon" ' 'parameter must be present.'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
def search(self, request, q, zipcode='', citycode=None, lat=None, lon=None, **kwargs):
|
def search(self, request, q, zipcode='', citycode=None, lat=None, lon=None, **kwargs):
|
||||||
if kwargs.get('format', 'json') != 'json':
|
if kwargs.get('format', 'json') != 'json':
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
result = self.addresses(request, q=q, zipcode=zipcode, citycode=citycode,
|
result = self.addresses(
|
||||||
lat=lat, lon=lon, page_limit=1)
|
request, q=q, zipcode=zipcode, citycode=citycode, lat=lat, lon=lon, page_limit=1
|
||||||
|
)
|
||||||
return result['data']
|
return result['data']
|
||||||
|
|
||||||
@endpoint(description=_('Reverse geocoding'),
|
@endpoint(
|
||||||
parameters={
|
description=_('Reverse geocoding'),
|
||||||
'lat': {'description': _('Latitude'), 'example_value': 48.833708},
|
parameters={
|
||||||
'lon': {'description': _('Longitude'), 'example_value': 2.323349},
|
'lat': {'description': _('Latitude'), 'example_value': 48.833708},
|
||||||
})
|
'lon': {'description': _('Longitude'), 'example_value': 2.323349},
|
||||||
|
},
|
||||||
|
)
|
||||||
def reverse(self, request, lat, lon, **kwargs):
|
def reverse(self, request, lat, lon, **kwargs):
|
||||||
if kwargs.get('format', 'json') != 'json':
|
if kwargs.get('format', 'json') != 'json':
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -196,18 +225,18 @@ class BaseAdresse(BaseResource):
|
||||||
break
|
break
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@endpoint(description=_('Streets from zipcode'),
|
@endpoint(
|
||||||
parameters={
|
description=_('Streets from zipcode'),
|
||||||
'id': {'description': _('Street identifier')},
|
parameters={
|
||||||
'q': {'description': _("Street name")},
|
'id': {'description': _('Street identifier')},
|
||||||
'zipcode': {'description': _('Zipcode')},
|
'q': {'description': _("Street name")},
|
||||||
'citycode': {'description': _('INSEE City code')},
|
'zipcode': {'description': _('Zipcode')},
|
||||||
'page_limit': {'description': _('Maximum number of results to return'),
|
'citycode': {'description': _('INSEE City code')},
|
||||||
'example_value': 30},
|
'page_limit': {'description': _('Maximum number of results to return'), 'example_value': 30},
|
||||||
'distinct': {'description': _('Remove duplicate streets')},
|
'distinct': {'description': _('Remove duplicate streets')},
|
||||||
})
|
},
|
||||||
def streets(self, request, zipcode=None, citycode=None,
|
)
|
||||||
q=None, id=None, distinct=True, page_limit=None):
|
def streets(self, request, zipcode=None, citycode=None, q=None, id=None, distinct=True, page_limit=None):
|
||||||
result = []
|
result = []
|
||||||
if id is not None:
|
if id is not None:
|
||||||
try:
|
try:
|
||||||
|
@ -234,29 +263,38 @@ class BaseAdresse(BaseResource):
|
||||||
streets = streets[:page_limit]
|
streets = streets[:page_limit]
|
||||||
|
|
||||||
for street in streets:
|
for street in streets:
|
||||||
result.append({'id': str(street.id),
|
result.append(
|
||||||
'text': street.name,
|
{
|
||||||
'type': street.type,
|
'id': str(street.id),
|
||||||
'city': street.city,
|
'text': street.name,
|
||||||
'citycode': street.citycode,
|
'type': street.type,
|
||||||
'zipcode': street.zipcode})
|
'city': street.city,
|
||||||
|
'citycode': street.citycode,
|
||||||
|
'zipcode': street.zipcode,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return {'data': result}
|
return {'data': result}
|
||||||
|
|
||||||
@endpoint(description=_('Cities list'),
|
@endpoint(
|
||||||
parameters={
|
description=_('Cities list'),
|
||||||
'id': {'description': _('Get exactly one city using its code and postal code '
|
parameters={
|
||||||
'separated with a dot'),
|
'id': {
|
||||||
'example_value': '75056.75014'},
|
'description': _(
|
||||||
'q': {'description': _("Search text in name or postal code"),
|
'Get exactly one city using its code and postal code ' 'separated with a dot'
|
||||||
'example_value': 'Paris'},
|
),
|
||||||
'code': {'description': _('INSEE code (or multiple codes separated with commas)'),
|
'example_value': '75056.75014',
|
||||||
'example_value': '75056'},
|
},
|
||||||
'region_code': {'description': _('Region code'), 'example_value': '11'},
|
'q': {'description': _("Search text in name or postal code"), 'example_value': 'Paris'},
|
||||||
'department_code': {'description': _('Department code'), 'example_value': '75'},
|
'code': {
|
||||||
})
|
'description': _('INSEE code (or multiple codes separated with commas)'),
|
||||||
def cities(self, request, id=None, q=None, code=None, region_code=None,
|
'example_value': '75056',
|
||||||
department_code=None):
|
},
|
||||||
|
'region_code': {'description': _('Region code'), 'example_value': '11'},
|
||||||
|
'department_code': {'description': _('Department code'), 'example_value': '75'},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
def cities(self, request, id=None, q=None, code=None, region_code=None, department_code=None):
|
||||||
cities = CityModel.objects.all()
|
cities = CityModel.objects.all()
|
||||||
|
|
||||||
if id is not None:
|
if id is not None:
|
||||||
|
@ -267,8 +305,9 @@ class BaseAdresse(BaseResource):
|
||||||
cities = cities.filter(code=code, zipcode=zipcode)
|
cities = cities.filter(code=code, zipcode=zipcode)
|
||||||
if q:
|
if q:
|
||||||
unaccented_q = simplify(q)
|
unaccented_q = simplify(q)
|
||||||
cities = cities.filter(Q(unaccent_name__istartswith=unaccented_q) |
|
cities = cities.filter(
|
||||||
Q(zipcode__istartswith=unaccented_q))
|
Q(unaccent_name__istartswith=unaccented_q) | Q(zipcode__istartswith=unaccented_q)
|
||||||
|
)
|
||||||
if code:
|
if code:
|
||||||
if ',' in code:
|
if ',' in code:
|
||||||
codes = [c.strip() for c in code.split(',')]
|
codes = [c.strip() for c in code.split(',')]
|
||||||
|
@ -283,13 +322,14 @@ class BaseAdresse(BaseResource):
|
||||||
cities = cities.select_related('department', 'region')
|
cities = cities.select_related('department', 'region')
|
||||||
return {'data': [city.to_json() for city in cities]}
|
return {'data': [city.to_json() for city in cities]}
|
||||||
|
|
||||||
@endpoint(description=_('Departments list'),
|
@endpoint(
|
||||||
parameters={
|
description=_('Departments list'),
|
||||||
'id': {'description': _('Get exactly one department using its code'),
|
parameters={
|
||||||
'example_value': '59'},
|
'id': {'description': _('Get exactly one department using its code'), 'example_value': '59'},
|
||||||
'q': {'description': _('Search text in name or code'), 'example_value': 'Nord'},
|
'q': {'description': _('Search text in name or code'), 'example_value': 'Nord'},
|
||||||
'region_code': {'description': _('Region code'), 'example_value': '32'},
|
'region_code': {'description': _('Region code'), 'example_value': '32'},
|
||||||
})
|
},
|
||||||
|
)
|
||||||
def departments(self, request, id=None, q=None, region_code=None):
|
def departments(self, request, id=None, q=None, region_code=None):
|
||||||
departments = DepartmentModel.objects.all()
|
departments = DepartmentModel.objects.all()
|
||||||
|
|
||||||
|
@ -297,21 +337,22 @@ class BaseAdresse(BaseResource):
|
||||||
departments = departments.filter(code=id)
|
departments = departments.filter(code=id)
|
||||||
if q:
|
if q:
|
||||||
unaccented_q = simplify(q)
|
unaccented_q = simplify(q)
|
||||||
departments = departments.filter(Q(unaccent_name__istartswith=unaccented_q) |
|
departments = departments.filter(
|
||||||
Q(code__istartswith=unaccented_q))
|
Q(unaccent_name__istartswith=unaccented_q) | Q(code__istartswith=unaccented_q)
|
||||||
|
)
|
||||||
if region_code:
|
if region_code:
|
||||||
departments = departments.filter(region__code=region_code)
|
departments = departments.filter(region__code=region_code)
|
||||||
|
|
||||||
departments = departments.select_related('region')
|
departments = departments.select_related('region')
|
||||||
return {'data': [department.to_json() for department in departments]}
|
return {'data': [department.to_json() for department in departments]}
|
||||||
|
|
||||||
@endpoint(description=_('Regions list'),
|
@endpoint(
|
||||||
parameters={
|
description=_('Regions list'),
|
||||||
'id': {'description': _('Get exactly one region using its code'),
|
parameters={
|
||||||
'example_value': '32'},
|
'id': {'description': _('Get exactly one region using its code'), 'example_value': '32'},
|
||||||
'q': {'description': _('Search text in name or code'),
|
'q': {'description': _('Search text in name or code'), 'example_value': 'Hauts-de-France'},
|
||||||
'example_value': 'Hauts-de-France'},
|
},
|
||||||
})
|
)
|
||||||
def regions(self, request, id=None, q=None):
|
def regions(self, request, id=None, q=None):
|
||||||
regions = RegionModel.objects.all()
|
regions = RegionModel.objects.all()
|
||||||
|
|
||||||
|
@ -319,8 +360,9 @@ class BaseAdresse(BaseResource):
|
||||||
regions = regions.filter(code=id)
|
regions = regions.filter(code=id)
|
||||||
if q:
|
if q:
|
||||||
unaccented_q = simplify(q)
|
unaccented_q = simplify(q)
|
||||||
regions = regions.filter(Q(unaccent_name__istartswith=unaccented_q) |
|
regions = regions.filter(
|
||||||
Q(code__istartswith=unaccented_q))
|
Q(unaccent_name__istartswith=unaccented_q) | Q(code__istartswith=unaccented_q)
|
||||||
|
)
|
||||||
|
|
||||||
return {'data': [region.to_json() for region in regions]}
|
return {'data': [region.to_json() for region in regions]}
|
||||||
|
|
||||||
|
@ -362,7 +404,10 @@ class BaseAdresse(BaseResource):
|
||||||
|
|
||||||
for department in departments:
|
for department in departments:
|
||||||
ban_gz = self.requests.get(
|
ban_gz = self.requests.get(
|
||||||
'https://adresse.data.gouv.fr/data/ban/adresses/latest/addok/adresses-addok-{}.ndjson.gz'.format(department))
|
'https://adresse.data.gouv.fr/data/ban/adresses/latest/addok/adresses-addok-{}.ndjson.gz'.format(
|
||||||
|
department
|
||||||
|
)
|
||||||
|
)
|
||||||
if ban_gz.status_code != 200:
|
if ban_gz.status_code != 200:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -386,7 +431,8 @@ class BaseAdresse(BaseResource):
|
||||||
'city': street_info['city'],
|
'city': street_info['city'],
|
||||||
'zipcode': street_info['postcode'],
|
'zipcode': street_info['postcode'],
|
||||||
'type': street_info['type'],
|
'type': street_info['type'],
|
||||||
})
|
},
|
||||||
|
)
|
||||||
if line is _not_found:
|
if line is _not_found:
|
||||||
raise Exception('bano file is empty')
|
raise Exception('bano file is empty')
|
||||||
|
|
||||||
|
@ -409,8 +455,7 @@ class BaseAdresse(BaseResource):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
error = 'invalid json, got: %s' % response.text
|
error = 'invalid json, got: %s' % response.text
|
||||||
if error:
|
if error:
|
||||||
self.logger.error('failed to update api geo data for endpoint %s: %s',
|
self.logger.error('failed to update api geo data for endpoint %s: %s', endpoint, error)
|
||||||
endpoint, error)
|
|
||||||
return
|
return
|
||||||
if not result:
|
if not result:
|
||||||
raise Exception('api geo returns empty json')
|
raise Exception('api geo returns empty json')
|
||||||
|
@ -449,8 +494,7 @@ class BaseAdresse(BaseResource):
|
||||||
defaults['department'] = DepartmentModel.objects.get(code=data['codeDepartement'])
|
defaults['department'] = DepartmentModel.objects.get(code=data['codeDepartement'])
|
||||||
if data.get('codeRegion'):
|
if data.get('codeRegion'):
|
||||||
defaults['region'] = RegionModel.objects.get(code=data['codeRegion'])
|
defaults['region'] = RegionModel.objects.get(code=data['codeRegion'])
|
||||||
CityModel.objects.update_or_create(
|
CityModel.objects.update_or_create(code=data['code'], zipcode=zipcode, defaults=defaults)
|
||||||
code=data['code'], zipcode=zipcode, defaults=defaults)
|
|
||||||
CityModel.objects.filter(last_update__lt=start_update).delete()
|
CityModel.objects.filter(last_update__lt=start_update).delete()
|
||||||
|
|
||||||
def clean_addresses_cache(self):
|
def clean_addresses_cache(self):
|
||||||
|
@ -478,7 +522,6 @@ class BaseAdresse(BaseResource):
|
||||||
|
|
||||||
|
|
||||||
class UnaccentNameMixin(object):
|
class UnaccentNameMixin(object):
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
self.unaccent_name = simplify(self.name)
|
self.unaccent_name = simplify(self.name)
|
||||||
super(UnaccentNameMixin, self).save(*args, **kwargs)
|
super(UnaccentNameMixin, self).save(*args, **kwargs)
|
||||||
|
|
|
@ -6,4 +6,5 @@ from passerelle.apps.bdp.models import Bdp
|
||||||
class BdpAdmin(admin.ModelAdmin):
|
class BdpAdmin(admin.ModelAdmin):
|
||||||
prepopulated_fields = {'slug': ('title',)}
|
prepopulated_fields = {'slug': ('title',)}
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Bdp, BdpAdmin)
|
admin.site.register(Bdp, BdpAdmin)
|
||||||
|
|
|
@ -14,16 +14,41 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Bdp',
|
name='Bdp',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(verbose_name='Title', max_length=50)),
|
('title', models.CharField(verbose_name='Title', max_length=50)),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('service_url', models.CharField(help_text='BDP Web Service URL', max_length=128, verbose_name='Service URL')),
|
(
|
||||||
|
'service_url',
|
||||||
|
models.CharField(
|
||||||
|
help_text='BDP Web Service URL', max_length=128, verbose_name='Service URL'
|
||||||
|
),
|
||||||
|
),
|
||||||
('username', models.CharField(max_length=128, verbose_name='Username', blank=True)),
|
('username', models.CharField(max_length=128, verbose_name='Username', blank=True)),
|
||||||
('password', models.CharField(max_length=128, verbose_name='Password', blank=True)),
|
('password', models.CharField(max_length=128, verbose_name='Password', blank=True)),
|
||||||
('verify_cert', models.BooleanField(default=True, verbose_name='Check HTTPS Certificate validity')),
|
(
|
||||||
('keystore', models.FileField(help_text='Certificate and private key in PEM format', upload_to=b'bdp', null=True, verbose_name='Keystore', blank=True)),
|
'verify_cert',
|
||||||
('users', models.ManyToManyField(to='base.ApiUser', related_name='_bdp_users_+', related_query_name='+', blank=True)),
|
models.BooleanField(default=True, verbose_name='Check HTTPS Certificate validity'),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'keystore',
|
||||||
|
models.FileField(
|
||||||
|
help_text='Certificate and private key in PEM format',
|
||||||
|
upload_to=b'bdp',
|
||||||
|
null=True,
|
||||||
|
verbose_name='Keystore',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='base.ApiUser', related_name='_bdp_users_+', related_query_name='+', blank=True
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'BDP Web Service',
|
'verbose_name': 'BDP Web Service',
|
||||||
|
|
|
@ -14,7 +14,13 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='bdp',
|
model_name='bdp',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Debug Enabled', blank=True, choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Debug Enabled',
|
||||||
|
blank=True,
|
||||||
|
choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,7 +14,12 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='bdp',
|
model_name='bdp',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,7 +14,19 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='bdp',
|
model_name='bdp',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -8,20 +8,21 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from passerelle.base.models import BaseResource
|
from passerelle.base.models import BaseResource
|
||||||
|
|
||||||
|
|
||||||
class Bdp(BaseResource):
|
class Bdp(BaseResource):
|
||||||
service_url = models.CharField(max_length=128, blank=False,
|
service_url = models.CharField(
|
||||||
verbose_name=_('Service URL'),
|
max_length=128, blank=False, verbose_name=_('Service URL'), help_text=_('BDP Web Service URL')
|
||||||
help_text=_('BDP Web Service URL'))
|
)
|
||||||
username = models.CharField(max_length=128, blank=True,
|
username = models.CharField(max_length=128, blank=True, verbose_name=_('Username'))
|
||||||
verbose_name=_('Username'))
|
password = models.CharField(max_length=128, blank=True, verbose_name=_('Password'))
|
||||||
password = models.CharField(max_length=128, blank=True,
|
verify_cert = models.BooleanField(default=True, verbose_name=_('Check HTTPS Certificate validity'))
|
||||||
verbose_name=_('Password'))
|
keystore = models.FileField(
|
||||||
verify_cert = models.BooleanField(default=True,
|
upload_to='bdp',
|
||||||
verbose_name=_('Check HTTPS Certificate validity'))
|
blank=True,
|
||||||
keystore = models.FileField(upload_to='bdp',
|
null=True,
|
||||||
blank=True, null=True,
|
verbose_name=_('Keystore'),
|
||||||
verbose_name=_('Keystore'),
|
help_text=_('Certificate and private key in PEM format'),
|
||||||
help_text=_('Certificate and private key in PEM format'))
|
)
|
||||||
|
|
||||||
category = _('Business Process Connectors')
|
category = _('Business Process Connectors')
|
||||||
|
|
||||||
|
@ -40,16 +41,13 @@ class Bdp(BaseResource):
|
||||||
|
|
||||||
def get_api(self, endpoint, **params):
|
def get_api(self, endpoint, **params):
|
||||||
options = self.requests_options()
|
options = self.requests_options()
|
||||||
return requests.get(self.service_url + '/api/' + endpoint,
|
return requests.get(self.service_url + '/api/' + endpoint, params=params, **options).json()
|
||||||
params=params, **options).json()
|
|
||||||
|
|
||||||
def post_api(self, endpoint, obj):
|
def post_api(self, endpoint, obj):
|
||||||
data = json.dumps(obj)
|
data = json.dumps(obj)
|
||||||
headers = {'Content-Type': 'application/json'}
|
headers = {'Content-Type': 'application/json'}
|
||||||
options = self.requests_options()
|
options = self.requests_options()
|
||||||
request = requests.post(
|
request = requests.post(self.service_url + '/api/' + endpoint, data=data, headers=headers, **options)
|
||||||
self.service_url + '/api/' + endpoint,
|
|
||||||
data=data, headers=headers, **options)
|
|
||||||
result = {
|
result = {
|
||||||
'status_code': request.status_code,
|
'status_code': request.status_code,
|
||||||
'x_request_id': request.headers.get('x-request-id'),
|
'x_request_id': request.headers.get('x-request-id'),
|
||||||
|
|
|
@ -5,5 +5,9 @@ from .views import BdpDetailView, ResourcesView, PostAdherentView
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^(?P<slug>[\w,-]+)/$', BdpDetailView.as_view(), name='bdp-view'),
|
url(r'^(?P<slug>[\w,-]+)/$', BdpDetailView.as_view(), name='bdp-view'),
|
||||||
url(r'^(?P<slug>[\w,-]+)/(?P<resources>[\w,-]+)/$', ResourcesView.as_view(), name='bdp-resources'),
|
url(r'^(?P<slug>[\w,-]+)/(?P<resources>[\w,-]+)/$', ResourcesView.as_view(), name='bdp-resources'),
|
||||||
url(r'^(?P<slug>[\w,-]+)/post/adherent/$', csrf_exempt(PostAdherentView.as_view()), name='bdp-post-adherent'),
|
url(
|
||||||
|
r'^(?P<slug>[\w,-]+)/post/adherent/$',
|
||||||
|
csrf_exempt(PostAdherentView.as_view()),
|
||||||
|
name='bdp-post-adherent',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -40,16 +40,20 @@ class PostAdherentView(View, SingleObjectMixin):
|
||||||
@utils.protected_api('can_access')
|
@utils.protected_api('can_access')
|
||||||
@utils.to_json()
|
@utils.to_json()
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
data = json_loads(request.body) # JSON w.c.s. formdata
|
data = json_loads(request.body) # JSON w.c.s. formdata
|
||||||
date_de_naissance = data['fields'].get('date_de_naissance')
|
date_de_naissance = data['fields'].get('date_de_naissance')
|
||||||
# force 1973-04-18T00:00:00Z
|
# force 1973-04-18T00:00:00Z
|
||||||
date_de_naissance = date_de_naissance[:10] + 'T00:00:00Z'
|
date_de_naissance = date_de_naissance[:10] + 'T00:00:00Z'
|
||||||
abonnements = data['fields'].get('abonnements_raw') or \
|
abonnements = (
|
||||||
data['fields'].get('abonnements_raw') or \
|
data['fields'].get('abonnements_raw')
|
||||||
request.GET.get('abonnements')
|
or data['fields'].get('abonnements_raw')
|
||||||
bibliotheque_id = data['fields'].get('bibliotheque_raw') or \
|
or request.GET.get('abonnements')
|
||||||
data['fields'].get('bibliotheque') or \
|
)
|
||||||
request.GET.get('bibliotheque')
|
bibliotheque_id = (
|
||||||
|
data['fields'].get('bibliotheque_raw')
|
||||||
|
or data['fields'].get('bibliotheque')
|
||||||
|
or request.GET.get('bibliotheque')
|
||||||
|
)
|
||||||
adherent = {
|
adherent = {
|
||||||
'nom': data['fields'].get('nom'),
|
'nom': data['fields'].get('nom'),
|
||||||
'prenom': data['fields'].get('prenom'),
|
'prenom': data['fields'].get('prenom'),
|
||||||
|
|
|
@ -18,11 +18,19 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CartaDSCS',
|
name='CartaDSCS',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('title', models.CharField(max_length=50, verbose_name='Title')),
|
('title', models.CharField(max_length=50, verbose_name='Title')),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
|
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
|
||||||
('wsdl_base_url', models.URLField(help_text='ex: https://example.net/adscs/webservices/', verbose_name='WSDL Base URL')),
|
(
|
||||||
|
'wsdl_base_url',
|
||||||
|
models.URLField(
|
||||||
|
help_text='ex: https://example.net/adscs/webservices/', verbose_name='WSDL Base URL'
|
||||||
|
),
|
||||||
|
),
|
||||||
('username', models.CharField(max_length=64, verbose_name='Username')),
|
('username', models.CharField(max_length=64, verbose_name='Username')),
|
||||||
('password', models.CharField(max_length=64, verbose_name='Password')),
|
('password', models.CharField(max_length=64, verbose_name='Password')),
|
||||||
('iv', models.CharField(max_length=16, verbose_name='Initialisation Vector')),
|
('iv', models.CharField(max_length=16, verbose_name='Initialisation Vector')),
|
||||||
|
@ -31,7 +39,15 @@ class Migration(migrations.Migration):
|
||||||
('ftp_username', models.CharField(max_length=64, verbose_name='FTP Username')),
|
('ftp_username', models.CharField(max_length=64, verbose_name='FTP Username')),
|
||||||
('ftp_password', models.CharField(max_length=64, verbose_name='FTP Password')),
|
('ftp_password', models.CharField(max_length=64, verbose_name='FTP Password')),
|
||||||
('ftp_client_name', models.CharField(max_length=64, verbose_name='FTP Client Name')),
|
('ftp_client_name', models.CharField(max_length=64, verbose_name='FTP Client Name')),
|
||||||
('users', models.ManyToManyField(blank=True, related_name='_cartadscs_users_+', related_query_name='+', to='base.ApiUser')),
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
related_name='_cartadscs_users_+',
|
||||||
|
related_query_name='+',
|
||||||
|
to='base.ApiUser',
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Cart@DS CS',
|
'verbose_name': 'Cart@DS CS',
|
||||||
|
@ -40,7 +56,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CartaDSDossier',
|
name='CartaDSDossier',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('email', models.CharField(max_length=256)),
|
('email', models.CharField(max_length=256)),
|
||||||
('tracking_code', models.CharField(max_length=20)),
|
('tracking_code', models.CharField(max_length=20)),
|
||||||
('commune_id', models.CharField(max_length=20)),
|
('commune_id', models.CharField(max_length=20)),
|
||||||
|
@ -59,10 +78,16 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CartaDSFile',
|
name='CartaDSFile',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('tracking_code', models.CharField(max_length=20)),
|
('tracking_code', models.CharField(max_length=20)),
|
||||||
('id_piece', models.CharField(max_length=20)),
|
('id_piece', models.CharField(max_length=20)),
|
||||||
('uploaded_file', models.FileField(upload_to=passerelle.apps.cartads_cs.models.cartads_file_location)),
|
(
|
||||||
|
'uploaded_file',
|
||||||
|
models.FileField(upload_to=passerelle.apps.cartads_cs.models.cartads_file_location),
|
||||||
|
),
|
||||||
('last_update_datetime', models.DateTimeField(auto_now=True)),
|
('last_update_datetime', models.DateTimeField(auto_now=True)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -16,7 +16,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CartaDSDataCache',
|
name='CartaDSDataCache',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('data_type', models.CharField(max_length=50)),
|
('data_type', models.CharField(max_length=50)),
|
||||||
('data_parameters', django.contrib.postgres.fields.jsonb.JSONField(default={})),
|
('data_parameters', django.contrib.postgres.fields.jsonb.JSONField(default={})),
|
||||||
('data_values', django.contrib.postgres.fields.jsonb.JSONField(default={})),
|
('data_values', django.contrib.postgres.fields.jsonb.JSONField(default={})),
|
||||||
|
|
|
@ -15,6 +15,12 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='cartadscs',
|
model_name='cartadscs',
|
||||||
name='client_name',
|
name='client_name',
|
||||||
field=models.CharField(blank=True, help_text='Only useful in shared environments.', max_length=64, null=True, verbose_name='Client Name'),
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
help_text='Only useful in shared environments.',
|
||||||
|
max_length=64,
|
||||||
|
null=True,
|
||||||
|
verbose_name='Client Name',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -15,7 +15,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CartaDSSubscriber',
|
name='CartaDSSubscriber',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('name_id', models.CharField(max_length=32, null=True)),
|
('name_id', models.CharField(max_length=32, null=True)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,7 +14,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ChoositRegisterGateway',
|
name='ChoositRegisterGateway',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(verbose_name='Title', max_length=50)),
|
('title', models.CharField(verbose_name='Title', max_length=50)),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
|
@ -30,7 +33,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ChoositRegisterNewsletter',
|
name='ChoositRegisterNewsletter',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('name', models.CharField(max_length=16)),
|
('name', models.CharField(max_length=16)),
|
||||||
('description', models.CharField(max_length=128, blank=True)),
|
('description', models.CharField(max_length=128, blank=True)),
|
||||||
],
|
],
|
||||||
|
@ -43,13 +49,27 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ChoositSMSGateway',
|
name='ChoositSMSGateway',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(verbose_name='Title', max_length=50)),
|
('title', models.CharField(verbose_name='Title', max_length=50)),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('key', models.CharField(max_length=64, verbose_name='Key')),
|
('key', models.CharField(max_length=64, verbose_name='Key')),
|
||||||
('default_country_code', models.CharField(default='33', max_length=3, verbose_name='Default country code')),
|
(
|
||||||
('users', models.ManyToManyField(to='base.ApiUser', related_name='_choositsmsgateway_users_+', related_query_name='+', blank=True)),
|
'default_country_code',
|
||||||
|
models.CharField(default='33', max_length=3, verbose_name='Default country code'),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='base.ApiUser',
|
||||||
|
related_name='_choositsmsgateway_users_+',
|
||||||
|
related_query_name='+',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'db_table': 'sms_choosit',
|
'db_table': 'sms_choosit',
|
||||||
|
|
|
@ -14,13 +14,25 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='choositregistergateway',
|
model_name='choositregistergateway',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Debug Enabled', blank=True, choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Debug Enabled',
|
||||||
|
blank=True,
|
||||||
|
choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='choositsmsgateway',
|
model_name='choositsmsgateway',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Debug Enabled', blank=True, choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Debug Enabled',
|
||||||
|
blank=True,
|
||||||
|
choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,13 +14,23 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='choositregistergateway',
|
model_name='choositregistergateway',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='choositsmsgateway',
|
model_name='choositsmsgateway',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,13 +14,37 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='choositregistergateway',
|
model_name='choositregistergateway',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='choositsmsgateway',
|
model_name='choositsmsgateway',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -26,8 +26,8 @@ class ChoositSMSGateway(SMSResource):
|
||||||
'data': [
|
'data': [
|
||||||
[u'0033688888888', u'Choosit error: bad JSON response'],
|
[u'0033688888888', u'Choosit error: bad JSON response'],
|
||||||
[u'0033677777777', u'Choosit error: bad JSON response'],
|
[u'0033677777777', u'Choosit error: bad JSON response'],
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'response': {
|
'response': {
|
||||||
|
@ -40,7 +40,7 @@ class ChoositSMSGateway(SMSResource):
|
||||||
[u'0033688888888', u'Choosit error: not ok'],
|
[u'0033688888888', u'Choosit error: not ok'],
|
||||||
[u'0033677777777', u'Choosit error: not ok'],
|
[u'0033677777777', u'Choosit error: not ok'],
|
||||||
],
|
],
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'response': {
|
'response': {
|
||||||
|
@ -53,9 +53,8 @@ class ChoositSMSGateway(SMSResource):
|
||||||
[u'0033688888888', {'result': u'Envoi terminé', 'sms_id': 1234}],
|
[u'0033688888888', {'result': u'Envoi terminé', 'sms_id': 1234}],
|
||||||
[u'0033677777777', {'result': u'Envoi terminé', 'sms_id': 1234}],
|
[u'0033677777777', {'result': u'Envoi terminé', 'sms_id': 1234}],
|
||||||
],
|
],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
URL = 'http://sms.choosit.com/webservice'
|
URL = 'http://sms.choosit.com/webservice'
|
||||||
|
@ -97,6 +96,5 @@ class ChoositSMSGateway(SMSResource):
|
||||||
else:
|
else:
|
||||||
results.append(output)
|
results.append(output)
|
||||||
if any(isinstance(result, string_types) for result in results):
|
if any(isinstance(result, string_types) for result in results):
|
||||||
raise APIError('Choosit error: some destinations failed',
|
raise APIError('Choosit error: some destinations failed', data=list(zip(destinations, results)))
|
||||||
data=list(zip(destinations, results)))
|
|
||||||
return list(zip(destinations, results))
|
return list(zip(destinations, results))
|
||||||
|
|
|
@ -32,37 +32,30 @@ CERTIFICATE_TYPES = [
|
||||||
{"id": "NAI", "text": "Naissance"},
|
{"id": "NAI", "text": "Naissance"},
|
||||||
{"id": "MAR", "text": "Mariage"},
|
{"id": "MAR", "text": "Mariage"},
|
||||||
{"id": "REC", "text": "Reconnaissance"},
|
{"id": "REC", "text": "Reconnaissance"},
|
||||||
{"id": "DEC", "text": "Décès"}
|
{"id": "DEC", "text": "Décès"},
|
||||||
]
|
]
|
||||||
|
|
||||||
SEXES = [
|
SEXES = [{"id": "M", "text": "Homme"}, {"id": "F", "text": "Femme"}, {"id": "NA", "text": "Autre"}]
|
||||||
{"id": "M", "text": "Homme"},
|
|
||||||
{"id": "F", "text": "Femme"},
|
|
||||||
{"id": "NA", "text": "Autre"}
|
|
||||||
]
|
|
||||||
|
|
||||||
TITLES = [
|
TITLES = [
|
||||||
{"id": "M", "text": "Monsieur"},
|
{"id": "M", "text": "Monsieur"},
|
||||||
{"id": "Mme", "text": "Madame"},
|
{"id": "Mme", "text": "Madame"},
|
||||||
{"id": "Mlle", "text": "Mademoiselle"}
|
{"id": "Mlle", "text": "Mademoiselle"},
|
||||||
]
|
]
|
||||||
|
|
||||||
DOCUMENT_TYPES = [
|
DOCUMENT_TYPES = [
|
||||||
{"id": "CPI", "text": "Copie intégrale"},
|
{"id": "CPI", "text": "Copie intégrale"},
|
||||||
{"id": "EXTAF", "text": "Extrait avec filiation"},
|
{"id": "EXTAF", "text": "Extrait avec filiation"},
|
||||||
{"id": "EXTSF", "text": "Extrait sans filiation"},
|
{"id": "EXTSF", "text": "Extrait sans filiation"},
|
||||||
{"id": "EXTPL", "text": "Extrait plurilingue"}
|
{"id": "EXTPL", "text": "Extrait plurilingue"},
|
||||||
]
|
]
|
||||||
|
|
||||||
CONCERNED = [
|
CONCERNED = [{"id": "reconnu", "text": "Reconnu"}, {"id": "auteur", "text": "Auteur"}]
|
||||||
{"id": "reconnu", "text": "Reconnu"},
|
|
||||||
{"id": "auteur", "text": "Auteur"}
|
|
||||||
]
|
|
||||||
|
|
||||||
ORIGINS = [
|
ORIGINS = [
|
||||||
{"id": "internet", "text": "Internet"},
|
{"id": "internet", "text": "Internet"},
|
||||||
{"id": "guichet", "text": "Guichet"},
|
{"id": "guichet", "text": "Guichet"},
|
||||||
{"id": "courrier", "text": "Courrier"}
|
{"id": "courrier", "text": "Courrier"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,8 +66,8 @@ def is_clean(element):
|
||||||
|
|
||||||
|
|
||||||
class BaseType(object):
|
class BaseType(object):
|
||||||
"""Base data binding object
|
"""Base data binding object"""
|
||||||
"""
|
|
||||||
tagname = None
|
tagname = None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -82,8 +75,7 @@ class BaseType(object):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_element(cls, tagname, value=None, namespace=None, nsmap=None):
|
def make_element(cls, tagname, value=None, namespace=None, nsmap=None):
|
||||||
M = xobject.ElementMaker(annotate=False, namespace=namespace,
|
M = xobject.ElementMaker(annotate=False, namespace=namespace, nsmap=nsmap)
|
||||||
nsmap=nsmap)
|
|
||||||
return M(tagname, value)
|
return M(tagname, value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -115,19 +107,17 @@ class CityWebType(BaseType):
|
||||||
|
|
||||||
|
|
||||||
class SimpleType(CityWebType):
|
class SimpleType(CityWebType):
|
||||||
"""Data binding class for SimpleType
|
"""Data binding class for SimpleType"""
|
||||||
"""
|
|
||||||
allowed_values = None
|
allowed_values = None
|
||||||
|
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
if value not in self.allowed_values:
|
if value not in self.allowed_values:
|
||||||
raise APIError('<%s> value (%s) not in %s' % (self.tagname, value,
|
raise APIError('<%s> value (%s) not in %s' % (self.tagname, value, self.allowed_values))
|
||||||
self.allowed_values))
|
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
class DateType(CityWebType):
|
class DateType(CityWebType):
|
||||||
|
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
try:
|
try:
|
||||||
self.value = parse_date(value)
|
self.value = parse_date(value)
|
||||||
|
@ -139,8 +129,8 @@ class DateType(CityWebType):
|
||||||
|
|
||||||
|
|
||||||
class ComplexType(CityWebType):
|
class ComplexType(CityWebType):
|
||||||
"""Data binding class for ComplexType
|
"""Data binding class for ComplexType"""
|
||||||
"""
|
|
||||||
sequence = None
|
sequence = None
|
||||||
pattern = None
|
pattern = None
|
||||||
|
|
||||||
|
@ -229,8 +219,7 @@ class Place(ComplexType):
|
||||||
|
|
||||||
class Address(ComplexType):
|
class Address(ComplexType):
|
||||||
tagname = 'adresse'
|
tagname = 'adresse'
|
||||||
sequence = ('ligneAdr1', 'ligneAdr2', 'codePostal',
|
sequence = ('ligneAdr1', 'ligneAdr2', 'codePostal', 'lieu', 'mail', 'tel')
|
||||||
'lieu', 'mail', 'tel')
|
|
||||||
pattern = 'address_'
|
pattern = 'address_'
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
|
@ -273,8 +262,7 @@ class EventPlace(Place):
|
||||||
|
|
||||||
|
|
||||||
class Person(ComplexType):
|
class Person(ComplexType):
|
||||||
sequence = ('noms', 'prenoms', 'genre', 'adresse', 'sexe',
|
sequence = ('noms', 'prenoms', 'genre', 'adresse', 'sexe', 'pere', 'mere', 'naissance')
|
||||||
'pere', 'mere', 'naissance')
|
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
super(Person, self).__init__(data)
|
super(Person, self).__init__(data)
|
||||||
|
@ -314,8 +302,7 @@ class Parent(Person):
|
||||||
|
|
||||||
|
|
||||||
class ConcernedCommon(Person):
|
class ConcernedCommon(Person):
|
||||||
sequence = ('noms', 'prenoms', 'genre', 'sexe',
|
sequence = ('noms', 'prenoms', 'genre', 'sexe', 'parent1', 'parent2', 'naissance')
|
||||||
'parent1', 'parent2', 'naissance')
|
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
super(ConcernedCommon, self).__init__(data)
|
super(ConcernedCommon, self).__init__(data)
|
||||||
|
@ -344,8 +331,7 @@ class Applicant(ComplexType):
|
||||||
|
|
||||||
class Event(ComplexType):
|
class Event(ComplexType):
|
||||||
tagname = 'evenement'
|
tagname = 'evenement'
|
||||||
sequence = ('interesse', 'conjoint', 'natureEvenement',
|
sequence = ('interesse', 'conjoint', 'natureEvenement', 'typeInteresse', 'dateEvenement', 'lieuEvenement')
|
||||||
'typeInteresse', 'dateEvenement', 'lieuEvenement')
|
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
certificate_type = data['certificate_type']
|
certificate_type = data['certificate_type']
|
||||||
|
@ -362,8 +348,16 @@ class Event(ComplexType):
|
||||||
class CivilStatusApplication(ComplexType):
|
class CivilStatusApplication(ComplexType):
|
||||||
tagname = 'demandeEtatCivil'
|
tagname = 'demandeEtatCivil'
|
||||||
sequence = (
|
sequence = (
|
||||||
'identifiant', 'demandeur', 'natureDocument', 'nbExemplaire',
|
'identifiant',
|
||||||
'dateDemande', 'evenement', 'motif', 'origine', 'commentaire')
|
'demandeur',
|
||||||
|
'natureDocument',
|
||||||
|
'nbExemplaire',
|
||||||
|
'dateDemande',
|
||||||
|
'evenement',
|
||||||
|
'motif',
|
||||||
|
'origine',
|
||||||
|
'commentaire',
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
self.identifiant = data['application_id']
|
self.identifiant = data['application_id']
|
||||||
|
@ -388,5 +382,5 @@ class CivilStatusApplication(ComplexType):
|
||||||
with atomic_write(filepath) as fd:
|
with atomic_write(filepath) as fd:
|
||||||
fd.write(force_bytes(content))
|
fd.write(force_bytes(content))
|
||||||
# set read only permission for owner and group
|
# set read only permission for owner and group
|
||||||
os.chmod(filepath, stat.S_IRUSR|stat.S_IRGRP)
|
os.chmod(filepath, stat.S_IRUSR | stat.S_IRGRP)
|
||||||
return filename
|
return filename
|
||||||
|
|
|
@ -14,12 +14,35 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CityWeb',
|
name='CityWeb',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(verbose_name='Title', max_length=50)),
|
('title', models.CharField(verbose_name='Title', max_length=50)),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('log_level', models.CharField(default=b'INFO', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')])),
|
(
|
||||||
('users', models.ManyToManyField(to='base.ApiUser', related_name='_cityweb_users_+', related_query_name='+', blank=True)),
|
'log_level',
|
||||||
|
models.CharField(
|
||||||
|
default=b'INFO',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='base.ApiUser', related_name='_cityweb_users_+', related_query_name='+', blank=True
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': "CityWeb - Demande d'acte d'\xe9tat civil",
|
'verbose_name': "CityWeb - Demande d'acte d'\xe9tat civil",
|
||||||
|
|
|
@ -24,8 +24,15 @@ from passerelle.compat import json_loads
|
||||||
from passerelle.utils.api import endpoint
|
from passerelle.utils.api import endpoint
|
||||||
from passerelle.utils.jsonresponse import APIError
|
from passerelle.utils.jsonresponse import APIError
|
||||||
|
|
||||||
from .cityweb import (CivilStatusApplication, TITLES, SEXES, DOCUMENT_TYPES,
|
from .cityweb import (
|
||||||
CERTIFICATE_TYPES, CONCERNED, ORIGINS)
|
CivilStatusApplication,
|
||||||
|
TITLES,
|
||||||
|
SEXES,
|
||||||
|
DOCUMENT_TYPES,
|
||||||
|
CERTIFICATE_TYPES,
|
||||||
|
CONCERNED,
|
||||||
|
ORIGINS,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CityWeb(BaseResource):
|
class CityWeb(BaseResource):
|
||||||
|
@ -52,8 +59,7 @@ class CityWeb(BaseResource):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def basepath(self):
|
def basepath(self):
|
||||||
return os.path.join(
|
return os.path.join(default_storage.path('cityweb'), self.slug)
|
||||||
default_storage.path('cityweb'), self.slug)
|
|
||||||
|
|
||||||
@endpoint(perm='can_access', description=_('Get title list'))
|
@endpoint(perm='can_access', description=_('Get title list'))
|
||||||
def titles(self, request):
|
def titles(self, request):
|
||||||
|
@ -71,14 +77,20 @@ class CityWeb(BaseResource):
|
||||||
def origins(self, request):
|
def origins(self, request):
|
||||||
return {'data': ORIGINS}
|
return {'data': ORIGINS}
|
||||||
|
|
||||||
@endpoint(name='certificate-types', perm='can_access',
|
@endpoint(
|
||||||
description=_('Get certificate type list'), parameters={'exclude': {'example_value': 'REC'}})
|
name='certificate-types',
|
||||||
|
perm='can_access',
|
||||||
|
description=_('Get certificate type list'),
|
||||||
|
parameters={'exclude': {'example_value': 'REC'}},
|
||||||
|
)
|
||||||
def certificate_types(self, request, exclude=''):
|
def certificate_types(self, request, exclude=''):
|
||||||
return {'data': [item for item in CERTIFICATE_TYPES
|
return {'data': [item for item in CERTIFICATE_TYPES if item.get('id') not in exclude.split(',')]}
|
||||||
if item.get('id') not in exclude.split(',')]}
|
|
||||||
|
|
||||||
@endpoint(name='document-types', perm='can_access',
|
@endpoint(
|
||||||
description=_('Get document type list'), parameters={'exclude': {'example_value': 'EXTPL'}})
|
name='document-types',
|
||||||
|
perm='can_access',
|
||||||
|
description=_('Get document type list'),
|
||||||
|
parameters={'exclude': {'example_value': 'EXTPL'}},
|
||||||
|
)
|
||||||
def document_types(self, request, exclude=''):
|
def document_types(self, request, exclude=''):
|
||||||
return {'data': [item for item in DOCUMENT_TYPES
|
return {'data': [item for item in DOCUMENT_TYPES if item.get('id') not in exclude.split(',')]}
|
||||||
if item.get('id') not in exclude.split(',')]}
|
|
||||||
|
|
|
@ -6,8 +6,6 @@ from django.db import models, migrations
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = []
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = []
|
||||||
]
|
|
||||||
|
|
|
@ -7,7 +7,14 @@ from django.db import migrations, models
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
replaces = [('clicrdv', '0001_initial'), ('clicrdv', '0002_clicrdv_group_id'), ('clicrdv', '0003_auto_20160920_0903'), ('clicrdv', '0004_newclicrdv'), ('clicrdv', '0005_auto_20161218_1701'), ('clicrdv', '0006_auto_20170920_0951')]
|
replaces = [
|
||||||
|
('clicrdv', '0001_initial'),
|
||||||
|
('clicrdv', '0002_clicrdv_group_id'),
|
||||||
|
('clicrdv', '0003_auto_20160920_0903'),
|
||||||
|
('clicrdv', '0004_newclicrdv'),
|
||||||
|
('clicrdv', '0005_auto_20161218_1701'),
|
||||||
|
('clicrdv', '0006_auto_20170920_0951'),
|
||||||
|
]
|
||||||
|
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
|
@ -20,19 +27,59 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ClicRdv',
|
name='ClicRdv',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('title', models.CharField(max_length=50, verbose_name='Title')),
|
('title', models.CharField(max_length=50, verbose_name='Title')),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('log_level', models.CharField(choices=[('NOTSET', 'NOTSET'), ('DEBUG', 'DEBUG'), ('INFO', 'INFO'), ('WARNING', 'WARNING'), ('ERROR', 'ERROR'), ('CRITICAL', 'CRITICAL')], default='INFO', max_length=10, verbose_name='Log Level')),
|
(
|
||||||
('server', models.CharField(choices=[('www.clicrdv.com', 'Production (www.clicrdv.com)'), ('sandbox.clicrdv.com', 'SandBox (sandbox.clicrdv.com)')], default='sandbox.clicrdv.com', max_length=64, verbose_name='Server')),
|
'log_level',
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
('NOTSET', 'NOTSET'),
|
||||||
|
('DEBUG', 'DEBUG'),
|
||||||
|
('INFO', 'INFO'),
|
||||||
|
('WARNING', 'WARNING'),
|
||||||
|
('ERROR', 'ERROR'),
|
||||||
|
('CRITICAL', 'CRITICAL'),
|
||||||
|
],
|
||||||
|
default='INFO',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'server',
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
('www.clicrdv.com', 'Production (www.clicrdv.com)'),
|
||||||
|
('sandbox.clicrdv.com', 'SandBox (sandbox.clicrdv.com)'),
|
||||||
|
],
|
||||||
|
default='sandbox.clicrdv.com',
|
||||||
|
max_length=64,
|
||||||
|
verbose_name='Server',
|
||||||
|
),
|
||||||
|
),
|
||||||
('group_id', models.IntegerField(default=0, verbose_name='Group Id')),
|
('group_id', models.IntegerField(default=0, verbose_name='Group Id')),
|
||||||
('apikey', models.CharField(max_length=64, verbose_name='API Key')),
|
('apikey', models.CharField(max_length=64, verbose_name='API Key')),
|
||||||
('username', models.CharField(max_length=64, verbose_name='Username')),
|
('username', models.CharField(max_length=64, verbose_name='Username')),
|
||||||
('password', models.CharField(max_length=64, verbose_name='Password')),
|
('password', models.CharField(max_length=64, verbose_name='Password')),
|
||||||
('websource', models.CharField(blank=True, max_length=64, null=True, verbose_name='Web source')),
|
(
|
||||||
('default_comment', models.CharField(blank=True, max_length=250, null=True, verbose_name='Default comment')),
|
'websource',
|
||||||
('users', models.ManyToManyField(blank=True, related_name='_clicrdv_users_+', related_query_name='+', to='base.ApiUser')),
|
models.CharField(blank=True, max_length=64, null=True, verbose_name='Web source'),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'default_comment',
|
||||||
|
models.CharField(blank=True, max_length=250, null=True, verbose_name='Default comment'),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True, related_name='_clicrdv_users_+', related_query_name='+', to='base.ApiUser'
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Clicrdv Agenda',
|
'verbose_name': 'Clicrdv Agenda',
|
||||||
|
|
|
@ -10,5 +10,4 @@ class Migration(migrations.Migration):
|
||||||
('clicrdv', '0001_initial'),
|
('clicrdv', '0001_initial'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = []
|
||||||
]
|
|
||||||
|
|
|
@ -7,13 +7,13 @@ from django.db import migrations
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('clicrdv', '0001_squashed_0006_auto_20170920_0951'),
|
('clicrdv', '0001_squashed_0006_auto_20170920_0951'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='clicrdv',
|
model_name='clicrdv',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -10,5 +10,4 @@ class Migration(migrations.Migration):
|
||||||
('clicrdv', '0002_clicrdv_group_id'),
|
('clicrdv', '0002_clicrdv_group_id'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = []
|
||||||
]
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
@ -15,19 +16,56 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='NewClicRdv',
|
name='NewClicRdv',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(verbose_name='Title', max_length=50)),
|
('title', models.CharField(verbose_name='Title', max_length=50)),
|
||||||
('slug', models.SlugField(verbose_name='Identifier')),
|
('slug', models.SlugField(verbose_name='Identifier')),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('log_level', models.CharField(default='NOTSET', max_length=10, verbose_name='Log Level', choices=[('NOTSET', 'NOTSET'), ('DEBUG', 'DEBUG'), ('INFO', 'INFO'), ('WARNING', 'WARNING'), ('ERROR', 'ERROR'), ('CRITICAL', 'CRITICAL'), ('FATAL', 'FATAL')])),
|
(
|
||||||
('server', models.CharField(default='sandbox.clicrdv.com', max_length=64, choices=[('www.clicrdv.com', 'Production (www.clicrdv.com)'), ('sandbox.clicrdv.com', 'SandBox (sandbox.clicrdv.com)')])),
|
'log_level',
|
||||||
|
models.CharField(
|
||||||
|
default='NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
('NOTSET', 'NOTSET'),
|
||||||
|
('DEBUG', 'DEBUG'),
|
||||||
|
('INFO', 'INFO'),
|
||||||
|
('WARNING', 'WARNING'),
|
||||||
|
('ERROR', 'ERROR'),
|
||||||
|
('CRITICAL', 'CRITICAL'),
|
||||||
|
('FATAL', 'FATAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'server',
|
||||||
|
models.CharField(
|
||||||
|
default='sandbox.clicrdv.com',
|
||||||
|
max_length=64,
|
||||||
|
choices=[
|
||||||
|
('www.clicrdv.com', 'Production (www.clicrdv.com)'),
|
||||||
|
('sandbox.clicrdv.com', 'SandBox (sandbox.clicrdv.com)'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
('group_id', models.IntegerField(default=0)),
|
('group_id', models.IntegerField(default=0)),
|
||||||
('apikey', models.CharField(max_length=64)),
|
('apikey', models.CharField(max_length=64)),
|
||||||
('username', models.CharField(max_length=64)),
|
('username', models.CharField(max_length=64)),
|
||||||
('password', models.CharField(max_length=64)),
|
('password', models.CharField(max_length=64)),
|
||||||
('websource', models.CharField(max_length=64, null=True, blank=True)),
|
('websource', models.CharField(max_length=64, null=True, blank=True)),
|
||||||
('default_comment', models.CharField(max_length=250, null=True, blank=True)),
|
('default_comment', models.CharField(max_length=250, null=True, blank=True)),
|
||||||
('users', models.ManyToManyField(to='base.ApiUser', related_name='_newclicrdv_users_+', related_query_name='+', blank=True)),
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='base.ApiUser',
|
||||||
|
related_name='_newclicrdv_users_+',
|
||||||
|
related_query_name='+',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Clicrdv Agenda',
|
'verbose_name': 'Clicrdv Agenda',
|
||||||
|
|
|
@ -22,15 +22,14 @@ from passerelle.utils.api import endpoint
|
||||||
|
|
||||||
CLICRDV_SERVERS = (
|
CLICRDV_SERVERS = (
|
||||||
('www.clicrdv.com', 'Production (www.clicrdv.com)'),
|
('www.clicrdv.com', 'Production (www.clicrdv.com)'),
|
||||||
('sandbox.clicrdv.com', 'SandBox (sandbox.clicrdv.com)')
|
('sandbox.clicrdv.com', 'SandBox (sandbox.clicrdv.com)'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ClicRdv(BaseResource):
|
class ClicRdv(BaseResource):
|
||||||
server = models.CharField(
|
server = models.CharField(
|
||||||
_('Server'),
|
_('Server'), max_length=64, choices=CLICRDV_SERVERS, default='sandbox.clicrdv.com'
|
||||||
max_length=64,
|
)
|
||||||
choices=CLICRDV_SERVERS,
|
|
||||||
default='sandbox.clicrdv.com')
|
|
||||||
group_id = models.IntegerField(_('Group Id'), default=0)
|
group_id = models.IntegerField(_('Group Id'), default=0)
|
||||||
apikey = models.CharField(_('API Key'), max_length=64)
|
apikey = models.CharField(_('API Key'), max_length=64)
|
||||||
username = models.CharField(_('Username'), max_length=64)
|
username = models.CharField(_('Username'), max_length=64)
|
||||||
|
@ -120,8 +119,7 @@ class ClicRdv(BaseResource):
|
||||||
datetimes = []
|
datetimes = []
|
||||||
for timeslot in self.get_available_timeslots(intervention):
|
for timeslot in self.get_available_timeslots(intervention):
|
||||||
parsed = datetime.datetime.strptime(timeslot, '%Y-%m-%d %H:%M:%S')
|
parsed = datetime.datetime.strptime(timeslot, '%Y-%m-%d %H:%M:%S')
|
||||||
datetimed = {'id': parsed.strftime('%Y-%m-%d-%H:%M:%S'),
|
datetimed = {'id': parsed.strftime('%Y-%m-%d-%H:%M:%S'), 'text': date_format(parsed, 'j F Y H:i')}
|
||||||
'text': date_format(parsed, 'j F Y H:i')}
|
|
||||||
datetimes.append(datetimed)
|
datetimes.append(datetimed)
|
||||||
datetimes.sort(key=lambda x: x.get('id'))
|
datetimes.sort(key=lambda x: x.get('id'))
|
||||||
return datetimes
|
return datetimes
|
||||||
|
@ -130,8 +128,7 @@ class ClicRdv(BaseResource):
|
||||||
dates = []
|
dates = []
|
||||||
for timeslot in self.get_available_timeslots(intervention):
|
for timeslot in self.get_available_timeslots(intervention):
|
||||||
parsed = datetime.datetime.strptime(timeslot, '%Y-%m-%d %H:%M:%S')
|
parsed = datetime.datetime.strptime(timeslot, '%Y-%m-%d %H:%M:%S')
|
||||||
date = {'id': parsed.strftime('%Y-%m-%d'),
|
date = {'id': parsed.strftime('%Y-%m-%d'), 'text': date_format(parsed, 'j F Y')}
|
||||||
'text': date_format(parsed, 'j F Y')}
|
|
||||||
if date in dates:
|
if date in dates:
|
||||||
continue
|
continue
|
||||||
dates.append(date)
|
dates.append(date)
|
||||||
|
@ -142,12 +139,11 @@ class ClicRdv(BaseResource):
|
||||||
if not date:
|
if not date:
|
||||||
raise Exception('no date value')
|
raise Exception('no date value')
|
||||||
times = []
|
times = []
|
||||||
for timeslot in self.get_available_timeslots(intervention,
|
for timeslot in self.get_available_timeslots(
|
||||||
date_start='%s 00:00:00' % date,
|
intervention, date_start='%s 00:00:00' % date, date_end='%s 23:59:59' % date
|
||||||
date_end='%s 23:59:59' % date):
|
):
|
||||||
parsed = datetime.datetime.strptime(timeslot, '%Y-%m-%d %H:%M:%S')
|
parsed = datetime.datetime.strptime(timeslot, '%Y-%m-%d %H:%M:%S')
|
||||||
timed = {'id': parsed.strftime('%H:%M:%S'),
|
timed = {'id': parsed.strftime('%H:%M:%S'), 'text': time_format(parsed, 'H:i')}
|
||||||
'text': time_format(parsed, 'H:i')}
|
|
||||||
times.append(timed)
|
times.append(timed)
|
||||||
times.sort(key=lambda x: x.get('id'))
|
times.sort(key=lambda x: x.get('id'))
|
||||||
return times
|
return times
|
||||||
|
@ -158,12 +154,13 @@ class ClicRdv(BaseResource):
|
||||||
return response
|
return response
|
||||||
return {'success': True}
|
return {'success': True}
|
||||||
|
|
||||||
|
|
||||||
def create_appointment(self, intervention, websource, data):
|
def create_appointment(self, intervention, websource, data):
|
||||||
fields = data.get('fields') or {}
|
fields = data.get('fields') or {}
|
||||||
extra = data.get('extra') or {}
|
extra = data.get('extra') or {}
|
||||||
|
|
||||||
def get_data(key, default=None):
|
def get_data(key, default=None):
|
||||||
return data.get(key) or extra.get(key) or fields.get(key) or default
|
return data.get(key) or extra.get(key) or fields.get(key) or default
|
||||||
|
|
||||||
if intervention:
|
if intervention:
|
||||||
intervention = int(intervention)
|
intervention = int(intervention)
|
||||||
else:
|
else:
|
||||||
|
@ -184,17 +181,17 @@ class ClicRdv(BaseResource):
|
||||||
'email': get_data('clicrdv_email', ''),
|
'email': get_data('clicrdv_email', ''),
|
||||||
'firstphone': get_data('clicrdv_firstphone', ''),
|
'firstphone': get_data('clicrdv_firstphone', ''),
|
||||||
'secondphone': get_data('clicrdv_secondphone', ''),
|
'secondphone': get_data('clicrdv_secondphone', ''),
|
||||||
},
|
},
|
||||||
'date': date,
|
'date': date,
|
||||||
'intervention_ids': [intervention],
|
'intervention_ids': [intervention],
|
||||||
'websource': websource,
|
'websource': websource,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
comments = get_data('clicrdv_comments') or self.default_comment
|
comments = get_data('clicrdv_comments') or self.default_comment
|
||||||
if comments:
|
if comments:
|
||||||
appointment['comments'] = comments
|
appointment['comments'] = comments
|
||||||
# optional parameters, if any...
|
# optional parameters, if any...
|
||||||
for fieldname in (list(fields.keys()) + list(extra.keys()) + list(data.keys())):
|
for fieldname in list(fields.keys()) + list(extra.keys()) + list(data.keys()):
|
||||||
if fieldname.startswith('clicrdv_fiche_'):
|
if fieldname.startswith('clicrdv_fiche_'):
|
||||||
appointment['appointment']['fiche'][fieldname[14:]] = get_data(fieldname) or ''
|
appointment['appointment']['fiche'][fieldname[14:]] = get_data(fieldname) or ''
|
||||||
response = self.request('appointments', 'post', json=appointment)
|
response = self.request('appointments', 'post', json=appointment)
|
||||||
|
|
|
@ -7,17 +7,34 @@ from passerelle.apps.clicrdv.views import *
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^(?P<slug>[\w,-]+)/$', ClicRdvDetailView.as_view(), name='clicrdv-view'),
|
url(r'^(?P<slug>[\w,-]+)/$', ClicRdvDetailView.as_view(), name='clicrdv-view'),
|
||||||
|
url(
|
||||||
url(r'^(?P<slug>[\w,-]+)/interventions/(?P<intervention_id>\d+)/datetimes/$',
|
r'^(?P<slug>[\w,-]+)/interventions/(?P<intervention_id>\d+)/datetimes/$',
|
||||||
DateTimesView.as_view(), name='clicrdv-datetimes'),
|
DateTimesView.as_view(),
|
||||||
url(r'^(?P<slug>[\w,-]+)/interventions/(?P<intervention_id>\d+)/dates/$',
|
name='clicrdv-datetimes',
|
||||||
DatesView.as_view(), name='clicrdv-dates'),
|
),
|
||||||
url(r'^(?P<slug>[\w,-]+)/interventions/(?P<intervention_id>\d+)/(?P<date>[\d-]+)/times$',
|
url(
|
||||||
TimesView.as_view(), name='clicrdv-times'),
|
r'^(?P<slug>[\w,-]+)/interventions/(?P<intervention_id>\d+)/dates/$',
|
||||||
url(r'^(?P<slug>[\w,-]+)/interventions/(?P<intervention_id>\d+)/create$',
|
DatesView.as_view(),
|
||||||
csrf_exempt(CreateAppointmentView.as_view()), name='clicrdv-create-appointment'),
|
name='clicrdv-dates',
|
||||||
url(r'^(?P<slug>[\w,-]+)/create$',
|
),
|
||||||
csrf_exempt(CreateAppointmentView.as_view()), name='clicrdv-create-appointment-qs'),
|
url(
|
||||||
url(r'^(?P<slug>[\w,-]+)/(?P<appointment_id>\d+)/cancel$',
|
r'^(?P<slug>[\w,-]+)/interventions/(?P<intervention_id>\d+)/(?P<date>[\d-]+)/times$',
|
||||||
CancelAppointmentView.as_view(), name='clicrdv-cancel-appointment'),
|
TimesView.as_view(),
|
||||||
|
name='clicrdv-times',
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^(?P<slug>[\w,-]+)/interventions/(?P<intervention_id>\d+)/create$',
|
||||||
|
csrf_exempt(CreateAppointmentView.as_view()),
|
||||||
|
name='clicrdv-create-appointment',
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^(?P<slug>[\w,-]+)/create$',
|
||||||
|
csrf_exempt(CreateAppointmentView.as_view()),
|
||||||
|
name='clicrdv-create-appointment-qs',
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^(?P<slug>[\w,-]+)/(?P<appointment_id>\d+)/cancel$',
|
||||||
|
CancelAppointmentView.as_view(),
|
||||||
|
name='clicrdv-cancel-appointment',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -16,6 +16,7 @@ class DateTimesView(View, SingleObjectMixin):
|
||||||
|
|
||||||
input: https//passerelle/clicrdv/foobar/interventions/887/datetimes
|
input: https//passerelle/clicrdv/foobar/interventions/887/datetimes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = ClicRdv
|
model = ClicRdv
|
||||||
|
|
||||||
@utils.to_json()
|
@utils.to_json()
|
||||||
|
@ -31,6 +32,7 @@ class DatesView(View, SingleObjectMixin):
|
||||||
{ data: [ { id: '2014-05-07', text: "7 mai 2014" },
|
{ data: [ { id: '2014-05-07', text: "7 mai 2014" },
|
||||||
{ id: '2014-05-13', text: "13 mai 2014" } ], err: 0 }
|
{ id: '2014-05-13', text: "13 mai 2014" } ], err: 0 }
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = ClicRdv
|
model = ClicRdv
|
||||||
|
|
||||||
@utils.to_json()
|
@utils.to_json()
|
||||||
|
@ -46,6 +48,7 @@ class TimesView(View, SingleObjectMixin):
|
||||||
{ data: [ { id: '15:10:00', text: "15:10" },
|
{ data: [ { id: '15:10:00', text: "15:10" },
|
||||||
{ id: '15:30:00', text: "15:30" } ], err: 0 }
|
{ id: '15:30:00', text: "15:30" } ], err: 0 }
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = ClicRdv
|
model = ClicRdv
|
||||||
|
|
||||||
@utils.to_json()
|
@utils.to_json()
|
||||||
|
@ -77,6 +80,7 @@ class CreateAppointmentView(View, SingleObjectMixin):
|
||||||
output:
|
output:
|
||||||
{ data: { 'success': true, 'appointment_id': 123 }, err: 0 }
|
{ data: { 'success': true, 'appointment_id': 123 }, err: 0 }
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = ClicRdv
|
model = ClicRdv
|
||||||
|
|
||||||
@utils.protected_api('can_manage_appointment')
|
@utils.protected_api('can_manage_appointment')
|
||||||
|
@ -85,10 +89,11 @@ class CreateAppointmentView(View, SingleObjectMixin):
|
||||||
if intervention_id is None:
|
if intervention_id is None:
|
||||||
intervention_id = self.request.GET.get('intervention')
|
intervention_id = self.request.GET.get('intervention')
|
||||||
data = json_loads(request.body)
|
data = json_loads(request.body)
|
||||||
return {'data': self.get_object().create_appointment(
|
return {
|
||||||
intervention_id,
|
'data': self.get_object().create_appointment(
|
||||||
self.request.GET.get('websource'),
|
intervention_id, self.request.GET.get('websource'), data
|
||||||
data)}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class CancelAppointmentView(View, SingleObjectMixin):
|
class CancelAppointmentView(View, SingleObjectMixin):
|
||||||
|
@ -98,6 +103,7 @@ class CancelAppointmentView(View, SingleObjectMixin):
|
||||||
output:
|
output:
|
||||||
{ data: { 'success': true }, err: 0 }
|
{ data: { 'success': true }, err: 0 }
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = ClicRdv
|
model = ClicRdv
|
||||||
|
|
||||||
@utils.protected_api('can_manage_appointment')
|
@utils.protected_api('can_manage_appointment')
|
||||||
|
|
|
@ -14,15 +14,48 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CmisConnector',
|
name='CmisConnector',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(verbose_name='Title', max_length=50)),
|
('title', models.CharField(verbose_name='Title', max_length=50)),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('log_level', models.CharField(default=b'INFO', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')])),
|
(
|
||||||
('cmis_endpoint', models.URLField(help_text='URL of the CMIS Atom endpoint', max_length=400, verbose_name='CMIS Atom endpoint')),
|
'log_level',
|
||||||
|
models.CharField(
|
||||||
|
default=b'INFO',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'cmis_endpoint',
|
||||||
|
models.URLField(
|
||||||
|
help_text='URL of the CMIS Atom endpoint',
|
||||||
|
max_length=400,
|
||||||
|
verbose_name='CMIS Atom endpoint',
|
||||||
|
),
|
||||||
|
),
|
||||||
('username', models.CharField(max_length=128, verbose_name='Service username')),
|
('username', models.CharField(max_length=128, verbose_name='Service username')),
|
||||||
('password', models.CharField(max_length=128, verbose_name='Service password')),
|
('password', models.CharField(max_length=128, verbose_name='Service password')),
|
||||||
('users', models.ManyToManyField(to='base.ApiUser', related_name='_cmisconnector_users_+', related_query_name='+', blank=True)),
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='base.ApiUser',
|
||||||
|
related_name='_cmisconnector_users_+',
|
||||||
|
related_query_name='+',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'CMIS connector',
|
'verbose_name': 'CMIS connector',
|
||||||
|
|
|
@ -54,7 +54,7 @@ UPLOAD_SCHEMA = {
|
||||||
'content': {'type': 'string'},
|
'content': {'type': 'string'},
|
||||||
'content_type': {'type': 'string'},
|
'content_type': {'type': 'string'},
|
||||||
},
|
},
|
||||||
'required': ['content']
|
'required': ['content'],
|
||||||
},
|
},
|
||||||
'filename': {
|
'filename': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
|
@ -65,10 +65,7 @@ UPLOAD_SCHEMA = {
|
||||||
'pattern': FILE_PATH_PATTERN,
|
'pattern': FILE_PATH_PATTERN,
|
||||||
},
|
},
|
||||||
'object_type': {'type': 'string'},
|
'object_type': {'type': 'string'},
|
||||||
'properties': {
|
'properties': {'type': 'object', 'additionalProperties': {'type': 'string'}},
|
||||||
'type': 'object',
|
|
||||||
'additionalProperties': {'type': 'string'}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
'required': ['file', 'path'],
|
'required': ['file', 'path'],
|
||||||
'unflatten': True,
|
'unflatten': True,
|
||||||
|
@ -77,8 +74,8 @@ UPLOAD_SCHEMA = {
|
||||||
|
|
||||||
class CmisConnector(BaseResource):
|
class CmisConnector(BaseResource):
|
||||||
cmis_endpoint = models.URLField(
|
cmis_endpoint = models.URLField(
|
||||||
max_length=400, verbose_name=_('CMIS Atom endpoint'),
|
max_length=400, verbose_name=_('CMIS Atom endpoint'), help_text=_('URL of the CMIS Atom endpoint')
|
||||||
help_text=_('URL of the CMIS Atom endpoint'))
|
)
|
||||||
username = models.CharField(max_length=128, verbose_name=_('Service username'))
|
username = models.CharField(max_length=128, verbose_name=_('Service username'))
|
||||||
password = models.CharField(max_length=128, verbose_name=_('Service password'))
|
password = models.CharField(max_length=128, verbose_name=_('Service password'))
|
||||||
category = _('Business Process Connectors')
|
category = _('Business Process Connectors')
|
||||||
|
@ -94,7 +91,8 @@ class CmisConnector(BaseResource):
|
||||||
'application/json': UPLOAD_SCHEMA,
|
'application/json': UPLOAD_SCHEMA,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
)
|
||||||
def uploadfile(self, request, post_data):
|
def uploadfile(self, request, post_data):
|
||||||
error, error_msg, data = self._validate_inputs(post_data)
|
error, error_msg, data = self._validate_inputs(post_data)
|
||||||
if error:
|
if error:
|
||||||
|
@ -114,7 +112,7 @@ class CmisConnector(BaseResource):
|
||||||
return {'data': {'properties': doc.properties}}
|
return {'data': {'properties': doc.properties}}
|
||||||
|
|
||||||
def _validate_inputs(self, data):
|
def _validate_inputs(self, data):
|
||||||
""" process dict
|
"""process dict
|
||||||
return a tuple (error, error_msg, data)
|
return a tuple (error, error_msg, data)
|
||||||
"""
|
"""
|
||||||
file_ = data['file']
|
file_ = data['file']
|
||||||
|
@ -149,11 +147,11 @@ def wrap_cmis_error(f):
|
||||||
raise APIError("invalid property name: %s" % e)
|
raise APIError("invalid property name: %s" % e)
|
||||||
except CmisException as e:
|
except CmisException as e:
|
||||||
raise APIError("cmis binding error: %s" % e)
|
raise APIError("cmis binding error: %s" % e)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
class CMISGateway(object):
|
class CMISGateway(object):
|
||||||
|
|
||||||
def __init__(self, cmis_endpoint, username, password, logger):
|
def __init__(self, cmis_endpoint, username, password, logger):
|
||||||
self._cmis_client = CmisClient(cmis_endpoint, username, password)
|
self._cmis_client = CmisClient(cmis_endpoint, username, password)
|
||||||
self._logger = logger
|
self._logger = logger
|
||||||
|
@ -182,11 +180,13 @@ class CMISGateway(object):
|
||||||
return folder
|
return folder
|
||||||
|
|
||||||
@wrap_cmis_error
|
@wrap_cmis_error
|
||||||
def create_doc(self, file_name, file_path, file_byte_content,
|
def create_doc(
|
||||||
content_type=None, object_type=None, properties=None):
|
self, file_name, file_path, file_byte_content, content_type=None, object_type=None, properties=None
|
||||||
|
):
|
||||||
folder = self._get_or_create_folder(file_path)
|
folder = self._get_or_create_folder(file_path)
|
||||||
properties = properties or {}
|
properties = properties or {}
|
||||||
if object_type:
|
if object_type:
|
||||||
properties['cmis:objectTypeId'] = object_type
|
properties['cmis:objectTypeId'] = object_type
|
||||||
return folder.createDocument(file_name, contentFile=BytesIO(file_byte_content),
|
return folder.createDocument(
|
||||||
contentType=content_type, properties=properties)
|
file_name, contentFile=BytesIO(file_byte_content), contentType=content_type, properties=properties
|
||||||
|
)
|
||||||
|
|
|
@ -19,6 +19,5 @@ from django.conf.urls import include, url
|
||||||
from .views import CmisTypeView
|
from .views import CmisTypeView
|
||||||
|
|
||||||
management_urlpatterns = [
|
management_urlpatterns = [
|
||||||
url(r'^(?P<connector_slug>[\w,-]+)/type/$',
|
url(r'^(?P<connector_slug>[\w,-]+)/type/$', CmisTypeView.as_view(), name='cmis-type'),
|
||||||
CmisTypeView.as_view(), name='cmis-type'),
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -30,8 +30,7 @@ class CmisTypeView(TemplateView):
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.connector = CmisConnector.objects.get(slug=kwargs['connector_slug'])
|
self.connector = CmisConnector.objects.get(slug=kwargs['connector_slug'])
|
||||||
client = CmisClient(self.connector.cmis_endpoint, self.connector.username,
|
client = CmisClient(self.connector.cmis_endpoint, self.connector.username, self.connector.password)
|
||||||
self.connector.password)
|
|
||||||
self.repo = client.getDefaultRepository()
|
self.repo = client.getDefaultRepository()
|
||||||
|
|
||||||
type_id = request.GET.get('id')
|
type_id = request.GET.get('id')
|
||||||
|
|
|
@ -20,7 +20,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CryptedFile',
|
name='CryptedFile',
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
(
|
||||||
|
'uuid',
|
||||||
|
models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False),
|
||||||
|
),
|
||||||
('filename', models.CharField(max_length=512)),
|
('filename', models.CharField(max_length=512)),
|
||||||
('content_type', models.CharField(max_length=128)),
|
('content_type', models.CharField(max_length=128)),
|
||||||
('creation_timestamp', models.DateTimeField(auto_now_add=True)),
|
('creation_timestamp', models.DateTimeField(auto_now_add=True)),
|
||||||
|
@ -29,14 +32,44 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Cryptor',
|
name='Cryptor',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('title', models.CharField(max_length=50, verbose_name='Title')),
|
('title', models.CharField(max_length=50, verbose_name='Title')),
|
||||||
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
|
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('public_key', models.TextField(blank=True, validators=[passerelle.apps.cryptor.models.validate_rsa_key], verbose_name='Encryption RSA public key (PEM format)')),
|
(
|
||||||
('private_key', models.TextField(blank=True, validators=[passerelle.apps.cryptor.models.validate_rsa_key], verbose_name='Decryption RSA private key (PEM format)')),
|
'public_key',
|
||||||
('redirect_url_base', models.URLField(blank=True, help_text='Base URL for redirect, empty for local', max_length=256, verbose_name='Base URL of decryption system')),
|
models.TextField(
|
||||||
('users', models.ManyToManyField(blank=True, related_name='_cryptor_users_+', related_query_name='+', to='base.ApiUser')),
|
blank=True,
|
||||||
|
validators=[passerelle.apps.cryptor.models.validate_rsa_key],
|
||||||
|
verbose_name='Encryption RSA public key (PEM format)',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'private_key',
|
||||||
|
models.TextField(
|
||||||
|
blank=True,
|
||||||
|
validators=[passerelle.apps.cryptor.models.validate_rsa_key],
|
||||||
|
verbose_name='Decryption RSA private key (PEM format)',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'redirect_url_base',
|
||||||
|
models.URLField(
|
||||||
|
blank=True,
|
||||||
|
help_text='Base URL for redirect, empty for local',
|
||||||
|
max_length=256,
|
||||||
|
verbose_name='Base URL of decryption system',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True, related_name='_cryptor_users_+', related_query_name='+', to='base.ApiUser'
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Encryption / Decryption',
|
'verbose_name': 'Encryption / Decryption',
|
||||||
|
|
|
@ -52,15 +52,16 @@ FILE_SCHEMA = {
|
||||||
"filename": {"type": "string"},
|
"filename": {"type": "string"},
|
||||||
"content_type": {"type": "string"},
|
"content_type": {"type": "string"},
|
||||||
"content": {"type": "string"},
|
"content": {"type": "string"},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# encrypt and decrypt are borrowed from
|
# encrypt and decrypt are borrowed from
|
||||||
# https://www.pycryptodome.org/en/latest/src/examples.html#encrypt-data-with-rsa
|
# https://www.pycryptodome.org/en/latest/src/examples.html#encrypt-data-with-rsa
|
||||||
|
|
||||||
|
|
||||||
def write_encrypt(out_file, data, key_pem):
|
def write_encrypt(out_file, data, key_pem):
|
||||||
public_key = RSA.import_key(key_pem)
|
public_key = RSA.import_key(key_pem)
|
||||||
session_key = get_random_bytes(16)
|
session_key = get_random_bytes(16)
|
||||||
|
@ -115,15 +116,18 @@ def validate_rsa_key(key):
|
||||||
|
|
||||||
|
|
||||||
class Cryptor(BaseResource):
|
class Cryptor(BaseResource):
|
||||||
public_key = models.TextField(blank=True,
|
public_key = models.TextField(
|
||||||
verbose_name=_('Encryption RSA public key (PEM format)'),
|
blank=True, verbose_name=_('Encryption RSA public key (PEM format)'), validators=[validate_rsa_key]
|
||||||
validators=[validate_rsa_key])
|
)
|
||||||
private_key = models.TextField(blank=True,
|
private_key = models.TextField(
|
||||||
verbose_name=_('Decryption RSA private key (PEM format)'),
|
blank=True, verbose_name=_('Decryption RSA private key (PEM format)'), validators=[validate_rsa_key]
|
||||||
validators=[validate_rsa_key])
|
)
|
||||||
redirect_url_base = models.URLField(max_length=256, blank=True,
|
redirect_url_base = models.URLField(
|
||||||
verbose_name=_('Base URL of decryption system'),
|
max_length=256,
|
||||||
help_text=_('Base URL for redirect, empty for local'))
|
blank=True,
|
||||||
|
verbose_name=_('Base URL of decryption system'),
|
||||||
|
help_text=_('Base URL for redirect, empty for local'),
|
||||||
|
)
|
||||||
|
|
||||||
category = _('Misc')
|
category = _('Misc')
|
||||||
|
|
||||||
|
@ -136,20 +140,23 @@ class Cryptor(BaseResource):
|
||||||
return _('this file-decrypt endpoint')
|
return _('this file-decrypt endpoint')
|
||||||
|
|
||||||
def get_filename(self, uuid, create=False):
|
def get_filename(self, uuid, create=False):
|
||||||
dirname = os.path.join(default_storage.path(self.get_connector_slug()),
|
dirname = os.path.join(
|
||||||
self.slug, uuid[0:2], uuid[2:4])
|
default_storage.path(self.get_connector_slug()), self.slug, uuid[0:2], uuid[2:4]
|
||||||
|
)
|
||||||
if create:
|
if create:
|
||||||
makedir(dirname)
|
makedir(dirname)
|
||||||
filename = os.path.join(dirname, uuid)
|
filename = os.path.join(dirname, uuid)
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
|
@endpoint(
|
||||||
@endpoint(name='file-encrypt', perm='can_encrypt',
|
name='file-encrypt',
|
||||||
description=_('Encrypt a file'),
|
perm='can_encrypt',
|
||||||
post={
|
description=_('Encrypt a file'),
|
||||||
'description': _('File to encrypt'),
|
post={
|
||||||
'request_body': {'schema': {'application/json': FILE_SCHEMA}}
|
'description': _('File to encrypt'),
|
||||||
})
|
'request_body': {'schema': {'application/json': FILE_SCHEMA}},
|
||||||
|
},
|
||||||
|
)
|
||||||
def file_encrypt(self, request, post_data):
|
def file_encrypt(self, request, post_data):
|
||||||
if not self.public_key:
|
if not self.public_key:
|
||||||
raise APIError('missing public key')
|
raise APIError('missing public key')
|
||||||
|
@ -168,8 +175,7 @@ class Cryptor(BaseResource):
|
||||||
if self.redirect_url_base:
|
if self.redirect_url_base:
|
||||||
redirect_url_base = self.redirect_url_base
|
redirect_url_base = self.redirect_url_base
|
||||||
else:
|
else:
|
||||||
redirect_url_base = request.build_absolute_uri('%sfile-decrypt/' % (
|
redirect_url_base = request.build_absolute_uri('%sfile-decrypt/' % (self.get_absolute_url(),))
|
||||||
self.get_absolute_url(),))
|
|
||||||
redirect_url = urljoin(redirect_url_base, uuid)
|
redirect_url = urljoin(redirect_url_base, uuid)
|
||||||
|
|
||||||
content_filename = self.get_filename(uuid, create=True)
|
content_filename = self.get_filename(uuid, create=True)
|
||||||
|
@ -189,16 +195,19 @@ class Cryptor(BaseResource):
|
||||||
|
|
||||||
return {'data': metadata}
|
return {'data': metadata}
|
||||||
|
|
||||||
@endpoint(name='file-decrypt', perm='can_decrypt',
|
@endpoint(
|
||||||
description=_('Decrypt a file'),
|
name='file-decrypt',
|
||||||
pattern=r'(?P<uuid>[\w-]+)$',
|
perm='can_decrypt',
|
||||||
example_pattern='{uuid}/',
|
description=_('Decrypt a file'),
|
||||||
parameters={
|
pattern=r'(?P<uuid>[\w-]+)$',
|
||||||
'uuid': {
|
example_pattern='{uuid}/',
|
||||||
'description': _('File identifier'),
|
parameters={
|
||||||
'example_value': '12345678-abcd-4321-abcd-123456789012',
|
'uuid': {
|
||||||
},
|
'description': _('File identifier'),
|
||||||
})
|
'example_value': '12345678-abcd-4321-abcd-123456789012',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
def file_decrypt(self, request, uuid):
|
def file_decrypt(self, request, uuid):
|
||||||
if not self.private_key:
|
if not self.private_key:
|
||||||
raise APIError('missing private key')
|
raise APIError('missing private key')
|
||||||
|
|
|
@ -16,12 +16,15 @@
|
||||||
|
|
||||||
import django.apps
|
import django.apps
|
||||||
|
|
||||||
|
|
||||||
class AppConfig(django.apps.AppConfig):
|
class AppConfig(django.apps.AppConfig):
|
||||||
name = 'passerelle.apps.csvdatasource'
|
name = 'passerelle.apps.csvdatasource'
|
||||||
label = 'csvdatasource'
|
label = 'csvdatasource'
|
||||||
|
|
||||||
def get_connector_model(self):
|
def get_connector_model(self):
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
return models.CsvDataSource
|
return models.CsvDataSource
|
||||||
|
|
||||||
|
|
||||||
default_app_config = 'passerelle.apps.csvdatasource.AppConfig'
|
default_app_config = 'passerelle.apps.csvdatasource.AppConfig'
|
||||||
|
|
|
@ -41,25 +41,38 @@ class QueryForm(forms.ModelForm):
|
||||||
if named:
|
if named:
|
||||||
line = line.split(':', 1)
|
line = line.split(':', 1)
|
||||||
if len(line) != 2:
|
if len(line) != 2:
|
||||||
errors.append(ValidationError(
|
errors.append(
|
||||||
_('Syntax error line %d: each line must be prefixed '
|
ValidationError(
|
||||||
'with an identifier followed by a colon.') % (i + 1)))
|
_(
|
||||||
|
'Syntax error line %d: each line must be prefixed '
|
||||||
|
'with an identifier followed by a colon.'
|
||||||
|
)
|
||||||
|
% (i + 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
name, line = line
|
name, line = line
|
||||||
if not identifier_re.match(name):
|
if not identifier_re.match(name):
|
||||||
errors.append(
|
errors.append(
|
||||||
ValidationError(_('Syntax error line %d: invalid identifier, '
|
ValidationError(
|
||||||
'it must starts with a letter and only '
|
_(
|
||||||
'contains letters, digits and _.') % (i + 1)))
|
'Syntax error line %d: invalid identifier, '
|
||||||
|
'it must starts with a letter and only '
|
||||||
|
'contains letters, digits and _.'
|
||||||
|
)
|
||||||
|
% (i + 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
get_code(line)
|
get_code(line)
|
||||||
except SyntaxError as e:
|
except SyntaxError as e:
|
||||||
errors.append(ValidationError(
|
errors.append(
|
||||||
_('Syntax error line %(line)d at character %(character)d') % {
|
ValidationError(
|
||||||
'line': i + 1,
|
_('Syntax error line %(line)d at character %(character)d')
|
||||||
'character': e.offset
|
% {'line': i + 1, 'character': e.offset}
|
||||||
}))
|
)
|
||||||
|
)
|
||||||
if errors:
|
if errors:
|
||||||
raise ValidationError(errors)
|
raise ValidationError(errors)
|
||||||
return lines
|
return lines
|
||||||
|
|
|
@ -14,19 +14,41 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CsvDataSource',
|
name='CsvDataSource',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('title', models.CharField(verbose_name='Title', max_length=50)),
|
('title', models.CharField(verbose_name='Title', max_length=50)),
|
||||||
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
('slug', models.SlugField(verbose_name='Identifier', unique=True)),
|
||||||
('description', models.TextField(verbose_name='Description')),
|
('description', models.TextField(verbose_name='Description')),
|
||||||
('csv_file', models.FileField(help_text='Supported file formats: csv, ods, xls, xlsx',
|
(
|
||||||
upload_to=b'csv', verbose_name='Spreadsheet file')),
|
'csv_file',
|
||||||
('columns_keynames', models.CharField(default=b'id, text',
|
models.FileField(
|
||||||
help_text='ex: id,text,data1,data2',
|
help_text='Supported file formats: csv, ods, xls, xlsx',
|
||||||
max_length=256,
|
upload_to=b'csv',
|
||||||
verbose_name='Column keynames',
|
verbose_name='Spreadsheet file',
|
||||||
blank=True)),
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'columns_keynames',
|
||||||
|
models.CharField(
|
||||||
|
default=b'id, text',
|
||||||
|
help_text='ex: id,text,data1,data2',
|
||||||
|
max_length=256,
|
||||||
|
verbose_name='Column keynames',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
('skip_header', models.BooleanField(default=False, verbose_name='Skip first line')),
|
('skip_header', models.BooleanField(default=False, verbose_name='Skip first line')),
|
||||||
('users', models.ManyToManyField(to='base.ApiUser', related_name='_csvdatasource_users_+', related_query_name='+', blank=True)),
|
(
|
||||||
|
'users',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='base.ApiUser',
|
||||||
|
related_name='_csvdatasource_users_+',
|
||||||
|
related_query_name='+',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'CSV File',
|
'verbose_name': 'CSV File',
|
||||||
|
|
|
@ -14,7 +14,13 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='csvdatasource',
|
model_name='csvdatasource',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Debug Enabled', blank=True, choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Debug Enabled',
|
||||||
|
blank=True,
|
||||||
|
choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,7 +14,12 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='csvdatasource',
|
model_name='csvdatasource',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[(b'DEBUG', b'DEBUG'), (b'INFO', b'INFO')],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,7 +14,19 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='csvdatasource',
|
model_name='csvdatasource',
|
||||||
name='log_level',
|
name='log_level',
|
||||||
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')]),
|
field=models.CharField(
|
||||||
|
default=b'NOTSET',
|
||||||
|
max_length=10,
|
||||||
|
verbose_name='Log Level',
|
||||||
|
choices=[
|
||||||
|
(b'NOTSET', b'NOTSET'),
|
||||||
|
(b'DEBUG', b'DEBUG'),
|
||||||
|
(b'INFO', b'INFO'),
|
||||||
|
(b'WARNING', b'WARNING'),
|
||||||
|
(b'ERROR', b'ERROR'),
|
||||||
|
(b'CRITICAL', b'CRITICAL'),
|
||||||
|
],
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,13 +14,54 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Query',
|
name='Query',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),
|
||||||
|
),
|
||||||
('slug', models.SlugField(verbose_name='Name')),
|
('slug', models.SlugField(verbose_name='Name')),
|
||||||
('filters', models.TextField(help_text='List of filter clauses (Python expression)', verbose_name='Filters', blank=True)),
|
(
|
||||||
('projections', models.TextField(help_text='List of projections (name:expression)', verbose_name='Projections', blank=True)),
|
'filters',
|
||||||
('order', models.TextField(help_text='Columns to use for sorting rows', verbose_name='Sort Order', blank=True)),
|
models.TextField(
|
||||||
('distinct', models.TextField(help_text='Distinct columns', verbose_name='Distinct', blank=True)),
|
help_text='List of filter clauses (Python expression)',
|
||||||
('structure', models.CharField(choices=[(b'array', 'Array'), (b'dict', 'Dictionary'), (b'keyed-distinct', 'Keyed Dictionary'), (b'tuples', 'Tuples'), (b'onerow', 'Single Row'), (b'one', 'Single Value')], default=b'dict', help_text='Data structure used for the response', max_length=20, verbose_name='Structure')),
|
verbose_name='Filters',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'projections',
|
||||||
|
models.TextField(
|
||||||
|
help_text='List of projections (name:expression)',
|
||||||
|
verbose_name='Projections',
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'order',
|
||||||
|
models.TextField(
|
||||||
|
help_text='Columns to use for sorting rows', verbose_name='Sort Order', blank=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'distinct',
|
||||||
|
models.TextField(help_text='Distinct columns', verbose_name='Distinct', blank=True),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'structure',
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
(b'array', 'Array'),
|
||||||
|
(b'dict', 'Dictionary'),
|
||||||
|
(b'keyed-distinct', 'Keyed Dictionary'),
|
||||||
|
(b'tuples', 'Tuples'),
|
||||||
|
(b'onerow', 'Single Row'),
|
||||||
|
(b'one', 'Single Value'),
|
||||||
|
],
|
||||||
|
default=b'dict',
|
||||||
|
help_text='Data structure used for the response',
|
||||||
|
max_length=20,
|
||||||
|
verbose_name='Structure',
|
||||||
|
),
|
||||||
|
),
|
||||||
('resource', models.ForeignKey(to='csvdatasource.CsvDataSource', on_delete=models.CASCADE)),
|
('resource', models.ForeignKey(to='csvdatasource.CsvDataSource', on_delete=models.CASCADE)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
|
|
|
@ -17,7 +17,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='TableRow',
|
name='TableRow',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
|
'id',
|
||||||
|
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
('line_number', models.IntegerField()),
|
('line_number', models.IntegerField()),
|
||||||
('data', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=dict)),
|
('data', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=dict)),
|
||||||
],
|
],
|
||||||
|
@ -28,6 +31,8 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='tablerow',
|
model_name='tablerow',
|
||||||
name='resource',
|
name='resource',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='csvdatasource.CsvDataSource'),
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to='csvdatasource.CsvDataSource'
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -8,7 +8,9 @@ def generate_slug(instance):
|
||||||
slug = instance.slug
|
slug = instance.slug
|
||||||
i = 1
|
i = 1
|
||||||
while True:
|
while True:
|
||||||
queryset = instance._meta.model.objects.filter(slug=slug, resource=instance.resource).exclude(pk=instance.pk)
|
queryset = instance._meta.model.objects.filter(slug=slug, resource=instance.resource).exclude(
|
||||||
|
pk=instance.pk
|
||||||
|
)
|
||||||
if not queryset.exists():
|
if not queryset.exists():
|
||||||
break
|
break
|
||||||
slug = '%s-%s' % (instance.slug, i)
|
slug = '%s-%s' % (instance.slug, i)
|
||||||
|
|
|
@ -16,21 +16,48 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='csvdatasource',
|
model_name='csvdatasource',
|
||||||
name='columns_keynames',
|
name='columns_keynames',
|
||||||
field=models.CharField(blank=True, default='id, text', help_text='ex: id,text,data1,data2', max_length=256, verbose_name='Column keynames'),
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default='id, text',
|
||||||
|
help_text='ex: id,text,data1,data2',
|
||||||
|
max_length=256,
|
||||||
|
verbose_name='Column keynames',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='csvdatasource',
|
model_name='csvdatasource',
|
||||||
name='csv_file',
|
name='csv_file',
|
||||||
field=models.FileField(help_text='Supported file formats: csv, ods, xls, xlsx', upload_to='csv', verbose_name='Spreadsheet file'),
|
field=models.FileField(
|
||||||
|
help_text='Supported file formats: csv, ods, xls, xlsx',
|
||||||
|
upload_to='csv',
|
||||||
|
verbose_name='Spreadsheet file',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='query',
|
model_name='query',
|
||||||
name='resource',
|
name='resource',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='queries', to='csvdatasource.CsvDataSource'),
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name='queries',
|
||||||
|
to='csvdatasource.CsvDataSource',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='query',
|
model_name='query',
|
||||||
name='structure',
|
name='structure',
|
||||||
field=models.CharField(choices=[('array', 'Array'), ('dict', 'Dictionary'), ('keyed-distinct', 'Keyed Dictionary'), ('tuples', 'Tuples'), ('onerow', 'Single Row'), ('one', 'Single Value')], default='dict', help_text='Data structure used for the response', max_length=20, verbose_name='Structure'),
|
field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
('array', 'Array'),
|
||||||
|
('dict', 'Dictionary'),
|
||||||
|
('keyed-distinct', 'Keyed Dictionary'),
|
||||||
|
('tuples', 'Tuples'),
|
||||||
|
('onerow', 'Single Row'),
|
||||||
|
('one', 'Single Value'),
|
||||||
|
],
|
||||||
|
default='dict',
|
||||||
|
help_text='Data structure used for the response',
|
||||||
|
max_length=20,
|
||||||
|
verbose_name='Structure',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -15,6 +15,10 @@ class Migration(migrations.Migration):
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='csvdatasource',
|
model_name='csvdatasource',
|
||||||
name='csv_file',
|
name='csv_file',
|
||||||
field=models.FileField(help_text='Supported file formats: csv, ods, xls, xlsx', upload_to=passerelle.apps.csvdatasource.models.upload_to, verbose_name='Spreadsheet file'),
|
field=models.FileField(
|
||||||
|
help_text='Supported file formats: csv, ods, xls, xlsx',
|
||||||
|
upload_to=passerelle.apps.csvdatasource.models.upload_to,
|
||||||
|
verbose_name='Spreadsheet file',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -52,7 +52,7 @@ code_cache = OrderedDict()
|
||||||
def get_code(expr):
|
def get_code(expr):
|
||||||
# limit size of code cache to 1024
|
# limit size of code cache to 1024
|
||||||
if len(code_cache) > 1024:
|
if len(code_cache) > 1024:
|
||||||
for key in list(code_cache.keys())[:len(code_cache) - 1024]:
|
for key in list(code_cache.keys())[: len(code_cache) - 1024]:
|
||||||
code_cache.pop(key)
|
code_cache.pop(key)
|
||||||
if expr not in code_cache:
|
if expr not in code_cache:
|
||||||
code_cache[expr] = compile(expr, '<inline>', 'eval')
|
code_cache[expr] = compile(expr, '<inline>', 'eval')
|
||||||
|
@ -65,21 +65,13 @@ class Query(models.Model):
|
||||||
label = models.CharField(_('Label'), max_length=100)
|
label = models.CharField(_('Label'), max_length=100)
|
||||||
description = models.TextField(_('Description'), blank=True)
|
description = models.TextField(_('Description'), blank=True)
|
||||||
filters = models.TextField(
|
filters = models.TextField(
|
||||||
_('Filters'),
|
_('Filters'), blank=True, help_text=_('List of filter clauses (Python expression)')
|
||||||
blank=True,
|
)
|
||||||
help_text=_('List of filter clauses (Python expression)'))
|
order = models.TextField(_('Sort Order'), blank=True, help_text=_('Columns to use for sorting rows'))
|
||||||
order = models.TextField(
|
distinct = models.TextField(_('Distinct'), blank=True, help_text=_('Distinct columns'))
|
||||||
_('Sort Order'),
|
|
||||||
blank=True,
|
|
||||||
help_text=_('Columns to use for sorting rows'))
|
|
||||||
distinct = models.TextField(
|
|
||||||
_('Distinct'),
|
|
||||||
blank=True,
|
|
||||||
help_text=_('Distinct columns'))
|
|
||||||
projections = models.TextField(
|
projections = models.TextField(
|
||||||
_('Projections'),
|
_('Projections'), blank=True, help_text=_('List of projections (name:expression)')
|
||||||
blank=True,
|
)
|
||||||
help_text=_('List of projections (name:expression)'))
|
|
||||||
structure = models.CharField(
|
structure = models.CharField(
|
||||||
_('Structure'),
|
_('Structure'),
|
||||||
max_length=20,
|
max_length=20,
|
||||||
|
@ -89,9 +81,11 @@ class Query(models.Model):
|
||||||
('keyed-distinct', _('Keyed Dictionary')),
|
('keyed-distinct', _('Keyed Dictionary')),
|
||||||
('tuples', _('Tuples')),
|
('tuples', _('Tuples')),
|
||||||
('onerow', _('Single Row')),
|
('onerow', _('Single Row')),
|
||||||
('one', _('Single Value'))],
|
('one', _('Single Value')),
|
||||||
|
],
|
||||||
default='dict',
|
default='dict',
|
||||||
help_text=_('Data structure used for the response'))
|
help_text=_('Data structure used for the response'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['slug']
|
ordering = ['slug']
|
||||||
|
@ -123,12 +117,10 @@ class Query(models.Model):
|
||||||
return self.slug
|
return self.slug
|
||||||
|
|
||||||
def delete_url(self):
|
def delete_url(self):
|
||||||
return reverse('csv-delete-query',
|
return reverse('csv-delete-query', kwargs={'connector_slug': self.resource.slug, 'pk': self.pk})
|
||||||
kwargs={'connector_slug': self.resource.slug, 'pk': self.pk})
|
|
||||||
|
|
||||||
def edit_url(self):
|
def edit_url(self):
|
||||||
return reverse('csv-edit-query',
|
return reverse('csv-edit-query', kwargs={'connector_slug': self.resource.slug, 'pk': self.pk})
|
||||||
kwargs={'connector_slug': self.resource.slug, 'pk': self.pk})
|
|
||||||
|
|
||||||
|
|
||||||
def upload_to(instance, filename):
|
def upload_to(instance, filename):
|
||||||
|
@ -137,20 +129,23 @@ def upload_to(instance, filename):
|
||||||
|
|
||||||
class CsvDataSource(BaseResource):
|
class CsvDataSource(BaseResource):
|
||||||
csv_file = models.FileField(
|
csv_file = models.FileField(
|
||||||
_('Spreadsheet file'),
|
_('Spreadsheet file'), upload_to=upload_to, help_text=_('Supported file formats: csv, ods, xls, xlsx')
|
||||||
upload_to=upload_to,
|
)
|
||||||
help_text=_('Supported file formats: csv, ods, xls, xlsx'))
|
|
||||||
columns_keynames = models.CharField(
|
columns_keynames = models.CharField(
|
||||||
max_length=256,
|
max_length=256,
|
||||||
verbose_name=_('Column keynames'),
|
verbose_name=_('Column keynames'),
|
||||||
default='id, text',
|
default='id, text',
|
||||||
help_text=_('ex: id,text,data1,data2'), blank=True)
|
help_text=_('ex: id,text,data1,data2'),
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
skip_header = models.BooleanField(_('Skip first line'), default=False)
|
skip_header = models.BooleanField(_('Skip first line'), default=False)
|
||||||
_dialect_options = JSONField(editable=False, null=True)
|
_dialect_options = JSONField(editable=False, null=True)
|
||||||
sheet_name = models.CharField(_('Sheet name'), blank=True, max_length=150)
|
sheet_name = models.CharField(_('Sheet name'), blank=True, max_length=150)
|
||||||
|
|
||||||
category = _('Data Sources')
|
category = _('Data Sources')
|
||||||
documentation_url = 'https://doc-publik.entrouvert.com/admin-fonctionnel/parametrage-avance/source-de-donnees-csv/'
|
documentation_url = (
|
||||||
|
'https://doc-publik.entrouvert.com/admin-fonctionnel/parametrage-avance/source-de-donnees-csv/'
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Spreadsheet File')
|
verbose_name = _('Spreadsheet File')
|
||||||
|
@ -173,9 +168,7 @@ class CsvDataSource(BaseResource):
|
||||||
def _detect_dialect_options(self):
|
def _detect_dialect_options(self):
|
||||||
content = self.get_content_without_bom()
|
content = self.get_content_without_bom()
|
||||||
dialect = csv.Sniffer().sniff(content)
|
dialect = csv.Sniffer().sniff(content)
|
||||||
self.dialect_options = {
|
self.dialect_options = {k: v for k, v in vars(dialect).items() if not k.startswith('_')}
|
||||||
k: v for k, v in vars(dialect).items() if not k.startswith('_')
|
|
||||||
}
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
cache = kwargs.pop('cache', True)
|
cache = kwargs.pop('cache', True)
|
||||||
|
@ -193,7 +186,8 @@ class CsvDataSource(BaseResource):
|
||||||
TableRow.objects.filter(resource=self).delete()
|
TableRow.objects.filter(resource=self).delete()
|
||||||
for block in batch(enumerate(self.get_rows()), 5000):
|
for block in batch(enumerate(self.get_rows()), 5000):
|
||||||
TableRow.objects.bulk_create(
|
TableRow.objects.bulk_create(
|
||||||
TableRow(resource=self, line_number=i, data=data) for i, data in block)
|
TableRow(resource=self, line_number=i, data=data) for i, data in block
|
||||||
|
)
|
||||||
|
|
||||||
def csv_file_datetime(self):
|
def csv_file_datetime(self):
|
||||||
ctime = os.fstat(self.csv_file.fileno()).st_ctime
|
ctime = os.fstat(self.csv_file.fileno()).st_ctime
|
||||||
|
@ -205,8 +199,7 @@ class CsvDataSource(BaseResource):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def dialect_options(self):
|
def dialect_options(self):
|
||||||
"""turn dict items into string
|
"""turn dict items into string"""
|
||||||
"""
|
|
||||||
file_type = self.csv_file.name.split('.')[-1]
|
file_type = self.csv_file.name.split('.')[-1]
|
||||||
if file_type in ('ods', 'xls', 'xlsx'):
|
if file_type in ('ods', 'xls', 'xlsx'):
|
||||||
return None
|
return None
|
||||||
|
@ -317,8 +310,7 @@ class CsvDataSource(BaseResource):
|
||||||
query = Query(filters='\n'.join(filters))
|
query = Query(filters='\n'.join(filters))
|
||||||
return self.execute_query(request, query, query_params=params.dict())
|
return self.execute_query(request, query, query_params=params.dict())
|
||||||
|
|
||||||
@endpoint(perm='can_access', methods=['get'],
|
@endpoint(perm='can_access', methods=['get'], name='query', pattern=r'^(?P<query_name>[\w-]+)/$')
|
||||||
name='query', pattern=r'^(?P<query_name>[\w-]+)/$')
|
|
||||||
def select(self, request, query_name, **kwargs):
|
def select(self, request, query_name, **kwargs):
|
||||||
try:
|
try:
|
||||||
query = Query.objects.get(resource=self.id, slug=query_name)
|
query = Query.objects.get(resource=self.id, slug=query_name)
|
||||||
|
@ -371,8 +363,7 @@ class CsvDataSource(BaseResource):
|
||||||
filters = query.get_list('filters')
|
filters = query.get_list('filters')
|
||||||
|
|
||||||
if filters:
|
if filters:
|
||||||
data = [row for new_row, row in stream_expressions(filters, data, kind='filters')
|
data = [row for new_row, row in stream_expressions(filters, data, kind='filters') if all(new_row)]
|
||||||
if all(new_row)]
|
|
||||||
|
|
||||||
order = query.get_list('order')
|
order = query.get_list('order')
|
||||||
if order:
|
if order:
|
||||||
|
@ -391,11 +382,13 @@ class CsvDataSource(BaseResource):
|
||||||
try:
|
try:
|
||||||
hash(new_row)
|
hash(new_row)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
raise APIError(u'distinct value is unhashable',
|
raise APIError(
|
||||||
data={
|
u'distinct value is unhashable',
|
||||||
'row': repr(row),
|
data={
|
||||||
'distinct': repr(new_row),
|
'row': repr(row),
|
||||||
})
|
'distinct': repr(new_row),
|
||||||
|
},
|
||||||
|
)
|
||||||
if new_row in seen:
|
if new_row in seen:
|
||||||
continue
|
continue
|
||||||
new_data.append(row)
|
new_data.append(row)
|
||||||
|
@ -413,24 +406,21 @@ class CsvDataSource(BaseResource):
|
||||||
titles.append(name)
|
titles.append(name)
|
||||||
expressions.append(expr)
|
expressions.append(expr)
|
||||||
new_data = []
|
new_data = []
|
||||||
for new_row, row in stream_expressions(expressions, data, kind='projection',
|
for new_row, row in stream_expressions(expressions, data, kind='projection', titles=titles):
|
||||||
titles=titles):
|
|
||||||
new_data.append(dict(zip(titles, new_row)))
|
new_data.append(dict(zip(titles, new_row)))
|
||||||
data = new_data
|
data = new_data
|
||||||
|
|
||||||
if 'id' in request.GET:
|
if 'id' in request.GET:
|
||||||
# always provide a ?id= filter.
|
# always provide a ?id= filter.
|
||||||
filters = ["id == %r" % force_text(request.GET['id'])]
|
filters = ["id == %r" % force_text(request.GET['id'])]
|
||||||
data = [row for new_row, row in stream_expressions(filters, data, kind='filters')
|
data = [row for new_row, row in stream_expressions(filters, data, kind='filters') if new_row[0]]
|
||||||
if new_row[0]]
|
|
||||||
|
|
||||||
# allow jsonp queries by select2
|
# allow jsonp queries by select2
|
||||||
# filtering is done there after projection because we need a projection named text for
|
# filtering is done there after projection because we need a projection named text for
|
||||||
# retro-compatibility with previous use of the csvdatasource with select2
|
# retro-compatibility with previous use of the csvdatasource with select2
|
||||||
if 'q' in request.GET:
|
if 'q' in request.GET:
|
||||||
filters = ["%s in normalize(text.lower())" % repr(normalize(request.GET['q'].lower()))]
|
filters = ["%s in normalize(text.lower())" % repr(normalize(request.GET['q'].lower()))]
|
||||||
data = [row for new_row, row in stream_expressions(filters, data, kind='filters')
|
data = [row for new_row, row in stream_expressions(filters, data, kind='filters') if new_row[0]]
|
||||||
if new_row[0]]
|
|
||||||
|
|
||||||
# force rendition of iterator as list
|
# force rendition of iterator as list
|
||||||
data = list(data)
|
data = list(data)
|
||||||
|
@ -450,7 +440,7 @@ class CsvDataSource(BaseResource):
|
||||||
raise APIError('invalid offset parameter')
|
raise APIError('invalid offset parameter')
|
||||||
|
|
||||||
# paginate data
|
# paginate data
|
||||||
data = data[offset:offset+limit]
|
data = data[offset : offset + limit]
|
||||||
|
|
||||||
if query.structure == 'array':
|
if query.structure == 'array':
|
||||||
return {'data': [[row[t] for t in titles] for row in data]}
|
return {'data': [[row[t] for t in titles] for row in data]}
|
||||||
|
@ -539,4 +529,4 @@ class TableRow(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('line_number',)
|
ordering = ('line_number',)
|
||||||
unique_together = (('resource', 'line_number'))
|
unique_together = ('resource', 'line_number')
|
||||||
|
|
|
@ -19,12 +19,16 @@ from django.conf.urls import include, url
|
||||||
from .views import *
|
from .views import *
|
||||||
|
|
||||||
management_urlpatterns = [
|
management_urlpatterns = [
|
||||||
url(r'^(?P<connector_slug>[\w,-]+)/download/$',
|
url(r'^(?P<connector_slug>[\w,-]+)/download/$', CsvDownload.as_view(), name='csv-download'),
|
||||||
CsvDownload.as_view(), name='csv-download'),
|
url(r'^(?P<connector_slug>[\w,-]+)/queries/new/$', NewQueryView.as_view(), name='csv-new-query'),
|
||||||
url(r'^(?P<connector_slug>[\w,-]+)/queries/new/$',
|
url(
|
||||||
NewQueryView.as_view(), name='csv-new-query'),
|
r'^(?P<connector_slug>[\w,-]+)/queries/(?P<pk>[\w,-]+)/$',
|
||||||
url(r'^(?P<connector_slug>[\w,-]+)/queries/(?P<pk>[\w,-]+)/$',
|
UpdateQueryView.as_view(),
|
||||||
UpdateQueryView.as_view(), name='csv-edit-query'),
|
name='csv-edit-query',
|
||||||
url(r'^(?P<connector_slug>[\w,-]+)/queries/(?P<pk>[\w,-]+)/delete$',
|
),
|
||||||
DeleteQueryView.as_view(), name='csv-delete-query'),
|
url(
|
||||||
|
r'^(?P<connector_slug>[\w,-]+)/queries/(?P<pk>[\w,-]+)/delete$',
|
||||||
|
DeleteQueryView.as_view(),
|
||||||
|
name='csv-delete-query',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -29,9 +29,11 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from ..models import Invoice
|
from ..models import Invoice
|
||||||
|
|
||||||
|
|
||||||
def u(s):
|
def u(s):
|
||||||
return force_text(s, 'iso-8859-15')
|
return force_text(s, 'iso-8859-15')
|
||||||
|
|
||||||
|
|
||||||
class Loader(object):
|
class Loader(object):
|
||||||
def __init__(self, connector):
|
def __init__(self, connector):
|
||||||
self.connector = connector
|
self.connector = connector
|
||||||
|
@ -45,6 +47,7 @@ class Loader(object):
|
||||||
fd = archive.open('data_full.csv')
|
fd = archive.open('data_full.csv')
|
||||||
if six.PY3:
|
if six.PY3:
|
||||||
import io
|
import io
|
||||||
|
|
||||||
fd = io.TextIOWrapper(fd, 'iso-8859-15')
|
fd = io.TextIOWrapper(fd, 'iso-8859-15')
|
||||||
csvfile = six.StringIO(fd.read())
|
csvfile = six.StringIO(fd.read())
|
||||||
csvreader = csv.reader(csvfile, delimiter='\t')
|
csvreader = csv.reader(csvfile, delimiter='\t')
|
||||||
|
@ -59,9 +62,11 @@ class Loader(object):
|
||||||
invoice['amount'] = str(Decimal(invoice['total_amount']) - paid_amount)
|
invoice['amount'] = str(Decimal(invoice['total_amount']) - paid_amount)
|
||||||
invoice['paid'] = bool(Decimal(invoice['amount']) == 0)
|
invoice['paid'] = bool(Decimal(invoice['amount']) == 0)
|
||||||
invoice['issue_date'] = datetime.datetime.strptime(
|
invoice['issue_date'] = datetime.datetime.strptime(
|
||||||
row['DAT_GENERATION_FAC'], '%d/%m/%Y').strftime('%Y-%m-%d')
|
row['DAT_GENERATION_FAC'], '%d/%m/%Y'
|
||||||
|
).strftime('%Y-%m-%d')
|
||||||
invoice['pay_limit_date'] = datetime.datetime.strptime(
|
invoice['pay_limit_date'] = datetime.datetime.strptime(
|
||||||
row['DAT_LIMITEPAIE_FAC'], '%d/%m/%Y').strftime('%Y-%m-%d')
|
row['DAT_LIMITEPAIE_FAC'], '%d/%m/%Y'
|
||||||
|
).strftime('%Y-%m-%d')
|
||||||
invoice['online_payment'] = True
|
invoice['online_payment'] = True
|
||||||
invoice['no_online_payment_reason'] = None
|
invoice['no_online_payment_reason'] = None
|
||||||
if not invoice['paid']:
|
if not invoice['paid']:
|
||||||
|
@ -73,10 +78,12 @@ class Loader(object):
|
||||||
invoice['online_payment'] = False
|
invoice['online_payment'] = False
|
||||||
invoice['no_online_payment_reason'] = 'autobilling'
|
invoice['no_online_payment_reason'] = 'autobilling'
|
||||||
|
|
||||||
obj, created = Invoice.objects.update_or_create(resource=self.connector,
|
obj, created = Invoice.objects.update_or_create(
|
||||||
external_id=row['ID_FAC'], defaults=invoice)
|
resource=self.connector, external_id=row['ID_FAC'], defaults=invoice
|
||||||
|
)
|
||||||
invoice_filename = '%s_%s.pdf' % (
|
invoice_filename = '%s_%s.pdf' % (
|
||||||
datetime.datetime.strptime(row['DAT_DEBUT_PGE'], '%d/%m/%Y').strftime('%Y-%m'),
|
datetime.datetime.strptime(row['DAT_DEBUT_PGE'], '%d/%m/%Y').strftime('%Y-%m'),
|
||||||
row['ID_FAC'])
|
row['ID_FAC'],
|
||||||
|
)
|
||||||
if invoice_filename in archive_files:
|
if invoice_filename in archive_files:
|
||||||
obj.write_pdf(archive.read(invoice_filename))
|
obj.write_pdf(archive.read(invoice_filename))
|
||||||
|
|
|
@ -52,7 +52,9 @@ def normalize_adult(adult):
|
||||||
def normalize_family(family, adults):
|
def normalize_family(family, adults):
|
||||||
return {
|
return {
|
||||||
'external_id': family['id_fam'],
|
'external_id': family['id_fam'],
|
||||||
'adults': [adults[family[id]] for id in ('id_per1', 'id_per2') if family[id] and adults.get(family[id])],
|
'adults': [
|
||||||
|
adults[family[id]] for id in ('id_per1', 'id_per2') if family[id] and adults.get(family[id])
|
||||||
|
],
|
||||||
'children': [],
|
'children': [],
|
||||||
'invoices': [],
|
'invoices': [],
|
||||||
'login': family['id_fam'],
|
'login': family['id_fam'],
|
||||||
|
@ -65,6 +67,7 @@ def normalize_family(family, adults):
|
||||||
'city': family['lib_commune_adr'],
|
'city': family['lib_commune_adr'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def normalize_child(child):
|
def normalize_child(child):
|
||||||
sex = child['typ_sexe_per']
|
sex = child['typ_sexe_per']
|
||||||
if sex == 'G':
|
if sex == 'G':
|
||||||
|
@ -74,27 +77,30 @@ def normalize_child(child):
|
||||||
'first_name': child['lib_prenom_per'],
|
'first_name': child['lib_prenom_per'],
|
||||||
'last_name': child['lib_nom_per'],
|
'last_name': child['lib_nom_per'],
|
||||||
'sex': sex,
|
'sex': sex,
|
||||||
'birthdate': get_date(child['dat_naissance'])
|
'birthdate': get_date(child['dat_naissance']),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def normalize_invoice(i):
|
def normalize_invoice(i):
|
||||||
invoice = {'external_id': i['id_fac'],
|
invoice = {
|
||||||
'label': i['id_fac'],
|
'external_id': i['id_fac'],
|
||||||
'total_amount': Decimal(i['mnt_facture_fac']),
|
'label': i['id_fac'],
|
||||||
'amount': Decimal(i['mnt_solde_fac']),
|
'total_amount': Decimal(i['mnt_facture_fac']),
|
||||||
'issue_date': i['dat_generation_fac'],
|
'amount': Decimal(i['mnt_solde_fac']),
|
||||||
'pay_limit_date': get_date(i['dat_limitepaie_fac']),
|
'issue_date': i['dat_generation_fac'],
|
||||||
'autobilling': i['on_prelevauto_ins'] == 'O',
|
'pay_limit_date': get_date(i['dat_limitepaie_fac']),
|
||||||
'online_payment': True,
|
'autobilling': i['on_prelevauto_ins'] == 'O',
|
||||||
'payment_date': get_datetime(i['dat_reglement']),
|
'online_payment': True,
|
||||||
'litigation_date': get_date(i['dat_perception_fac']),
|
'payment_date': get_datetime(i['dat_reglement']),
|
||||||
'paid': Decimal(i['mnt_solde_fac']) == 0
|
'litigation_date': get_date(i['dat_perception_fac']),
|
||||||
|
'paid': Decimal(i['mnt_solde_fac']) == 0,
|
||||||
}
|
}
|
||||||
return invoice
|
return invoice
|
||||||
|
|
||||||
|
|
||||||
class Dialect(csv.Dialect):
|
class Dialect(csv.Dialect):
|
||||||
'''Because sometimes it cannot be sniffed by csv.Sniffer'''
|
'''Because sometimes it cannot be sniffed by csv.Sniffer'''
|
||||||
|
|
||||||
delimiter = ';'
|
delimiter = ';'
|
||||||
doublequote = False
|
doublequote = False
|
||||||
escapechar = None
|
escapechar = None
|
||||||
|
@ -104,13 +110,16 @@ class Dialect(csv.Dialect):
|
||||||
|
|
||||||
|
|
||||||
class Loader(object):
|
class Loader(object):
|
||||||
|
|
||||||
def __init__(self, connector):
|
def __init__(self, connector):
|
||||||
self.connector = connector
|
self.connector = connector
|
||||||
|
|
||||||
def clean(self, archive):
|
def clean(self, archive):
|
||||||
for filename in ('extract_prcit_personne.csv', 'extract_prcit_famille.csv',
|
for filename in (
|
||||||
'extract_prcit_enfant.csv', 'extract_prcit_facture.csv'):
|
'extract_prcit_personne.csv',
|
||||||
|
'extract_prcit_famille.csv',
|
||||||
|
'extract_prcit_enfant.csv',
|
||||||
|
'extract_prcit_facture.csv',
|
||||||
|
):
|
||||||
if not filename in archive.namelist():
|
if not filename in archive.namelist():
|
||||||
raise ValidationError(_('Missing %(filename)s file in zip.') % {'filename': filename})
|
raise ValidationError(_('Missing %(filename)s file in zip.') % {'filename': filename})
|
||||||
|
|
||||||
|
@ -118,6 +127,7 @@ class Loader(object):
|
||||||
fd = self.archive.open(filename)
|
fd = self.archive.open(filename)
|
||||||
if six.PY3:
|
if six.PY3:
|
||||||
import io
|
import io
|
||||||
|
|
||||||
fd = io.TextIOWrapper(fd, 'iso-8859-15')
|
fd = io.TextIOWrapper(fd, 'iso-8859-15')
|
||||||
|
|
||||||
reader = csv.reader(fd, Dialect)
|
reader = csv.reader(fd, Dialect)
|
||||||
|
@ -144,7 +154,6 @@ class Loader(object):
|
||||||
families[invoice['id_fam']]['invoices'].append(normalize_invoice(invoice))
|
families[invoice['id_fam']]['invoices'].append(normalize_invoice(invoice))
|
||||||
return families
|
return families
|
||||||
|
|
||||||
|
|
||||||
def load(self, archive):
|
def load(self, archive):
|
||||||
self.archive = archive
|
self.archive = archive
|
||||||
|
|
||||||
|
@ -157,20 +166,32 @@ class Loader(object):
|
||||||
import_start_timestamp = timezone.now()
|
import_start_timestamp = timezone.now()
|
||||||
try:
|
try:
|
||||||
for family_data in families.values():
|
for family_data in families.values():
|
||||||
data = dict_cherry_pick(family_data,
|
data = dict_cherry_pick(
|
||||||
('login', 'password', 'family_quotient',
|
family_data,
|
||||||
'zipcode', 'street_number', 'street_name',
|
(
|
||||||
'address_complement', 'city'))
|
'login',
|
||||||
family, created = Family.objects.update_or_create(external_id=family_data['external_id'],
|
'password',
|
||||||
resource=self.connector, defaults=data)
|
'family_quotient',
|
||||||
|
'zipcode',
|
||||||
|
'street_number',
|
||||||
|
'street_name',
|
||||||
|
'address_complement',
|
||||||
|
'city',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
family, created = Family.objects.update_or_create(
|
||||||
|
external_id=family_data['external_id'], resource=self.connector, defaults=data
|
||||||
|
)
|
||||||
|
|
||||||
for adult_data in family_data.get('adults') or []:
|
for adult_data in family_data.get('adults') or []:
|
||||||
Adult.objects.update_or_create(family=family,
|
Adult.objects.update_or_create(
|
||||||
external_id=adult_data['external_id'], defaults=adult_data)
|
family=family, external_id=adult_data['external_id'], defaults=adult_data
|
||||||
|
)
|
||||||
|
|
||||||
for child_data in family_data.get('children') or []:
|
for child_data in family_data.get('children') or []:
|
||||||
Child.objects.get_or_create(family=family,
|
Child.objects.get_or_create(
|
||||||
external_id=child_data['external_id'], defaults=child_data)
|
family=family, external_id=child_data['external_id'], defaults=child_data
|
||||||
|
)
|
||||||
|
|
||||||
for invoice_data in family_data.get('invoices') or []:
|
for invoice_data in family_data.get('invoices') or []:
|
||||||
storage = DefaultStorage()
|
storage = DefaultStorage()
|
||||||
|
@ -179,17 +200,27 @@ class Loader(object):
|
||||||
invoice_path = os.path.join(invoices_dir, invoice_filename)
|
invoice_path = os.path.join(invoices_dir, invoice_filename)
|
||||||
# create invoice object only if associated pdf exists
|
# create invoice object only if associated pdf exists
|
||||||
if os.path.exists(invoice_path):
|
if os.path.exists(invoice_path):
|
||||||
invoice, created = Invoice.objects.update_or_create(resource=self.connector,
|
invoice, created = Invoice.objects.update_or_create(
|
||||||
family=family, external_id=invoice_data['external_id'], defaults=invoice_data)
|
resource=self.connector,
|
||||||
|
family=family,
|
||||||
|
external_id=invoice_data['external_id'],
|
||||||
|
defaults=invoice_data,
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.connector.logger.error('Error occured while importing data: %s', e)
|
self.connector.logger.error('Error occured while importing data: %s', e)
|
||||||
|
|
||||||
Family.objects.filter(resource=self.connector, update_timestamp__lte=import_start_timestamp).delete()
|
Family.objects.filter(resource=self.connector, update_timestamp__lte=import_start_timestamp).delete()
|
||||||
Adult.objects.filter(family__resource=self.connector, update_timestamp__lte=import_start_timestamp).delete()
|
Adult.objects.filter(
|
||||||
Child.objects.filter(family__resource=self.connector, update_timestamp__lte=import_start_timestamp).delete()
|
family__resource=self.connector, update_timestamp__lte=import_start_timestamp
|
||||||
|
).delete()
|
||||||
|
Child.objects.filter(
|
||||||
|
family__resource=self.connector, update_timestamp__lte=import_start_timestamp
|
||||||
|
).delete()
|
||||||
# remove obsolete invoices and their pdfs
|
# remove obsolete invoices and their pdfs
|
||||||
for invoice in Invoice.objects.filter(resource=self.connector, update_timestamp__lte=import_start_timestamp):
|
for invoice in Invoice.objects.filter(
|
||||||
|
resource=self.connector, update_timestamp__lte=import_start_timestamp
|
||||||
|
):
|
||||||
if invoice.has_pdf:
|
if invoice.has_pdf:
|
||||||
os.unlink(invoice.pdf_filename())
|
os.unlink(invoice.pdf_filename())
|
||||||
invoice.delete()
|
invoice.delete()
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue