utils: add date type to endpoint parameters (#72641)
This commit is contained in:
parent
d2bcff79fb
commit
5d8b8b5bea
|
@ -384,15 +384,12 @@ class Resource(BaseResource, HTTPResource):
|
|||
},
|
||||
'date_of_birth': {
|
||||
'description': _('Beneficiary date of birth'),
|
||||
'type': 'date',
|
||||
'example_value': '1987-10-23',
|
||||
},
|
||||
},
|
||||
)
|
||||
def search(self, request, first_name, last_name, date_of_birth, NameID=None, commune_naissance=None):
|
||||
try:
|
||||
date_of_birth = datetime.datetime.strptime(date_of_birth, '%Y-%m-%d').date()
|
||||
except (ValueError, TypeError):
|
||||
raise APIError('invalid date_of_birth: %r' % date_of_birth)
|
||||
if date_of_birth.year < 1900:
|
||||
raise APIError('date_of_birth must be >= 1900')
|
||||
if commune_naissance:
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import base64
|
||||
import datetime
|
||||
import re
|
||||
from urllib import parse as urlparse
|
||||
|
||||
|
@ -183,6 +182,7 @@ class MDPH13Resource(BaseResource, HTTPResource):
|
|||
},
|
||||
'date_de_naissance': {
|
||||
'description': _('MDPH13 beneficiary date of birth'),
|
||||
'type': 'date',
|
||||
'example_value': '1992-03-05',
|
||||
},
|
||||
'email': {
|
||||
|
@ -201,15 +201,17 @@ class MDPH13Resource(BaseResource, HTTPResource):
|
|||
int(file_number)
|
||||
except ValueError:
|
||||
raise APIError('numero_dossier must be a number', http_status=400)
|
||||
try:
|
||||
dob = datetime.datetime.strptime(date_de_naissance.strip(), '%Y-%m-%d').date()
|
||||
except ValueError:
|
||||
raise APIError('date_de_naissance must be a date YYYY-MM-DD', http_status=400)
|
||||
email = email.strip()
|
||||
if not self.EMAIL_RE.match(email):
|
||||
raise APIError('email is not valid', http_status=400)
|
||||
link, created, updated = Link.create_or_update(
|
||||
resource=self, NameID=NameID, file_number=file_number, secret=secret, dob=dob, email=email, ip=ip
|
||||
resource=self,
|
||||
NameID=NameID,
|
||||
file_number=file_number,
|
||||
secret=secret,
|
||||
dob=date_de_naissance,
|
||||
email=email,
|
||||
ip=ip,
|
||||
)
|
||||
return {'link_id': link.pk, 'created': created, 'updated': updated}
|
||||
|
||||
|
|
|
@ -587,6 +587,7 @@ class PlanitechConnector(BaseResource):
|
|||
},
|
||||
'start_date': {
|
||||
'description': _('Start date'),
|
||||
'type': 'date',
|
||||
'example_value': '2018-10-10',
|
||||
},
|
||||
'start_days': {
|
||||
|
@ -595,6 +596,7 @@ class PlanitechConnector(BaseResource):
|
|||
},
|
||||
'end_date': {
|
||||
'description': _('End date'),
|
||||
'type': 'date',
|
||||
'example_value': '2018-12-10',
|
||||
},
|
||||
'start_time': {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
import inspect
|
||||
|
||||
from django.urls import reverse
|
||||
from django.utils.dateparse import parse_date
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
# make APIError available from this module
|
||||
|
@ -208,6 +209,12 @@ class endpoint:
|
|||
return 'integer'
|
||||
elif isinstance(value, float):
|
||||
return 'float'
|
||||
elif isinstance(value, str):
|
||||
try:
|
||||
if parse_date(value):
|
||||
return 'date'
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
params = []
|
||||
available_params = self.parameters
|
||||
|
|
|
@ -34,6 +34,7 @@ from django.db.models import Q
|
|||
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, resolve_url
|
||||
from django.urls import re_path, reverse
|
||||
from django.utils.dateparse import parse_date
|
||||
from django.utils.encoding import force_bytes, force_str
|
||||
from django.utils.timezone import is_naive, make_aware
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
@ -386,6 +387,13 @@ class GenericEndpointView(GenericConnectorMixin, SingleObjectMixin, View):
|
|||
d[parameter] = float(d[parameter])
|
||||
except ValueError:
|
||||
raise InvalidParameterValue(parameter)
|
||||
elif parameter_info.get('type') == 'date':
|
||||
try:
|
||||
d[parameter] = parse_date(d[parameter].strip())
|
||||
except ValueError:
|
||||
raise InvalidParameterValue('%s (not a valid date)' % parameter)
|
||||
if not d[parameter]:
|
||||
raise InvalidParameterValue('%s (YYYY-MM-DD expected)' % parameter)
|
||||
if request.method == 'POST' and self.endpoint.endpoint_info.post:
|
||||
request_body = self.endpoint.endpoint_info.post.get('request_body', {})
|
||||
if 'application/json' in request_body.get('schema', {}):
|
||||
|
|
|
@ -734,10 +734,13 @@ def test_endpoint_typed_params(app, db, monkeypatch):
|
|||
'floating': {
|
||||
'type': 'float',
|
||||
},
|
||||
'date': {
|
||||
'type': 'date',
|
||||
},
|
||||
},
|
||||
)
|
||||
def httpcall(obj, request, boolean=False, integer=1, floating=1.1):
|
||||
return {'boolean': boolean, 'integer': integer, 'floating': floating}
|
||||
def httpcall(obj, request, boolean=False, integer=1, floating=1.1, date=None):
|
||||
return {'boolean': boolean, 'integer': integer, 'floating': floating, 'date': date}
|
||||
|
||||
monkeypatch.setattr(StubInvoicesConnector, 'httpcall', httpcall, raising=False)
|
||||
|
||||
|
@ -780,6 +783,18 @@ def test_endpoint_typed_params(app, db, monkeypatch):
|
|||
assert json_res['err'] == 1
|
||||
assert json_res['err_desc'] == 'invalid value for parameter "floating"'
|
||||
|
||||
json_res = app.get('/stub-invoices/fake/httpcall?date=1970-01-01').json
|
||||
assert json_res['date'] == '1970-01-01'
|
||||
json_res = app.get('/stub-invoices/fake/httpcall?date=nodate', status=400).json
|
||||
assert json_res['err'] == 1
|
||||
assert json_res['err_desc'] == 'invalid value for parameter "date (YYYY-MM-DD expected)"'
|
||||
json_res = app.get('/stub-invoices/fake/httpcall?date=', status=400).json
|
||||
assert json_res['err'] == 1
|
||||
assert json_res['err_desc'] == 'invalid value for parameter "date (YYYY-MM-DD expected)"'
|
||||
json_res = app.get('/stub-invoices/fake/httpcall?date=1970-02-31', status=400).json
|
||||
assert json_res['err'] == 1
|
||||
assert json_res['err_desc'] == 'invalid value for parameter "date (not a valid date)"'
|
||||
|
||||
|
||||
def test_endpoint_params_type_detection(app, db, monkeypatch):
|
||||
@endpoint(
|
||||
|
@ -794,6 +809,9 @@ def test_endpoint_params_type_detection(app, db, monkeypatch):
|
|||
'float_by_example': {
|
||||
'example_value': 1.1,
|
||||
},
|
||||
'date_by_example': {
|
||||
'example_value': '1970-01-01',
|
||||
},
|
||||
},
|
||||
)
|
||||
def httpcall(
|
||||
|
@ -805,6 +823,7 @@ def test_endpoint_params_type_detection(app, db, monkeypatch):
|
|||
bool_by_example=None,
|
||||
int_by_example=None,
|
||||
float_by_example=None,
|
||||
date_by_example=None,
|
||||
):
|
||||
return {
|
||||
'boolean': boolean,
|
||||
|
@ -813,6 +832,7 @@ def test_endpoint_params_type_detection(app, db, monkeypatch):
|
|||
'bool_by_example': bool_by_example,
|
||||
'int_by_example': int_by_example,
|
||||
'float_by_example': float_by_example,
|
||||
'date_by_example': date_by_example,
|
||||
}
|
||||
|
||||
monkeypatch.setattr(StubInvoicesConnector, 'httpcall', httpcall, raising=False)
|
||||
|
@ -835,6 +855,9 @@ def test_endpoint_params_type_detection(app, db, monkeypatch):
|
|||
json_res = app.get('/stub-invoices/fake/httpcall?float_by_example=1.5').json
|
||||
assert json_res['float_by_example'] == 1.5
|
||||
|
||||
json_res = app.get('/stub-invoices/fake/httpcall?date_by_example=1970-01-01').json
|
||||
assert json_res['date_by_example'] == '1970-01-01'
|
||||
|
||||
res = app.get('/stub-invoices/fake/')
|
||||
for param in res.pyquery('ul.get-params li'):
|
||||
param_details = param.getchildren()
|
||||
|
@ -847,6 +870,8 @@ def test_endpoint_params_type_detection(app, db, monkeypatch):
|
|||
assert typ == 'integer'
|
||||
elif 'float' in name:
|
||||
assert typ == 'float'
|
||||
elif 'date' in name:
|
||||
assert typ == 'date'
|
||||
else:
|
||||
assert typ == 'string'
|
||||
|
||||
|
|
|
@ -272,17 +272,14 @@ def test_link_bad_file_number(mdph13):
|
|||
assert str(e.value) == 'numero_dossier must be a number'
|
||||
|
||||
|
||||
def test_link_bad_date_de_naissance(mdph13):
|
||||
with pytest.raises(APIError) as e:
|
||||
mdph13.link(
|
||||
request=None,
|
||||
NameID=NAME_ID,
|
||||
numero_dossier=FILE_NUMBER,
|
||||
secret=None,
|
||||
date_de_naissance='34-45-6',
|
||||
email=None,
|
||||
)
|
||||
assert str(e.value) == 'date_de_naissance must be a date YYYY-MM-DD'
|
||||
def test_link_bad_date_de_naissance(app, mdph13):
|
||||
url = '/mdph13/test1/link/?NameID=%s&numero_dossier=%s&date_de_naissance=%s&secret=%s&email=%s'
|
||||
url = url % (NAME_ID, FILE_NUMBER, '34-45-6', None, None)
|
||||
response = app.post(url, status=400)
|
||||
assert response.json['err_class'] == 'passerelle.views.InvalidParameterValue'
|
||||
assert (
|
||||
response.json['err_desc'] == 'invalid value for parameter "date_de_naissance (YYYY-MM-DD expected)"'
|
||||
)
|
||||
|
||||
|
||||
def test_link_bad_email(mdph13):
|
||||
|
@ -298,74 +295,49 @@ def test_link_bad_email(mdph13):
|
|||
assert str(e.value) == 'email is not valid'
|
||||
|
||||
|
||||
def test_link_nok_dossier_inconnu(mdph13, mock_http):
|
||||
def test_link_nok_dossier_inconnu(app, mdph13, mock_http):
|
||||
mock_http.add_response(DOSSIER_INCONNU)
|
||||
with pytest.raises(APIError) as e:
|
||||
mdph13.link(
|
||||
request=None,
|
||||
NameID=NAME_ID,
|
||||
numero_dossier=FILE_NUMBER,
|
||||
secret=SECRET,
|
||||
date_de_naissance=DOB_ISOFORMAT,
|
||||
email=EMAIL,
|
||||
)
|
||||
assert str(e.value) == 'dossier-inconnu'
|
||||
url = '/mdph13/test1/link/?NameID=%s&numero_dossier=%s&date_de_naissance=%s&secret=%s&email=%s'
|
||||
url = url % (NAME_ID, FILE_NUMBER, DOB_ISOFORMAT, SECRET, EMAIL)
|
||||
response = app.post(url)
|
||||
assert response.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
|
||||
assert response.json['err_desc'] == 'dossier-inconnu'
|
||||
|
||||
|
||||
def test_link_nok_secret_invalide(mdph13, mock_http):
|
||||
def test_link_nok_secret_invalide(app, mdph13, mock_http):
|
||||
mock_http.add_response(SECRET_INVALIDE)
|
||||
with pytest.raises(APIError) as e:
|
||||
mdph13.link(
|
||||
request=None,
|
||||
NameID=NAME_ID,
|
||||
numero_dossier=FILE_NUMBER,
|
||||
secret=SECRET,
|
||||
date_de_naissance=DOB_ISOFORMAT,
|
||||
email=EMAIL,
|
||||
)
|
||||
assert str(e.value) == 'secret-invalide'
|
||||
url = '/mdph13/test1/link/?NameID=%s&numero_dossier=%s&date_de_naissance=%s&secret=%s&email=%s'
|
||||
url = url % (NAME_ID, FILE_NUMBER, DOB_ISOFORMAT, SECRET, EMAIL)
|
||||
response = app.post(url)
|
||||
assert response.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
|
||||
assert response.json['err_desc'] == 'secret-invalide'
|
||||
|
||||
|
||||
def test_link_numero_dont_match(mdph13, mock_http):
|
||||
def test_link_numero_dont_match(app, mdph13, mock_http):
|
||||
mock_http.add_response(json.dumps({'err': 0, 'data': {'numero': '456'}}))
|
||||
with pytest.raises(APIError) as e:
|
||||
mdph13.link(
|
||||
request=None,
|
||||
NameID=NAME_ID,
|
||||
numero_dossier=FILE_NUMBER,
|
||||
secret=SECRET,
|
||||
date_de_naissance=DOB_ISOFORMAT,
|
||||
email=EMAIL,
|
||||
)
|
||||
assert str(e.value) == 'numero-must-match-numero-dossier'
|
||||
url = '/mdph13/test1/link/?NameID=%s&numero_dossier=%s&date_de_naissance=%s&secret=%s&email=%s'
|
||||
url = url % (NAME_ID, FILE_NUMBER, DOB_ISOFORMAT, SECRET, EMAIL)
|
||||
response = app.post(url)
|
||||
assert response.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
|
||||
assert response.json['err_desc'] == 'numero-must-match-numero-dossier'
|
||||
|
||||
|
||||
def test_link_ok(mdph13, mock_http):
|
||||
def test_link_ok(app, mdph13, mock_http):
|
||||
# check first time link
|
||||
mock_http.add_response(VALID_RESPONSE)
|
||||
assert not Link.objects.count()
|
||||
response = mdph13.link(
|
||||
request=None,
|
||||
NameID=NAME_ID,
|
||||
numero_dossier=FILE_NUMBER,
|
||||
secret=SECRET,
|
||||
date_de_naissance=DOB_ISOFORMAT,
|
||||
email=EMAIL,
|
||||
ip=IP,
|
||||
)
|
||||
url = '/mdph13/test1/link/?NameID=%s&numero_dossier=%s&date_de_naissance=%s&secret=%s&email=%s&ip=%s'
|
||||
url = url % (NAME_ID, FILE_NUMBER, DOB_ISOFORMAT, SECRET, EMAIL, IP)
|
||||
response = app.post(url)
|
||||
link = Link.objects.get()
|
||||
assert response == {'link_id': link.pk, 'created': True, 'updated': False}
|
||||
assert response.json == {'err': 0, 'link_id': link.pk, 'created': True, 'updated': False}
|
||||
# check relinking with update
|
||||
mock_http.add_response(VALID_RESPONSE)
|
||||
response = mdph13.link(
|
||||
request=None,
|
||||
NameID=NAME_ID,
|
||||
numero_dossier=FILE_NUMBER,
|
||||
secret=SECRET + 'a',
|
||||
date_de_naissance=DOB_ISOFORMAT,
|
||||
email=EMAIL,
|
||||
)
|
||||
assert response == {
|
||||
url = '/mdph13/test1/link/?NameID=%s&numero_dossier=%s&date_de_naissance=%s&secret=%s&email=%s&ip=%s'
|
||||
url = url % (NAME_ID, FILE_NUMBER, DOB_ISOFORMAT, SECRET + 'a', EMAIL, IP)
|
||||
response = app.post(url)
|
||||
assert response.json == {
|
||||
'err': 0,
|
||||
'link_id': link.pk,
|
||||
'created': False,
|
||||
'updated': True,
|
||||
|
|
|
@ -992,11 +992,12 @@ def test_get_freegaps(app, connector, monkeypatch, settings):
|
|||
# bad date format
|
||||
response = app.get(
|
||||
'/planitech/slug-planitech/getfreegaps?start_time=11:00&&end_time=14:00'
|
||||
'&start_date=notadate&display=place'
|
||||
'&start_date=notadate&display=place',
|
||||
status=400,
|
||||
)
|
||||
json_resp = response.json
|
||||
assert json_resp['err'] == 1
|
||||
assert json_resp['err_desc'] == "Invalid date format: notadate"
|
||||
assert json_resp['err_desc'] == 'invalid value for parameter "start_date (YYYY-MM-DD expected)"'
|
||||
|
||||
# bad time format
|
||||
response = app.get(
|
||||
|
|
Loading…
Reference in New Issue