diff --git a/geonode/layers/utils.py b/geonode/layers/utils.py index 29d8af47d1e..ee904fc0642 100644 --- a/geonode/layers/utils.py +++ b/geonode/layers/utils.py @@ -177,6 +177,20 @@ def get_files(filename): 'distinct by spelling and not just case.') % filename raise GeoNodeException(msg) + if 'geosafe' in settings.INSTALLED_APPS: + matches = glob.glob(glob_name + ".[jJ][sS][oO][nN]") + logger.debug('Checking JSON file') + logger.debug('Number of matches JSON file : %s' % len(matches)) + logger.debug('glob name: %s' % glob_name) + if len(matches) == 1: + files['json'] =matches[0] + elif len(matches) > 1: + msg = ('Multiple impact summary report (json) for %s exist; ' + 'they need to be distinct by spelling and not just case.' + ) % filename + raise GeoNodeException(msg) + + return files diff --git a/geonode/static/geosafe/img/land_cover.svg b/geonode/static/geosafe/img/land_cover.svg new file mode 100644 index 00000000000..2f0ffda6ed7 --- /dev/null +++ b/geonode/static/geosafe/img/land_cover.svg @@ -0,0 +1,15 @@ + + + + + + diff --git a/geonode/static/geosafe/img/volcanic-ash.svg b/geonode/static/geosafe/img/volcanic-ash.svg new file mode 100644 index 00000000000..34822fb7c71 --- /dev/null +++ b/geonode/static/geosafe/img/volcanic-ash.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + diff --git a/geosafe/helpers/__init__.py b/geosafe/helpers/__init__.py new file mode 100644 index 00000000000..750dd405e7c --- /dev/null +++ b/geosafe/helpers/__init__.py @@ -0,0 +1,5 @@ +# coding=utf-8 + +__author__ = 'Rizky Maulana Nugraha ' + +__date__ = '5/17/16' diff --git a/geosafe/helpers/impact_summary/__init__.py b/geosafe/helpers/impact_summary/__init__.py new file mode 100644 index 00000000000..750dd405e7c --- /dev/null +++ b/geosafe/helpers/impact_summary/__init__.py @@ -0,0 +1,5 @@ +# coding=utf-8 + +__author__ = 'Rizky Maulana Nugraha ' + +__date__ = '5/17/16' diff --git a/geosafe/helpers/impact_summary/landcover_summary.py b/geosafe/helpers/impact_summary/landcover_summary.py new file mode 100644 index 00000000000..76359098b60 --- /dev/null +++ b/geosafe/helpers/impact_summary/landcover_summary.py @@ -0,0 +1,48 @@ +# coding=utf-8 +from collections import OrderedDict + +from geosafe.helpers.impact_summary.summary_base import ImpactSummary + +__author__ = 'Rizky Maulana Nugraha ' +__date__ = '5/18/16' + + +class StructureSummary(ImpactSummary): + + def total(self): + return self.total_buildings() + + def total_buildings(self): + return self.summary_dict().get('Total') + + def total_affected(self): + if 'Affected buildings' in self.summary_dict().keys(): + return self.summary_dict().get('Affected buildings') + elif 'Not affected buildings' in self.summary_dict().keys(): + not_affected = self.summary_dict().get('Not affected buildings') + return int(self.total_buildings()) - int(not_affected) + + def breakdown_dict(self): + ret_val = OrderedDict() + for key, value in self.summary_dict().iteritems(): + contain_total = 'total' in key.lower() + contain_affected = 'affected' in key.lower() + contain_not = 'not' in key.lower() + if contain_total or (contain_affected and not contain_not): + continue + + ret_val[key] = int(value) + return ret_val + + def category_css_class(self, category): + css_class = ImpactSummary.category_css_class(category) + if not css_class: + if 'flood' in category.lower(): + css_class = 'hazard-category-high' + elif 'dry' in category.lower(): + css_class = 'hazard-category-low' + elif 'wet' in category.lower(): + css_class = 'hazard-category-medium' + elif 'radius' in category.lower(): + css_class = 'hazard-category-high' + return css_class diff --git a/geosafe/helpers/impact_summary/polygon_people_summary.py b/geosafe/helpers/impact_summary/polygon_people_summary.py new file mode 100644 index 00000000000..6bdb2162187 --- /dev/null +++ b/geosafe/helpers/impact_summary/polygon_people_summary.py @@ -0,0 +1,54 @@ +# coding=utf-8 +from collections import OrderedDict + +from geosafe.helpers.impact_summary.summary_base import ImpactSummary + +__author__ = 'Rizky Maulana Nugraha ' +__date__ = '5/18/16' + + +class PolygonPeopleSummary(ImpactSummary): + + def total(self): + return self.total_people() + + def total_people(self): + return int(self.summary_dict().get('Total people')) + + def total_affected(self): + if 'Total affected people' in self.summary_dict().keys(): + return int(self.summary_dict().get('Total affected people')) + return 0 + + def breakdown_dict(self): + ret_val = OrderedDict() + for key, value in self.summary_dict().iteritems(): + contain_total = 'total' in key.lower() + contain_affected = 'affected' in key.lower() + contain_not = 'not' in key.lower() + contain_unaffected = 'unaffected' in key.lower() + if (contain_total or + (contain_affected and + not contain_not and + not contain_unaffected)): + continue + + ret_val[key] = int(value) + return ret_val + + def category_css_class(self, category): + css_class = ImpactSummary.category_css_class(category) + if not css_class: + if 'people' in category.lower(): + css_class = 'hazard-category-high' + elif 'fatalities' in category.lower(): + css_class = 'hazard-category-high' + elif 'displaced' in category.lower(): + css_class = 'hazard-category-high' + elif 'affected' in category.lower(): + css_class = 'hazard-category-high' + elif 'floodprone' in category.lower(): + css_class = 'hazard-category-high' + elif 'radius' in category.lower(): + css_class = 'hazard-category-high' + return css_class diff --git a/geosafe/helpers/impact_summary/population_summary.py b/geosafe/helpers/impact_summary/population_summary.py new file mode 100644 index 00000000000..1b7f02a131a --- /dev/null +++ b/geosafe/helpers/impact_summary/population_summary.py @@ -0,0 +1,54 @@ +# coding=utf-8 +from collections import OrderedDict + +from geosafe.helpers.impact_summary.summary_base import ImpactSummary + +__author__ = 'Rizky Maulana Nugraha ' +__date__ = '5/18/16' + + +class PopulationSummary(ImpactSummary): + + def total(self): + return self.total_populations() + + def total_populations(self): + return self.summary_dict().get('Total population') + + def total_affected(self): + if 'Total affected population' in self.summary_dict().keys(): + return int(self.summary_dict().get('Total affected population')) + return 0 + + def breakdown_dict(self): + ret_val = OrderedDict() + for key, value in self.summary_dict().iteritems(): + contain_total = 'total' in key.lower() + contain_affected = 'affected' in key.lower() + contain_not = 'not' in key.lower() + contain_unaffected = 'unaffected' in key.lower() + if (contain_total or + (contain_affected and + not contain_not and + not contain_unaffected)): + continue + + ret_val[key] = int(value) + return ret_val + + def category_css_class(self, category): + css_class = ImpactSummary.category_css_class(category) + if not css_class: + if 'people' in category.lower(): + css_class = 'hazard-category-high' + elif 'fatalities' in category.lower(): + css_class = 'hazard-category-high' + elif 'displaced' in category.lower(): + css_class = 'hazard-category-high' + elif 'affected' in category.lower(): + css_class = 'hazard-category-high' + elif 'floodprone' in category.lower(): + css_class = 'hazard-category-high' + elif 'radius' in category.lower(): + css_class = 'hazard-category-high' + return css_class diff --git a/geosafe/helpers/impact_summary/road_summary.py b/geosafe/helpers/impact_summary/road_summary.py new file mode 100644 index 00000000000..313419656de --- /dev/null +++ b/geosafe/helpers/impact_summary/road_summary.py @@ -0,0 +1,55 @@ +# coding=utf-8 +from collections import OrderedDict + +from geosafe.helpers.impact_summary.summary_base import ImpactSummary + +__author__ = 'Rizky Maulana Nugraha ' +__date__ = '6/13/16' + + +class RoadSummary(ImpactSummary): + + def total(self): + return self.total_roads() + + def total_roads(self): + for idx, val in enumerate(self.summary_attributes()): + if 'total' in val.lower(): + if self.is_summary_exists(): + return int(self.impact_data.get('impact summary').get( + 'fields')[0][idx]) + return 0 + + def total_affected(self): + lowercase_keys = [k.lower() for k in self.summary_attributes()] + for idx, val in enumerate(lowercase_keys): + if 'flooded' in val or 'closed' in val: + return int(self.impact_data.get('impact summary').get( + 'fields')[0][idx]) + return 0 + + def breakdown_dict(self): + ret_val = OrderedDict() + for idx, key in enumerate(self.summary_attributes()): + contain_total = 'total' in key.lower() + contain_affected = 'affected' in key.lower() + contain_not = 'not' in key.lower() + contain_unaffected = 'unaffected' in key.lower() + if (contain_total or + (contain_affected and + not contain_not and + not contain_unaffected)): + continue + + ret_val[key] = int(self.impact_data.get('impact summary').get( + 'fields')[0][idx]) + return ret_val + + def category_css_class(self, category): + css_class = ImpactSummary.category_css_class(category) + if not css_class: + if 'closed' in category.lower(): + css_class = 'hazard-category-high' + elif 'flooded' in category.lower(): + css_class = 'hazard-category-high' + return css_class diff --git a/geosafe/helpers/impact_summary/structure_summary.py b/geosafe/helpers/impact_summary/structure_summary.py new file mode 100644 index 00000000000..76359098b60 --- /dev/null +++ b/geosafe/helpers/impact_summary/structure_summary.py @@ -0,0 +1,48 @@ +# coding=utf-8 +from collections import OrderedDict + +from geosafe.helpers.impact_summary.summary_base import ImpactSummary + +__author__ = 'Rizky Maulana Nugraha ' +__date__ = '5/18/16' + + +class StructureSummary(ImpactSummary): + + def total(self): + return self.total_buildings() + + def total_buildings(self): + return self.summary_dict().get('Total') + + def total_affected(self): + if 'Affected buildings' in self.summary_dict().keys(): + return self.summary_dict().get('Affected buildings') + elif 'Not affected buildings' in self.summary_dict().keys(): + not_affected = self.summary_dict().get('Not affected buildings') + return int(self.total_buildings()) - int(not_affected) + + def breakdown_dict(self): + ret_val = OrderedDict() + for key, value in self.summary_dict().iteritems(): + contain_total = 'total' in key.lower() + contain_affected = 'affected' in key.lower() + contain_not = 'not' in key.lower() + if contain_total or (contain_affected and not contain_not): + continue + + ret_val[key] = int(value) + return ret_val + + def category_css_class(self, category): + css_class = ImpactSummary.category_css_class(category) + if not css_class: + if 'flood' in category.lower(): + css_class = 'hazard-category-high' + elif 'dry' in category.lower(): + css_class = 'hazard-category-low' + elif 'wet' in category.lower(): + css_class = 'hazard-category-medium' + elif 'radius' in category.lower(): + css_class = 'hazard-category-high' + return css_class diff --git a/geosafe/helpers/impact_summary/summary_base.py b/geosafe/helpers/impact_summary/summary_base.py new file mode 100644 index 00000000000..bff1bb63442 --- /dev/null +++ b/geosafe/helpers/impact_summary/summary_base.py @@ -0,0 +1,129 @@ +# coding=utf-8 + +import json +from collections import OrderedDict + +from geonode.layers.models import Layer, LayerFile + +__author__ = 'Rizky Maulana Nugraha ' +__date__ = '5/17/16' + + +class ImpactSummary(object): + + def __init__(self, impact_layer): + self._impact_layer = impact_layer + self._impact_data = self.read_impact_data_json() + + @property + def impact_layer(self): + """ + + :return: Impact Layer + :rtype: Layer + """ + return self._impact_layer + + @impact_layer.setter + def impact_layer(self, impact_layer): + self._impact_layer = impact_layer + + @property + def impact_data(self): + """ + + :return: Impact data dictionary + :rtype: dict + """ + return self._impact_data + + @impact_data.setter + def impact_data(self, value): + self._impact_data = value + + def read_impact_data_json(self): + """Read impact_data.json file from a given impact layer + + :return: dictionary of impact data + :rtype: dict + """ + try: + json_file = self.impact_layer.upload_session.layerfile_set.get( + file__endswith=".json") + impact_data = json.loads(json_file.file.read()) + return impact_data + except LayerFile.DoesNotExist: + return {} + + def is_summary_exists(self): + return self.impact_data or self.impact_data.get('impact summary') + + def maximum_category_value(self): + if self.is_summary_exists(): + max_val = max([f.get('value') for f in self.summary_fields()]) + return max_val + return 0 + + def summary_fields(self): + """convert impact data to list of key-value pair + + :return: list of dict of category and value + """ + fields = [] + if self.is_summary_exists(): + fields = self.impact_data.get('impact summary').get('fields') + + ret_val = [] + for f in fields: + ret_val.append({ + "category": f[0], + "value": f[1] + }) + + return ret_val + + def summary_dict(self): + """convert summary fields to key value pair""" + ret_val = OrderedDict() + for f in self.summary_fields(): + ret_val[f['category']] = f['value'] + + return ret_val + + def summary_attributes(self): + ret_val = OrderedDict() + if self.is_summary_exists(): + attrs = self.impact_data.get('impact summary').get('attributes') + return attrs + + def category_list(self): + if self.is_summary_exists(): + return [f.get('category') for f in self.summary_fields()] + + def exposure_type(self): + return self.impact_data.get('exposure') + + @classmethod + def category_css_class(cls, category): + """Get css-class from a given category + + :param category: category string + :type category: str + + :return: + """ + if 'high' in category.lower(): + return 'hazard-category-high' + elif 'medium' in category.lower() or 'moderate' in category.lower(): + return 'hazard-category-medium' + elif 'low' in category.lower(): + return 'hazard-category-low' + elif 'total' in category.lower(): + return 'hazard-category-total' + elif 'not affected' in category.lower(): + return 'hazard-category-not-affected' + elif 'affected' in category.lower(): + return 'hazard-category-affected' + else: + return '' + diff --git a/geosafe/migrations/0011_auto__add_field_analysis_task_state.py b/geosafe/migrations/0011_auto__add_field_analysis_task_state.py new file mode 100644 index 00000000000..5bb0bd05f66 --- /dev/null +++ b/geosafe/migrations/0011_auto__add_field_analysis_task_state.py @@ -0,0 +1,279 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'Analysis.task_state' + db.add_column(u'geosafe_analysis', 'task_state', + self.gf('django.db.models.fields.CharField')(max_length=10, null=True, blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Analysis.task_state' + db.delete_column(u'geosafe_analysis', 'task_state') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'base.contactrole': { + 'Meta': {'unique_together': "(('contact', 'resource', 'role'),)", 'object_name': 'ContactRole'}, + 'contact': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['people.Profile']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['base.ResourceBase']"}), + 'role': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'base.license': { + 'Meta': {'ordering': "('name',)", 'object_name': 'License'}, + 'abbreviation': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_en': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'license_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'license_text_en': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name_en': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}) + }, + u'base.region': { + 'Meta': {'ordering': "('name',)", 'object_name': 'Region'}, + 'code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + u'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + u'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'name_en': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': u"orm['base.Region']"}), + u'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + u'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + u'base.resourcebase': { + 'Meta': {'object_name': 'ResourceBase'}, + 'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'bbox_x0': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '19', 'decimal_places': '10', 'blank': 'True'}), + 'bbox_x1': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '19', 'decimal_places': '10', 'blank': 'True'}), + 'bbox_y0': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '19', 'decimal_places': '10', 'blank': 'True'}), + 'bbox_y1': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '19', 'decimal_places': '10', 'blank': 'True'}), + 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['base.TopicCategory']", 'null': 'True', 'blank': 'True'}), + 'constraints_other': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'contacts': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['people.Profile']", 'through': u"orm['base.ContactRole']", 'symmetrical': 'False'}), + 'csw_anytext': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'csw_insert_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'csw_mdsource': ('django.db.models.fields.CharField', [], {'default': "'local'", 'max_length': '256'}), + 'csw_schema': ('django.db.models.fields.CharField', [], {'default': "'http://www.isotc211.org/2005/gmd'", 'max_length': '64'}), + 'csw_type': ('django.db.models.fields.CharField', [], {'default': "'dataset'", 'max_length': '32'}), + 'csw_typename': ('django.db.models.fields.CharField', [], {'default': "'gmd:MD_Metadata'", 'max_length': '32'}), + 'csw_wkt_geometry': ('django.db.models.fields.TextField', [], {'default': "'POLYGON((-180 -90,-180 90,180 90,180 -90,-180 -90))'"}), + 'data_quality_statement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'date_type': ('django.db.models.fields.CharField', [], {'default': "'publication'", 'max_length': '255'}), + 'detail_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'distribution_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'distribution_url': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'edition': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'featured': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_published': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'language': ('django.db.models.fields.CharField', [], {'default': "'eng'", 'max_length': '3'}), + 'license': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['base.License']", 'null': 'True', 'blank': 'True'}), + 'maintenance_frequency': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'metadata_uploaded': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'metadata_xml': ('django.db.models.fields.TextField', [], {'default': '\'\'', 'null': 'True', 'blank': 'True'}), + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'owned_resource'", 'null': 'True', 'to': u"orm['people.Profile']"}), + 'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'polymorphic_base.resourcebase_set'", 'null': 'True', 'to': u"orm['contenttypes.ContentType']"}), + 'popular_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'purpose': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'rating': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}), + 'regions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['base.Region']", 'null': 'True', 'blank': 'True'}), + 'restriction_code_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['base.RestrictionCodeType']", 'null': 'True', 'blank': 'True'}), + 'share_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'spatial_representation_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['base.SpatialRepresentationType']", 'null': 'True', 'blank': 'True'}), + 'srid': ('django.db.models.fields.CharField', [], {'default': "'EPSG:4326'", 'max_length': '255'}), + 'supplemental_information': ('django.db.models.fields.TextField', [], {'default': "u'No information provided'"}), + 'temporal_extent_end': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'temporal_extent_start': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'thumbnail_url': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '36'}) + }, + u'base.restrictioncodetype': { + 'Meta': {'ordering': "('identifier',)", 'object_name': 'RestrictionCodeType'}, + 'description': ('django.db.models.fields.TextField', [], {'max_length': '255'}), + 'description_en': ('django.db.models.fields.TextField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'gn_description': ('django.db.models.fields.TextField', [], {'max_length': '255'}), + 'gn_description_en': ('django.db.models.fields.TextField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'is_choice': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'base.spatialrepresentationtype': { + 'Meta': {'ordering': "('identifier',)", 'object_name': 'SpatialRepresentationType'}, + 'description': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'description_en': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'gn_description': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'gn_description_en': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'is_choice': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'base.topiccategory': { + 'Meta': {'ordering': "('identifier',)", 'object_name': 'TopicCategory'}, + 'description': ('django.db.models.fields.TextField', [], {'default': "''"}), + 'description_en': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}), + 'gn_description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}), + 'gn_description_en': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'identifier': ('django.db.models.fields.CharField', [], {'default': "'location'", 'max_length': '255'}), + 'is_choice': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'geosafe.analysis': { + 'Meta': {'object_name': 'Analysis'}, + 'aggregation_layer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'aggregation_layer'", 'null': 'True', 'to': u"orm['layers.Layer']"}), + 'exposure_layer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'exposure_layer'", 'to': u"orm['layers.Layer']"}), + 'extent_option': ('django.db.models.fields.IntegerField', [], {'default': '2'}), + 'hazard_layer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hazard_layer'", 'to': u"orm['layers.Layer']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'impact_function_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'impact_layer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'impact_layer'", 'null': 'True', 'to': u"orm['layers.Layer']"}), + 'keep': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'report_map': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'report_table': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'task_id': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'task_state': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['people.Profile']", 'null': 'True', 'blank': 'True'}) + }, + u'geosafe.metadata': { + 'Meta': {'object_name': 'Metadata'}, + 'category': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '30', 'null': 'True', 'blank': 'True'}), + 'layer': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'metadata'", 'unique': 'True', 'primary_key': 'True', 'to': u"orm['layers.Layer']"}), + 'layer_purpose': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20', 'null': 'True', 'blank': 'True'}) + }, + u'layers.layer': { + 'Meta': {'object_name': 'Layer', '_ormbases': [u'base.ResourceBase']}, + 'abstract_en': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'charset': ('django.db.models.fields.CharField', [], {'default': "'UTF-8'", 'max_length': '255'}), + 'constraints_other_en': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'data_quality_statement_en': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'default_style': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'layer_default_style'", 'null': 'True', 'to': u"orm['layers.Style']"}), + 'distribution_description_en': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'purpose_en': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'resourcebase_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['base.ResourceBase']", 'unique': 'True', 'primary_key': 'True'}), + 'service': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'layer_set'", 'null': 'True', 'to': u"orm['services.Service']"}), + 'store': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'storeType': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'styles': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'layer_styles'", 'symmetrical': 'False', 'to': u"orm['layers.Style']"}), + 'supplemental_information_en': ('django.db.models.fields.TextField', [], {'default': "u'No information provided'", 'null': 'True', 'blank': 'True'}), + 'title_en': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'typename': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'upload_session': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['layers.UploadSession']", 'null': 'True', 'blank': 'True'}), + 'workspace': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + u'layers.style': { + 'Meta': {'object_name': 'Style'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'sld_body': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'sld_title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'sld_url': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True'}), + 'sld_version': ('django.db.models.fields.CharField', [], {'max_length': '12', 'null': 'True', 'blank': 'True'}), + 'workspace': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + u'layers.uploadsession': { + 'Meta': {'object_name': 'UploadSession'}, + 'context': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'error': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'processed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'traceback': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['people.Profile']"}) + }, + u'people.profile': { + 'Meta': {'object_name': 'Profile'}, + 'area': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'city': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'country': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True', 'blank': 'True'}), + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'delivery': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'fax': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'organization': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'position': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'profile': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), + 'voice': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'zipcode': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + u'services.service': { + 'Meta': {'object_name': 'Service', '_ormbases': [u'base.ResourceBase']}, + 'access_constraints': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'api_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'base_url': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '200', 'db_index': 'True'}), + 'connection_params': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'external_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'fees': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}), + 'first_noanswer': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'last_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'method': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}), + 'noanswer_retries': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'online_resource': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'service_set'", 'null': 'True', 'to': u"orm['services.Service']"}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'profiles': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['people.Profile']", 'through': u"orm['services.ServiceProfileRole']", 'symmetrical': 'False'}), + u'resourcebase_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['base.ResourceBase']", 'unique': 'True', 'primary_key': 'True'}), + 'resources_ref': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'store_ref': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4'}), + 'username': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'version': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), + 'workspace_ref': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}) + }, + u'services.serviceprofilerole': { + 'Meta': {'object_name': 'ServiceProfileRole'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'profiles': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['people.Profile']"}), + 'role': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'service': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['services.Service']"}) + } + } + + complete_apps = ['geosafe'] \ No newline at end of file diff --git a/geosafe/models.py b/geosafe/models.py index 360bf536f72..0190342a58d 100644 --- a/geosafe/models.py +++ b/geosafe/models.py @@ -131,6 +131,14 @@ class Meta: null=True ) + task_state = models.CharField( + max_length=10, + verbose_name='Task State', + help_text='Task State recorded in the model', + blank=True, + null=True + ) + keep = models.BooleanField( verbose_name='Keep impact result', help_text='True if the impact will be kept', @@ -180,14 +188,27 @@ def get_task_result(self): return AsyncResult(self.task_id) def get_label_class(self): - result = self.get_task_result() - if result.state == 'SUCCESS': + state = self.get_task_state() + if state == 'SUCCESS': return 'success' - elif result.state == 'FAILURE': + elif state == 'FAILURE': return 'danger' else: return 'info' + def get_task_state(self): + """Check task state + + State need to be evaluated from task result. + However after a certain time, the task result is removed from broker. + In this case, the state will always return 'PENDING'. For this, we + receive the actual result from self.state, which is the cached state + + :return: + """ + result = self.get_task_result() + return self.task_state if result.state == 'PENDING' else result.state + def get_default_impact_title(self): layer_name = '%s on %s' % ( self.hazard_layer.name, diff --git a/geosafe/signals.py b/geosafe/signals.py index 976aad61e98..59982f085bc 100644 --- a/geosafe/signals.py +++ b/geosafe/signals.py @@ -43,4 +43,5 @@ def analysis_post_save(sender, instance, created, **kwargs): async_result = process_impact_result.delay( instance.id, impact_url_result) instance.task_id = async_result.task_id + instance.task_state = async_result.state instance.save() diff --git a/geosafe/static/geosafe/css/impact_summary.css b/geosafe/static/geosafe/css/impact_summary.css new file mode 100644 index 00000000000..c948a6acd0d --- /dev/null +++ b/geosafe/static/geosafe/css/impact_summary.css @@ -0,0 +1,169 @@ +/* impact summary classes */ + +/* impact modal dialog */ +#impact-card-modal{ + color: #cacaca; +} +#impact-card-modal .modal-dialog{ + /*width: 460px;*/ +} +#impact-card-modal .modal-title{ + text-align: center; +} +#impact-card-modal .impact-icons{ + text-align: center; + background: #3c3c3c; + margin-left: -20px; + margin-right: -20px; + margin-top: -20px; + padding: 10px; +} +#impact-card-modal .impact-icons img{ + height: 20px; +} +#impact-card-modal .modal-footer{ + margin-top: 0px; + text-align: center; + border-top: 1px solid #606060; +} +#impact-card-modal .modal-header{ + border-bottom: 1px solid #606060; +} +#impact-card-modal .modal-content{ + background: #454545; +} +#impact-card-modal .modal-body{ + padding-bottom: 0px; +} +#impact-card-modal .btn{ + background: #6c6c6c; + color: #eeeeee; + border: none; + height: 30px; + padding-top: 5px; +} +#impact-card-modal .modal-header .btn{ + background: transparent; +} + +.save-analysis{ + vertical-align: middle; + display: inline-block; + margin-left: 5px; +} +.save-analysis .onoffswitch-label{ + margin-bottom: 0; +} +.save-analysis.processing .onoffswitch-inner, +.save-analysis.processing .onoffswitch-switch{ + display: none; +} +.save-analysis.processing{ + width: 130px; +} +.save-analysis.processing .processing-indicator{ + display: inline-block; + white-space: nowrap; + height: 30px; + padding-left: 10px; + padding-right: 10px; + padding-top: 5px; +} +.save-analysis .processing-indicator{ + display: none; +} +.save-analysis .onoffswitch-inner:before{ + content: "SAVE"; + padding: 0; +} +.save-analysis .onoffswitch-inner:after{ + content: "NOT"; + padding: 0; + text-align: center; +} + +/* impact statistics */ +.impact-summary { + margin-left: -20px; + margin-right: -20px; + border: 1px solid #606060; + border-bottom: none; + border-left: none; + border-right: none; + display: flex; +} +.summary{ + display: flex; + flex-direction: column; + border-right: 1px solid #606060; +} +.summary .highlight{ + margin-left: -15px; + padding: 15px; + border-bottom: 1px solid #606060; +} + +.summary .highlight:last-child{ + border-bottom: none; +} + +.summary .highlight div{ + padding-left: 0; + padding-right: 0; +} + +.summary .highlight .svg{ + width: 100%; + height: 100%; +} + +.summary .highlight .number{ + font-size: 30pt; +} + +.category-breakdown{ + padding: 15px; + display: flex; + flex-direction: column; +} +.category-breakdown .title{ + padding-bottom: 15px; +} +.breakdown{ + display: flex; + flex-direction: row; + border-top: 1px solid #606060; + padding-top: 5px; + padding-bottom: 5px; +} +.breakdown .value svg{ + fill: #606060; +} +.breakdown .value{ + padding-left: 0; + display: flex; + align-items: center; +} +.breakdown .category{ + padding-right: 0; +} + +/* impact level class */ +.hazard-category-high .category, .hazard-category-high .value{ + color: #fd7e71; +} +.hazard-category-high text, .hazard-category-high rect{ + fill: #fd7e71; +} +.hazard-category-medium .category, .hazard-category-medium .value{ + color: #fdb558; +} +.hazard-category-medium text, .hazard-category-medium rect{ + fill: #fdb558; +} +.hazard-category-low .category, .hazard-category-low .value{ + color: #63d46f; +} +.hazard-category-low text, .hazard-category-low rect{ + fill: #63d46f; +} diff --git a/geosafe/static/geosafe/img/land_cover.svg b/geosafe/static/geosafe/img/land_cover.svg new file mode 100644 index 00000000000..2f0ffda6ed7 --- /dev/null +++ b/geosafe/static/geosafe/img/land_cover.svg @@ -0,0 +1,15 @@ + + + + + + diff --git a/geosafe/static/geosafe/img/volcanic-ash.svg b/geosafe/static/geosafe/img/volcanic-ash.svg new file mode 100644 index 00000000000..34822fb7c71 --- /dev/null +++ b/geosafe/static/geosafe/img/volcanic-ash.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + diff --git a/geosafe/tasks/analysis.py b/geosafe/tasks/analysis.py index fb065740fb4..ac092a4334d 100644 --- a/geosafe/tasks/analysis.py +++ b/geosafe/tasks/analysis.py @@ -123,6 +123,8 @@ def process_impact_result(analysis_id, impact_url_result): for name in zf.namelist(): basename, ext = os.path.splitext(name) if ext in ['.shp', '.tif']: + # process this in the for loop to make sure it works only + # when we found the layer saved_layer = file_upload( os.path.join(dir_name, name), overwrite=True) @@ -150,6 +152,7 @@ def process_impact_result(analysis_id, impact_url_result): if os.path.exists(report_table_path): analysis.assign_report_table(report_table_path) + analysis.task_state = 'SUCCESS' analysis.save() if current_impact: diff --git a/geosafe/templates/geosafe/analysis/create.html b/geosafe/templates/geosafe/analysis/create.html index 2e70c9c889d..f2dd7071cbd 100644 --- a/geosafe/templates/geosafe/analysis/create.html +++ b/geosafe/templates/geosafe/analysis/create.html @@ -52,7 +52,7 @@ .options-panel .option:last-child { margin-bottom:0; } -.options-panel svg { +.options-panel svg, .options-panel i { position:absolute; top:0; bottom:0; @@ -142,6 +142,12 @@ .options-panel .list:hover { display: block; } +#impact-function.loading svg, #impact-function i { + display: none; +} +#impact-function.loading i, #impact-function svg { + display: block; +} .list-title { font-size: 14px; margin: 0; @@ -332,15 +338,23 @@ var last_click; $(".option>a").click(function () { {# special case when only contains one layer #} + var $list_box = $(this).next().filter(".list"); if($(this).hasClass('one')){ {# automatically click the only layer #} - $(this).next().filter(".list").find("a")[0].click(); + $list_box.find("a")[0].click(); return; } if(last_click!=this){ $(last_click).next().filter(".list").removeClass("show"); } - $(this).next().filter(".list").toggleClass("show"); + $list_box.toggleClass("show"); + + {# correcting position for impact #} + if($list_box.closest("#impact-option").length > 0){ + var box_height = $list_box.height(); + var pos_y = -box_height + 40; + $list_box.css("top", pos_y); + } last_click=this; }); var $analysis_form = $(".report.section form"); @@ -381,6 +395,10 @@ 'hazard_id': $("#id_hazard_layer").val() }; + {# create spinning animation #} + var if_function = $("#impact-function"); + if_function.addClass('loading'); + $.get('{% url 'geosafe:impact-function-filter' %}', chosen_combination, function (data) { console.log(data); var select = $("#id_impact_function_id"); @@ -388,7 +406,7 @@ select.empty(); ul.empty(); // clear styles - $("#impact-function").removeClass("set"); + if_function.removeClass("set").removeClass("loading"); $("#impact-function-list .selected").removeClass("selected"); if (data.length == 0) { console.log('No IF found') @@ -399,6 +417,11 @@ $li.append($a); $li.appendTo(ul); } + + if(data.length > 1){ + if_function.addClass("has-children"); + } + for (var i = 0; i < data.length; i++) { var id = data[i]['id']; var name = data[i]['name']; @@ -880,7 +903,7 @@ update_hazard_layer({{ analysis.hazard_layer_id }}); update_exposure_layer({{ analysis.exposure_layer_id }}); {# check if impact process is done #} - {% if analysis.get_task_result.successful %} + {% if analysis.get_task_state == 'SUCCESS' %} update_impact_layer({{ analysis.impact_layer_id }}); {% else %} {# impact not yet processed #} @@ -891,7 +914,7 @@ {% endif %} {% if analysis.get_task_result %} - {% if not analysis.get_task_result.successful and not analysis.get_task_result.failed %} + {% if not analysis.get_task_state == 'SUCCESS' and not analysis.get_task_state == 'FAILURE' %} {# Automatic check in 30 sec #} function check_analysis(){ var check_analysis_url = '{% url 'geosafe:check-analysis' analysis_id=analysis.id %}'; diff --git a/geosafe/templates/geosafe/analysis/list.html b/geosafe/templates/geosafe/analysis/list.html index 2fbf2403596..0b17d5a700a 100644 --- a/geosafe/templates/geosafe/analysis/list.html +++ b/geosafe/templates/geosafe/analysis/list.html @@ -119,10 +119,19 @@

List of Analysis

{% if not analysis.get_task_result %} Analysis not yet running - {% elif analysis.get_task_result.successful %} + {% elif analysis.get_task_state == 'SUCCESS' %} {{ analysis.impact_layer }} {% else %} - Task Status: {{ analysis.get_task_result.state }} +
Task Status: {{ analysis.get_task_state }}
+ {% if analysis.get_task_state == 'FAILURE' %} +
+
+ {% csrf_token %} + + +
+
+ {% endif %} {% endif %} diff --git a/geosafe/templates/geosafe/analysis/modal/impact_card.html b/geosafe/templates/geosafe/analysis/modal/impact_card.html index 2ae55678c12..d2886235a71 100644 --- a/geosafe/templates/geosafe/analysis/modal/impact_card.html +++ b/geosafe/templates/geosafe/analysis/modal/impact_card.html @@ -1,82 +1,8 @@ {% load bootstrap_tags %} {% load staticfiles %} - +