Skip to content

Commit

Permalink
fix flood realtime bugs:
Browse files Browse the repository at this point in the history
- standardize color mapping in landing page: issue inasafe/inasafe-realtime#48
- default highlight latest flood report: issue inasafe/inasafe-realtime#42
- improvements for flood table: issue inasafe/inasafe-realtime#11
- add filters: issue inasafe/inasafe-realtime#11
  • Loading branch information
lucernae committed Feb 7, 2017
1 parent 958e6ca commit 6235834
Show file tree
Hide file tree
Showing 15 changed files with 519 additions and 126 deletions.
6 changes: 6 additions & 0 deletions django_project/realtime/forms/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# coding=utf-8

__copyright__ = "Copyright 2016, The InaSAFE Project"
__license__ = "GPL version 3"
__email__ = "[email protected]"
__revision__ = ':%H$'
Original file line number Diff line number Diff line change
@@ -1,54 +1,12 @@
# coding=utf-8
"""Forms for realtime app."""
from bootstrap3_datetime.widgets import DateTimePicker

from django import forms
from django.utils.translation import ugettext_lazy as _
from realtime.models.earthquake import Earthquake
from realtime.models.ash import Ash


class EarthquakeForm(forms.ModelForm):
class Meta:
model = Earthquake
fields = [
'shake_id',
'magnitude',
'time',
'depth',
'location',
'location_description'
]


date_format = 'YYYY-MM-DD'
date_picker = DateTimePicker(
format=date_format,
options={
'pickTime': False
})
datetime_format = 'YYYY-MM-DD HH:mm:ss'
datetime_picker = DateTimePicker(
format=datetime_format,
options={
'pickTime': True,
'pickSeconds': True,
})


class FilterForm(forms.Form):
start_date = forms.DateField(widget=date_picker, label=_('Start Date'))
end_date = forms.DateField(widget=date_picker, label=_('End Date'))
minimum_magnitude = forms.IntegerField(
min_value=0,
max_value=10,
label=_('Minimum Magnitude'))
maximum_magnitude = forms.IntegerField(
min_value=0,
max_value=10,
label=_('Maximum Magnitude'))
# hidden field for felt shakes
felt = forms.BooleanField()


class AshUploadForm(forms.ModelForm):
Expand All @@ -70,7 +28,12 @@ class Meta:

event_time = forms.DateTimeField(
# initial=datetime.datetime.now(),
widget=datetime_picker)
widget=DateTimePicker(
format=datetime_format,
options={
'pickTime': True,
'pickSeconds': True,
}))
alert_level = forms.ChoiceField(
choices=[
('normal', 'Normal'),
Expand Down
51 changes: 51 additions & 0 deletions django_project/realtime/forms/earthquake.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# coding=utf-8
"""Forms for realtime app."""
from bootstrap3_datetime.widgets import DateTimePicker
from django import forms
from django.utils.translation import ugettext_lazy as _

from realtime.models.earthquake import Earthquake


class EarthquakeForm(forms.ModelForm):
class Meta:
model = Earthquake
fields = [
'shake_id',
'magnitude',
'time',
'depth',
'location',
'location_description'
]


date_format = 'YYYY-MM-DD'
datetime_format = 'YYYY-MM-DD HH:mm:ss'


class FilterForm(forms.Form):
start_date = forms.DateField(
widget=DateTimePicker(
format=date_format,
options={
'pickTime': False
}),
label=_('Start Date'))
end_date = forms.DateField(
widget=DateTimePicker(
format=date_format,
options={
'pickTime': False
}),
label=_('End Date'))
minimum_magnitude = forms.IntegerField(
min_value=0,
max_value=10,
label=_('Minimum Magnitude'))
maximum_magnitude = forms.IntegerField(
min_value=0,
max_value=10,
label=_('Maximum Magnitude'))
# hidden field for felt shakes
felt = forms.BooleanField()
37 changes: 37 additions & 0 deletions django_project/realtime/forms/flood.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# coding=utf-8
"""Forms for realtime app."""
from bootstrap3_datetime.widgets import DateTimePicker
from django import forms
from django.utils.translation import ugettext_lazy as _

date_format = 'YYYY-MM-DD'
datetime_format = 'YYYY-MM-DD HH:mm:ss'


class FilterForm(forms.Form):
start_date = forms.DateField(
widget=DateTimePicker(
format=date_format,
options={
'pickTime': False
}),
label=_('Start Date'))
end_date = forms.DateField(
widget=DateTimePicker(
format=date_format,
options={
'pickTime': False
}),
label=_('End Date'))
min_people_affected = forms.IntegerField(
min_value=0,
label=_('Minimum Number of People Affected'))
max_people_affected = forms.IntegerField(
min_value=0,
label=_('Maximum Number of People Affected'))
min_boundary_flooded = forms.IntegerField(
min_value=0,
label=_('Minimum Number of RW Flooded'))
max_boundary_flooded = forms.IntegerField(
min_value=0,
label=_('Maximum Number of RW Flooded'))
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# coding=utf-8
import datetime

import pytz
from django.core.management.base import BaseCommand
from realtime.tasks.flood import recalculate_impact_info

from realtime.models.flood import Flood

__author__ = 'Rizky Maulana Nugraha "lucernae" <[email protected]>'
__date__ = '07/02/17'


class Command(BaseCommand):
"""Script to recalculate impact data.
"""
help = (
'Command to re-calculate total affected and boundary flooded in '
'flood.')

def handle(self, *args, **options):
using_range = False
if len(args) == 3:
if args[0] == 'range':
using_range = True
Command.recalculate_flood_from_range(args[1], args[2])

if len(args) > 0 and not using_range:
for a in args:
print 'Process flood : %s' % a
flood = Flood.objects.get(event_id=a)
try:
recalculate_impact_info(flood)
except Exception as e:
print e

elif not using_range:
floods = Flood.objects.all().order_by('-time')
print 'Process flood (%s)' % len(floods)
for flood in floods:
try:
recalculate_impact_info(flood)
except Exception as e:
print e

@staticmethod
def recalculate_flood_from_range(start_event_id, end_event_id):
format_str = '%Y%m%d%H-6-rw'
start_time = datetime.datetime.strptime(start_event_id, format_str)
if not end_event_id == 'now':
end_time = datetime.datetime.strptime(end_event_id, format_str)
else:
end_time = datetime.datetime.utcnow()
# convert to UTC
start_time = start_time.replace(tzinfo=pytz.UTC)
end_time = end_time.replace(tzinfo=pytz.UTC)
time_diff = end_time - start_time
total_hours = int(time_diff.total_seconds() / 3600)
success = 0
failed = 0
for i in range(0, total_hours):
hour_diff = datetime.timedelta(hours=i + 1)
target_time = start_time + hour_diff
event_id = target_time.strftime(format_str)
try:
print 'Processing flood: %s' % event_id
flood = Flood.objects.get(event_id=event_id)
recalculate_impact_info(flood)
success += 1
except Exception as e:
failed += 1
print e

print 'Recalculate process done'
print 'Success: %s. Failed: %s' % (success, failed)
26 changes: 26 additions & 0 deletions django_project/realtime/migrations/0025_auto_20170206_2046.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('realtime', '0024_auto_20170206_2044'),
]

operations = [
migrations.AddField(
model_name='flood',
name='boundary_flooded',
field=models.IntegerField(default=0, help_text=b'Total boundary affected by flood', verbose_name=b'Total boundary flooded'),
preserve_default=True,
),
migrations.AddField(
model_name='flood',
name='total_affected',
field=models.IntegerField(default=0, help_text=b'Total affected people by flood', verbose_name=b'Total affected people by flood'),
preserve_default=True,
),
]
8 changes: 8 additions & 0 deletions django_project/realtime/models/flood.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ class Meta:
through='FloodEventBoundary',
verbose_name='Flooded Boundaries',
help_text='The linked boundaries flooded by this event')
total_affected = models.IntegerField(
verbose_name='Total affected people by flood',
help_text='Total affected people by flood',
default=0)
boundary_flooded = models.IntegerField(
verbose_name='Total boundary flooded',
help_text='Total boundary affected by flood',
default=0)

objects = models.GeoManager()

Expand Down
44 changes: 43 additions & 1 deletion django_project/realtime/serializers/flood_serializer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# coding=utf-8

import pytz
from django.core.urlresolvers import reverse
from rest_framework import serializers
from realtime.models.flood import Flood, FloodReport
Expand Down Expand Up @@ -96,12 +96,54 @@ def get_url(self, serializer_field, obj):
# auto bind to get_url method
url = CustomSerializerMethodField()

def get_time_description(self, serializer_field, obj):
"""
:param serializer_field:
:type serializer_field: CustomSerializerMethodField
:param obj:
:type obj: Flood
:return:
"""
utc_time = obj.time.replace(tzinfo=pytz.utc)
jakarta_time = utc_time.astimezone(tz=pytz.timezone('Asia/Jakarta'))
description_format = (
'{interval} hour report for %d %B %Y at %H:%M:%S').format(
interval=obj.interval)
return jakarta_time.strftime(description_format)

# auto bind to get_time_description method
time_description = CustomSerializerMethodField()

def get_event_id_formatted(self, serializer_field, obj):
"""
:param serializer_field:
:type serializer_field: CustomSerializerMethodField
:param obj:
:type obj: Flood
:return:
"""
utc_time = obj.time.replace(tzinfo=pytz.utc)
jakarta_time = utc_time.astimezone(tz=pytz.timezone('Asia/Jakarta'))
event_id_format = '%Y%m%d%H%M%S'
return jakarta_time.strftime(event_id_format)

# auto bind to get_event_id_formatted method
event_id_formatted = CustomSerializerMethodField()

class Meta:
model = Flood
fields = (
'url',
'event_id',
'event_id_formatted',
'time',
'time_description',
'total_affected',
'boundary_flooded',
'interval',
'source',
'region',
Expand Down
24 changes: 18 additions & 6 deletions django_project/realtime/signals/flood.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

from realtime.app_settings import LOGGER_NAME
from realtime.models.flood import Flood
from realtime.tasks.flood import process_hazard_layer, process_impact_layer
from realtime.tasks.flood import (
process_hazard_layer,
process_impact_layer,
recalculate_impact_info)

__author__ = 'Rizky Maulana Nugraha <[email protected]>'
__date__ = '12/4/15'
Expand All @@ -20,12 +23,21 @@


@receiver(post_save, sender=Flood)
def flood_post_save(sender, **kwargs):
def flood_post_save(
sender, instance, created=None, update_fields=None, **kwargs):
"""Extract impact layer of the flood"""
try:
instance = kwargs.get('instance')
chain(
process_hazard_layer.si(instance),
process_impact_layer.si(instance))()
fields = ['total_affected', 'boundary_flooded']
update_fields = update_fields or []
for field in fields:
# if total_affected or boundary_flooded is updated,
# do not recalculate
if field in update_fields:
break
else:
chain(
process_hazard_layer.si(instance),
process_impact_layer.si(instance),
recalculate_impact_info(instance))()
except Exception as e:
LOGGER.exception(e)
Loading

0 comments on commit 6235834

Please sign in to comment.