Projet

Général

Profil

0001-change-schema-of-api-formdefs-api-user-forms-and-api.patch

Benjamin Dauvergne, 09 octobre 2016 18:54

Télécharger (20 ko)

Voir les différences:

Subject: [PATCH] change schema of /api/formdefs, /api/user/forms and
 /api/user/drafts APIs (#13184)

All responses now have the form {"err": x, "data": y}.
 help/fr/api-user.page | 127 ++++++++++++++++++++++++++------------------------
 tests/test_api.py     | 115 ++++++++++++++++++++++++++-------------------
 wcs/api.py            |  29 ++++++------
 3 files changed, 148 insertions(+), 123 deletions(-)
help/fr/api-user.page
63 63
    </p>
64 64
<screen>
65 65
<output style="prompt">$ </output><input>curl https://www.example.net/api/user/forms</input>
66
<output>[
67
    {
68
        "category_id": "1",
69
        "category_name": "Divers",
70
        "datetime": "2014-03-28 15:36:52",
71
        "form_name": "Demande d'inscription",
72
        "form_slug": "demande-d-inscription",
73
        "form_number": "123",
74
        "form_number_raw": "123",
75
        "form_receipt_date": "28/03/2014",
76
        "form_receipt_time": "15:36",
77
        "form_status": "Nouveau",
78
        "form_status_is_endpoint": false,
79
        "form_uri": "demande-d-inscription/123/",
80
        "form_url": "http://www.example.net/demande-d-inscription/123/",
81
        "form_url_backoffice": "http://www.example.net/backoffice/demande-d-inscription/123/",
82
        "name": "Demande d'inscription",
83
        "status": "Nouveau",
84
        "title": "Demande d'inscription #123 (Nouveau)",
85
        "url": "http://www.example.net/demande-d-inscription/123/",
86
    },
87
    {
88
        "category_id": "2",
89
        "category_name": "Prise de rendez-vous",
90
        "datetime": "2014-03-17 10:39:52",
91
        "form_name": "Rendez-vous avec le service B",
92
        "form_slug": "rendez-vous-service-b",
93
        "form_number": "456",
94
        "form_number_raw": "456",
95
        "form_receipt_date": "17/03/2014",
96
        "form_receipt_time": "10:39",
97
        "form_status": "En cours",
98
        "form_status_is_endpoint": false,
99
        "form_uri": "rendez-vous-service-b/456/",
100
        "form_url": "http://www.example.net/rendez-vous-service-b/456/",
101
        "form_url_backoffice": "http://www.example.net/backoffice/rendez-vous-service-b/456/",
102
        "name": "Rendez-vous avec le service B"",
103
        "status": "Nouveau",
104
        "title": "Rendez-vous avec le service B #456 (En cours)",
105
        "url": "http://www.example.net/rendez-vous-service-b/456/",
106
    },
107
    {
108
        "category_id": "3",
109
        "category_name": "Modification de vos coordonn\u00e9es",
110
        "datetime": "2014-03-17 10:42:17",
111
        "form_name": "Changement d'adresse",
112
        "form_slug": "changement-d-adresse",
113
        "form_number": "424",
114
        "form_number_raw": "424",
115
        "form_receipt_date": "17/03/2014",
116
        "form_receipt_time": "10:42",
117
        "form_status": "Traitement de la demande termin\u00e9",
118
        "form_status_is_endpoint": true,
119
        "form_uri": "changement-d-adresse/424/",
120
        "form_url": "http://www.example.net/changement-d-adresse/424/",
121
        "form_url_backoffice": "http://www.example.net/backoffice/changement-d-adresse/424/",
122
        "name": "Changement d'adresse",
123
        "status": "Traitement de la demande termin\u00e9",
124
        "title": "Changement d'adresse #424 (Traitement de la demande termin\u00e9)",
125
        "url": "http://www.example.net/changement-d-adresse/424/",
126
    }
127
]</output></screen>
66
<output>{
67
    "err": 0,
68
    "data": [
69
        {
70
            "category_id": "1",
71
            "category_name": "Divers",
72
            "datetime": "2014-03-28 15:36:52",
73
            "form_name": "Demande d'inscription",
74
            "form_slug": "demande-d-inscription",
75
            "form_number": "123",
76
            "form_number_raw": "123",
77
            "form_receipt_date": "28/03/2014",
78
            "form_receipt_time": "15:36",
79
            "form_status": "Nouveau",
80
            "form_status_is_endpoint": false,
81
            "form_uri": "demande-d-inscription/123/",
82
            "form_url": "http://www.example.net/demande-d-inscription/123/",
83
            "form_url_backoffice": "http://www.example.net/backoffice/demande-d-inscription/123/",
84
            "name": "Demande d'inscription",
85
            "status": "Nouveau",
86
            "title": "Demande d'inscription #123 (Nouveau)",
87
            "url": "http://www.example.net/demande-d-inscription/123/",
88
        },
89
        {
90
            "category_id": "2",
91
            "category_name": "Prise de rendez-vous",
92
            "datetime": "2014-03-17 10:39:52",
93
            "form_name": "Rendez-vous avec le service B",
94
            "form_slug": "rendez-vous-service-b",
95
            "form_number": "456",
96
            "form_number_raw": "456",
97
            "form_receipt_date": "17/03/2014",
98
            "form_receipt_time": "10:39",
99
            "form_status": "En cours",
100
            "form_status_is_endpoint": false,
101
            "form_uri": "rendez-vous-service-b/456/",
102
            "form_url": "http://www.example.net/rendez-vous-service-b/456/",
103
            "form_url_backoffice": "http://www.example.net/backoffice/rendez-vous-service-b/456/",
104
            "name": "Rendez-vous avec le service B"",
105
            "status": "Nouveau",
106
            "title": "Rendez-vous avec le service B #456 (En cours)",
107
            "url": "http://www.example.net/rendez-vous-service-b/456/",
108
        },
109
        {
110
            "category_id": "3",
111
            "category_name": "Modification de vos coordonn\u00e9es",
112
            "datetime": "2014-03-17 10:42:17",
113
            "form_name": "Changement d'adresse",
114
            "form_slug": "changement-d-adresse",
115
            "form_number": "424",
116
            "form_number_raw": "424",
117
            "form_receipt_date": "17/03/2014",
118
            "form_receipt_time": "10:42",
119
            "form_status": "Traitement de la demande termin\u00e9",
120
            "form_status_is_endpoint": true,
121
            "form_uri": "changement-d-adresse/424/",
122
            "form_url": "http://www.example.net/changement-d-adresse/424/",
123
            "form_url_backoffice": "http://www.example.net/backoffice/changement-d-adresse/424/",
124
            "name": "Changement d'adresse",
125
            "status": "Traitement de la demande termin\u00e9",
126
            "title": "Changement d'adresse #424 (Traitement de la demande termin\u00e9)",
127
            "url": "http://www.example.net/changement-d-adresse/424/",
128
        }
129
    ]
130
}</output></screen>
128 131

  
129 132
<p>
130 133
Il est possible de recevoir un ensemble plus complet de données en passant un
tests/test_api.py
167 167
    output = get_app(pub).get('/categories?%s&signature=%s' % (query, signature))
168 168
    assert output.json == {'data': []}
169 169
    output = get_app(pub).get('/json?%s&signature=%s' % (query, signature))
170
    assert output.json == []
170
    assert output.json == {'err': 0, 'data': []}
171 171

  
172 172
def test_get_user_from_api_query_string_error_unknown_nameid_valid_endpoint(pub):
173 173
    # check the categories and forms endpoints accept an unknown NameID
......
181 181
    output = get_app(pub).get('/categories?%s&signature=%s' % (query, signature))
182 182
    assert output.json == {'data': []}
183 183
    output = get_app(pub).get('/json?%s&signature=%s' % (query, signature))
184
    assert output.json == []
184
    assert output.json == {'err': 0, 'data': []}
185 185

  
186 186
def test_get_user_from_api_query_string_error_success_sha1(pub, local_user):
187 187
    timestamp = datetime.datetime.utcnow().isoformat()[:19] + 'Z'
......
276 276
    resp2 = get_app(pub).get('/', headers={'Accept': 'application/json'})
277 277
    resp3 = get_app(pub).get('/api/formdefs/')
278 278
    assert resp1.json == resp2.json == resp3.json
279
    assert resp1.json[0]['title'] == 'test'
280
    assert resp1.json[0]['url'] == 'http://example.net/test/'
281
    assert resp1.json[0]['count'] == 0
282
    assert resp1.json[0]['redirection'] == False
283
    assert resp1.json[0]['description'] == 'plop'
284
    assert resp1.json[0]['keywords'] == ['mobile', 'test']
285
    assert resp1.json[0]['functions'].keys() == ['_receiver']
286
    assert resp1.json[0]['functions']['_receiver']['label'] == 'Recipient'
287
    assert resp1.json[0]['functions']['_receiver']['role']['slug'] == role.slug
288
    assert resp1.json[0]['functions']['_receiver']['role']['name'] == role.name
279
    assert resp1.json['data'][0]['title'] == 'test'
280
    assert resp1.json['data'][0]['url'] == 'http://example.net/test/'
281
    assert resp1.json['data'][0]['count'] == 0
282
    assert resp1.json['data'][0]['redirection'] == False
283
    assert resp1.json['data'][0]['description'] == 'plop'
284
    assert resp1.json['data'][0]['keywords'] == ['mobile', 'test']
285
    assert resp1.json['data'][0]['functions'].keys() == ['_receiver']
286
    assert resp1.json['data'][0]['functions']['_receiver']['label'] == 'Recipient'
287
    assert resp1.json['data'][0]['functions']['_receiver']['role']['slug'] == role.slug
288
    assert resp1.json['data'][0]['functions']['_receiver']['role']['name'] == role.name
289 289

  
290 290
def test_limited_formdef_list(pub, local_user):
291 291
    Role.wipe()
......
302 302
    formdef.store()
303 303

  
304 304
    resp = get_app(pub).get('/api/formdefs/')
305
    assert len(resp.json) == 1
305
    assert resp.json['err'] == 0
306
    assert len(resp.json['data']) == 1
306 307

  
307 308
    # check it's not advertised
308 309
    formdef.roles = [role.id]
......
311 312
    resp2 = get_app(pub).get(sign_uri('/api/formdefs/?NameID='))
312 313
    resp3 = get_app(pub).get(sign_uri('/api/formdefs/?NameID=XXX'))
313 314
    resp4 = get_app(pub).get(sign_uri('/api/formdefs/?NameID=%s' % local_user.name_identifiers[0]))
314
    assert len(resp.json) == 0
315
    assert resp.json['err'] == 0
316
    assert len(resp.json['data']) == 0
315 317
    assert resp.json == resp2.json == resp3.json == resp4.json
316 318

  
317 319
    # unless user has correct roles
318 320
    local_user.roles = [role.id]
319 321
    local_user.store()
320 322
    resp = get_app(pub).get(sign_uri('/api/formdefs/?NameID=%s' % local_user.name_identifiers[0]))
321
    assert len(resp.json) == 1
323
    assert resp.json['err'] == 0
324
    assert len(resp.json['data']) == 1
322 325

  
323 326
    local_user.roles = []
324 327
    local_user.store()
......
330 333
    resp2 = get_app(pub).get(sign_uri('/api/formdefs/?NameID='))
331 334
    resp3 = get_app(pub).get(sign_uri('/api/formdefs/?NameID=XXX'))
332 335
    resp4 = get_app(pub).get(sign_uri('/api/formdefs/?NameID=%s' % local_user.name_identifiers[0]))
333
    assert len(resp.json) == 1
334
    assert resp.json[0]['authentication_required']
336
    assert resp.json['err'] == 0
337
    assert len(resp.json['data']) == 1
338
    assert resp.json['data'][0]['authentication_required']
335 339
    assert resp.json == resp2.json == resp3.json == resp4.json
336 340

  
337 341
def test_formdef_list_redirection(pub):
......
344 348
    formdef.store()
345 349

  
346 350
    resp1 = get_app(pub).get('/json')
347
    assert resp1.json[0]['title'] == 'test'
348
    assert resp1.json[0]['url'] == 'http://example.net/test/'
349
    assert resp1.json[0]['count'] == 0
350
    assert resp1.json[0]['redirection'] == True
351
    assert resp1.json['err'] == 0
352
    assert resp1.json['data'][0]['title'] == 'test'
353
    assert resp1.json['data'][0]['url'] == 'http://example.net/test/'
354
    assert resp1.json['data'][0]['count'] == 0
355
    assert resp1.json['data'][0]['redirection'] == True
351 356

  
352 357

  
353 358
def test_formdef_schema(pub):
......
739 744
    resp = get_app(pub).get('/api/categories/category/formdefs/')
740 745
    resp2 = get_app(pub).get('/category/json')
741 746
    assert resp.json == resp2.json
742
    assert len(resp.json) == 2
743
    assert resp.json[0]['title'] == 'test'
744
    assert resp.json[0]['url'] == 'http://example.net/test/'
745
    assert resp.json[0]['count'] == 0
746
    assert resp.json[0]['redirection'] == False
747
    assert resp.json[0]['category'] == 'Category'
748
    assert resp.json[0]['category_slug'] == 'category'
747
    assert resp.json['err'] == 0
748
    assert len(resp.json['data']) == 2
749
    assert resp.json['data'][0]['title'] == 'test'
750
    assert resp.json['data'][0]['url'] == 'http://example.net/test/'
751
    assert resp.json['data'][0]['count'] == 0
752
    assert resp.json['data'][0]['redirection'] == False
753
    assert resp.json['data'][0]['category'] == 'Category'
754
    assert resp.json['data'][0]['category_slug'] == 'category'
749 755

  
750 756
def test_categories_full(pub):
751 757
    test_categories(pub)
......
996 1002
    formdef.data_class().wipe()
997 1003

  
998 1004
    resp = get_app(pub).get(sign_uri('/api/user/forms', user=local_user))
999
    assert len(resp.json) == 0
1005
    assert resp.json['err'] == 0
1006
    assert len(resp.json['data']) == 0
1000 1007

  
1001 1008
    formdata = formdef.data_class()()
1002 1009
    formdata.data = {'0': 'foo@localhost', '1': 'xxx'}
......
1008 1015
    resp = get_app(pub).get(sign_uri('/api/user/forms', user=local_user))
1009 1016
    resp2 = get_app(pub).get(sign_uri('/myspace/forms', user=local_user))
1010 1017
    resp3 = get_app(pub).get(sign_uri('/api/users/%s/forms' % local_user.id))
1011
    assert len(resp.json) == 1
1012
    assert resp.json[0]['form_name'] == 'test'
1013
    assert resp.json[0]['form_slug'] == 'test'
1014
    assert resp.json[0]['form_status'] == 'New'
1015
    assert resp.json[0]['keywords'] == ['hello', 'world']
1018
    assert resp.json['err'] == 0
1019
    assert len(resp.json['data']) == 1
1020
    assert resp.json['data'][0]['form_name'] == 'test'
1021
    assert resp.json['data'][0]['form_slug'] == 'test'
1022
    assert resp.json['data'][0]['form_status'] == 'New'
1023
    assert resp.json['data'][0]['keywords'] == ['hello', 'world']
1016 1024
    assert resp.json == resp2.json == resp3.json
1017 1025

  
1018
    resp = get_app(pub).get(sign_uri('/api/user/forms?full=on', user=local_user))
1019
    assert resp.json[0]['fields']['foobar'] == 'foo@localhost'
1020
    assert resp.json[0]['keywords'] == ['hello', 'world']
1026
    resp = get_app(pub).get(sign_uri('/api/user/forms?&full=on', user=local_user))
1027
    assert resp.json['err'] == 0
1028
    assert resp.json['data'][0]['fields']['foobar'] == 'foo@localhost'
1029
    assert resp.json['data'][0]['keywords'] == ['hello', 'world']
1021 1030

  
1022 1031
    formdef.disabled = True
1023 1032
    formdef.store()
1024 1033
    resp = get_app(pub).get(sign_uri('/api/user/forms', user=local_user))
1025
    assert len(resp.json) == 1
1034
    assert resp.json['err'] == 0
1035
    assert len(resp.json['data']) == 1
1036

  
1037
    resp = get_app(pub).get(sign_uri('/api/user/forms?&NameID=xxx'))
1038
    assert resp.json == {'err': 1, 'err_desc': 'unknown user', 'data': []}
1039

  
1026 1040

  
1027 1041
def test_user_drafts(pub, local_user):
1028 1042
    FormDef.wipe()
......
1038 1052
    formdef.store()
1039 1053

  
1040 1054
    resp = get_app(pub).get(sign_uri('/api/user/drafts', user=local_user))
1041
    assert len(resp.json) == 0
1055
    assert resp.json['err'] == 0
1056
    assert len(resp.json['data']) == 0
1042 1057

  
1043 1058
    formdata = formdef.data_class()()
1044 1059
    upload = PicklableUpload('test.txt', 'text/plain', 'ascii')
......
1052 1067

  
1053 1068
    resp = get_app(pub).get(sign_uri('/api/user/drafts', user=local_user))
1054 1069
    resp2 = get_app(pub).get(sign_uri('/myspace/drafts', user=local_user))
1055
    assert len(resp.json) == 1
1070
    assert resp.json['err'] == 0
1071
    assert len(resp.json['data']) == 1
1056 1072
    assert resp.json == resp2.json
1057
    assert not 'fields' in resp.json[0]
1058
    assert resp.json[0]['keywords'] == ['hello', 'world']
1073
    assert not 'fields' in resp.json['data'][0]
1074
    assert resp.json['data'][0]['keywords'] == ['hello', 'world']
1059 1075

  
1060 1076
    resp = get_app(pub).get(sign_uri('/api/user/drafts?full=on', user=local_user))
1061
    assert 'fields' in resp.json[0]
1062
    assert resp.json[0]['fields']['foobar'] == 'foo@localhost'
1063
    assert 'file' not in resp.json[0]['fields'] # no file export in full lists
1064
    assert resp.json[0]['keywords'] == ['hello', 'world']
1077
    assert resp.json['err'] == 0
1078
    assert 'fields' in resp.json['data'][0]
1079
    assert resp.json['data'][0]['fields']['foobar'] == 'foo@localhost'
1080
    assert 'file' not in resp.json['data'][0]['fields']  # no file export in full lists
1081
    assert resp.json['data'][0]['keywords'] == ['hello', 'world']
1065 1082

  
1066 1083
    formdef.enable_tracking_codes = False
1067 1084
    formdef.store()
1068 1085
    resp = get_app(pub).get(sign_uri('/api/user/drafts', user=local_user))
1069
    assert len(resp.json) == 0
1086
    assert resp.json['err'] == 0
1087
    assert len(resp.json['data']) == 0
1070 1088

  
1071 1089
    formdef.enable_tracking_codes = True
1072 1090
    formdef.disabled = True
1073 1091
    formdef.store()
1074 1092
    resp = get_app(pub).get(sign_uri('/api/user/drafts', user=local_user))
1075
    assert len(resp.json) == 0
1093
    assert resp.json['err'] == 0
1094
    assert len(resp.json['data']) == 0
1076 1095

  
1077 1096
def test_api_list_formdata(pub, local_user):
1078 1097
    Role.wipe()
wcs/api.py
338 338
            del formdict['category_position']
339 339

  
340 340
        get_response().set_content_type('application/json')
341
        return json.dumps(list_forms)
341
        return json.dumps({'err': 0, 'data': list_forms})
342 342

  
343 343
    def _q_lookup(self, component):
344 344
        return ApiFormdefDirectory(FormDef.get_by_urlname(component))
......
432 432

  
433 433
    def drafts(self):
434 434
        get_response().set_content_type('application/json')
435
        user = self.user or get_user_from_api_query_string() or get_request().user
435
        try:
436
            user = self.user or get_user_from_api_query_string() or get_request().user
437
        except UnknownNameIdAccessForbiddenError:
438
            user = None
436 439
        if not user:
437
            raise AccessForbiddenError('no user specified')
440
            return json.dumps({'err': 1, 'err_desc': 'unknown user', 'data': []})
438 441
        drafts = []
439 442
        for form in self.get_user_forms(user):
440 443
            if not form.is_draft():
......
457 460
                d.update(form.get_json_export_dict(include_files=False))
458 461
            drafts.append(d)
459 462

  
460
        return json.dumps(drafts,
461
                cls=misc.JSONEncoder,
462
                encoding=get_publisher().site_charset)
463
        return json.dumps({'err': 0, 'data': drafts}, cls=misc.JSONEncoder,
464
                          encoding=get_publisher().site_charset)
463 465

  
464 466
    def forms(self):
465 467
        get_response().set_content_type('application/json')
466
        user = self.user or get_user_from_api_query_string() or get_request().user
468
        try:
469
            user = self.user or get_user_from_api_query_string() or get_request().user
470
        except UnknownNameIdAccessForbiddenError:
471
            user = None
467 472
        if not user:
468
            raise AccessForbiddenError('no user specified')
473
            return json.dumps({'err': 1, 'err_desc': 'unknown user', 'data': []})
469 474
        forms = []
470 475
        for form in self.get_user_forms(user):
471 476
            if form.is_draft():
......
494 499
            if get_request().form.get('full') == 'on':
495 500
                d.update(form.get_json_export_dict(include_files=False))
496 501
            forms.append(d)
497

  
498
        return json.dumps(forms,
499
                cls=misc.JSONEncoder,
500
                encoding=get_publisher().site_charset)
502
        return json.dumps({'err': 0, 'data': forms}, cls=misc.JSONEncoder,
503
                          encoding=get_publisher().site_charset)
501 504

  
502 505

  
503 506
class ApiUsersDirectory(Directory):
......
605 608
        for role in Role.select():
606 609
            list_roles.append(role.get_json_export_dict())
607 610
        get_response().set_content_type('application/json')
608
        return json.dumps({'data': list_roles})
611
        return json.dumps({'err': 0, 'data': list_roles})
609 612

  
610 613
    def _q_traverse(self, path):
611 614
        get_request().is_json_marker = True
612
-