diff --git a/django_project/realtime/forms/__init__.py b/django_project/realtime/forms/__init__.py new file mode 100644 index 00000000..571998b9 --- /dev/null +++ b/django_project/realtime/forms/__init__.py @@ -0,0 +1,6 @@ +# coding=utf-8 + +__copyright__ = "Copyright 2016, The InaSAFE Project" +__license__ = "GPL version 3" +__email__ = "info@inasafe.org" +__revision__ = ':%H$' diff --git a/django_project/realtime/forms.py b/django_project/realtime/forms/ash.py similarity index 52% rename from django_project/realtime/forms.py rename to django_project/realtime/forms/ash.py index 66c72972..717d5753 100644 --- a/django_project/realtime/forms.py +++ b/django_project/realtime/forms/ash.py @@ -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): @@ -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'), diff --git a/django_project/realtime/forms/earthquake.py b/django_project/realtime/forms/earthquake.py new file mode 100644 index 00000000..12f41d42 --- /dev/null +++ b/django_project/realtime/forms/earthquake.py @@ -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() diff --git a/django_project/realtime/forms/flood.py b/django_project/realtime/forms/flood.py new file mode 100644 index 00000000..27bb8494 --- /dev/null +++ b/django_project/realtime/forms/flood.py @@ -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')) diff --git a/django_project/realtime/management/commands/recalculateimpactdata.py b/django_project/realtime/management/commands/recalculateimpactdata.py new file mode 100644 index 00000000..b3dd551a --- /dev/null +++ b/django_project/realtime/management/commands/recalculateimpactdata.py @@ -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" ' +__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) diff --git a/django_project/realtime/migrations/0025_auto_20170206_2046.py b/django_project/realtime/migrations/0025_auto_20170206_2046.py new file mode 100644 index 00000000..289491d3 --- /dev/null +++ b/django_project/realtime/migrations/0025_auto_20170206_2046.py @@ -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, + ), + ] diff --git a/django_project/realtime/models/flood.py b/django_project/realtime/models/flood.py index 71b9f1ef..da5ffc48 100644 --- a/django_project/realtime/models/flood.py +++ b/django_project/realtime/models/flood.py @@ -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() diff --git a/django_project/realtime/serializers/flood_serializer.py b/django_project/realtime/serializers/flood_serializer.py index ebed2092..45a5252b 100644 --- a/django_project/realtime/serializers/flood_serializer.py +++ b/django_project/realtime/serializers/flood_serializer.py @@ -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 @@ -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', diff --git a/django_project/realtime/signals/flood.py b/django_project/realtime/signals/flood.py index c78fc2de..389cab57 100644 --- a/django_project/realtime/signals/flood.py +++ b/django_project/realtime/signals/flood.py @@ -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 ' __date__ = '12/4/15' @@ -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) diff --git a/django_project/realtime/static/realtime/js/flood/flood.js b/django_project/realtime/static/realtime/js/flood/flood.js index 654c32dc..67451239 100644 --- a/django_project/realtime/static/realtime/js/flood/flood.js +++ b/django_project/realtime/static/realtime/js/flood/flood.js @@ -280,17 +280,13 @@ function createDownloadReportHandler(report_url) { * @param {function} dataHandler Function to handle retrieved data * @return {Function} Update handler function */ -function createUpdateFilterHandler(url, form_filter, location_filter, dataHandler) { +function createUpdateFilterHandler(url, form_filter, dataHandler) { var updateFilterHandler = function (e, reset) { if (e.preventDefault) { e.preventDefault(); } var form_filter_query = form_filter.serialize(); - var location_filter_query = ""; - if (location_filter.isEnabled() && reset!==true) { - location_filter_query += "&in_bbox=" + location_filter.getBounds().toBBoxString(); - } - $.get(url + "?" + form_filter_query + location_filter_query, dataHandler); + $.get(url + "?" + form_filter_query, dataHandler); }; return updateFilterHandler; } @@ -300,18 +296,18 @@ function createUpdateFilterHandler(url, form_filter, location_filter, dataHandle * @param data_input {{}} a geo json collections * @param min_date {string} date formattable string * @param max_date {string} date formattable string - * @param min_magnitude {string} float string - * @param max_magnitude {string} float string + * @param min_people_affected {string} float string + * @param max_people_affected {string} float string * @return {{features: Array, type: *}} */ -function clientFilter(data_input, min_date, max_date, min_magnitude, max_magnitude){ +function clientFilter(data_input, min_date, max_date, min_people_affected, max_people_affected, min_boundary_flooded, max_boundary_flooded){ var filtered_features = []; - var features = data_input.features; + var features = data_input; for(var i=0;i parseFloat(max_people_affected)){ + continue + } + + // boundary flooded + var boundary_flooded = feature.boundary_flooded; + if(min_boundary_flooded && boundary_flooded < parseFloat(min_boundary_flooded)){ continue } - if(max_magnitude && magnitude > parseFloat(max_magnitude)){ + if(max_boundary_flooded && boundary_flooded > parseFloat(max_boundary_flooded)){ continue } // filtered filtered_features.push(feature); } - return { - features: filtered_features, - type: data_input.type - }; + return filtered_features; } /** @@ -378,22 +381,21 @@ function clientExtentFilter(data_input, bounds){ * @param {function} dataHandler Function to handle retrieved data * @return {Function} Update handler function */ -function createClientUpdateFilterHandler(url, form_filter, location_filter, dataHandler) { +function createClientUpdateFilterHandler(url, form_filter, dataHandler) { var updateFilterHandler = function (e, reset) { if (e.preventDefault) { e.preventDefault(); } // filter by bounds var filtered = event_json; - if(reset !== true){ - filtered = clientExtentFilter(event_json, location_filter.getBounds()); - } filtered = clientFilter( filtered, $("#id_start_date", form_filter).val(), $("#id_end_date", form_filter).val(), - $("#id_minimum_magnitude", form_filter).val(), - $("#id_maximum_magnitude", form_filter).val() + $("#id_min_people_affected", form_filter).val(), + $("#id_max_people_affected", form_filter).val(), + $("#id_min_boundary_flooded", form_filter).val(), + $("#id_max_boundary_flooded", form_filter).val() ); dataHandler(filtered); }; @@ -407,17 +409,30 @@ function createClientUpdateFilterHandler(url, form_filter, location_filter, data function modifyMapDescriptions(target){ var $target = $(target); - var magnitude_string = ""; - var min_magnitude = $("#id_minimum_magnitude").val(); - var max_magnitude = $("#id_maximum_magnitude").val(); - if(min_magnitude && max_magnitude){ - magnitude_string = 'with magnitudes between '+min_magnitude+' and '+max_magnitude; + var people_affected_string = ""; + var min_people_affected = $("#id_min_people_affected").val(); + var max_people_affected = $("#id_max_people_affected").val(); + var boundary_flooded_string = ""; + var min_boundary_flooded = $("#id_min_boundary_flooded").val(); + var max_boundary_flooded = $("#id_max_boundary_flooded").val(); + if(min_people_affected && max_people_affected){ + people_affected_string = 'with people affected between '+min_people_affected+' and '+max_people_affected; + } + else if(min_people_affected){ + people_affected_string = 'with people affected greater or equal than '+min_people_affected; + } + else if(max_people_affected){ + people_affected_string = 'with people affected less or equal than '+max_people_affected; + } + + if(min_boundary_flooded && max_boundary_flooded){ + boundary_flooded_string = 'with RW flooded between '+min_boundary_flooded+' and '+max_boundary_flooded; } - else if(min_magnitude){ - magnitude_string = 'with magnitudes greater or equal than '+min_magnitude; + else if(min_boundary_flooded){ + boundary_flooded_string = 'with RW flooded greater or equal than '+min_boundary_flooded; } - else if(max_magnitude){ - magnitude_string = 'with magnitudes less or equal than '+max_magnitude; + else if(max_boundary_flooded){ + boundary_flooded_string = 'with RW flooded less or equal than '+max_boundary_flooded; } var date_string = ''; @@ -436,9 +451,12 @@ function modifyMapDescriptions(target){ var end_moment = moment(end_date); date_string = 'before '+end_moment.format('LL'); } - var description = 'Earthquake events'; - if(magnitude_string){ - description+=' '+magnitude_string; + var description = 'Flood events'; + if(people_affected_string){ + description+=' '+people_affected_string; + } + if(boundary_flooded_string){ + description+=' '+boundary_flooded_string; } if(date_string){ description+=' '+date_string; @@ -446,23 +464,6 @@ function modifyMapDescriptions(target){ $target.text(description); } -/** - * Modify location filter plugin styles. - * This function is used to overrides original styles - */ -function modifyLocationFilterStyle(){ - var $location_filter_container = $(".location-filter"); - $location_filter_container.removeClass('button-container').addClass('leaflet-bar'); - var $enable_button = $(".enable-button", $location_filter_container); - $enable_button.text(""); - $enable_button.click(function(){ - // disable text - $("a", $location_filter_container).text(""); - var $toggle_button = $(".enable-button", $location_filter_container); - $toggle_button.toggleClass("remove-button"); - }); -} - /** * Modify default search and show labels of dynatable * Removes ':' from the text diff --git a/django_project/realtime/tasks/flood.py b/django_project/realtime/tasks/flood.py index bfc6c05c..0e9623f6 100644 --- a/django_project/realtime/tasks/flood.py +++ b/django_project/realtime/tasks/flood.py @@ -14,6 +14,7 @@ from django.contrib.gis.geos.collections import MultiPolygon from django.contrib.gis.geos.geometry import GEOSGeometry from django.contrib.gis.geos.polygon import Polygon +from django.db.models import Sum from realtime.app_settings import LOGGER_NAME from realtime.models.flood import ( @@ -65,6 +66,9 @@ def process_hazard_layer(flood): FloodEventBoundary.objects.filter(flood=flood).delete() + kelurahan = BoundaryAlias.objects.get(alias=OSM_LEVEL_7_NAME) + rw = BoundaryAlias.objects.get(alias=OSM_LEVEL_8_NAME) + for feat in layer: pkey = feat.get('pkey') level_name = feat.get('level_name') @@ -81,7 +85,6 @@ def process_hazard_layer(flood): geos_geometry = MultiPolygon(geos_geometry) # check parent exists - kelurahan = BoundaryAlias.objects.get(alias=OSM_LEVEL_7_NAME) try: boundary_kelurahan = Boundary.objects.get( name__iexact=parent_name.strip(), @@ -94,7 +97,6 @@ def process_hazard_layer(flood): boundary_alias=kelurahan) boundary_kelurahan.save() - rw = BoundaryAlias.objects.get(alias=OSM_LEVEL_8_NAME) try: boundary_rw = Boundary.objects.get( upstream_id=pkey, boundary_alias=rw) @@ -161,6 +163,9 @@ def process_impact_layer(flood): layer = source[0] ImpactEventBoundary.objects.filter(flood=flood).delete() + + kelurahan = BoundaryAlias.objects.get(alias=OSM_LEVEL_7_NAME) + for feat in layer: level_7_name = feat.get('NAMA_KELUR').strip() hazard_class = feat.get('affected') @@ -175,8 +180,6 @@ def process_impact_layer(flood): if hazard_class <= 1: continue - kelurahan = BoundaryAlias.objects.get(alias=OSM_LEVEL_7_NAME) - try: boundary_kelurahan = Boundary.objects.get( name__iexact=level_7_name, @@ -204,6 +207,38 @@ def process_impact_layer(flood): return True +@app.task(queue='inasafe-django') +def recalculate_impact_info(flood): + """Recalculate flood impact data. + + :param flood: Flood object + :type flood: realtime.models.flood.Flood + """ + # calculate total boundary flooded in RW level + rw = BoundaryAlias.objects.get(alias=OSM_LEVEL_8_NAME) + boundary_flooded = FloodEventBoundary.objects.filter( + flood=flood, + boundary__boundary_alias=rw).count() + flood.boundary_flooded = boundary_flooded or 0 + + # calculate total population affected in kelurahan level + kelurahan = BoundaryAlias.objects.get(alias=OSM_LEVEL_7_NAME) + total_population_affected = ImpactEventBoundary.objects.filter( + flood=flood, + parent_boundary__boundary_alias=kelurahan + ).aggregate( + total_population_affected=Sum('population_affected')) + try: + flood.total_affected = total_population_affected[ + 'total_population_affected'] or 0 + except KeyError: + flood.total_affected = 0 + pass + + # prevent infinite recursive save + flood.save(update_fields=['total_affected', 'boundary_flooded']) + + @app.task(queue='inasafe-django') def create_flood_report(): process_flood.delay() diff --git a/django_project/realtime/templates/realtime/flood/index.html b/django_project/realtime/templates/realtime/flood/index.html index 5315a586..54fd5ab3 100644 --- a/django_project/realtime/templates/realtime/flood/index.html +++ b/django_project/realtime/templates/realtime/flood/index.html @@ -55,16 +55,75 @@

{% trans "Map" %}

{% endblock main_content %} {% block filter_content %} -{#
#} -{#
#} -{#
#} -{#

{% trans "Filters" %}

#} -{#
#} -{#
#} -{# Lorem Ip-sunni...#} -{#
#} -{#
#} -{#
#} +
+
+
+

{% trans "Filters" %}

+
+
+
+ + + + {{ form.start_date|bootstrap }} +
+
+ + {{ form.end_date|bootstrap }} +
+
+
+ + + {{ form.min_people_affected|bootstrap }} +
+
+ + {{ form.max_people_affected|bootstrap }} +
+
+
+ + + {{ form.min_boundary_flooded|bootstrap }} +
+
+ + {{ form.max_boundary_flooded|bootstrap }} +
+
+
+ + + +
+ + + + + + + + +
+
+
+
{% endblock filter_content %} {% block table_content %} @@ -79,7 +138,10 @@

{% trans "Flood" %}

{% trans "Event ID" %} - {% trans "Time" %} + {% trans "Event ID" %} + {% trans "Time" %} + {% trans "Population Affected" %} + {% trans "RW Flooded" %} @@ -150,7 +212,7 @@

{% trans "Flood" %}

dynatable.settings.dataset.originalRecords = jsonTableContents; dynatable.paginationPerPage.set(100); - dynatable.sorts.add('time', -1); + dynatable.sorts.add('event_id_formatted', -1); dynatable.process(); // programatically show first flood in row @@ -196,7 +258,8 @@

{% trans "Flood" %}

}, dataset: { records: jsonTableContents, - sorts: {'magnitude': -1} + sorts: {'magnitude': -1}, + search: false, } }).data('dynatable'); @@ -204,9 +267,69 @@

{% trans "Flood" %}

addActionColumn('#realtime-table', 'Action'); $.get(get_events_url, function(data){ - var event_json = data; + event_json = data; getEventsJson(event_json); }); + + // add content filter handler + // update via ajax request + var $event_filter = $("#event-filter"); + {% if server_side_filter %} + var _updateFilterHandler = createUpdateFilterHandler(get_events_url, + $event_filter, + getEventsJson); + {% else %} + // update via client filters + var _updateFilterHandler = createClientUpdateFilterHandler(get_events_url, + $event_filter, + getEventsJson); + {% endif %} + var updateFilterHandler = function (e, reset) { + _updateFilterHandler(e, reset); + modifyMapDescriptions(".map-title"); + }; + + {# Modify location filter styles#} + modifySearchAndShowLabels(); + + $(".submit-filter").click(updateFilterHandler); + var clearFilterHandler = function (e) { + e.preventDefault(); + var $event_filter = $("#event-filter"); + $event_filter.find("input[type=text].form-control").val(''); + $event_filter.find("input[type=number].form-control").val(''); + $event_filter.find("input[type=checkbox]").prop("checked", false); + updateFilterHandler(e); + $(".submit-filter, .clear-filter").hide(); + }; + $(".clear-filter").click(clearFilterHandler); + + {# Disable date input text#} + $event_filter.find(".date-filter input").attr("readonly", "readonly"); + {# Disable filter button if no filter exists#} + + var show_filter_button = function (e) { + var is_show_filter = false; + $event_filter.find("input[type=text],input[type=number]").each(function (idx, el) { + if ($(el).val()) { + is_show_filter = true; + } + }); + $event_filter.find("input[type=checkbox]").each(function (idx, el) { + if($(el).prop("checked") == true){ + is_show_filter = true; + } + }); + if (is_show_filter) { + $event_filter.find("button.btn").show(); + } + else { + $event_filter.find("button.btn").hide(); + } + }; + + show_filter_button(); + $event_filter.bind('mousemove click keyup focus blur', show_filter_button); }); {% endblock js_container %} diff --git a/django_project/realtime/views/ash.py b/django_project/realtime/views/ash.py index 6af14b0e..43b426fb 100644 --- a/django_project/realtime/views/ash.py +++ b/django_project/realtime/views/ash.py @@ -25,7 +25,7 @@ from realtime.app_settings import LEAFLET_TILES, LANGUAGE_LIST, \ MAPQUEST_MAP_KEY from realtime.models.ash import Ash, AshReport -from realtime.forms import AshUploadForm +from realtime.forms.ash import AshUploadForm from realtime.models.volcano import Volcano from realtime.serializers.ash_serializer import AshSerializer, \ AshReportSerializer, AshGeoJsonSerializer diff --git a/django_project/realtime/views/earthquake.py b/django_project/realtime/views/earthquake.py index ccc6ea52..2c37c465 100644 --- a/django_project/realtime/views/earthquake.py +++ b/django_project/realtime/views/earthquake.py @@ -21,7 +21,7 @@ from rest_framework.response import Response from realtime.app_settings import ( LEAFLET_TILES, LANGUAGE_LIST, MAPQUEST_MAP_KEY) -from realtime.forms import FilterForm +from realtime.forms.earthquake import FilterForm from realtime.filters.earthquake_filter import EarthquakeFilter from realtime.models.earthquake import Earthquake, EarthquakeReport from realtime.serializers.earthquake_serializer import EarthquakeSerializer, \ diff --git a/django_project/realtime/views/flood.py b/django_project/realtime/views/flood.py index 467b311e..0bf1405b 100644 --- a/django_project/realtime/views/flood.py +++ b/django_project/realtime/views/flood.py @@ -5,6 +5,7 @@ from datetime import datetime, timedelta from django.core.exceptions import ValidationError, MultipleObjectsReturned from django.db.models.aggregates import Count +from django.db.models import Q from django.db.utils import IntegrityError from django.http.response import JsonResponse, HttpResponseServerError from django.shortcuts import render_to_response @@ -21,7 +22,7 @@ from realtime.app_settings import ( LEAFLET_TILES, LANGUAGE_LIST, MAPQUEST_MAP_KEY) -from realtime.forms import FilterForm +from realtime.forms.flood import FilterForm from realtime.models.flood import Flood, FloodReport, Boundary, \ FloodEventBoundary from realtime.serializers.flood_serializer import FloodSerializer, \ @@ -114,7 +115,6 @@ class FloodList(mixins.ListModelMixin, mixins.CreateModelMixin, search_fields = ('event_id', ) ordering = ('event_id', ) permission_classes = (DjangoModelPermissionsOrAnonReadOnly, ) - # pagination_class = Pagina def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) @@ -286,9 +286,22 @@ def delete(self, request, event_id, language): class FloodEventList(FloodList): + # only retrieve for 6 interval hours serializer_class = FloodSerializer pagination_class = None + def get_queryset(self): + """Return only 6-interval hours. + + :return: + """ + # this interval is specific for Jakarta (GMT+07) + # it will show up as 6 hourly flood data from 00:00 + query = ( + Q(time__hour=23) | Q(time__hour=5) | + Q(time__hour=11) | Q(time__hour=17)) + return Flood.objects.filter(query) + def flood_event_features(request, event_id): try: