Skip to content

Commit a1cea47

Browse files
authored
Merge pull request #246 from novafloss/validate-view-from-schema
Add a ValidateView that works with ContextForm JSON
2 parents 5e59d97 + 00b8dac commit a1cea47

File tree

9 files changed

+96
-10
lines changed

9 files changed

+96
-10
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ ChangeLog
55
master (unreleased)
66
===================
77

8-
- Nothing yet.
8+
- Add a ValidateView that works with ContextForm JSON (#246).
99

1010
Release 0.13.1 (2017-07-17)
1111
===========================

circle.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ machine:
44

55
dependencies:
66
override:
7-
- pip install --upgrade tox
7+
- pip install --upgrade tox virtualenv
88

99
test:
1010
override:

demo/demo/urls.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
from django.conf.urls import include, url
22
from django.contrib import admin
33

4-
from demo.views import FormPreview
4+
from demo.views import FormPreview, DemoValidateViewFromSchema
55

66
urlpatterns = [
77
url(r'^api/', include('formidable.urls', namespace='formidable')),
8+
url(r'^api/forms/(?P<pk>\d+)/validate_schema/?$',
9+
DemoValidateViewFromSchema.as_view(),
10+
name='form_validation_schema'),
811
url(r'^admin/', include(admin.site.urls)),
912
url(r'^preview/(?P<pk>\d+)/', FormPreview.as_view()),
1013
url(r'^forms/', include('demo.builder.urls', namespace='builder')),

demo/demo/views.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from django.views.generic.edit import FormView
44

55
from formidable.models import Formidable
6+
import formidable.views
67
from formidable.views import ContextFormDetail
78

89

@@ -24,3 +25,12 @@ class DemoContextFormDetail(ContextFormDetail):
2425

2526
def get_context(self, request, **kwargs):
2627
return kwargs['role']
28+
29+
30+
class DemoValidateViewFromSchema(formidable.views.ValidateViewFromSchema):
31+
32+
settings_permission_key = 'FORMIDABLE_PERMISSION_USING'
33+
34+
def get_formidable_object(self, kwargs):
35+
formidable = Formidable.objects.get(pk=kwargs['pk'])
36+
return formidable.to_json()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
TestContextFormEndPoint.test_queryset:
2+
- db: 'SELECT ... FROM "django_session" WHERE ("django_session"."expire_date" > # AND "django_session"."session_key" = #)'
3+
- db: 'SELECT ... FROM "formidable_formidable" WHERE "formidable_formidable"."id" = #'
4+
- db: 'SELECT ... FROM "formidable_field" WHERE "formidable_field"."form_id" = # ORDER BY "formidable_field"."order" ASC'
5+
- db: 'SELECT ... FROM "formidable_access" WHERE ("formidable_access"."access_id" = # AND NOT ("formidable_access"."level" = #) AND "formidable_access"."field_id" IN (...))'
6+
- db: SELECT ... FROM "formidable_item" WHERE "formidable_item"."field_id" IN (...) ORDER BY "formidable_item"."order" ASC
7+
- db: SELECT ... FROM "formidable_validation" WHERE "formidable_validation"."field_id" IN (...)
8+
- db: SELECT ... FROM "formidable_default" WHERE "formidable_default"."field_id" IN (...)
9+
- db: 'SELECT ... FROM "formidable_preset" WHERE "formidable_preset"."form_id" = #'
10+
- db: SELECT ... FROM "formidable_presetarg" WHERE "formidable_presetarg"."preset_id" IN (...)
11+
UpdateFormTestCase.test_queryset_on_get:
12+
- db: 'SELECT ... FROM "formidable_formidable" WHERE "formidable_formidable"."id" = #'
13+
- db: 'SELECT ... FROM "formidable_field" WHERE "formidable_field"."form_id" = # ORDER BY "formidable_field"."order" ASC'
14+
- db: SELECT ... FROM "formidable_item" WHERE "formidable_item"."field_id" IN (...) ORDER BY "formidable_item"."order" ASC
15+
- db: SELECT ... FROM "formidable_default" WHERE "formidable_default"."field_id" IN (...)
16+
- db: SELECT ... FROM "formidable_validation" WHERE "formidable_validation"."field_id" IN (...)
17+
- db: SELECT ... FROM "formidable_access" WHERE "formidable_access"."field_id" IN (...)
18+
- db: 'SELECT ... FROM "formidable_preset" WHERE "formidable_preset"."form_id" = #'
19+
- db: SELECT ... FROM "formidable_presetarg" WHERE "formidable_presetarg"."preset_id" IN (...)

demo/tests/tests_integration.py renamed to demo/tests/test_integration.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,8 @@ class Meta:
445445

446446
class TestValidationEndPoint(FormidableAPITestCase):
447447

448+
url = 'formidable:form_validation'
449+
448450
def setUp(self):
449451
super(TestValidationEndPoint, self).setUp()
450452
self.formidable = MyForm.to_formidable(label='title')
@@ -459,7 +461,7 @@ def test_validate_data_ok(self):
459461
session['role'] = 'padawan'
460462
session.save()
461463
res = self.client.get(
462-
reverse('formidable:form_validation', args=[self.formidable.pk]),
464+
reverse(self.url, args=[self.formidable.pk]),
463465
parameters, format='json'
464466
)
465467
self.assertEqual(res.status_code, 204)
@@ -473,7 +475,7 @@ def test_validate_presets_ok(self):
473475
session['role'] = 'padawan'
474476
session.save()
475477
res = self.client.get(
476-
reverse('formidable:form_validation', args=[self.formidable_p.pk]),
478+
reverse(self.url, args=[self.formidable_p.pk]),
477479
parameters, format='json'
478480
)
479481
self.assertEqual(res.status_code, 204)
@@ -487,7 +489,7 @@ def test_validate_presets_ko(self):
487489
session['role'] = 'padawan'
488490
session.save()
489491
res = self.client.get(
490-
reverse('formidable:form_validation', args=[self.formidable_p.pk]),
492+
reverse(self.url, args=[self.formidable_p.pk]),
491493
parameters, format='json'
492494
)
493495
self.assertEqual(res.status_code, 400)
@@ -504,7 +506,7 @@ def test_validate_data_ko(self):
504506
session['role'] = 'padawan'
505507
session.save()
506508
res = self.client.get(
507-
reverse('formidable:form_validation', args=[self.formidable.pk]),
509+
reverse(self.url, args=[self.formidable.pk]),
508510
parameters, format='json'
509511
)
510512
self.assertEqual(res.status_code, 400)
@@ -523,7 +525,12 @@ class WithFile(FormidableForm):
523525
session['role'] = 'padawan'
524526
session.save()
525527
res = self.client.get(
526-
reverse('formidable:form_validation', args=[formidable.pk]),
528+
reverse(self.url, args=[formidable.pk]),
527529
parameters, format='json'
528530
)
529531
self.assertEqual(res.status_code, 204)
532+
533+
534+
class TestValidationFromSchemaEndPoint(TestValidationEndPoint):
535+
536+
url = 'form_validation_schema'

demo/tests/test_permissions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def test_settings_key_not_define(self):
4242
self.assertEqual(len(permission_classes), 1)
4343
self.assertEqual(permission_classes[0], AllowAny)
4444

45+
@override_settings()
4546
def test_no_settings_key_define(self):
4647
del settings.FORMIDABLE_DEFAULT_PERMISSION
4748

formidable/forms/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,12 @@ def get_dynamic_form_class_from_schema(schema, field_factory=None):
7070
field_factory = field_factory or field_builder_from_schema.FormFieldFactory() # noqa
7171
doc = schema['description']
7272
for field in schema['fields']:
73-
attrs[field['slug']] = field_factory.produce(field)
73+
try:
74+
form_field = field_factory.produce(field)
75+
except field_builder.SkipField:
76+
pass
77+
else:
78+
attrs[field['slug']] = form_field
7479

7580
conditions = schema.get('conditions', None) or []
7681
attrs['_conditions'] = conditions_register.build(

formidable/views.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# -*- coding: utf-8 -*-
2+
23
from __future__ import unicode_literals
34

45
import logging
@@ -9,13 +10,16 @@
910
import six
1011
from formidable.accesses import get_accesses, get_context
1112
from formidable.exception_handler import ExceptionHandlerMixin
13+
from formidable.forms import (
14+
field_builder_from_schema, get_dynamic_form_class_from_schema
15+
)
1216
from formidable.forms.field_builder import (
1317
FileFieldBuilder, FormFieldFactory, SkipField
1418
)
1519
from formidable.forms.validations.presets import presets_register
1620
from formidable.models import Formidable
1721
from formidable.serializers import FormidableSerializer, SimpleAccessSerializer
18-
from formidable.serializers.forms import ContextFormSerializer
22+
from formidable.serializers.forms import ContextFormSerializer, contextualize
1923
from formidable.serializers.presets import PresetsClassSerializer
2024
from rest_framework import exceptions
2125
from rest_framework.generics import (
@@ -290,3 +294,40 @@ def get_form(self, form_class):
290294

291295
def get_form_kwargs(self):
292296
return {'data': self.request.GET}
297+
298+
299+
class ValidateViewFromSchema(ValidateView):
300+
"""
301+
Acts like `ValidateView` but it uses a Formidable JSON schema
302+
instead of a `Formidable` object.
303+
304+
"""
305+
306+
settings_permission_key = 'FORMIDABLE_PERMISSION_USING'
307+
308+
def get_formidable_object(self):
309+
"""
310+
This method should implement a way to retrieve the formidable
311+
object with its JSON representation.
312+
313+
"""
314+
raise NotImplemented
315+
316+
class ValidationFileFieldBuilder(field_builder_from_schema.FileFieldBuilder): # noqa
317+
318+
def build(self, *args, **kwargs):
319+
raise SkipField
320+
321+
def get_form_class(self, formidable):
322+
"""
323+
Retrieve form class from JSON definition, for a given role.
324+
325+
"""
326+
role = get_context(self.request, self.kwargs)
327+
328+
factory = field_builder_from_schema.FormFieldFactory(
329+
field_map={'file': self.ValidationFileFieldBuilder}
330+
)
331+
schema = contextualize(formidable, role)
332+
return get_dynamic_form_class_from_schema(schema,
333+
field_factory=factory)

0 commit comments

Comments
 (0)