diff --git a/src/angular/planit/src/app/assessment/assessment-overview.component.ts b/src/angular/planit/src/app/assessment/assessment-overview.component.ts
index 4315e8c68..46e7c8e15 100644
--- a/src/angular/planit/src/app/assessment/assessment-overview.component.ts
+++ b/src/angular/planit/src/app/assessment/assessment-overview.component.ts
@@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { Risk } from '../shared';
+import { RiskService } from '../core/services/risk.service';
@Component({
selector: 'va-overview',
@@ -9,54 +10,13 @@ import { Risk } from '../shared';
export class AssessmentOverviewComponent implements OnInit {
public risks: Risk[];
- constructor () {}
+ constructor (private riskService: RiskService) {}
ngOnInit() {
- this.risks = [{
- name: 'Heat on the elderly',
- hazard: 'heat',
- communitySystem: 'elderly',
- potentialImpact: 0,
- adaptiveCapacity: 2,
- indicators: [
- {name: 'Extreme Heat Events', url: '#'},
- {name: 'Heat Wave Incidents', url: '#'},
- {name: 'Heat Wave Duration Index', url: '#'}
- ]
- }, {
- name: 'Heat on asphalt',
- hazard: 'heat',
- communitySystem: 'asphalt',
- potentialImpact: 1,
- adaptiveCapacity: 1,
- indicators: [
- {name: 'Cooling Degree Days', url: '#'},
- {name: 'Heat Wave Incidents', url: '#'},
- {name: 'Heat Wave Duration Index', url: '#'}
- ]
- }, {
- name: 'Extreme cold days on agriculture',
- hazard: 'extreme_cold',
- communitySystem: 'agriculture',
- potentialImpact: 2,
- adaptiveCapacity: 0,
- indicators: [
- {name: 'Accumulated Freezing Degree Days', url: '#'},
- {name: 'Extreme Cold Events', url: '#'},
- {name: 'Frost Days', url: '#'},
- ]
- },
- {
- name: 'Water-bourne disease on ecological function',
- hazard: 'water_bourne_disease',
- communitySystem: 'ecological_function',
- potentialImpact: 2,
- adaptiveCapacity: 2,
- indicators: [
- {name: 'Total Precipitation', url: '#'},
- {name: 'Precipitation Threshold', url: '#'},
- {name: 'Extreme Precipitation Events', url: '#'},
- ]
- }];
+
+ this.riskService.list().subscribe(risks => {
+ this.risks = risks;
+ });
}
}
+
diff --git a/src/angular/planit/src/app/assessment/risk-popover/risk-popover.component.html b/src/angular/planit/src/app/assessment/risk-popover/risk-popover.component.html
index af407ee03..938990113 100644
--- a/src/angular/planit/src/app/assessment/risk-popover/risk-popover.component.html
+++ b/src/angular/planit/src/app/assessment/risk-popover/risk-popover.component.html
@@ -2,14 +2,14 @@
Donec dictum hendrerit dui, nec dictum ante molestie eleifend. Quisque accumsan nisl lectus, in vulputate erat iaculis quis. Aenean at nisl vehicula, fermentum leo vel, ultricies sapien.
Related Indicators
-
- {{ indicator.name }}
+
+ {{ indicator }}
{{ risk.name }}
+ popoverTitle="{{ risk.weatherEvent.name }} on {{ risk.communitySystem.name }}"
+ placement="right">{{ risk.weatherEvent.name }} on {{ risk.communitySystem.name }}
diff --git a/src/angular/planit/src/app/core/services/risk.service.ts b/src/angular/planit/src/app/core/services/risk.service.ts
new file mode 100644
index 000000000..4799ad05c
--- /dev/null
+++ b/src/angular/planit/src/app/core/services/risk.service.ts
@@ -0,0 +1,22 @@
+import { Injectable } from '@angular/core';
+
+import { Observable } from 'rxjs/Rx';
+
+import { Risk } from '../../shared/models/risk.model';
+import { PlanItApiHttp } from './api-http.service';
+import { environment } from '../../../environments/environment';
+
+@Injectable()
+export class RiskService {
+
+ constructor(private apiHttp: PlanItApiHttp) {}
+
+ list(): Observable
{
+ const url = `${environment.apiUrl}/api/risks/`;
+ return this.apiHttp.get(url).map(resp => {
+ const vals = resp.json() || [];
+ return vals.map(r => r as Risk);
+ });
+ }
+
+}
diff --git a/src/angular/planit/src/app/risk-wizard/steps/identify-step.component.ts b/src/angular/planit/src/app/risk-wizard/steps/identify-step.component.ts
index bceece4d3..738851186 100644
--- a/src/angular/planit/src/app/risk-wizard/steps/identify-step.component.ts
+++ b/src/angular/planit/src/app/risk-wizard/steps/identify-step.component.ts
@@ -39,8 +39,8 @@ export class IdentifyStepComponent extends WizardStepComponent implements
fromData(risk: Risk): IdentifyStepFormModel {
return {
- hazard: risk.hazard,
- communitySystem: risk.communitySystem
+ hazard: risk.impactDescription,
+ communitySystem: risk.communitySystem.name
};
}
@@ -60,8 +60,8 @@ export class IdentifyStepComponent extends WizardStepComponent implements
}
toData(data: IdentifyStepFormModel, risk: Risk) {
- risk.hazard = data.hazard;
- risk.communitySystem = data.communitySystem;
+ risk.impactDescription = data.hazard;
+ risk.communitySystem.name = data.communitySystem;
return risk;
}
}
diff --git a/src/angular/planit/src/app/shared/index.ts b/src/angular/planit/src/app/shared/index.ts
index 984592251..44c395d74 100644
--- a/src/angular/planit/src/app/shared/index.ts
+++ b/src/angular/planit/src/app/shared/index.ts
@@ -1,3 +1,4 @@
+export { CommunitySystem } from './models/community-system.model';
export { Concern } from './models/concern.model';
export { Risk } from './models/risk.model';
export { User } from './models/user.model';
diff --git a/src/angular/planit/src/app/shared/models/community-system.model.ts b/src/angular/planit/src/app/shared/models/community-system.model.ts
new file mode 100644
index 000000000..46ea888d7
--- /dev/null
+++ b/src/angular/planit/src/app/shared/models/community-system.model.ts
@@ -0,0 +1,3 @@
+export class CommunitySystem {
+ name: string;
+}
diff --git a/src/angular/planit/src/app/shared/models/concern.model.ts b/src/angular/planit/src/app/shared/models/concern.model.ts
index 0d88a038b..c661fc0ef 100644
--- a/src/angular/planit/src/app/shared/models/concern.model.ts
+++ b/src/angular/planit/src/app/shared/models/concern.model.ts
@@ -1,4 +1,5 @@
export class Concern {
+ id: number;
indicator: string;
isRelative: boolean;
tagline: string;
diff --git a/src/angular/planit/src/app/shared/models/risk.model.ts b/src/angular/planit/src/app/shared/models/risk.model.ts
index 4dcedb003..bee67d2c3 100644
--- a/src/angular/planit/src/app/shared/models/risk.model.ts
+++ b/src/angular/planit/src/app/shared/models/risk.model.ts
@@ -1,10 +1,19 @@
+import { CommunitySystem } from './community-system.model';
+import { WeatherEvent } from './weather-event.model';
+import { Indicator } from 'climate-change-components';
+
export class Risk {
- name: string;
- communitySystem: string;
- hazard: string;
- potentialImpact?: number;
- adaptiveCapacity?: number;
- indicators: [{name: string, url: string}];
+ id?: string;
+ weatherEvent: WeatherEvent;
+ communitySystem: CommunitySystem;
+ probability?: string;
+ frequency?: string;
+ intensity?: string;
+ impactMagnitude?: string;
+ impactDescription?: string;
+ adaptiveCapacity?: string;
+ relatedAdaptiveValues?: string[];
+ adaptiveCapacityDescription?: string;
constructor(object: Object) {
Object.assign(this, object);
diff --git a/src/angular/planit/src/app/shared/models/weather-event.model.ts b/src/angular/planit/src/app/shared/models/weather-event.model.ts
index 50fa34551..c950c935e 100644
--- a/src/angular/planit/src/app/shared/models/weather-event.model.ts
+++ b/src/angular/planit/src/app/shared/models/weather-event.model.ts
@@ -3,6 +3,7 @@ import { Indicator } from 'climate-change-components';
export class WeatherEvent {
name: string;
+ coastalOnly: boolean;
concern?: Concern;
indicators?: string[];
displayClass: string;
diff --git a/src/django/planit/urls.py b/src/django/planit/urls.py
index 2ecfaab9d..10d5b4246 100644
--- a/src/django/planit/urls.py
+++ b/src/django/planit/urls.py
@@ -22,14 +22,14 @@
from climate_api.views import ClimateAPIProxyView
import planit_data.views as planit_data_views
-import action_steps.views as action_steps_views
from users.views import CurrentUserView, PlanitObtainAuthToken, OrganizationViewSet, UserViewSet
router = routers.DefaultRouter()
+router.register(r'community-system', planit_data_views.CommunitySystemViewSet)
router.register(r'organizations', OrganizationViewSet)
router.register(r'users', UserViewSet)
router.register(r'risks', planit_data_views.OrganizationRiskView, base_name='organizationrisk')
-router.register(r'collaborators', action_steps_views.CollaboratorViewSet)
+router.register(r'weather-event', planit_data_views.WeatherEventViewSet)
urlpatterns = [
url(r'^api/climate-api/(?P.*)$',
diff --git a/src/django/planit_data/serializers.py b/src/django/planit_data/serializers.py
index aea0225fa..80707b4d8 100644
--- a/src/django/planit_data/serializers.py
+++ b/src/django/planit_data/serializers.py
@@ -9,8 +9,15 @@
)
-class ConcernSerializer(serializers.ModelSerializer):
+class CommunitySystemSerializer(serializers.ModelSerializer):
+ """Serialize community systems."""
+ class Meta:
+ model = CommunitySystem
+ fields = ('name',)
+
+class ConcernSerializer(serializers.ModelSerializer):
+ """Serialize concerns."""
indicator = serializers.SlugRelatedField(
many=False,
read_only=True,
@@ -35,17 +42,30 @@ class Meta:
fields = ('id', 'indicator', 'isRelative',)
-class OrganizationRiskSerializer(serializers.ModelSerializer):
- weatherEvent = serializers.PrimaryKeyRelatedField(
- many=False,
- queryset=WeatherEvent.objects.all(),
- source='weather_event'
- )
- communitySystem = serializers.PrimaryKeyRelatedField(
+class WeatherEventSerializer(serializers.ModelSerializer):
+ """Serialize weather events with only keys for related fields."""
+ concern = serializers.PrimaryKeyRelatedField(
many=False,
- queryset=CommunitySystem.objects.all(),
- source='community_system'
+ queryset=Concern.objects.all()
)
+ coastalOnly = serializers.BooleanField(source='coastal_only')
+ indicators = serializers.SlugRelatedField(many=True, read_only=True, slug_field='name')
+ displayClass = serializers.CharField(source='display_class')
+
+ class Meta:
+ model = WeatherEvent
+ fields = ('name', 'coastalOnly', 'concern', 'indicators', 'displayClass')
+
+
+class WeatherEventWithConcernSerializer(WeatherEventSerializer):
+ """Serialize weather events, with related concerns."""
+ concern = ConcernSerializer()
+
+
+class OrganizationRiskSerializer(serializers.ModelSerializer):
+ """Serialize organization risks for viewing, with related models."""
+ weatherEvent = WeatherEventSerializer(source='weather_event')
+ communitySystem = CommunitySystemSerializer(source='community_system')
impactMagnitude = serializers.ChoiceField(source='impact_magnitude',
required=False, allow_blank=True,
@@ -61,6 +81,29 @@ class OrganizationRiskSerializer(serializers.ModelSerializer):
adaptiveCapacityDescription = serializers.CharField(source='adaptive_capacity_description',
required=False, allow_blank=True)
+ class Meta:
+ model = OrganizationRisk
+ fields = ('id', 'weatherEvent', 'communitySystem', 'probability', 'frequency',
+ 'intensity', 'impactMagnitude', 'impactDescription', 'adaptiveCapacity',
+ 'relatedAdaptiveValues', 'adaptiveCapacityDescription')
+
+
+class OrganizationRiskCreateSerializer(OrganizationRiskSerializer):
+ """Serializer for creating and updating risks.
+
+ Takes ID for related weather event and community system.
+ """
+ weatherEvent = serializers.PrimaryKeyRelatedField(
+ many=False,
+ queryset=WeatherEvent.objects.all(),
+ source='weather_event'
+ )
+ communitySystem = serializers.PrimaryKeyRelatedField(
+ many=False,
+ queryset=CommunitySystem.objects.all(),
+ source='community_system'
+ )
+
def create(self, validated_data):
# Pulling the organization from the request instead of as a serialized field
# ensures that users can't modify a different organization's risks
@@ -72,28 +115,10 @@ def create(self, validated_data):
return OrganizationRisk.objects.create(organization=organization, **validated_data)
- class Meta:
- model = OrganizationRisk
- fields = ('id', 'weatherEvent', 'communitySystem', 'probability', 'frequency',
- 'intensity', 'impactMagnitude', 'impactDescription', 'adaptiveCapacity',
- 'relatedAdaptiveValues', 'adaptiveCapacityDescription')
-
-
-class WeatherEventSerializer(serializers.ModelSerializer):
-
- concern = ConcernSerializer()
- coastalOnly = serializers.BooleanField(source='coastal_only')
- indicators = serializers.SlugRelatedField(many=True, read_only=True, slug_field='name')
- displayClass = serializers.CharField(source='display_class')
-
- class Meta:
- model = WeatherEvent
- fields = ('name', 'coastalOnly', 'concern', 'indicators', 'displayClass')
-
class WeatherEventRankSerializer(serializers.ModelSerializer):
-
- weatherEvent = WeatherEventSerializer(source='weather_event')
+ """Serialize weather events by rank."""
+ weatherEvent = WeatherEventWithConcernSerializer(source='weather_event')
class Meta:
model = WeatherEventRank
diff --git a/src/django/planit_data/tests/test_serializers.py b/src/django/planit_data/tests/test_serializers.py
index 187d6c68c..22d03e76b 100644
--- a/src/django/planit_data/tests/test_serializers.py
+++ b/src/django/planit_data/tests/test_serializers.py
@@ -4,7 +4,11 @@
from rest_framework.test import APIRequestFactory
from planit_data.models import CommunitySystem, Concern, Indicator, WeatherEvent
-from planit_data.serializers import ConcernSerializer, OrganizationRiskSerializer
+from planit_data.serializers import (
+ ConcernSerializer,
+ OrganizationRiskCreateSerializer,
+)
+
from users.models import PlanItLocation, PlanItOrganization, PlanItUser
@@ -70,7 +74,7 @@ def test_context_request_can_be_set_afterwards(self, calculate_mock):
serializer.data
-class OrganizationRiskSerializerTestCase(TestCase):
+class OrganizationRiskCreateSerializerTestCase(TestCase):
def setUp(self):
self.user = PlanItUser.objects.create_user('mike@mike.phl', 'Mike', 'M',
password='mike12345')
@@ -89,17 +93,19 @@ def setUp(self):
def test_create_context_requires_request(self):
"""Ensure the Serializer raises an error if the context does not have a request"""
- serializer = OrganizationRiskSerializer(data={'weatherEvent': self.weather_event.id,
+ serializer = OrganizationRiskCreateSerializer(data={'weatherEvent': self.weather_event.id,
'communitySystem': self.community_system.id})
- serializer.is_valid()
+ if not serializer.is_valid():
+ print(serializer.errors)
with self.assertRaises(ValueError):
serializer.save()
def test_create_context_works_with_request(self):
"""Ensure the Serializer works if the context does have a request"""
- serializer = OrganizationRiskSerializer(data={'weatherEvent': self.weather_event.id,
+ serializer = OrganizationRiskCreateSerializer(data={'weatherEvent': self.weather_event.id,
'communitySystem': self.community_system.id},
- context={'request': self.request})
- serializer.is_valid()
+ context={'request': self.request})
+ if not serializer.is_valid():
+ print(serializer.errors)
# No exception
serializer.save()
diff --git a/src/django/planit_data/views.py b/src/django/planit_data/views.py
index 2e4babf9b..30b59ea81 100644
--- a/src/django/planit_data/views.py
+++ b/src/django/planit_data/views.py
@@ -4,11 +4,21 @@
from rest_framework.views import APIView
from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet
-from planit_data.models import Concern, OrganizationRisk, WeatherEventRank
+from planit_data.models import (
+ CommunitySystem,
+ Concern,
+ OrganizationRisk,
+ WeatherEvent,
+ WeatherEventRank,
+)
+
from planit_data.serializers import (
ConcernSerializer,
+ CommunitySystemSerializer,
+ OrganizationRiskCreateSerializer,
OrganizationRiskSerializer,
WeatherEventRankSerializer,
+ WeatherEventSerializer,
)
@@ -18,17 +28,35 @@ class ConcernViewSet(ReadOnlyModelViewSet):
permission_classes = [IsAuthenticated]
+class CommunitySystemViewSet(ReadOnlyModelViewSet):
+ queryset = CommunitySystem.objects.all()
+ serializer_class = CommunitySystemSerializer
+ permission_classes = [IsAuthenticated]
+ pagination_class = None
+
+
class OrganizationRiskView(ModelViewSet):
model_class = OrganizationRisk
permission_classes = [IsAuthenticated]
- serializer_class = OrganizationRiskSerializer
pagination_class = None
+ def get_serializer_class(self):
+ if self.action == 'update' or self.action == 'create' or self.action == 'partial_update':
+ return OrganizationRiskCreateSerializer
+ return OrganizationRiskSerializer
+
def get_queryset(self):
org_id = self.request.user.primary_organization_id
return OrganizationRisk.objects.filter(organization_id=org_id)
+class WeatherEventViewSet(ReadOnlyModelViewSet):
+ queryset = WeatherEvent.objects.all()
+ permission_classes = [IsAuthenticated]
+ serializer_class = WeatherEventSerializer
+ pagination_class = None
+
+
class WeatherEventRankView(APIView):
model_class = WeatherEventRank