Skip to content

Commit

Permalink
feat(form): add question for static content (#396)
Browse files Browse the repository at this point in the history
* feat(form): add question for static content

This adds a question type that can be used for inserting static content
like subheadings, additional text, images, videos, links etc. inside
forms (it will be rendered as markdown in the frontend).
Since it is not an actual question, no corresponding answer type
is required.

* Fix merge conflict in migrations
  • Loading branch information
czosel authored Apr 29, 2019
1 parent 1092852 commit 56e4687
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 2 deletions.
6 changes: 6 additions & 0 deletions caluma/form/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ class QuestionFactory(DjangoModelFactory):
sub_form = Maybe(
"is_form", yes_declaration=SubFactory(FormFactory), no_declaration=None
)
static_content = Maybe(
"is_static",
yes_declaration=Faker("multilang", faker_provider="text"),
no_declaration=None,
)

data_source = Maybe(
"is_dynamic", yes_declaration="MyDataSource", no_declaration=None
Expand All @@ -50,6 +55,7 @@ class Params:
models.Question.TYPE_DYNAMIC_MULTIPLE_CHOICE,
]
)
is_static = LazyAttribute(lambda q: q.type == models.Question.TYPE_STATIC)


class OptionFactory(DjangoModelFactory):
Expand Down
43 changes: 43 additions & 0 deletions caluma/form/migrations/0014_auto_20190429_0910.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-04-29 09:10
from __future__ import unicode_literals

from django.db import migrations, models
import localized_fields.fields.text_field


class Migration(migrations.Migration):

dependencies = [("form", "0013_auto_20190418_0733")]

operations = [
migrations.AddField(
model_name="question",
name="static_content",
field=localized_fields.fields.text_field.LocalizedTextField(
blank=True, null=True, required=[]
),
),
migrations.AlterField(
model_name="question",
name="type",
field=models.CharField(
choices=[
("multiple_choice", "multiple_choice"),
("integer", "integer"),
("float", "float"),
("date", "date"),
("choice", "choice"),
("textarea", "textarea"),
("text", "text"),
("table", "table"),
("form", "form"),
("file", "file"),
("dynamic_choice", "dynamic_choice"),
("dynamic_multiple_choice", "dynamic_multiple_choice"),
("static", "static"),
],
max_length=23,
),
),
]
5 changes: 4 additions & 1 deletion caluma/form/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.db import models, transaction
from django.db.models.signals import post_init
from django.dispatch import receiver
from localized_fields.fields import LocalizedField
from localized_fields.fields import LocalizedField, LocalizedTextField

from ..core.models import SlugModel, UUIDModel
from .storage_clients import client
Expand Down Expand Up @@ -49,6 +49,7 @@ class Question(SlugModel):
TYPE_FILE = "file"
TYPE_DYNAMIC_CHOICE = "dynamic_choice"
TYPE_DYNAMIC_MULTIPLE_CHOICE = "dynamic_multiple_choice"
TYPE_STATIC = "static"

TYPE_CHOICES = (
TYPE_MULTIPLE_CHOICE,
Expand All @@ -63,6 +64,7 @@ class Question(SlugModel):
TYPE_FILE,
TYPE_DYNAMIC_CHOICE,
TYPE_DYNAMIC_MULTIPLE_CHOICE,
TYPE_STATIC,
)
TYPE_CHOICES_TUPLE = ((type_choice, type_choice) for type_choice in TYPE_CHOICES)

Expand All @@ -73,6 +75,7 @@ class Question(SlugModel):
is_archived = models.BooleanField(default=False)
placeholder = LocalizedField(blank=True, null=True, required=False)
info_text = LocalizedField(blank=True, null=True, required=False)
static_content = LocalizedTextField(blank=True, null=True, required=False)
configuration = JSONField(default=dict)
meta = JSONField(default=dict)
data_source = models.CharField(max_length=255, blank=True, null=True)
Expand Down
36 changes: 36 additions & 0 deletions caluma/form/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def resolve_type(cls, instance, info):
models.Question.TYPE_TABLE: TableQuestion,
models.Question.TYPE_FORM: FormQuestion,
models.Question.TYPE_FILE: FileQuestion,
models.Question.TYPE_STATIC: StaticQuestion,
}

return QUESTION_OBJECT_TYPE[instance.type]
Expand Down Expand Up @@ -117,6 +118,7 @@ class Meta:
"answers",
"row_form",
"sub_form",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -136,6 +138,7 @@ class Meta:
"answers",
"row_form",
"sub_form",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -153,6 +156,7 @@ class Meta:
"row_form",
"sub_form",
"placeholder",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -173,6 +177,7 @@ class Meta:
"row_form",
"sub_form",
"placeholder",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand Down Expand Up @@ -214,6 +219,7 @@ class Meta:
"row_form",
"sub_form",
"placeholder",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -235,6 +241,7 @@ class Meta:
"row_form",
"sub_form",
"placeholder",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -255,6 +262,7 @@ class Meta:
"answers",
"row_form",
"sub_form",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -275,6 +283,7 @@ class Meta:
"answers",
"row_form",
"sub_form",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -291,6 +300,7 @@ class Meta:
"answers",
"sub_form",
"placeholder",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -307,6 +317,7 @@ class Meta:
"answers",
"row_form",
"placeholder",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -324,6 +335,24 @@ class Meta:
"row_form",
"sub_form",
"placeholder",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)


class StaticQuestion(QuestionQuerysetMixin, DjangoObjectType):
class Meta:
model = models.Question
exclude_fields = (
"type",
"configuration",
"options",
"answers",
"row_form",
"sub_form",
"placeholder",
"is_required",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand Down Expand Up @@ -465,6 +494,12 @@ class Meta:
return_field_type = Question


class SaveStaticQuestion(SaveQuestion):
class Meta:
serializer_class = serializers.SaveStaticQuestionSerializer
return_field_type = Question


class SaveOption(UserDefinedPrimaryKeyMixin, Mutation):
class Meta:
serializer_class = serializers.SaveOptionSerializer
Expand Down Expand Up @@ -733,6 +768,7 @@ class Mutation(object):
save_table_question = SaveTableQuestion().Field()
save_form_question = SaveFormQuestion().Field()
save_file_question = SaveFileQuestion().Field()
save_static_question = SaveStaticQuestion().Field()

save_document = SaveDocument().Field()
save_document_string_answer = SaveDocumentStringAnswer().Field()
Expand Down
19 changes: 19 additions & 0 deletions caluma/form/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,25 @@ class Meta(SaveQuestionSerializer.Meta):
fields = SaveQuestionSerializer.Meta.fields


class SaveStaticQuestionSerializer(SaveQuestionSerializer):
static_content = CharField(required=True)

def validate(self, data):
data["type"] = models.Question.TYPE_STATIC
return super().validate(data)

class Meta(SaveQuestionSerializer.Meta):
fields = (
"label",
"slug",
"info_text",
"is_hidden",
"meta",
"is_archived",
"static_content",
)


class SaveOptionSerializer(serializers.ModelSerializer):
class Meta:
fields = ("slug", "label", "meta")
Expand Down
35 changes: 35 additions & 0 deletions caluma/form/tests/snapshots/snap_test_question.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from snapshottest import Snapshot


snapshots = Snapshot()

snapshots["test_save_question[true-True-SaveTextQuestion] 1"] = {
Expand Down Expand Up @@ -605,3 +606,37 @@
]
}
}

snapshots["test_save_static_question[static] 1"] = {
"saveStaticQuestion": {
"clientMutationId": "testid",
"question": {
"__typename": "StaticQuestion",
"id": "U3RhdGljUXVlc3Rpb246ZWZmb3J0LW1lZXQ=",
"label": "Brian Williams",
"meta": {},
"slug": "effort-meet",
"staticContent": """Line whatever team suggest traditional boy. Drop argue move. Anyone remember prove.
Kid avoid player relationship to range whose. Draw free property consider.""",
},
}
}

snapshots["test_query_all_questions[static-question__configuration12] 1"] = {
"allQuestions": {
"edges": [
{
"node": {
"__typename": "StaticQuestion",
"id": "U3RhdGljUXVlc3Rpb246ZWZmb3J0LW1lZXQ=",
"infoText": "",
"label": "Brian Williams",
"meta": {},
"slug": "effort-meet",
"staticContent": """Line whatever team suggest traditional boy. Drop argue move. Anyone remember prove.
Kid avoid player relationship to range whose. Draw free property consider.""",
}
}
]
}
}
2 changes: 1 addition & 1 deletion caluma/form/tests/test_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def test_complex_document_query_performance(
}
"""

with django_assert_num_queries(11):
with django_assert_num_queries(12):
result = schema_executor(query, variables={"id": str(document.pk)})
assert not result.errors

Expand Down
34 changes: 34 additions & 0 deletions caluma/form/tests/test_question.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
(models.Question.TYPE_FILE, {}),
(models.Question.TYPE_DYNAMIC_CHOICE, {"data_source": "MyDataSource"}),
(models.Question.TYPE_DYNAMIC_MULTIPLE_CHOICE, {"data_source": "MyDataSource"}),
(models.Question.TYPE_STATIC, {}),
],
)
def test_query_all_questions(
Expand Down Expand Up @@ -108,6 +109,9 @@ def test_query_all_questions(
slug
}
}
... on StaticQuestion {
staticContent
}
}
}
}
Expand Down Expand Up @@ -595,3 +599,33 @@ def test_save_form_question(db, snapshot, question, question_option, schema_exec
result = schema_executor(query, variables=inp)
assert not result.errors
snapshot.assert_match(result.data)


@pytest.mark.parametrize("question__type", [models.Question.TYPE_STATIC])
def test_save_static_question(db, snapshot, question, schema_executor):
query = """
mutation SaveStaticQuestion($input: SaveStaticQuestionInput!) {
saveStaticQuestion(input: $input) {
question {
id
slug
label
meta
__typename
... on StaticQuestion {
staticContent
}
}
clientMutationId
}
}
"""

inp = {
"input": extract_serializer_input_fields(
serializers.SaveStaticQuestionSerializer, question
)
}
result = schema_executor(query, variables=inp)
assert not bool(result.errors)
snapshot.assert_match(result.data)
1 change: 1 addition & 0 deletions caluma/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class Query(
form_schema.TableQuestion,
form_schema.FormQuestion,
form_schema.FileQuestion,
form_schema.StaticQuestion,
form_schema.StringAnswer,
form_schema.ListAnswer,
form_schema.IntegerAnswer,
Expand Down
Loading

0 comments on commit 56e4687

Please sign in to comment.