From 171627a078a275f4d124f7208f8981ccbe96c0f8 Mon Sep 17 00:00:00 2001
From: Emmanuel Cazenave <ecazenave@entrouvert.com>
Date: Wed, 13 Nov 2019 12:29:51 +0100
Subject: [PATCH] jsonschema: use draft 4 and avoid schemas references (#37621)

---
 passerelle/apps/astregs/models.py         | 77 ++++++++---------------
 passerelle/apps/atal/schemas.py           | 28 +++------
 passerelle/apps/gesbac/models.py          | 57 ++---------------
 passerelle/apps/vivaticket/models.py      | 28 ++-------
 passerelle/contrib/iparapheur/models.py   | 22 ++-----
 passerelle/contrib/iws/models.py          |  8 +--
 passerelle/contrib/lille_kimoce/models.py | 22 +------
 passerelle/contrib/planitech/models.py    | 42 ++++---------
 tests/test_atal.py                        | 27 ++++++++
 9 files changed, 96 insertions(+), 215 deletions(-)

diff --git a/passerelle/apps/astregs/models.py b/passerelle/apps/astregs/models.py
index 27b026bc..d1e67876 100644
--- a/passerelle/apps/astregs/models.py
+++ b/passerelle/apps/astregs/models.py
@@ -28,161 +28,146 @@ from passerelle.utils.api import endpoint
 from passerelle.utils.jsonresponse import APIError
 
 ASSOCIATION_SCHEMA = {
-    "$schema": "http://json-schema.org/draft-03/schema#",
+    "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "AstreGS assocation",
     "description": "",
     "type": "object",
+    "required": [
+        "Financier", "CodeFamille", "CatTiers", "NomEnregistrement", "StatutTiers",
+        "Type", "NumeroSiret", "NumeroSiretFin", "AdresseTitre", "AdresseIsAdresseDeCommande",
+        "AdresseIsAdresseDeFacturation"
+    ],
     "properties": {
         "Financier": {
             "description": "financial association",
             "type": "string",
-            "required": True,
             "enum": ["true", "false"]
         },
         "CodeFamille": {
             "description": "association family code",
             "type": "string",
-            "required": True
         },
         "CatTiers": {
             "description": "association category",
             "type": "string",
-            "required": True
         },
         "NomEnregistrement": {
             "description": "association name",
             "type": "string",
-            "required": True
         },
         "StatutTiers": {
             "description": "association status",
             "type": "string",
-            "required": True,
             "enum": ["PROPOSE", "VALIDE", "REFUSE", "BLOQUE", "A COMPLETER"]
         },
         "Type": {
             "description": "association type",
             "type": "string",
-            "required": True,
             "enum": ["D", "F", "*"]
         },
         "NumeroSiret": {
             "description": "SIREN number",
             "type": "string",
-            "required": True
         },
         "NumeroSiretFin": {
             "description": "NIC number",
             "type": "string",
-            "required": True
         },
         "AdresseTitre": {
             "type": "string",
-            "required": True
         },
         "AdresseIsAdresseDeCommande": {
             "type": "string",
-            "required": True,
             "enum": ["true", "false"]
         },
         "AdresseIsAdresseDeFacturation": {
             "type": "string",
-            "required": True,
             "enum": ["true", "false"]
         }
     }
 }
 
 CONTACT_SCHEMA = {
-    "$schema": "http://json-schema.org/draft-03/schema#",
+    "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "AstreGS contact",
     "description": "",
     "type": "object",
+    "required": [
+        "CodeContact", "CodeTitreCivilite", "Nom", "AdresseDestinataire", "CodePostal", "Ville",
+        "EncodeKeyStatut"
+    ],
     "properties": {
         "CodeContact": {
             "type": "string",
-            "required": True
         },
         "CodeTitreCivilite": {
             "type": "string",
-            "required": True
         },
         "Nom": {
             "type": "string",
-            "required": True
         },
         "AdresseDestinataire": {
             "type": "string",
-            "required": True
         },
         "CodePostal": {
             "type": "string",
-            "required": True
         },
         "Ville": {
             "type": "string",
-            "required": True
         },
         "EncodeKeyStatut": {
             "type": "string",
-            "required": True
         }
     }
 }
 
 DOCUMENT_SCHEMA = {
-    "$schema": "http://json-schema.org/draft-03/schema#",
+    "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "AstreGS assocation",
     "description": "",
     "type": "object",
+    "required": [
+        "Sujet", "Entite", "CodType", "Type", "hdnCodeTrt", "EncodeKeyEntite", "CodeDomaine",
+        "CodDom", "document"
+    ],
     "properties": {
         "Sujet": {
             "type": "string",
-            "required": True
         },
         "Entite": {
             "type": "string",
-            "required": True
         },
         "CodType": {
             "type": "string",
-            "required": True
         },
         "Type": {
             "type": "string",
-            "required": True
         },
         "hdnCodeTrt": {
             "type": "string",
-            "required": True
         },
         "EncodeKeyEntite": {
             "type": "string",
-            "required": True
         },
         "CodeDomaine": {
             "type": "string",
-            "required": True
         },
         "CodDom": {
             "type": "string",
-            "required": True
         },
         "document": {
             "required": True,
             "type": "object",
+            "required": ['filename', 'content_type', 'content'],
             'properties': {
                 'filename': {
                     'type': 'string',
-                    'required': True
                 },
                 'content_type': {
                     'type': 'string',
-                    'required': True
                 },
                 'content': {
                     'type': 'string',
-                    'required': True
                 }
             }
         }
@@ -190,93 +175,83 @@ DOCUMENT_SCHEMA = {
 }
 
 GRANT_SCHEMA = {
-    "$schema": "http://json-schema.org/draft-03/schema#",
+    "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "AstreGS grant",
     "description": "",
     "type": "object",
+    "required": [
+        "Libelle", "LibelleCourt", "ModGestion", "TypeAide", "Sens", "CodeTiersDem",
+        "CodeServiceGestionnaire", "CodeServiceUtilisateur"
+    ],
     "properties": {
         "Libelle": {
             "type": "string",
-            "required": True
         },
         "LibelleCourt": {
             "type": "string",
-            "required": True
         },
         "ModGestion": {
             "type": "string",
-            "required": True,
             "enum": ["1", "2", "3", "4"]
         },
         "TypeAide": {
             "type": "string",
-            "required": True
         },
         "Sens": {
             "type": "string",
-            "required": True
         },
         "CodeTiersDem": {
             "type": "string",
-            "required": True
         },
         "CodeServiceGestionnaire": {
             "type": "string",
-            "required": True
         },
         "CodeServiceUtilisateur": {
             "type": "string",
-            "required": True
         }
     }
 }
 
 INDANA_SCHEMA = {
-    "$schema": "http://json-schema.org/draft-03/schema#",
+    "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "AstreGS INDANA indicator",
     "description": "",
     "type": "object",
+    "required": ["CodeDossier", "CodeInd_1", "AnneeInd_1", "ValInd_1"],
     "properties": {
         "CodeDossier": {
             "type": "string",
-            "required": True
         },
         "CodeInd_1": {
             "type": "string",
-            "required": True
         },
         "AnneeInd_1": {
             "type": "string",
-            "required": True
         },
         "ValInd_1": {
             "type": "string",
-            "required": True
         },
         "IndAide": {
             "type": "string",
-            "required": False
         }
     }
 }
 
 INDANA_KEY_SCHEMA = {
-    "$schema": "http://json-schema.org/draft-03/schema#",
+    "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "AstreGS INDANA indicator key",
     "description": "",
     "type": "object",
+    "required": ["CodeDossier", "CodeInd_1", "AnneeInd_1"],
     "properties": {
         "CodeDossier": {
             "type": "string",
-            "required": True
         },
         "CodeInd_1": {
             "type": "string",
-            "required": True
         },
         "AnneeInd_1": {
             "type": "string",
-            "required": True
         }
     }
 }
diff --git a/passerelle/apps/atal/schemas.py b/passerelle/apps/atal/schemas.py
index 7dea8346..faf2fa7e 100644
--- a/passerelle/apps/atal/schemas.py
+++ b/passerelle/apps/atal/schemas.py
@@ -18,13 +18,13 @@
 
 
 INSERT_DEMANDE_COMPLET_BY_TYPE = {
-    '$schema': 'http://json-schema.org/draft-03/schema#',
+    '$schema': 'http://json-schema.org/draft-04/schema#',
     'type': 'object',
+    'required': ['type_demande'],
     'additionalProperties': False,
     'properties': {
         'type_demande': {
             'type': 'string',
-            'required': True,
         },
         'code_service_demandeur': {
             'type': 'string',
@@ -144,46 +144,38 @@ INSERT_DEMANDE_COMPLET_BY_TYPE = {
 }
 
 INSERT_ACTION_COMMENT = {
-    '$schema': 'http://json-schema.org/draft-03/schema#',
+    '$schema': 'http://json-schema.org/draft-04/schema#',
     'type': 'object',
+    'required': ['numero_demande', 'commentaire'],
     'properties': {
         'numero_demande': {
             'type': 'string',
-            'required': True,
         },
         'commentaire': {
             'type': 'string',
-            'required': True,
         }
     }
 }
 
 UPLOAD = {
-    '$schema': 'http://json-schema.org/draft-03/schema#',
-    'definitions': {
+    '$schema': 'http://json-schema.org/draft-04/schema#',
+    'type': 'object',
+    'required': ['file', 'numero_demande', 'nom_fichier'],
+    'properties': {
         'file': {
             'type': 'object',
+            'required': ['content'],
             'properties': {
                 'content': {
                     'type': 'string',
-                    'required': True
                 },
-            },
-            'required': True
-        }
-    },
-    'type': 'object',
-    'properties': {
-        'file': {
-            '$ref': '#/definitions/file'
+            }
         },
         'numero_demande': {
             'type': 'string',
-            'required': True,
         },
         'nom_fichier': {
             'type': 'string',
-            'required': True,
         }
     }
 }
diff --git a/passerelle/apps/gesbac/models.py b/passerelle/apps/gesbac/models.py
index 7520fc37..9af3adfe 100644
--- a/passerelle/apps/gesbac/models.py
+++ b/passerelle/apps/gesbac/models.py
@@ -34,215 +34,175 @@ CSV_DELIMITER = ';'
 APPLICANT_SCHEMA = OrderedDict((
     ("form_id", {
         "type": "string",
-        "required": True
     }),
     ("demand_date", {
         "type": "string",
         "pattern": "^[0-9]{8}$",
-        "required": True
     }),
     ("demand_time", {
         "type": "string",
         "pattern": "^[0-9]{6}$",
-        "required": True
     }),
     ("producer_code", {
         "type": "integer",
-        "required": True
     }),
     ("invariant_number", {
         "type": "string",
-        "required": False,
         "maxLength": 10,
         "default": ""
     }),
     ("city_insee_code", {
         "type": "string",
-        "required": True
     }),
     ("street_rivoli_code", {
         "type": "string",
-        "required": True
     }),
     ("street_name", {
         "type": "string",
-        "required": True
     }),
     ("address_complement", {
         "type": "string",
         "maxLength": 32,
-        "required": False,
         "default": ""
     }),
     ("street_number", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("bis_ter", {
         "type": "string",
         "maxLength": 3,
-        "required": False,
         "default": ""
     }),
     ("building", {
         "type": "string",
         "maxLength": 5,
-        "required": False,
         "default": ""
     }),
     ("hall", {
         "type": "string",
         "maxLength": 5,
-        "required": False,
         "default": ""
     }),
     ("appartment_number", {
         "type": "string",
         "maxLength": 5,
-        "required": False,
         "default": ""
     }),
     ("producer_social_reason", {
         "type": "string",
         "maxLength": 38,
-        "required": False,
         "default": ""
     }),
     ("producer_title_code", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("producer_last_name", {
         "type": "string",
         "maxLength": 38,
-        "required": False,
         "default": ""
     }),
     ("producer_first_name", {
         "type": "string",
         "maxLength": 32,
-        "required": False,
         "default": ""
     }),
     ("producer_phone", {
         "type": "string",
         "maxLength": 20,
-        "required": False,
         "default": ""
     }),
     ("producer_email", {
         "type": "string",
         "maxLength": 50,
-        "required": False,
         "default": ""
     }),
     ("owner_last_name", {
         "type": "string",
         "maxLength": 38,
-        "required": False,
         "default": ""
     }),
     ("owner_first_name", {
         "type": "string",
         "maxLength": 32,
-        "required": False,
         "default": ""
     }),
     ("owner_phone", {
         "type": "string",
         "maxLength": 20,
-        "required": False,
         "default": ""
     }),
     ("owner_email", {
         "type": "string",
         "maxLength": 50,
-        "required": False,
         "default": ""
     }),
     ("activity_code", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("family_members_number", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("houses_number", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("t1_flats_number", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("t2_flats_number", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("t3_flats_number", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("t4_flats_number", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("t5_flats_number", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("t6_flats_number", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("shops_number", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("garden_size", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("expected_date", {
         "type": "string",
         "pattern": "^[0-9]{8}$",
-        "required": False,
         "default": ""
     }),
     ("expected_time", {
         "type": "string",
         "pattern": "^[0-9]{4}$",
-        "required": False,
         "default": ""
     }),
     ("modification_code", {
         "type": "integer",
-        "required": False,
         "default": 0
     }),
     ("demand_reason_label", {
         "type": "string",
-        "required": False,
         "default": ""
     }),
     ("comment", {
         "type": "string",
         "maxLength": 500,
-        "required": False,
         "default": ""
     }))
 )
@@ -250,53 +210,43 @@ APPLICANT_SCHEMA = OrderedDict((
 CARD_SCHEMA = OrderedDict((
     ("card_subject", {
         "type": "integer",
-        "required": True
     }),
     ("card_type", {
         "type": "integer",
-        "required": True
     }),
     ("card_demand_reason", {
         "type": "integer",
-        "required": True
     }),
     ("cards_quantity", {
         "type": "integer",
-        "required": True,
 
     }),
     ("card_number", {
         "type": "string",
         "maxLength": 20,
-        "required": False
     }),
     ("card_bar_code", {
         "type": "string",
         "maxLength": 20,
-        "required": False,
         "default": "",
     }),
     ("card_code", {
         "type": "string",
         "maxLength": 20,
-        "required": False,
         "default": "",
     }),
     ("card_validity_start_date", {
         "type": "string",
-        "required": False,
         "pattern": "^[0-9]{8}$",
         "default": "",
     }),
     ("card_validity_end_date", {
         "type": "string",
-        "required": False,
         "pattern": "^[0-9]{8}$",
         "default": "",
     }),
     ("card_comment", {
         "type": "string",
-        "required": False,
         "maxLength": 100,
         "default": "",
     }))
@@ -306,10 +256,15 @@ DEMAND_SCHEMA = APPLICANT_SCHEMA.copy()
 DEMAND_SCHEMA.update(CARD_SCHEMA)
 
 SCHEMA = {
-    "$schema": "http://json-schema.org/draft-03/schema#",
+    "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "Gesbac",
     "description": "",
     "type": "object",
+    "required": [
+        "form_id", "demand_date", "demand_time", "producer_code", "city_insee_code",
+        "street_rivoli_code", "street_name", "card_subject", "card_type", "card_demand_reason",
+        "cards_quantity"
+    ],
     "properties": DEMAND_SCHEMA,
 }
 
diff --git a/passerelle/apps/vivaticket/models.py b/passerelle/apps/vivaticket/models.py
index 52dd73a9..c5ddbd2b 100644
--- a/passerelle/apps/vivaticket/models.py
+++ b/passerelle/apps/vivaticket/models.py
@@ -26,122 +26,104 @@ from passerelle.utils.api import endpoint
 from passerelle.utils.jsonresponse import APIError
 
 EVENTBOOK_SCHEMA = {
-    "$schema": "http://json-schema.org/draft-03/schema#",
+    "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "Vivaticket",
     "description": "",
     "type": "object",
+    "required": [
+        "id", "email", "start_datetime", "end_datetime", "event", "theme", "room", "quantity",
+        "form_url"
+    ],
     "properties": {
         "id": {
             "description": "formdata id",
             "type": "string",
-            "required": True
         },
         "title": {
             "description": "user title",
             "type": "string",
-            "required": False
         },
         "last_name": {
             "description": "user last name",
             "type": "string",
-            "required": False
         },
         "first_name": {
             "description": "user first name",
             "type": "string",
-            "required": False
         },
         "social_reason": {
             "description": "user social reason",
             "type": "string",
-            "required": False
         },
         "address": {
             "description": "user address",
             "type": "string",
-            "required": False
         },
         "zipcode": {
             "description": "user zipcode",
             "type": "string",
-            "required": False
         },
         "city": {
             "description": "user city",
             "type": "string",
-            "required": False
         },
         "country": {
             "description": "user country",
             "type": "string",
-            "required": False
         },
         "phone": {
             "description": "user phone",
             "type": "string",
-            "required": False
         },
         "mobile": {
             "description": "user mobile",
             "type": "string",
-            "required": False
         },
         "email": {
             "description": "user email",
             "type": "string",
-            "required": True
         },
         "start_datetime": {
             "description": "event start datetime",
             "type": "string",
             "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}$",
-            "required": True
         },
         "end_datetime": {
             "description": "event end datetime",
             "type": "string",
             "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}$",
-            "required": True
         },
         "event": {
             "description": "event id",
             "type": "string",
-            "required": True
         },
         "theme": {
             "description": "theme id",
             "type": "string",
-            "required": True
         },
         "room": {
             "description": "room id",
             "type": "string",
-            "required": True
         },
         "quantity": {
             "description": "quantity",
             "type": "integer",
-            "required": True
         },
         "booking_comment": {
             "description": "booking comment",
             "type": "string",
-            "required": False,
         },
         "room_comment": {
             "description": "room comment",
             "type": "string",
-            "required": False,
         },
         "form_url": {
             "description": "form url",
             "type": "string",
-            "required": True
         },
         "school_level": {
             "description": "School Level code",
             "type": "string",
-            "required": False
         }
     }
 }
diff --git a/passerelle/contrib/iparapheur/models.py b/passerelle/contrib/iparapheur/models.py
index 6178cec5..40f607b4 100644
--- a/passerelle/contrib/iparapheur/models.py
+++ b/passerelle/contrib/iparapheur/models.py
@@ -30,47 +30,37 @@ from passerelle.utils.jsonresponse import APIError
 
 
 CREATE_FILE_SCHEMA = {
-    '$schema': 'http://json-schema.org/draft-03/schema#',
+    '$schema': 'http://json-schema.org/draft-04/schema#',
     'title': 'Iparapheur create file',
-    'definitions': {
+    'type': 'object',
+    'required': ['file', 'title', 'type', 'subtype', 'visibility'],
+    'properties': {
         'file': {
             'type': 'object',
+            'required': ['content', 'content_type'],
             'properties': {
                 'content': {
                     'type': 'string',
-                    'required': True
                 },
                 'content_type': {
                     'type': 'string',
-                    'required': True
                 }
-            },
-            'required': True
-        }
-    },
-    'type': 'object',
-    'properties': {
-        'file': {
-            '$ref': '#/definitions/file'
+            }
         },
         'title': {
             'type': 'string',
-            'required': True
         },
         'type': {
             'type': 'string',
-            'required': True
         },
         'subtype': {
             'type': 'string',
-            'required': True
         },
         'email': {
             'type': 'string',
         },
         'visibility': {
             'type': 'string',
-            'required': True
         }
     }
 }
diff --git a/passerelle/contrib/iws/models.py b/passerelle/contrib/iws/models.py
index 52068687..ea50ba74 100644
--- a/passerelle/contrib/iws/models.py
+++ b/passerelle/contrib/iws/models.py
@@ -35,20 +35,19 @@ SYNDIC_C_TYPEPB = {"DECHET": "8007", "ENCOMBRANT": "8009"}
 NS = '{http://isilog.fr}'
 
 BOOKDATE_SCHEMA = {
-    "$schema": "http://json-schema.org/draft-03/schema#",
+    "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "IWS",
     "description": "",
     "type": "object",
+    "required": ["firstname", "lastname", "email_notif", "date", "token"],
     "properties": {
         "firstname": {
             "description": "Firstname",
             "type": "string",
-            "required": True
         },
         "lastname": {
             "description": "Lastname",
             "type": "string",
-            "required": True
         },
         "email": {
             "description": "Email",
@@ -57,7 +56,6 @@ BOOKDATE_SCHEMA = {
         "email_notif": {
             "description": "Email notification",
             "type": "boolean",
-            "required": True
         },
         "description": {
             "description": "Description of the request",
@@ -70,12 +68,10 @@ BOOKDATE_SCHEMA = {
         "date": {
             "description": "Booking date",
             "type": "string",
-            "required": True
         },
         "token": {
             "description": "Booking token",
             "type": "string",
-            "required": True
         }
     }
 }
diff --git a/passerelle/contrib/lille_kimoce/models.py b/passerelle/contrib/lille_kimoce/models.py
index 44843beb..73933882 100644
--- a/passerelle/contrib/lille_kimoce/models.py
+++ b/passerelle/contrib/lille_kimoce/models.py
@@ -27,95 +27,77 @@ from passerelle.utils.jsonresponse import APIError
 
 
 DEMAND_SCHEMA = {
-    '$schema': 'http://json-schema.org/draft-03/schema#',
+    '$schema': 'http://json-schema.org/draft-04/schema#',
     'title': 'KIMOCE',
     'description': '',
     'type': 'object',
+    'required': ['category', 'type', 'subtype', 'form_url', 'first_name', 'last_name', 'email'],
     'properties': {
         'category': {
             'description': 'demand category',
             'type': 'string',
-            'required': True
         },
         'type': {
             'description': 'demand type',
             'type': 'string',
-            'required': True
         },
         'subtype': {
             'description': 'demand sub type',
             'type': 'string',
-            'required': True
         },
         'form_url': {
             'description': 'form url',
             'type': 'string',
-            'required': True
         },
         'first_name': {
             'description': 'user first name',
             'type': 'string',
-            'required': True
         },
         'last_name': {
             'description': 'user last name',
             'type': 'string',
-            'required': True
         },
         'email': {
             'description': 'user email',
             'type': 'string',
-            'required': True
         },
         'priorityId': {
             'description': 'demand priority',
             'type': 'integer',
-            'required': False
         },
         'city': {
             'description': 'demand city',
             'type': 'string',
-            'required': False
         },
         'zipcode': {
             'description': 'demand zipcode',
             'type': 'string',
-            'required': False
         },
         'street_number': {
             'description': 'demand street number',
             'type': 'string',
-            'required': False
         },
         'street_name': {
             'description': 'demand street name',
             'type': 'string',
-            'required': False
         },
         'lat': {
             'description': 'demand latitude',
             'type': 'string',
-            'required': False
         },
         'lon': {
             'description': 'demand longitude',
             'type': 'string',
-            'required': False
         },
         'picture1': {
             'description': 'first picture data',
-            'type': 'any',
-            'required': False
         },
         'picture2': {
             'description': 'second picture data',
-            'type': 'any',
-            'required': False
         },
         'comment': {
             'description': 'demand comment',
             'type': 'string',
-            'required': False
         }
     }
 }
diff --git a/passerelle/contrib/planitech/models.py b/passerelle/contrib/planitech/models.py
index 03d7728f..46d1767b 100644
--- a/passerelle/contrib/planitech/models.py
+++ b/passerelle/contrib/planitech/models.py
@@ -37,145 +37,128 @@ from passerelle.utils.jsonresponse import APIError
 
 
 CREATE_RESERVATION_SCHEMA = {
-    "$schema": "http://json-schema.org/draft-03/schema#",
+    "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "Planitech createreservation",
     "description": "",
     "type": "object",
+    "required": [
+        "date", "start_time", "end_time", "place_id", "price", "name_id", "first_name",
+        "last_name", "email", "activity_id", "object", "type_id", "vat_rate"
+    ],
     "properties": {
         "date": {
             "description": "Date",
             "type": "string",
-            "required": True
         },
         "start_time": {
             "description": "Start time",
             "type": "string",
-            "required": True
         },
         "end_time": {
             "description": "End time",
             "type": "string",
-            "required": True
         },
         "place_id": {
             "description": "Place identifier",
             "type": "number",
-            "required": True
         },
         "price": {
             "description": "Price",
             "type": "number",
-            "required": True
         },
         "name_id": {
             "description": "Publik user nameID",
             "type": "string",
-            "required": True
         },
         "first_name": {
             "description": "First name",
             "type": "string",
-            "required": True
         },
         "last_name": {
             "description": "Last name",
             "type": "string",
-            "required": True
         },
         "email": {
             "description": "Email",
             "type": "string",
-            "required": True
         },
         "activity_id": {
             "description": "Activity identifier",
             "type": "number",
-            "required": True
         },
         "object": {
             "description": "Object",
             "type": "string",
-            "required": True
         },
         "type_id": {
             "description": "Rerservation type identifier",
             "type": "number",
-            "required": True
         },
         "vat_rate": {
             "description": "VAT rate",
             "type": "number",
-            "required": True
         },
         "price_code": {
             "description": "User price code",
             "type": "string",
-            "required": False
         }
     }
 }
 
 
 GET_RESERVATION_PRICE_SCHEMA = {
-    "$schema": "http://json-schema.org/draft-03/schema#",
+    "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "Planitech getreservationprice",
     "description": "",
     "type": "object",
+    "required": [
+        "date", "start_time", "end_time", "place_id", "name_id", "first_name", "last_name",
+        "email", "activity_id", "type_id"
+    ],
     "properties": {
         "date": {
             "description": "Date",
             "type": "string",
-            "required": True
         },
         "start_time": {
             "description": "Start time",
             "type": "string",
-            "required": True
         },
         "end_time": {
             "description": "End time",
             "type": "string",
-            "required": True
         },
         "place_id": {
             "description": "Place identifier",
             "type": "number",
-            "required": True
         },
         "name_id": {
             "description": "Publik user nameID",
             "type": "string",
-            "required": True
         },
         "first_name": {
             "description": "First name",
             "type": "string",
-            "required": True
         },
         "last_name": {
             "description": "Last name",
             "type": "string",
-            "required": True
         },
         "email": {
             "description": "Email",
             "type": "string",
-            "required": True
         },
         "activity_id": {
             "description": "Activity identifier",
             "type": "number",
-            "required": True
         },
         "type_id": {
             "description": "Rerservation type identifier",
             "type": "number",
-            "required": True
         },
         "price_code": {
             "description": "User price code",
             "type": "string",
-            "required": False
         }
     }
 }
@@ -186,20 +169,19 @@ RESERVATION_STATUS = {
 }
 
 UPDATE_RESERVATION_SCHEMA = {
-    "$schema": "http://json-schema.org/draft-03/schema#",
+    "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "Planitech updatereservation",
     "description": "",
     "type": "object",
+    "required": ["reservation_id", "status"],
     "properties": {
         "reservation_id": {
             "description": "Reservation Identifier",
             "type": "number",
-            "required": True
         },
         "status": {
             "description": "Status of the reservation",
             "type": "string",
-            "required": True,
             "enum": list(RESERVATION_STATUS.keys())
         }
     }
diff --git a/tests/test_atal.py b/tests/test_atal.py
index 1ee83f2d..c198b932 100644
--- a/tests/test_atal.py
+++ b/tests/test_atal.py
@@ -178,6 +178,33 @@ def test_upload(app, connector, monkeypatch):
         'err_desc': 'Invalid base64 string'
     }
 
+    # empty file
+    params = {
+        'numero_demande': 'DIT19050001',
+        'nom_fichier': 'data.json',
+        'file': {}
+    }
+    response = app.post_json('/atal/slug-atal/upload', params=params, status=400)
+    assert response.json == {
+        'data': None,
+        'err': 1,
+        'err_class': 'passerelle.utils.jsonresponse.APIError',
+        'err_desc': "'content' is a required property"
+    }
+
+    # no file
+    params = {
+        'numero_demande': 'DIT19050001',
+        'nom_fichier': 'data.json'
+    }
+    response = app.post_json('/atal/slug-atal/upload', params=params, status=400)
+    assert response.json == {
+        'data': None,
+        'err': 1,
+        'err_class': 'passerelle.utils.jsonresponse.APIError',
+        'err_desc': "'file' is a required property"
+    }
+
 
 def test_retrieve_details_demande(app, connector, monkeypatch):
     import passerelle.utils
-- 
2.20.1

