Skip to content

Commit a3af649

Browse files
Fix: failures in unit tests
1 parent 7afeb82 commit a3af649

File tree

7 files changed

+179
-91
lines changed

7 files changed

+179
-91
lines changed

api/serializers.py

Lines changed: 36 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
"""
2+
Provides serialization for API responses.
3+
4+
See `DRF serializer documentation <http://www.django-rest-framework.org/api-guide/serializers/>`_
5+
Used by the View classes api/views.py to serialize API responses as JSON or HTML.
6+
See DEFAULT_RENDERER_CLASSES setting in core.settings.contrib for the enabled renderers.
7+
"""
8+
9+
# -*- coding: utf-8 -*-
110
import logging
211

312
import django.core.exceptions
@@ -9,26 +18,16 @@
918
SavedFeatureSelection,
1019
validate_aoi,
1120
validate_mbtiles,
12-
normalize_not_in,
1321
PartnerExportRegion,
1422
)
1523
from rest_framework import serializers
1624
from rest_framework_gis import serializers as geo_serializers
1725
from tasks.models import ExportRun, ExportTask
1826

27+
# Get an instance of a logger
1928
LOG = logging.getLogger(__name__)
2029

2130

22-
def _slice_dict(in_dict, wanted_keys):
23-
return {k: in_dict[k] for k in wanted_keys if k in in_dict}
24-
25-
26-
def _update_attrs(model, v_data, keys):
27-
for key in keys:
28-
if key in v_data:
29-
setattr(model, key, v_data[key])
30-
31-
3231
class UserSerializer(serializers.ModelSerializer):
3332
class Meta:
3433
model = User
@@ -74,23 +73,11 @@ class Meta:
7473

7574
class ConfigurationSerializer(serializers.ModelSerializer):
7675
user = UserSerializer(read_only=True, default=serializers.CurrentUserDefault())
77-
# Override to bypass model-level validators; normalization + validation run in validate_yaml.
78-
yaml = serializers.CharField(validators=[])
7976

8077
class Meta:
8178
model = SavedFeatureSelection
8279
fields = ("uid", "name", "description", "yaml", "public", "user", "pinned")
8380

84-
def validate_yaml(self, value):
85-
from django.core.exceptions import ValidationError as DjangoValidationError
86-
from jobs.models import validate_feature_selection
87-
normalized = normalize_not_in(value)
88-
try:
89-
validate_feature_selection(normalized)
90-
except DjangoValidationError as e:
91-
raise serializers.ValidationError(e.messages)
92-
return normalized
93-
9481

9582
class JobGeomSerializer(serializers.ModelSerializer):
9683
"""Since Job Geoms can be large, these are serialized separately,
@@ -102,8 +89,7 @@ class Meta:
10289

10390

10491
class JobSerializer(serializers.ModelSerializer):
105-
user = UserSerializer(read_only=True)
106-
feature_selection = serializers.CharField(validators=[])
92+
user = UserSerializer(default=serializers.CurrentUserDefault())
10793

10894
class Meta:
10995
model = Job
@@ -135,9 +121,6 @@ class Meta:
135121
"simplified_geom": {"read_only": True},
136122
}
137123

138-
def validate_feature_selection(self, value):
139-
return _validate_and_normalize_feature_selection(value)
140-
141124
def validate(self, data):
142125
try:
143126
validate_aoi(data["the_geom"])
@@ -159,17 +142,6 @@ def validate_model(model):
159142
raise serializers.ValidationError(e.message_dict)
160143

161144

162-
def _validate_and_normalize_feature_selection(value):
163-
from django.core.exceptions import ValidationError as DjangoValidationError
164-
from jobs.models import validate_feature_selection as _validate_fs
165-
normalized = normalize_not_in(value)
166-
try:
167-
_validate_fs(normalized)
168-
except DjangoValidationError as e:
169-
raise serializers.ValidationError(e.messages)
170-
return normalized
171-
172-
173145
class PartnerExportRegionListSerializer(serializers.ModelSerializer):
174146
export_formats = serializers.ListField()
175147
feature_selection = serializers.CharField()
@@ -203,9 +175,6 @@ class PartnerExportRegionSerializer(serializers.ModelSerializer): # noqa
203175
event = serializers.CharField()
204176
description = serializers.CharField()
205177

206-
def validate_feature_selection(self, value):
207-
return _validate_and_normalize_feature_selection(value)
208-
209178
class Meta: # noqa
210179
model = PartnerExportRegion
211180
fields = (
@@ -232,7 +201,10 @@ class Meta: # noqa
232201
}
233202

234203
def create(self, validated_data): # noqa
235-
job_dict = _slice_dict(
204+
def slice_dict(in_dict, wanted_keys):
205+
return dict((k, in_dict[k]) for k in wanted_keys if k in in_dict)
206+
207+
job_dict = slice_dict(
236208
validated_data,
237209
[
238210
"the_geom",
@@ -245,7 +217,7 @@ def create(self, validated_data): # noqa
245217
job_dict["event"] = validated_data.get("event") or ""
246218
job_dict["description"] = validated_data.get("description") or ""
247219

248-
region_dict = _slice_dict(
220+
region_dict = slice_dict(
249221
validated_data,
250222
[
251223
"schedule_period",
@@ -279,6 +251,12 @@ def create(self, validated_data): # noqa
279251
return region
280252

281253
def update(self, instance, validated_data): # noqa
254+
def update_attrs(model, v_data, keys):
255+
for key in keys:
256+
if key in v_data:
257+
setattr(model, key, v_data[key])
258+
259+
# if re-assigning, check group membership
282260
if (
283261
not self.context["request"]
284262
.user.groups.filter(name=validated_data["group"].name)
@@ -289,15 +267,15 @@ def update(self, instance, validated_data): # noqa
289267
)
290268

291269
job = instance.job
292-
_update_attrs(
270+
update_attrs(
293271
job, validated_data, ["the_geom", "export_formats", "feature_selection"]
294272
)
295273
job.name = validated_data.get("name")
296274
job.event = validated_data.get("event") or ""
297275
job.description = validated_data.get("description") or ""
298276

299277
validate_model(job)
300-
_update_attrs(
278+
update_attrs(
301279
instance,
302280
validated_data,
303281
[
@@ -363,9 +341,6 @@ class HDXExportRegionSerializer(serializers.ModelSerializer): # noqa
363341
name = serializers.CharField()
364342
buffer_aoi = serializers.BooleanField()
365343

366-
def validate_feature_selection(self, value):
367-
return _validate_and_normalize_feature_selection(value)
368-
369344
def validate(self, data):
370345
"""
371346
Check for export formats for country exports.
@@ -407,15 +382,18 @@ class Meta: # noqa
407382
}
408383

409384
def create(self, validated_data): # noqa
410-
job_dict = _slice_dict(
385+
def slice_dict(in_dict, wanted_keys):
386+
return dict((k, in_dict[k]) for k in wanted_keys if k in in_dict)
387+
388+
job_dict = slice_dict(
411389
validated_data,
412390
["the_geom", "export_formats", "feature_selection", "buffer_aoi"],
413391
)
414392
job_dict["user"] = self.context["request"].user
415393
job_dict["name"] = validated_data.get("dataset_prefix")
416394
job_dict["description"] = validated_data.get("name")
417395

418-
region_dict = _slice_dict(
396+
region_dict = slice_dict(
419397
validated_data,
420398
[
421399
"extra_notes",
@@ -441,8 +419,13 @@ def create(self, validated_data): # noqa
441419
return region
442420

443421
def update(self, instance, validated_data): # noqa
422+
def update_attrs(model, v_data, keys):
423+
for key in keys:
424+
if key in v_data:
425+
setattr(model, key, v_data[key])
426+
444427
job = instance.job
445-
_update_attrs(
428+
update_attrs(
446429
job,
447430
validated_data,
448431
["the_geom", "export_formats", "feature_selection", "buffer_aoi"],
@@ -451,7 +434,7 @@ def update(self, instance, validated_data): # noqa
451434
job.description = validated_data.get("name")
452435

453436
validate_model(job)
454-
_update_attrs(
437+
update_attrs(
455438
instance,
456439
validated_data,
457440
[

api/validators.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,49 @@ def validate_search_bbox(extents):
3434
raise serializers.ValidationError(detail)
3535
except GEOSException:
3636
raise serializers.ValidationError(detail)
37+
38+
39+
def validate_bbox_params(data):
40+
"""
41+
Validates the bounding box parameters supplied during form sumission.
42+
43+
Args:
44+
the data supplied during form submission.
45+
46+
Returns:
47+
a tuple containing the validated extents in the form (xmin,ymin,xmax,ymax).
48+
49+
Raises:
50+
ValidationError: if the extents are invalid.
51+
"""
52+
detail = OrderedDict()
53+
54+
# test for number
55+
lon_coords = [float(data['xmin']), float(data['xmax'])]
56+
lat_coords = [float(data['ymin']), float(data['ymax'])]
57+
# test lat long value order
58+
if ((lon_coords[0] >= 0 and lon_coords[0] > lon_coords[1]) or
59+
(lon_coords[0] < 0 and lon_coords[0] > lon_coords[1])):
60+
detail['id'] = _('inverted_coordinates')
61+
detail['message'] = _('xmin greater than xmax.')
62+
raise serializers.ValidationError(detail)
63+
64+
if ((lat_coords[0] >= 0 and lat_coords[0] > lat_coords[1]) or
65+
(lat_coords[0] < 0 and lat_coords[0] > lat_coords[1])):
66+
detail['id'] = _('inverted_coordinates')
67+
detail['message'] = _('ymin greater than ymax.')
68+
raise serializers.ValidationError(detail)
69+
70+
# test lat long extents
71+
for lon in lon_coords:
72+
if (lon < -180 or lon > 180):
73+
detail['id'] = _('invalid_longitude')
74+
detail['message'] = _('Invalid longitude coordinate: %(lon)s') % {'lon': lon}
75+
raise serializers.ValidationError(detail)
76+
for lat in lat_coords:
77+
if (lat < -90 and lat > 90):
78+
detail['id'] = _('invalid_latitude')
79+
detail['message'] = _('Invalid latitude coordinate: %(lat)s') % {'lat': lat}
80+
raise serializers.ValidationError(detail)
81+
82+
return (data['xmin'], data['ymin'], data['xmax'], data['ymax'])

api/views.py

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Provides classes for handling API requests."""
22

3+
# -*- coding: utf-8 -*-
34
from distutils.util import strtobool
45
import itertools
56
from itertools import chain
@@ -297,14 +298,14 @@ def perform_create(self, serializer):
297298
if settings.SYNC_TO_HDX:
298299
sync_region(serializer.instance)
299300
else:
300-
LOG.debug("Stubbing interaction with HDX API.")
301+
print("Stubbing interaction with HDX API.")
301302

302303
def perform_update(self, serializer):
303304
serializer.save()
304305
if settings.SYNC_TO_HDX:
305306
sync_region(serializer.instance)
306307
else:
307-
LOG.debug("Stubbing interaction with HDX API.")
308+
print("Stubbing interaction with HDX API.")
308309

309310

310311
class PartnerExportRegionViewSet(viewsets.ModelViewSet):
@@ -347,19 +348,6 @@ def permalink(request, uid):
347348
return HttpResponseNotFound()
348349

349350

350-
def _period_week(dt):
351-
sunday = dt.strftime("%Y-%U-0")
352-
return datetime.strptime(sunday, "%Y-%U-%w").strftime("%Y-%m-%d")
353-
354-
355-
def _period_day(dt):
356-
return dt.strftime("%Y-%m-%d")
357-
358-
359-
def _period_month(dt):
360-
return dt.strftime("%Y-%m")
361-
362-
363351
def _is_superuser(request):
364352
"""Check if the current user is a superuser (works with both auth providers)."""
365353
if getattr(settings, 'AUTH_PROVIDER', 'legacy') == 'hanko':
@@ -380,12 +368,22 @@ def stats(request):
380368
period = request.GET.get("period", "day")
381369
is_csv = request.GET.get("csv", False) == "true"
382370

371+
def toWeek(dt):
372+
sunday = dt.strftime("%Y-%U-0")
373+
return datetime.strptime(sunday, "%Y-%U-%w").strftime("%Y-%m-%d")
374+
375+
def toDay(dt):
376+
return dt.strftime("%Y-%m-%d")
377+
378+
def toMonth(dt):
379+
return dt.strftime("%Y-%m")
380+
383381
if period == "day":
384-
period_fn = _period_day
382+
period_fn = toDay
385383
elif period == "week":
386-
period_fn = _period_week
384+
period_fn = toWeek
387385
elif period == "month":
388-
period_fn = _period_month
386+
period_fn = toMonth
389387

390388
users = (
391389
User.objects.only("date_joined")
@@ -457,12 +455,22 @@ def run_stats(request):
457455
period = request.GET.get("period", "day")
458456
is_csv = request.GET.get("csv", False) == "true"
459457

458+
def toWeek(dt):
459+
sunday = dt.strftime("%Y-%U-0")
460+
return datetime.strptime(sunday, "%Y-%U-%w").strftime("%Y-%m-%d")
461+
462+
def toDay(dt):
463+
return dt.strftime("%Y-%m-%d")
464+
465+
def toMonth(dt):
466+
return dt.strftime("%Y-%m")
467+
460468
if period == "day":
461-
period_fn = _period_day
469+
period_fn = toDay
462470
elif period == "week":
463-
period_fn = _period_week
471+
period_fn = toWeek
464472
elif period == "month":
465-
period_fn = _period_month
473+
period_fn = toMonth
466474

467475
run_queryset = ExportRun.objects.only("started_at", "status").order_by(
468476
"-started_at"

0 commit comments

Comments
 (0)