Skip to content

Commit

Permalink
Additional features and functionality:
Browse files Browse the repository at this point in the history
based on issue inasafe/inasafe-realtime#35

Celery:
- Limit prefetch multiplier explicitly to 1 (avoid hanging worker)

Earthquake:
- Add MMI Output FileField
- Add download button for MMI Output zip
- Auto zoom to first earthquake in the table

Flood:
- Fix signals to recalculate total affected population and flooded RW
- Add Data Source Field, since it needs to support PetaBencana
- Add code branching to handle old hazard data and new PetaBencana
- Add download button for Hazard File and Impact Layers
- Change download button icon to follow Earthquake pattern
- Auto zoom to first flood in the table

Ash:
- Add Impact Files FileField
- Add download button for Impact Files zip
- Change download button icon to follow Earthquake pattern
- Auto zoom to first ash event in the table
  • Loading branch information
lucernae committed Feb 9, 2017
1 parent 0a1bbd3 commit d782048
Show file tree
Hide file tree
Showing 24 changed files with 563 additions and 121 deletions.
1 change: 1 addition & 0 deletions django_project/core/settings/celery_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
CELERY_DEFAULT_ROUTING_KEY = "default"
CELERY_CREATE_MISSING_QUEUES = True
CELERYD_CONCURRENCY = 1
CELERYD_PREFETCH_MULTIPLIER = 1

CELERY_QUEUES = [
Queue('default', routing_key='default'),
Expand Down
32 changes: 32 additions & 0 deletions django_project/realtime/migrations/0026_auto_20170209_1905.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('realtime', '0025_auto_20170206_2046'),
]

operations = [
migrations.AddField(
model_name='ash',
name='impact_files',
field=models.FileField(help_text=b'Impact files processed zipped', upload_to=b'ash/impact_files/%Y/%m/%d', null=True, verbose_name=b'Impact Files', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='earthquake',
name='mmi_output',
field=models.FileField(help_text=b'MMI related file, layers, and data, zipped.', upload_to=b'earthquake/mmi_output', null=True, verbose_name=b'MMI related file zipped', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='ash',
name='eruption_height',
field=models.IntegerField(default=0, verbose_name=b'Eruption height in metres'),
preserve_default=True,
),
]
20 changes: 20 additions & 0 deletions django_project/realtime/migrations/0027_flood_data_source.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('realtime', '0026_auto_20170209_1905'),
]

operations = [
migrations.AddField(
model_name='flood',
name='data_source',
field=models.CharField(default=None, max_length=255, blank=True, help_text=b'The source of the hazard data used for analysis', null=True, verbose_name=b'The source of hazard data'),
preserve_default=True,
),
]
9 changes: 9 additions & 0 deletions django_project/realtime/models/ash.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ class Meta:
upload_to='ash/hazard_file/%Y/%m/%d',
blank=False
)
impact_files = models.FileField(
verbose_name='Impact Files',
help_text='Impact files processed zipped',
upload_to='ash/impact_files/%Y/%m/%d',
blank=True,
null=True
)
event_time = models.DateTimeField(
verbose_name='Event Date and Time',
help_text='The time the ash happened.',
Expand Down Expand Up @@ -67,6 +74,8 @@ def delete(self, using=None):
# delete all report
if self.hazard_file:
self.hazard_file.delete()
if self.impact_files:
self.impact_files.delete()
return super(Ash, self).delete(using=using)


Expand Down
8 changes: 8 additions & 0 deletions django_project/realtime/models/earthquake.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ class Meta:
upload_to='earthquake/grid',
blank=True,
null=True)
mmi_output = models.FileField(
verbose_name='MMI related file zipped',
help_text='MMI related file, layers, and data, zipped.',
upload_to='earthquake/mmi_output',
blank=True,
null=True)
magnitude = models.FloatField(
verbose_name='The magnitude',
help_text='The magnitude of the event.')
Expand Down Expand Up @@ -61,6 +67,8 @@ def delete(self, using=None):
# delete all report
if self.shake_grid:
self.shake_grid.delete()
if self.mmi_output:
self.mmi_output.delete()
for report in self.reports.all():
report.delete(using=using)
super(Earthquake, self).delete(using=using)
Expand Down
7 changes: 7 additions & 0 deletions django_project/realtime/models/flood.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ class Meta:
max_length=20,
unique=True,
blank=False)
data_source = models.CharField(
verbose_name='The source of hazard data',
help_text='The source of the hazard data used for analysis',
max_length=255,
blank=True,
null=True,
default=None)
time = models.DateTimeField(
verbose_name='Date and Time',
help_text='The time the flood reported.',
Expand Down
21 changes: 21 additions & 0 deletions django_project/realtime/serializers/ash_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ class Meta:
'url',
'id',
'volcano',
'hazard_file',
'impact_files',
'reports',
'event_time',
'task_status',
Expand All @@ -132,13 +134,32 @@ class AshGeoJsonSerializer(GeoFeatureModelSerializer):
def get_location(self, obj):
return obj.volcano.location

def get_event_id_formatted(self, serializer_field, obj):
"""
:param serializer_field:
:type serializer_field: CustomSerializerMethodField
:param obj:
:type obj: Ash
:return:
"""
dateformat = '%Y%m%d%H%M%S%z'
return '%s-%s' % (
obj.event_time.strftime(dateformat),
obj.volcano.volcano_name)

# auto bind to get_url method
event_id_formatted = CustomSerializerMethodField()

class Meta:
model = Ash
geo_field = 'location'
id = 'id',
fields = (
'id',
'event_id_formatted',
'volcano',
'hazard_file',
'impact_files',
'event_time',
'alert_level',
'task_status',
Expand Down
2 changes: 2 additions & 0 deletions django_project/realtime/serializers/earthquake_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class Meta:
'url',
'shake_id',
'shake_grid',
'mmi_output',
'magnitude',
'time',
'depth',
Expand All @@ -125,6 +126,7 @@ class Meta:
fields = (
'shake_id',
'shake_grid',
'mmi_output',
'magnitude',
'time',
'depth',
Expand Down
1 change: 1 addition & 0 deletions django_project/realtime/serializers/flood_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ class Meta:
fields = (
'url',
'event_id',
'data_source',
'event_id_formatted',
'time',
'time_description',
Expand Down
2 changes: 1 addition & 1 deletion django_project/realtime/signals/flood.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ def flood_post_save(
chain(
process_hazard_layer.si(instance),
process_impact_layer.si(instance),
recalculate_impact_info(instance))()
recalculate_impact_info.si(instance))()
except Exception as e:
LOGGER.exception(e)
10 changes: 9 additions & 1 deletion django_project/realtime/static/realtime/css/realtime.css
Original file line number Diff line number Diff line change
Expand Up @@ -263,4 +263,12 @@ th.dynatable-head a, th.dynatable-head a:hover {
/* ******************** */
.timepicker-picker td.separator{
line-height: 54px;
}
}


/* ******************** */
/* Dropdown in table */
/* ******************** */
.btn-group .dropdown-menu{
position: absolute;
}
125 changes: 110 additions & 15 deletions django_project/realtime/static/realtime/js/ash/ash.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,15 @@ function createShowEventHandler(map, markers, map_events) {

/**
* Closure to create handler for showReport
* use magic number 000 for url placeholder
* use magic number for url placeholder
*
* @param {string} report_url A report url that contains shake_id placeholder
* @return {function} Open the report based on shake_id in a new tab
* @param {string} report_url A report url that contains event_id placeholder
* @return {function} Open the report based on event_id in a new tab
*/
function createShowReportHandler(report_url) {
var showReportHandler = function (id) {
var url = report_url;
// replace magic number 000 with shake_id
// replace magic number
function createFindWithId(id){
return function (event) {
return event.properties.id == id;
Expand Down Expand Up @@ -171,6 +171,54 @@ function createShowReportHandler(report_url) {
return showReportHandler;
}

/**
* Closure to create handler for downloadReport
* use magic number for url placeholder
*
* @param {string} report_url A report url that contains event_id placeholder
* @return {function} Open the report based on event_id in a new tab
*/
function createDownloadReportHandler(report_url) {
var downloadReportHandler = function (id) {
var url = report_url;
// replace magic number 000 with shake_id
function createFindWithId(id){
return function (event) {
return event.properties.id == id;
}
}
var findWithId = createFindWithId(id);
var feature = event_json.features.find(findWithId);
var volcano_name = feature.properties.volcano.volcano_name;
var event_time = feature.properties.event_time;
var event_time_string = moment(event_time).format('YYYYMMDDHHmmssZZ');
var event_id_formatted = feature.properties.event_id_formatted;
var task_status = feature.properties.task_status;
if(task_status == 'PENDING'){
alert("Report is currently being generated. Refresh this page later.");
return;
}
else if(task_status == 'FAILED'){
alert("Report failed to generate.");
return;
}
url = url.replace('VOLCANOTEMPLATENAME', volcano_name)
.replace('1234567890123456789', event_time_string);
$.get(url, function (data) {
if (data && data.report_map) {
var pdf_url = data.report_map;
SaveToDisk(pdf_url, event_id_formatted+'-'+data.language+'.pdf');
}
}).fail(function(e){
console.log(e);
if(e.status == 404){
alert("No Report recorded for this event.");
}
});
};
return downloadReportHandler;
}


/**
* Create Action Writer based on button_templates
Expand Down Expand Up @@ -200,17 +248,64 @@ function createActionRowWriter(button_templates, date_format) {
var $span = $('<span></span>');
for (var i = 0; i < button_templates.length; i++) {
var button = button_templates[i];
var $inner_button = $('<span></span>');
$inner_button.addClass('row-action-icon')
$inner_button.addClass(button.css_class);
$inner_button.attr('title', button.name);
$inner_button.text(button.label);
var $button = $('<button></button>');
$button.addClass('btn btn-primary row-action-container');
$button.attr('title', button.name);
$button.attr('onclick', button.handler + "('" + record.id + "')");
$button.append($inner_button);
$span.append($button);
if(button.type == 'simple-button') {
var $inner_button = $('<span></span>');
$inner_button.addClass('row-action-icon');
$inner_button.addClass(button.css_class);
$inner_button.attr('title', button.name);
var $button = $('<button></button>');
$button.addClass('btn btn-primary row-action-container');
$button.attr('title', button.name);
$button.attr('onclick', button.handler + "('" + record.id + "')");
$button.append($inner_button);
$span.append($button);
}
else if(button.type == 'dropdown'){
var $button = $('<button></button>');
$button.addClass('btn btn-primary dropdown-toggle row-action-container');
$button.attr('title', button.name);
$button.attr('data-toggle', 'dropdown');
$button.attr('aria-haspopup', 'true');
$button.attr('aria-expanded', 'false');
var $inner_button = $('<span></span>');
$inner_button.addClass('row-action-icon');
$inner_button.addClass(button.css_class);
$inner_button.attr(button.name);
$button.append($inner_button);
var $menu = $('<ul></ul>');
$menu.addClass('dropdown-menu');
for(var j=0;j < button.actions.length;j++){
var action = button.actions[j];
if(action.active && $.isFunction(action.active) && !action.active(record)){
continue;
}
var $li = $('<li></li>');
var $action = $('<a></a>');
if(action.href == undefined){
$action.attr('href', '#');
}
else if($.isFunction(action.href)){
$action.attr('href', action.href(record));
}

if(action.download && $.isFunction(action.download)){
$action.attr('download', action.download(record));
}

if(action.handler){
$action.attr('onclick', action.handler + "('" + record.id + "')");
}

$action.text(action.text);
$li.append($action);
$menu.append($li);
}
var $group = $('<div></div>');
$group.addClass('btn-group');
$group.append($button);
$group.append($menu);
$span.append($group);
}
}
tr += '<td>' + $span.html() + '</td>';

Expand Down
Loading

0 comments on commit d782048

Please sign in to comment.