Skip to content

Commit

Permalink
Add validation for question in admin side.
Browse files Browse the repository at this point in the history
  • Loading branch information
Rup-Narayan-Rajbanshi committed Aug 8, 2023
1 parent 4f79377 commit d5699c4
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 15 deletions.
44 changes: 33 additions & 11 deletions apps/assessment_registry/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
MethodologyAttribute,
Question,
Answer,
SummaryIssue,
ScoreRating,
ScoreAnalyticalDensity,
Summary,
SummarySubPillarIssue,
SummaryFocus,
SummarySubDimmensionIssue,
)


Expand All @@ -24,12 +27,6 @@ def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)


@admin.register(Answer)
class AnswerAdmin(admin.ModelAdmin):
list_display = ('id', 'question')
readonly_fields = ('created_by', 'modified_by', 'client_id',)


class MethodologyAttributeInline(admin.TabularInline):
model = MethodologyAttribute
extra = 0
Expand All @@ -54,16 +51,41 @@ class AnalyticalDensityInline(admin.TabularInline):
exclude = ('created_by', 'modified_by', 'client_id')


class SummaryInline(admin.TabularInline):
model = Summary
extra = 0
exclude = ('created_by', 'modified_by', 'client_id')


class SummarySubPillarIssueInline(admin.TabularInline):
model = SummarySubPillarIssue
extra = 0
exclude = ('created_by', 'modified_by', 'client_id')


class SummaryFocusInline(admin.TabularInline):
model = SummaryFocus
extra = 0
exclude = ('created_by', 'modified_by', 'client_id')


class SummarySubDimmensionIssueInline(admin.TabularInline):
model = SummarySubDimmensionIssue
extra = 0
exclude = ('created_by', 'modified_by', 'client_id')


@admin.register(AssessmentRegistry)
class AssessmentRegistryAdmin(admin.ModelAdmin):
list_display = ('id', 'lead', 'project')
list_display = ('id', 'project', 'lead')

inlines = [
MethodologyAttributeInline,
ScoreInline,
AnalyticalDensityInline,
AnswerInline,
SummaryInline,
SummarySubPillarIssueInline,
SummaryFocusInline,
SummarySubDimmensionIssueInline,
]


admin.site.register(SummaryIssue)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 3.2.17 on 2023-08-08 05:15

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('assessment_registry', '0019_auto_20230804_0944'),
]

operations = [
migrations.AlterModelOptions(
name='summaryfocus',
options={'verbose_name': 'SummaryDimmension'},
),
]
124 changes: 123 additions & 1 deletion apps/assessment_registry/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from django.db import models
from django.contrib.postgres.fields import ArrayField
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _

from user_resource.models import UserResource
from geo.models import Region
Expand Down Expand Up @@ -212,7 +214,7 @@ class Meta:
ordering = ["id"]

def __str__(self):
return self.project.title
return self.lead.title


class MethodologyAttribute(UserResource):
Expand Down Expand Up @@ -297,6 +299,9 @@ class DocumentType(models.IntegerChoices):
)
external_link = models.URLField(max_length=500, blank=True)

def __str__(self):
return self.file.title


class ScoreRating(UserResource):
class AnalyticalStatement(models.IntegerChoices):
Expand Down Expand Up @@ -472,10 +477,118 @@ class QuestionSubSector(models.IntegerChoices):
'Buy-in and use by naional and local government agencies'
BUY_IN_AND_USE_BY_DEVELOPMENT_AND_STABILIZATION_ACTORS = 27, 'Buy-in and use by development and stabilization actors'

QUESTION_SECTOR_SUB_SECTOR_MAP = {
QuestionSector.RELEVANCE: [
QuestionSubSector.RELEVANCE,
],
QuestionSector.COMPREHENSIVENESS: [
QuestionSubSector.GEOGRAPHIC_COMPREHENSIVENESS,
QuestionSubSector.SECTORAL_COMPREHENSIVENESS,
QuestionSubSector.AFFECTED_AND_VULNERABLE_GROUPS_COMPREHENSIVENESS,
],
QuestionSector.ETHICS: [
QuestionSubSector.SAFETY_AND_PROTECTION,
QuestionSubSector.HUMANITARIAN_PRINCIPLES,
QuestionSubSector.CONTRIBUTION,
],
QuestionSector.METHODOLOGICAL_RIGOR: [
QuestionSubSector.TRANSPARENCY,
QuestionSubSector.MITIGATING_BIAS,
QuestionSubSector.PARTICIPATION,
QuestionSubSector.CONTEXT_SPECIFICITY,
],
QuestionSector.ANALYTICAL_VALUE: [
QuestionSubSector.ANALYTICAL_STANDARDS,
QuestionSubSector.DESCRIPTIONS,
QuestionSubSector.EXPLANATION,
QuestionSubSector.INTERPRETATION,
QuestionSubSector.ANTICIPATION,
QuestionSubSector.TIMELINESS,
],
QuestionSector.EFFECTIVE_COMMUNICATION: [
QuestionSubSector.USER_FRIENDLY_PRESENTATION,
QuestionSubSector.ACTIVE_DISSEMINATION,
],
QuestionSector.USE: [
QuestionSubSector.USE_FOR_COLLECTIVE_PLANNING,
QuestionSubSector.BUY_IN_AND_USE_BY_HUMANITARIAN_CLUSTERS_SECTORS,
QuestionSubSector.BUY_IN_AND_USE_BY_UN_AGENCIES,
QuestionSubSector.BUY_IN_AND_USE_BY_INTERNATIONAL_NGO,
QuestionSubSector.BUY_IN_AND_USE_BY_LOCAL_NGO,
QuestionSubSector.BUY_IN_AND_USE_BY_MEMBER_OF_RED_CROSS_RED_CRESENT_MOVEMENT,
QuestionSubSector.BUY_IN_AND_USE_BY_DONORS,
QuestionSubSector.BUY_IN_AND_USE_BY_NATIONAL_AND_LOCAL_GOVERNMENT_AGENCIES,
QuestionSubSector.BUY_IN_AND_USE_BY_DEVELOPMENT_AND_STABILIZATION_ACTORS,
],
QuestionSector.PEOPLE_CENTERED_AND_INCLUSIVE: [
QuestionSubSector.AFFECTED_AND_VULNERABLE_GROUPS_COMPREHENSIVENESS,
QuestionSubSector.SAFETY_AND_PROTECTION,
QuestionSubSector.PARTICIPATION,
QuestionSubSector.CONTEXT_SPECIFICITY,
],
QuestionSector.ACCOUNTABILITY_TO_AFFECTED_POPULATIONS: [
QuestionSubSector.PARTICIPATION,
QuestionSubSector.CONTEXT_SPECIFICITY,
QuestionSubSector.DESCRIPTIONS,
QuestionSubSector.ACTIVE_DISSEMINATION,
],
QuestionSector.DO_NOT_HARM: [
QuestionSubSector.SAFETY_AND_PROTECTION,
],
QuestionSector.DESIGNED_WITH_PURPOSE: [
QuestionSubSector.RELEVANCE,
],
QuestionSector.COMPETENCY_AND_CAPACITY: [
QuestionSubSector.SAFETY_AND_PROTECTION,
QuestionSubSector.CONTEXT_SPECIFICITY,
],
QuestionSector.IMPARTIALITY: [
QuestionSubSector.HUMANITARIAN_PRINCIPLES,
],
QuestionSector.COORDINATION_AND_DATA_MINIMIZATION: [
QuestionSubSector.RELEVANCE,
QuestionSubSector.CONTRIBUTION,
],
QuestionSector.JOINT_ANALYSIS: [
QuestionSubSector.MITIGATING_BIAS,
QuestionSubSector.ANALYTICAL_STANDARDS,
],
QuestionSector.ACKNOWLEDGE_DISSENTING_VOICES_IN_JOINT_NEEDS_ANALYSIS: [
QuestionSubSector.ANALYTICAL_STANDARDS,
],
QuestionSector.IFORMED_CONSENT_CONFIDENTIALITY_AND_DATA_SECURITY: [
QuestionSubSector.SAFETY_AND_PROTECTION,
],
QuestionSector.SHARING_RESULTS: [
QuestionSubSector.ACTIVE_DISSEMINATION,
],
QuestionSector.TRANSPARENCY_BETWEEN_ACTORS: [
QuestionSubSector.TRANSPARENCY,
QuestionSubSector.ANALYTICAL_STANDARDS,
],
QuestionSector.MINIMUM_TECHNICAL_STANDARDS: [
QuestionSubSector.MITIGATING_BIAS,
QuestionSubSector.ANALYTICAL_STANDARDS,
],
}

sector = models.IntegerField(choices=QuestionSector.choices)
sub_sector = models.IntegerField(choices=QuestionSubSector.choices)
question = models.CharField(max_length=500)

def clean(self):
sector = self.sector
sub_sector = self.sub_sector

if hasattr(self, 'sector'):
if hasattr(self, 'sub_sector'):
if sub_sector not in Question.QUESTION_SECTOR_SUB_SECTOR_MAP[sector]:
raise ValidationError('Invalid sebsector selected for given sector provided')

def save(self, *args, **kwargs):
self.full_clean()
super().save(*args, **kwargs)

class Meta:
ordering = ["id"]

Expand All @@ -499,6 +612,9 @@ class Meta:
ordering = ["id"]
unique_together = [["assessment_registry", "question"]]

def __str__(self):
return str(self.answer)


class Summary(UserResource):
class Pillar(models.IntegerChoices):
Expand Down Expand Up @@ -568,6 +684,9 @@ class Dimmension(models.IntegerChoices):
total_people_severly_in_need = models.IntegerField(null=True, blank=True)
total_people_critically_in_need = models.IntegerField(null=True, blank=True)

class Meta:
verbose_name = _("SummaryDimmension")


class SummaryIssue(models.Model):
class SubPillar(models.IntegerChoices):
Expand Down Expand Up @@ -683,6 +802,9 @@ class SubDimmension(models.IntegerChoices):
label = models.CharField(max_length=220)
full_label = models.CharField(max_length=220, blank=True)

def __str__(self):
return self.label


class SummarySubDimmensionIssue(UserResource):
assessment_registry = models.ForeignKey(
Expand Down
4 changes: 3 additions & 1 deletion apps/assessment_registry/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from rest_framework import serializers

from utils.common import get_hierarchy_level
from user_resource.serializers import UserResourceSerializer
from deep.serializers import ProjectPropertySerializerMixin, TempClientIdMixin, IntegerIDField

Expand Down Expand Up @@ -45,9 +46,10 @@ class Meta:
)

def validate(self, data):
from utils.common import get_hierarchy_level
if data.get('sub_pillar') is not None and data.get('sub_dimmension') is not None:
raise serializers.ValidationError("Cannot select both sub_pillar and sub_dimmension field.")
if not data.get('sub_pillar') and not data.get('sub_dimmension'):
raise serializers.ValidationError("Either sub_pillar or sub_dimmension must be selected")
if data.get('parent') is not None:
if data.get('sub_pillar') is not None:
if data.get('sub_pillar') != data.get('parent').sub_pillar:
Expand Down
2 changes: 2 additions & 0 deletions apps/assessment_registry/tests/test_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ def setUp(self):
self.question1 = QuestionFactory.create(
sector=Question.QuestionSector.RELEVANCE,
sub_sector=Question.QuestionSubSector.RELEVANCE,
question='test question'
)
self.question2 = QuestionFactory.create(
sector=Question.QuestionSector.COMPREHENSIVENESS,
sub_sector=Question.QuestionSubSector.GEOGRAPHIC_COMPREHENSIVENESS,
question='test question',
)
self.country1, self.country2 = RegionFactory.create_batch(2)
self.organization1, self.organization2 = OrganizationFactory.create_batch(2)
Expand Down
4 changes: 2 additions & 2 deletions apps/gallery/tests/test_mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def setUp(self):

def test_upload_preview_image(self):
file_text = b'preview image text'
with NamedTemporaryFile(suffix='.png') as t_file:
with NamedTemporaryFile(suffix='.jpeg') as t_file:
t_file.write(file_text)
t_file.seek(0)
response = self._client.post(
Expand All @@ -57,5 +57,5 @@ def test_upload_preview_image(self):
self.assertTrue(content['data']['fileUpload']['result']['file']["name"])
file_name = content['data']['fileUpload']['result']['file']["name"]
file_url = content['data']['fileUpload']['result']['file']["url"]
self.assertTrue(file_name.endswith('.png'))
self.assertTrue(file_name.endswith('.jpeg'))
self.assertTrue(file_url.endswith(file_name))

0 comments on commit d5699c4

Please sign in to comment.