Skip to content

Commit

Permalink
feat(form): add question for static content
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
czosel committed Apr 28, 2019
1 parent 719b4b8 commit c7564de
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 0 deletions.
6 changes: 6 additions & 0 deletions caluma/form/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,19 @@ 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,
)

class Meta:
model = models.Question

class Params:
is_table = LazyAttribute(lambda q: q.type == models.Question.TYPE_TABLE)
is_form = LazyAttribute(lambda q: q.type == models.Question.TYPE_FORM)
is_static = LazyAttribute(lambda q: q.type == models.Question.TYPE_STATIC)


class OptionFactory(DjangoModelFactory):
Expand Down
41 changes: 41 additions & 0 deletions caluma/form/migrations/0013_auto_20190428_1324.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-04-28 13:24
from __future__ import unicode_literals

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


class Migration(migrations.Migration):

dependencies = [("form", "0012_auto_20190416_1835")]

operations = [
migrations.AddField(
model_name="question",
name="static_content",
field=localized_fields.fields.field.LocalizedField(
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"),
("static", "static"),
],
max_length=15,
),
),
]
3 changes: 3 additions & 0 deletions caluma/form/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class Question(SlugModel):
TYPE_TABLE = "table"
TYPE_FORM = "form"
TYPE_FILE = "file"
TYPE_STATIC = "static"

TYPE_CHOICES = (
TYPE_MULTIPLE_CHOICE,
Expand All @@ -59,6 +60,7 @@ class Question(SlugModel):
TYPE_TABLE,
TYPE_FORM,
TYPE_FILE,
TYPE_STATIC,
)
TYPE_CHOICES_TUPLE = ((type_choice, type_choice) for type_choice in TYPE_CHOICES)

Expand All @@ -69,6 +71,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 = LocalizedField(blank=True, null=True, required=False)
configuration = JSONField(default=dict)
meta = JSONField(default=dict)
options = models.ManyToManyField(
Expand Down
35 changes: 35 additions & 0 deletions caluma/form/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,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 @@ -112,6 +113,7 @@ class Meta:
"answers",
"row_form",
"sub_form",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -130,6 +132,7 @@ class Meta:
"answers",
"row_form",
"sub_form",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -146,6 +149,7 @@ class Meta:
"row_form",
"sub_form",
"placeholder",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -165,6 +169,7 @@ class Meta:
"row_form",
"sub_form",
"placeholder",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -184,6 +189,7 @@ class Meta:
"row_form",
"sub_form",
"placeholder",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -203,6 +209,7 @@ class Meta:
"answers",
"row_form",
"sub_form",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -222,6 +229,7 @@ class Meta:
"answers",
"row_form",
"sub_form",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -237,6 +245,7 @@ class Meta:
"answers",
"sub_form",
"placeholder",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -252,6 +261,7 @@ class Meta:
"answers",
"row_form",
"placeholder",
"static_content",
)
use_connection = False
interfaces = (Question, graphene.Node)
Expand All @@ -268,6 +278,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 @@ -397,6 +425,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 @@ -663,6 +697,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 @@ -383,6 +383,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
34 changes: 34 additions & 0 deletions caluma/form/tests/snapshots/snap_test_question.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,3 +368,37 @@
},
}
}

snapshots["test_query_all_questions[static-question__configuration10] 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.""",
}
}
]
}
}

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.""",
},
}
}
34 changes: 34 additions & 0 deletions caluma/form/tests/test_question.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
(models.Question.TYPE_MULTIPLE_CHOICE, {}),
(models.Question.TYPE_FORM, {}),
(models.Question.TYPE_FILE, {}),
(models.Question.TYPE_STATIC, {}),
],
)
def test_query_all_questions(
Expand Down Expand Up @@ -85,6 +86,9 @@ def test_query_all_questions(
slug
}
}
... on StaticQuestion {
staticContent
}
}
}
}
Expand Down Expand Up @@ -477,3 +481,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 @@ -32,6 +32,7 @@ class Query(form_schema.Query, workflow_schema.Query, graphene.ObjectType):
form_schema.TableQuestion,
form_schema.FormQuestion,
form_schema.FileQuestion,
form_schema.StaticQuestion,
form_schema.StringAnswer,
form_schema.ListAnswer,
form_schema.IntegerAnswer,
Expand Down
35 changes: 35 additions & 0 deletions caluma/tests/snapshots/snap_test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,7 @@
saveTableQuestion(input: SaveTableQuestionInput!): SaveTableQuestionPayload
saveFormQuestion(input: SaveFormQuestionInput!): SaveFormQuestionPayload
saveFileQuestion(input: SaveFileQuestionInput!): SaveFileQuestionPayload
saveStaticQuestion(input: SaveStaticQuestionInput!): SaveStaticQuestionPayload
saveDocument(input: SaveDocumentInput!): SaveDocumentPayload
saveDocumentStringAnswer(input: SaveDocumentStringAnswerInput!): SaveDocumentStringAnswerPayload
saveDocumentIntegerAnswer(input: SaveDocumentIntegerAnswerInput!): SaveDocumentIntegerAnswerPayload
Expand Down Expand Up @@ -1068,6 +1069,22 @@
clientMutationId: String
}
input SaveStaticQuestionInput {
label: String!
slug: String!
infoText: String
isHidden: QuestionJexl
meta: JSONString
isArchived: Boolean
staticContent: String!
clientMutationId: String
}
type SaveStaticQuestionPayload {
question: Question
clientMutationId: String
}
input SaveTableQuestionInput {
slug: String!
label: String!
Expand Down Expand Up @@ -1182,6 +1199,24 @@
clientMutationId: String
}
type StaticQuestion implements Question, Node {
createdAt: DateTime!
modifiedAt: DateTime!
createdByUser: String
createdByGroup: String
slug: String!
label: String!
isHidden: QuestionJexl!
isArchived: Boolean!
infoText: String
meta: GenericScalar!
source: Question
forms(before: String, after: String, first: Int, last: Int, orderBy: [FormOrdering], slug: String, name: String, description: String, isPublished: Boolean, isArchived: Boolean, createdByUser: String, createdByGroup: String, metaHasKey: String, search: String): FormConnection
staticContent: String
id: ID!
isRequired: QuestionJexl!
}
type StringAnswer implements Answer, Node {
createdAt: DateTime!
modifiedAt: DateTime!
Expand Down

0 comments on commit c7564de

Please sign in to comment.