Skip to content

Commit 09f1dc8

Browse files
authored
Merge pull request #207 from Mosquito-Alert/refactor_report_responses
Refactor report responses
2 parents ce986af + c5ce0c9 commit 09f1dc8

File tree

10 files changed

+1227
-212
lines changed

10 files changed

+1227
-212
lines changed

tigacrafting/views.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,20 +1310,7 @@ def get_reports_unfiltered_sites_other(reports_imbornal):
13101310
return new_reports_unfiltered_sites_other
13111311

13121312
def get_reports_imbornal():
1313-
reports_imbornal = ReportResponse.objects.filter(
1314-
Q(question='Is this a storm drain or sewer?', answer='Yes') | Q(question=u'\xc9s un embornal o claveguera?',
1315-
answer=u'S\xed') | Q(
1316-
question=u'\xbfEs un imbornal o alcantarilla?', answer=u'S\xed') | Q(question='Selecciona lloc de cria',
1317-
answer='Embornals') | Q(
1318-
question='Selecciona lloc de cria', answer='Embornal o similar') | Q(question='Tipo de lugar de cría',
1319-
answer='Sumidero o imbornal') | Q(
1320-
question='Tipo de lugar de cría', answer='Sumideros') | Q(question='Type of breeding site',
1321-
answer='Storm drain') | Q(
1322-
question='Type of breeding site', answer='Storm drain or similar receptacle')).values('report').distinct()
1323-
1324-
reports_imbornal_new = ReportResponse.objects.filter(question_id=12).filter(answer_id=121).values('report').distinct()
1325-
1326-
return reports_imbornal | reports_imbornal_new
1313+
return Report.objects.filter(breeding_site_type=Report.BREEDING_SITE_TYPE_STORM_DRAIN)
13271314

13281315
def get_reports_unfiltered_adults_except_being_validated():
13291316
new_reports_unfiltered_adults = Report.objects.exclude(creation_time__year=2014).exclude(type='site').exclude(note__icontains='#345').exclude(photos=None).annotate(n_annotations=Count('expert_report_annotations')).filter(n_annotations=0).order_by('-server_upload_time')

tigamap/templates/tigamap/report_map.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
'{{ report.tigaprob_text }}</td></tr><tr><td>cc score:</td><td>{{ score|floatformat:2 }}</td></tr><tr><td>lat:</td><td>{{ lat }}</td></tr><tr><td>lon:</td><td>{{ lon }}</td></tr></table>{{ report.get_validated_photo_html | safe }}';
111111
{% else %}
112112
popup_text = '<table><tr><td>{% trans 'type' %}:</td><td>'+
113-
'{{ report.site_type_trans }}</td></tr><tr><td>cc score:</td><td>{{ score|floatformat:2 }}</td></tr><tr><td>lat:</td><td>{{ lat }}</td></tr><tr><td>lon:</td><td>{{ report.lon }}</td></tr></table>{{ report.get_validated_photo_html | safe }}';
113+
'{{ report.breeding_site_type }}</td></tr><tr><td>cc score:</td><td>{{ score|floatformat:2 }}</td></tr><tr><td>lat:</td><td>{{ lat }}</td></tr><tr><td>lon:</td><td>{{ report.lon }}</td></tr></table>{{ report.get_validated_photo_html | safe }}';
114114
{% endif %}
115115

116116
{% endwith %}
@@ -123,7 +123,7 @@
123123
'{{ report.tigaprob_text }}</td></tr><tr><td>lat:</td><td>{{ lat }}</td></tr><tr><td>lon:</td><td>{{ lon }}</td></tr></table>';
124124
{% else %}
125125
popup_text = '<table><tr><td>{% trans 'type' %}:</td><td>'+
126-
'{{ report.site_type_trans }}</td></tr><tr><td>lat:</td><td>{{ lat }}</td></tr><tr><td>lon:</td><td>{{ report.lon }}</td></tr></table>';
126+
'{{ report.breeding_site_type }}</td></tr><tr><td>lat:</td><td>{{ lat }}</td></tr><tr><td>lon:</td><td>{{ report.lon }}</td></tr></table>';
127127
{% endif %}
128128
{% endif %}
129129
{% if detailed == 'detailed' %}

tigascoring/xp_scoring.py

Lines changed: 7 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,12 @@
2222
SITE_STORM_DRAIN_REWARD = 4
2323
BREEDING_SITE_MOSQUITO_REWARD = 3
2424

25-
MOSQUITO_HOW_LOOKS_QUESTION_ID = 7
26-
MOSQUITO_THORAX_ANSWER_IDS = [711, 712, 713, 714]
27-
MOSQUITO_ABDOMEN_ANSWER_IDS = [721, 722, 723, 724]
28-
MOSQUITO_LEG_ANSWER_IDS = [731, 732, 733, 734]
29-
3025
MOSQUITO_BITE_QUESTION_ID = 8
3126
MOSQUITO_BITE_ANSWER_ID = 101
3227

3328
BREEDING_SITE_MOSQUITO_QUESTION_ID = 11
3429
BREEDING_SITE_MOSQUITO_ANSWER_ID = 101
3530

36-
SITE_WATER_QUESTION_ID = 10
37-
SITE_WATER_ANSWER_IDS = [81, 101]
38-
39-
STORM_DRAIN_QUESTION_ID = 12
40-
STORM_DRAIN_ANSWER_ID = 121
41-
4231
CULEX_CATEGORY_ID = 10
4332
AEDES_CATEGORY_IDS = [4, 5, 6, 7]
4433

@@ -88,53 +77,31 @@
8877

8978

9079
def is_thorax_answered(report):
91-
for response in report.responses.all():
92-
if response.question_id == MOSQUITO_HOW_LOOKS_QUESTION_ID and response.answer_id in MOSQUITO_THORAX_ANSWER_IDS:
93-
return True
94-
return False
80+
return report.user_perceived_mosquito_thorax is not None
9581

9682

9783
def is_abdomen_answered(report):
98-
for response in report.responses.all():
99-
if response.question_id == MOSQUITO_HOW_LOOKS_QUESTION_ID and response.answer_id in MOSQUITO_ABDOMEN_ANSWER_IDS:
100-
return True
101-
return False
84+
return report.user_perceived_mosquito_abdomen is not None
10285

10386

10487
def is_leg_answered(report):
105-
for response in report.responses.all():
106-
if response.question_id == MOSQUITO_HOW_LOOKS_QUESTION_ID and response.answer_id in MOSQUITO_LEG_ANSWER_IDS:
107-
return True
108-
return False
88+
return report.user_perceived_mosquito_legs is not None
10989

11090

11191
def is_water_answered(report):
112-
for response in report.responses.all():
113-
if response.question_id == SITE_WATER_QUESTION_ID and response.answer_id in SITE_WATER_ANSWER_IDS:
114-
return True
115-
return False
92+
return report.breeding_site_has_water is not None
11693

11794

11895
def is_bite_report_followed(report):
119-
for response in report.responses.all():
120-
if response.question_id == MOSQUITO_BITE_QUESTION_ID and response.answer_id == MOSQUITO_BITE_ANSWER_ID:
121-
return True
122-
return False
96+
return report.responses.filter(question_id=MOSQUITO_BITE_QUESTION_ID, answer_id=MOSQUITO_BITE_ANSWER_ID).exists()
12397

12498

12599
def is_mosquito_report_followed(report):
126-
for response in report.responses.all():
127-
if response.question_id == BREEDING_SITE_MOSQUITO_QUESTION_ID and response.answer_id == BREEDING_SITE_MOSQUITO_ANSWER_ID:
128-
return True
129-
return False
100+
return report.responses.filter(question_id=BREEDING_SITE_MOSQUITO_QUESTION_ID, answer_id=BREEDING_SITE_MOSQUITO_ANSWER_ID).exists()
130101

131102

132103
def is_storm_drain(report):
133-
for response in report.responses.all():
134-
if response.question_id == STORM_DRAIN_QUESTION_ID and response.answer_id == STORM_DRAIN_ANSWER_ID:
135-
return True
136-
return False
137-
104+
return report.breeding_site_type == Report.BREEDING_SITE_TYPE_STORM_DRAIN
138105

139106
def is_culex(validation_result):
140107
if validation_result['category'] is not None:

tigaserver_app/admin.py

Lines changed: 142 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from django.utils.encoding import smart_str
88
from django.http.response import HttpResponse
99
from django.utils.html import mark_safe
10+
from django.utils.translation import ugettext_lazy as _
1011

1112

1213
def export_full_csv(modeladmin, request, queryset):
@@ -116,43 +117,163 @@ class PhotoInline(admin.StackedInline):
116117

117118

118119
class ReportAdmin(admin.ModelAdmin):
119-
list_display = ('version_UUID', 'report_id', 'deleted', 'user', 'version_number', 'creation_time', 'version_time', 'type', 'mission',
120-
'package_version', 'os', 'n_photos', 'map_link', 'movelab_score', 'crowd_score')
121-
inlines = [ReportResponseInline, PhotoInline]
122-
ordering = ('creation_time', 'report_id', 'version_number')
123-
readonly_fields = ('deleted', 'version_UUID', 'user', 'report_id', 'version_number', 'other_versions_of_this_report', 'creation_time', 'version_time', 'server_upload_time', 'updated_at', 'datetime_fix_offset', 'phone_upload_time', 'type', 'mission', 'location_choice', 'current_location_lon', 'current_location_lat', 'selected_location_lon', 'selected_location_lat', 'note', 'package_name', 'package_version', 'device_manufacturer', 'device_model', 'os', 'os_version', 'os_language', 'app_language', 'n_photos', 'lon', 'lat', 'tigaprob', 'tigaprob_text', 'site_type', 'site_type_trans', 'embornals', 'fonts', 'basins', 'buckets', 'wells', 'other', 'masked_lat', 'masked_lon', 'map_link', 'movelab_score', 'crowd_score')
124-
fields = ('hide', 'deleted', 'map_link', 'version_UUID', 'user', 'report_id', 'version_number', 'other_versions_of_this_report', ('creation_time', 'version_time', 'datetime_fix_offset'), ('server_upload_time','phone_upload_time'), 'updated_at', 'type', 'mission', 'location_choice', 'current_location_lon', 'current_location_lat', 'selected_location_lon', 'selected_location_lat', 'note', 'package_name', 'package_version', 'device_manufacturer', 'device_model', 'os', 'os_version', 'os_language', 'app_language', 'n_photos', 'lon', 'lat', 'tigaprob', 'tigaprob_text', 'site_type', 'site_type_trans', 'embornals', 'fonts', 'basins', 'buckets', 'wells', 'other', 'masked_lat', 'masked_lon', 'movelab_score', 'crowd_score')
125-
search_fields = ('version_UUID',)
120+
list_display = (
121+
'version_UUID', 'report_id', 'deleted', 'user', 'version_number', 'creation_time', 'version_time', 'type', 'mission',
122+
'package_version', 'os', 'n_photos'
123+
)
126124
list_filter = ['os', 'type', 'mission', 'package_name', 'package_version']
125+
search_fields = ('version_UUID',)
126+
127+
inlines = [ReportResponseInline, PhotoInline]
127128
actions = [export_full_csv, export_full_csv_sc]
128129

130+
readonly_fields = [
131+
"deleted",
132+
"report_id",
133+
"version_number",
134+
"type",
135+
"user",
136+
"mission",
137+
"session",
138+
"server_upload_time",
139+
"updated_at",
140+
"version_time",
141+
"phone_upload_time",
142+
"creation_time",
143+
"other_versions_of_this_report"
144+
]
145+
146+
fieldsets = [
147+
(
148+
_('General info'),
149+
{
150+
"fields": [
151+
("report_id", "version_number"),
152+
("hide", "deleted"),
153+
"type",
154+
"user",
155+
("mission","session"),
156+
"other_versions_of_this_report",
157+
("server_upload_time", "updated_at"),
158+
("version_time", "datetime_fix_offset"),
159+
("creation_time", "phone_upload_time")
160+
]
161+
}
162+
),
163+
(
164+
_("Location information"),
165+
{
166+
"fields": [
167+
("country", "nuts_2", "nuts_3"),
168+
"location_choice",
169+
"point"
170+
]
171+
}
172+
),
173+
(
174+
_("Other"),
175+
{
176+
"fields": [
177+
("package_name", "package_version", "app_language"),
178+
("device_manufacturer", "device_model"),
179+
("os", "os_version", "os_language"),
180+
"note"
181+
],
182+
"classes": ["collapse",]
183+
}
184+
)
185+
]
186+
187+
def get_readonly_fields(self, request, obj=None):
188+
# Only allow to edit 'hide' field.
189+
result = super().get_readonly_fields(request, obj)
190+
191+
readonly_fields = [field.name for field in self.model._meta.get_fields()]
192+
allow_edit_fields = ['hide',]
193+
194+
for field_name in readonly_fields:
195+
if not field_name in allow_edit_fields:
196+
result.append(field_name)
197+
198+
return result
199+
200+
def get_fieldsets(self, request, obj = None):
201+
result = super().get_fieldsets(request, obj)
202+
203+
if not obj:
204+
return result
205+
206+
extra_fieldsets = []
207+
if obj.type == Report.TYPE_ADULT:
208+
extra_fieldsets.append(
209+
(
210+
_("Classification"),
211+
{
212+
"fields": [
213+
"ia_filter_1", "ia_filter_2"
214+
]
215+
}
216+
)
217+
)
218+
extra_fieldsets.append(
219+
(
220+
_("Specific information"),
221+
{
222+
"fields": [
223+
("event_environment", "event_moment"),
224+
"user_perceived_mosquito_specie",
225+
("user_perceived_mosquito_thorax", "user_perceived_mosquito_abdomen", "user_perceived_mosquito_legs")
226+
]
227+
}
228+
)
229+
)
230+
elif obj.type == Report.TYPE_BITE:
231+
extra_fieldsets.append(
232+
(
233+
_("Specific information"),
234+
{
235+
"fields": [
236+
("event_environment", "event_moment"),
237+
"bite_count",
238+
("head_bite_count", "left_arm_bite_count", "right_arm_bite_count", "chest_bite_count", "left_leg_bite_count", "right_leg_bite_count")
239+
]
240+
}
241+
)
242+
)
243+
elif obj.type == Report.TYPE_SITE:
244+
extra_fieldsets.append(
245+
(
246+
_("Specific information"),
247+
{
248+
"fields": [
249+
"breeding_site_type",
250+
"breeding_site_has_water",
251+
"breeding_site_in_public_area",
252+
"breeding_site_has_near_mosquitoes",
253+
"breeding_site_has_larvae"
254+
]
255+
}
256+
)
257+
)
258+
259+
return result + extra_fieldsets
260+
129261
def has_add_permission(self, request):
130262
return False
131263

132264
def has_delete_permission(self, request, obj=None):
133265
return False
134266

135267
def other_versions_of_this_report(self, obj):
136-
result = []
268+
result = ""
137269
for this_version in obj.other_versions:
138270
result += '<a href="/admin/tigaserver_app/report/%s">Version %s</a> ' % (
139271
this_version.version_UUID,
140272
this_version.version_number,
141273
)
142-
return result
274+
return mark_safe(result)
143275
other_versions_of_this_report.allow_tags = True
144276

145-
def movelab_score(self, obj):
146-
return obj.movelab_score
147-
148-
def crowd_score(self, obj):
149-
return obj.crowd_score
150-
151-
def map_link(self, obj):
152-
return '<a href="/single_report_map/%s/">Show map</a>' % obj.version_UUID
153-
map_link.allow_tags = True
154-
155-
156277
def export_csv_photo(modeladmin, request, queryset):
157278
response = HttpResponse(mimetype='text/csv')
158279
response['Content-Disposition'] = 'attachment; filename=tigatrapp_photos.csv'
@@ -247,7 +368,7 @@ def other_report_versions(self, obj):
247368
this_version.version_UUID,
248369
this_version.version_number,
249370
)
250-
return result
371+
return mark_safe(result)
251372
other_report_versions.allow_tags = True
252373

253374
def map_link(self, obj):

0 commit comments

Comments
 (0)