Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
ifirmawan committed May 23, 2024
2 parents 1855956 + f717b9b commit d1491a0
Show file tree
Hide file tree
Showing 9 changed files with 277 additions and 91 deletions.
105 changes: 53 additions & 52 deletions backend/api/v1/v1_data/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1153,63 +1153,50 @@ def validate_value(self, value):
return value

def validate(self, attrs):
if attrs.get("value") == "":
question = attrs.get("question")
value = attrs.get("value")

if value == "":
raise ValidationError(
"Value is required for Question:{0}".format(
attrs.get("question").id
)
f"Value is required for Question: {question.id}"
)

if (
isinstance(attrs.get("value"), list)
and len(attrs.get("value")) == 0
):
if isinstance(value, list) and len(value) == 0:
raise ValidationError(
"Value is required for Question:{0}".format(
attrs.get("question").id
)
f"Value is required for Question: {question.id}"
)

if not isinstance(attrs.get("value"), list) and attrs.get(
"question"
).type in [
if not isinstance(value, list) and question.type in [
QuestionTypes.geo,
QuestionTypes.option,
QuestionTypes.multiple_option,
]:
raise ValidationError(
"Valid list value is required for Question:{0}".format(
attrs.get("question").id
)
f"Valid list value is required for Question: {question.id}"
)
elif not isinstance(attrs.get("value"), str) and attrs.get(
"question"
).type in [

elif not isinstance(value, str) and question.type in [
QuestionTypes.text,
QuestionTypes.photo,
QuestionTypes.date,
]:
raise ValidationError(
"Valid string value is required for Question:{0}".format(
attrs.get("question").id
)
f"Valid string value is required for Question: {question.id}"
)

elif not (
isinstance(attrs.get("value"), int)
or isinstance(attrs.get("value"), float)
) and attrs.get("question").type in [
isinstance(value, int) or isinstance(value, float)) \
and question.type in [
QuestionTypes.number,
QuestionTypes.administration,
QuestionTypes.cascade,
]:
raise ValidationError(
"Valid number value is required for Question:{0}".format(
attrs.get("question").id
)
f"Valid number value is required for Question: {question.id}"
)

if attrs.get("question").type == QuestionTypes.administration:
attrs["value"] = int(float(attrs.get("value")))
if question.type == QuestionTypes.administration:
attrs["value"] = int(float(value))

return attrs

Expand Down Expand Up @@ -1251,7 +1238,7 @@ def create(self, validated_data):
data["created_by"] = self.context.get("user")

# check user role and form type
user: SystemUser = self.context.get("user")
user = self.context.get("user")
is_super_admin = user.user_access.role == UserRoleTypes.super_admin
is_county_admin = (
user.user_access.role == UserRoleTypes.admin
Expand All @@ -1265,6 +1252,7 @@ def create(self, validated_data):
]
if data.get("submission_type") in direct_submission_types:
direct_to_data = True

# save to pending data
if not direct_to_data:
obj_data = self.fields.get("data").create(data)
Expand All @@ -1281,77 +1269,90 @@ def create(self, validated_data):
submission_type=data.get("submission_type"),
)

pending_answers = []
answers = []

for answer in validated_data.get("answer"):
question = answer.get("question")
name = None
value = None
option = None

if answer.get("question").meta_uuid:
if question.meta_uuid:
obj_data.uuid = answer.get("value")
obj_data.save()

if answer.get("question").type in [
if question.type in [
QuestionTypes.geo,
QuestionTypes.option,
QuestionTypes.multiple_option,
]:
option = answer.get("value")
elif answer.get("question").type in [
elif question.type in [
QuestionTypes.text,
QuestionTypes.photo,
QuestionTypes.date,
QuestionTypes.autofield,
]:
name = answer.get("value")
elif answer.get("question").type == QuestionTypes.cascade:
elif question.type == QuestionTypes.cascade:
id = answer.get("value")
val = None
if answer.get("question").api:
ep = answer.get("question").api.get("endpoint")
if question.api:
ep = question.api.get("endpoint")
if "organisation" in ep:
val = Organisation.objects.filter(pk=id).first()
val = val.name
name = Organisation.objects.filter(pk=id).values_list(
'name', flat=True).first()
val = name
if "entity-data" in ep:
val = EntityData.objects.filter(pk=id).first()
val = val.name
name = EntityData.objects.filter(pk=id).values_list(
'name', flat=True).first()
val = name
if "entity-data" not in ep and "organisation" not in ep:
ep = ep.split("?")[0]
ep = f"{ep}?id={id}"
val = requests.get(ep).json()
val = val[0].get("name")

if answer.get("question").extra:
cs_type = answer.get("question").extra.get("type")
if question.extra:
cs_type = question.extra.get("type")
if cs_type == "entity":
val = EntityData.objects.filter(pk=id).first()
val = val.name
name = EntityData.objects.filter(pk=id).values_list(
'name', flat=True).first()
val = name
name = val
else:
# for administration,number question type
value = answer.get("value")

# save to pending answer
if not direct_to_data:
PendingAnswers.objects.create(
pending_answers.append(PendingAnswers(
pending_data=obj_data,
question=answer.get("question"),
question=question,
name=name,
value=value,
options=option,
created_by=self.context.get("user"),
created=data.get("submitedAt") or timezone.now(),
)
))

# save to form data
if direct_to_data:
Answers.objects.create(
answers.append(Answers(
data=obj_data,
question=answer.get("question"),
question=question,
name=name,
value=value,
options=option,
created_by=self.context.get("user"),
)
))

# bulk create pending answers / answers
if pending_answers:
PendingAnswers.objects.bulk_create(pending_answers)
if answers:
Answers.objects.bulk_create(answers)

if direct_to_data:
if data.get("uuid"):
Expand Down
64 changes: 37 additions & 27 deletions backend/api/v1/v1_mobile/tests/tests_api_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,21 @@ def test_mobile_sync_to_pending_datapoint(self):
"submission_type": SubmissionTypes.registration,
"answers": answers,
}

self.assertEqual(len(answers), len(questions))

# Submit correct data
response = self.client.post(
"/api/v1/device/sync",
post_data,
follow=True,
content_type="application/json",
**{"HTTP_AUTHORIZATION": f"Bearer {token}"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
# check N+1 query
def call_route():
# Submit correct data
response = self.client.post(
"/api/v1/device/sync",
post_data,
follow=True,
content_type="application/json",
**{"HTTP_AUTHORIZATION": f"Bearer {token}"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)

self.assertNumQueries(28, call_route)

pending_data = PendingFormData.objects.filter(
created_by=self.user
Expand Down Expand Up @@ -219,16 +222,19 @@ def test_mobile_sync_to_pending_datapoint(self):
assignment.save()

token = self.get_assignmen_token(self.passcode)
response = self.client.post(
"/api/v1/device/sync",
post_data,
follow=True,
content_type="application/json",
**{"HTTP_AUTHORIZATION": f"Bearer {token}"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)

# submit certification data
def call_second_route(post_data):
response = self.client.post(
"/api/v1/device/sync",
post_data,
follow=True,
content_type="application/json",
**{"HTTP_AUTHORIZATION": f"Bearer {token}"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)

self.assertNumQueries(28, call_second_route(post_data=post_data))

post_data = {
"formId": self.form.id,
"name": "testing datapoint for certification",
Expand All @@ -238,15 +244,19 @@ def test_mobile_sync_to_pending_datapoint(self):
"submission_type": SubmissionTypes.certification,
"answers": answers,
}
response = self.client.post(
"/api/v1/device/sync",
post_data,
follow=True,
content_type="application/json",
**{"HTTP_AUTHORIZATION": f"Bearer {token}"},
)

self.assertEqual(response.status_code, status.HTTP_200_OK)
# submit certification data
def call_third_route():
response = self.client.post(
"/api/v1/device/sync",
post_data,
follow=True,
content_type="application/json",
**{"HTTP_AUTHORIZATION": f"Bearer {token}"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)

self.assertNumQueries(29, call_third_route)

data = FormData.objects.all()
names = [d.name for d in data]
Expand Down
Loading

0 comments on commit d1491a0

Please sign in to comment.