Skip to content

Commit

Permalink
Merge pull request #65 from wmo-raf/dev
Browse files Browse the repository at this point in the history
Updates and Bug Fixes
  • Loading branch information
erick-otenyo authored Jun 5, 2024
2 parents af1c620 + 16ce997 commit 5381938
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 92 deletions.
78 changes: 24 additions & 54 deletions capeditor/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,18 @@ class AlertResponseType(blocks.StructBlock):
"target audience"))


class AlertAreaGeocodeBlock(blocks.StructBlock):
valueName = blocks.TextBlock(label=_("Value Name"),
help_text=_(
"User-assigned string designating the domain of the code. Acronyms SHOULD be "
"represented in all capital letters without periods (e.g., SAME, FIPS, ZIP"))
value = blocks.TextBlock(label=_("Value"),
help_text=_("A string (which may represent a number) denoting the value itself"))

class Meta:
help_text = _("Geographically-based code to describe a message target area")


class AlertAreaPolygonStructValue(StructValue):
@cached_property
def area(self):
Expand Down Expand Up @@ -213,6 +225,7 @@ class Meta:
ceiling = blocks.CharBlock(max_length=100, required=False, label=_("Ceiling"),
help_text=_("The maximum altitude of the affected area of the alert message."
"MUST NOT be used except in combination with the altitude element. "))
geocode = blocks.ListBlock(AlertAreaGeocodeBlock(required=False, label=_("Geocode")), default=[])


class AlertAreaCircleStructValue(StructValue):
Expand Down Expand Up @@ -265,13 +278,13 @@ class Meta:
areaDesc = blocks.TextBlock(label=_("Affected areas / Regions"),
help_text=_("The text describing the affected area of the alert message"))
circle = CircleFieldBlock(label=_("Circle"), help_text=_("Drag the marker to change position"))

altitude = blocks.CharBlock(max_length=100, required=False, label=_("Altitude"),
help_text=_("The specific or minimum altitude of the affected "
"area of the alert message"))
ceiling = blocks.CharBlock(max_length=100, required=False, label=_("Ceiling"),
help_text=_("The maximum altitude of the affected area of the alert message."
"MUST NOT be used except in combination with the altitude element. "))
geocode = blocks.ListBlock(AlertAreaGeocodeBlock(required=False, label=_("Geocode")), default=[])


class AlertAreaPredefinedStructValue(StructValue):
Expand Down Expand Up @@ -320,48 +333,11 @@ class Meta:
ceiling = blocks.CharBlock(max_length=100, required=False, label=_("Ceiling"),
help_text=_("The maximum altitude of the affected area of the alert message."
"MUST NOT be used except in combination with the altitude element. "))


class AlertAreaGeocodeStructValue(StructValue):
@cached_property
def area(self):
area_data = {
"areaDesc": self.get("areaDesc"),
"geocode": {"valueName": self.get("valueName"), "value": self.get("value")},
}

if self.get("altitude"):
area_data.update({"altitude": self.get("altitude")})
if self.get("ceiling"):
area_data.update({"ceiling": self.get("ceiling")})

return area_data

@cached_property
def geojson(self):
return {}


class AlertAreaGeocodeBlock(blocks.StructBlock):
class Meta:
value_class = AlertAreaGeocodeStructValue

areaDesc = blocks.TextBlock(label=_("Affected areas / Regions"),
help_text=_("The text describing the affected area of the alert message"))
valueName = blocks.TextBlock(label=_("Name"))
value = blocks.TextBlock(label=_("Value"))

altitude = blocks.CharBlock(max_length=100, required=False, label=_("Altitude"),
help_text=_("The specific or minimum altitude of the affected "
"area of the alert message"))
ceiling = blocks.CharBlock(max_length=100, required=False, label=_("Ceiling"),
help_text=_("The maximum altitude of the affected area of the alert message."
"MUST NOT be used except in combination with the altitude element. "))
geocode = blocks.ListBlock(AlertAreaGeocodeBlock(required=False, label=_("Geocode")), default=[])


SENDER_NAME_HELP_TEXT = _("The human-readable name of the agency or authority issuing this alert.")
CONTACT_HELP_TEXT = _("The text describing the contact for follow-up and confirmation of the alert message")
AUDIENCE_HELP_TEXT = _("The text describing the intended audience of the alert message")


class FileResourceStructValue(StructValue):
Expand Down Expand Up @@ -550,32 +526,31 @@ class AlertInfo(blocks.StructBlock):
('Expected', _("Expected - Responsive action SHOULD be taken soon (within next hour)")),
('Future', _("Future - Responsive action SHOULD be taken in the near future")),
('Past', _("Past - Responsive action is no longer required")),
('Unknown', _("Unknown - Urgency not known")),
# ('Unknown', _("Unknown - Urgency not known")), Not recommended
)

SEVERITY_CHOICES = (
('Extreme', _("Extreme - Extraordinary threat to life or property")),
('Severe', _("Severe - Significant threat to life or property")),
('Moderate', _("Moderate - Possible threat to life or property")),
('Minor', _("Minor - Minimal to no known threat to life or property")),
('Unknown', _("Unknown - Severity unknown")),
# ('Unknown', _("Unknown - Severity unknown")), Not recommended
)

CERTAINTY_CHOICES = (
('Observed', _("Observed - Determined to have occurred or to be ongoing")),
('Likely', _("Likely - Likely (percentage > ~50%)")),
('Possible', _("Possible - Possible but not likely (percentage <= ~50%)")),
('Unlikely', _("Unlikely - Not expected to occur (percentage ~ 0)")),
('Unknown', _("Unknown - Certainty unknown")),
# ('Unknown', _("Unknown - Certainty unknown")), Not recommended
)
event = blocks.ChoiceBlock(choices=get_hazard_types, label=_("Event"),
help_text=_("The text denoting the type of the subject event of the alert message. You "
"can define hazards events monitored by your institution from CAP settings"))

category = blocks.MultipleChoiceBlock(choices=CATEGORY_CHOICES, default="Met", label=_("Category"),
help_text=_("The code denoting the category of the subject"
" event of the alert message"),
widget=forms.CheckboxSelectMultiple)
category = blocks.ChoiceBlock(choices=CATEGORY_CHOICES, default="Met", label=_("Category"),
help_text=_("The code denoting the category of the subject"
" event of the alert message"))
language = blocks.ChoiceBlock(choices=LANGUAGE_CHOICES, default="en", required=False, label=_("Language"),
help_text=_("The code denoting the language of the alert message"), )

Expand Down Expand Up @@ -613,14 +588,13 @@ class AlertInfo(blocks.StructBlock):
senderName = blocks.CharBlock(max_length=255, label=_("Sender name"), required=False,
help_text=SENDER_NAME_HELP_TEXT)
contact = blocks.CharBlock(max_length=255, required=False, label=_("Contact"), help_text=CONTACT_HELP_TEXT)
audience = blocks.CharBlock(max_length=255, required=False, label=_("Audience"),
help_text=AUDIENCE_HELP_TEXT)
audience = blocks.TextBlock(required=False, label=_("Audience"),
help_text=_("The text describing the intended audience of the alert message"))
area = blocks.StreamBlock([
("polygon_block", AlertAreaPolygonBlock(label=_("Draw Polygon"))),
("circle_block", AlertAreaCircleBlock(label=_("Circle"))),
("geocode_block", AlertAreaGeocodeBlock(label=_("Geocode"))),
("predefined_block", AlertAreaPredefined(label=_("Predefined Area"))),
], label=_("Alert Area"), help_text=_("Polygon, Circle, Predefined area or Geocode"))
], label=_("Alert Area"), help_text=_("Polygon, Circle, or Predefined area"))

resource = blocks.StreamBlock([
("file_resource", FileResource()),
Expand Down Expand Up @@ -657,9 +631,5 @@ def clean(self, value):
return result


class AudienceTypeBlock(blocks.StructBlock):
audience = blocks.CharBlock(max_length=255, label=_("Audience"), help_text=_("Intended audience"))


class ContactBlock(blocks.StructBlock):
contact = blocks.CharBlock(max_length=255, label=_("Contact Detail"))
11 changes: 1 addition & 10 deletions capeditor/cap_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from wagtailmodelchooser import register_model_chooser

from capeditor.blocks import (
AudienceTypeBlock,
ContactBlock
)
from capeditor.forms.widgets import HazardEventTypeWidget, PolygonDrawWidget
Expand All @@ -39,11 +38,6 @@ class CapSetting(BaseSiteSetting, ClusterableModel):
], use_json_field=True, blank=True, null=True, verbose_name=_("Contact Details"),
help_text=_("Contact for follow-up and confirmation of the alert message"))

audience_types = StreamField([
("audience_type", AudienceTypeBlock(label=_("Audience Type")))
], use_json_field=True, blank=True, null=True, verbose_name=_("Audience Types"),
help_text=_("Target audiences for published alerts"))

class Meta:
verbose_name = _("CAP Settings")

Expand All @@ -59,9 +53,6 @@ class Meta:
InlinePanel("hazard_event_types", heading=_("Hazard Types"), label=_("Hazard Type"),
help_text=_("Hazards monitored by the institution")),
], heading=_("Hazard Types")),
ObjectList([
FieldPanel("audience_types"),
], heading=_("Audience Types")),
ObjectList([
InlinePanel("predefined_alert_areas", heading=_("Predefined Alert Areas"), label=_("Area"),
help_text=_("Predefined areas for alerts")),
Expand Down Expand Up @@ -91,7 +82,7 @@ class HazardEventTypes(Orderable):
setting = ParentalKey(CapSetting, on_delete=models.PROTECT, related_name="hazard_event_types")
is_in_wmo_event_types_list = models.BooleanField(default=True,
verbose_name=_("Select from WMO list of Hazards Event Types"))
event = models.CharField(max_length=255, unique=True, verbose_name=_("Hazard"), help_text=_("Name of Hazard"))
event = models.CharField(max_length=35, unique=True, verbose_name=_("Hazard"), help_text=_("Name of Hazard"))
icon = models.CharField(max_length=255, null=True, blank=True, verbose_name=_("Icon"), help_text=_("Matching icon"))

panels = [
Expand Down
23 changes: 23 additions & 0 deletions capeditor/migrations/0007_alter_capsetting_wmo_oid_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.11 on 2024-06-03 11:47

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('capeditor', '0006_capsetting_wmo_oid'),
]

operations = [
migrations.AlterField(
model_name='capsetting',
name='wmo_oid',
field=models.CharField(blank=True, help_text='WMO Register of Alerting Authorities Object Identifier (OID) of the sending institution. This will be used to generate CAP messages identifiers', max_length=255, null=True, verbose_name='WMO Register of Alerting Authorities OID'),
),
migrations.AlterField(
model_name='hazardeventtypes',
name='event',
field=models.CharField(help_text='Name of Hazard', max_length=35, unique=True, verbose_name='Hazard'),
),
]
17 changes: 17 additions & 0 deletions capeditor/migrations/0008_remove_capsetting_audience_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.7 on 2024-06-03 12:04

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('capeditor', '0007_alter_capsetting_wmo_oid_and_more'),
]

operations = [
migrations.RemoveField(
model_name='capsetting',
name='audience_types',
),
]
34 changes: 8 additions & 26 deletions capeditor/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
AlertInfo,
SENDER_NAME_HELP_TEXT,
CONTACT_HELP_TEXT,
AUDIENCE_HELP_TEXT,
AlertAddress,
AlertReference,
AlertIncident
Expand All @@ -34,7 +33,6 @@ def __init__(self, *args, **kwargs):
if cap_setting:
default_sender_name = cap_setting.sender_name
contacts = cap_setting.contacts
audience_types = cap_setting.audience_types

if default_sender_name:
info_field = self.fields.get("info")
Expand Down Expand Up @@ -71,25 +69,6 @@ def __init__(self, *args, **kwargs):
info_field.block.child_blocks[block_type].child_blocks[field_name].name = name
info_field.block.child_blocks[block_type].child_blocks[field_name].label = label

if audience_types:
audience_type_choices = []

for block in audience_types:
audience = block.value.get("audience")
audience_type_choices.append((audience, audience))

info_field = self.fields.get("info")
for block_type, block in info_field.block.child_blocks.items():
if block_type == "alert_info":
field_name = "audience"
audience_block = info_field.block.child_blocks[block_type].child_blocks[field_name]
label = audience_block.label or field_name
name = audience_block.name
info_field.block.child_blocks[block_type].child_blocks[field_name] = blocks.ChoiceBlock(
choices=audience_type_choices, required=False, help_text=AUDIENCE_HELP_TEXT)
info_field.block.child_blocks[block_type].child_blocks[field_name].name = name
info_field.block.child_blocks[block_type].child_blocks[field_name].label = label

def clean(self):
cleaned_data = super().clean()

Expand Down Expand Up @@ -129,17 +108,20 @@ class AbstractCapAlertPage(Page):
("Test", _("Test - Technical testing only, all recipients disregard")),
("Exercise", _("Exercise - Actionable only by designated exercise participants; "
"exercise identifier SHOULD appear in note")),
("system", _("System - For messages that support alert network internal functions")),
("System", _("System - For messages that support alert network internal functions")),
)

MESSAGE_TYPE_CHOICES = (
('Alert', _("Alert - Initial information requiring attention by targeted recipients")),
('Update', _("Update - Updates and supersedes the earlier message(s) identified in referenced alerts")),
('Cancel', _("Cancel - Cancels the earlier message(s) identified in references")),
('Ack', _("Acknowledge - Acknowledges receipt and acceptance of the message(s) "
"identified in references field")),
('Error', _("Error - Indicates rejection of the message(s) identified in references; "
"explanation SHOULD appear in note field")),

# Ack and Error are not applicable for this CAP tool implementation

# ('Ack', _("Acknowledge - Acknowledges receipt and acceptance of the message(s) "
# "identified in references field")),
# ('Error', _("Error - Indicates rejection of the message(s) identified in references; "
# "explanation SHOULD appear in note field")),
)

SCOPE_CHOICES = (
Expand Down
3 changes: 2 additions & 1 deletion capeditor/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytz
from dateutil.parser import isoparse
from rest_framework import serializers
from wagtail.api.v2.utils import get_full_url

from capeditor.constants import CAP_MESSAGE_ORDER_SEQUENCE
from capeditor.utils import order_dict_by_keys
Expand Down Expand Up @@ -62,7 +63,7 @@ def get_info(self, obj):
resources = []
for resource in info.value.resource:
if resource.get("type") == "doc":
resource["uri"] = request.build_absolute_uri(resource.get("uri"))
resource["uri"] = get_full_url(request, resource.get("uri"))
resource.pop("type")
# order resource according to CAP_MESSAGE_ORDER_SEQUENCE
resource_obj = order_dict_by_keys(resource, CAP_MESSAGE_ORDER_SEQUENCE.get("resource"))
Expand Down
17 changes: 17 additions & 0 deletions sandbox/home/migrations/0024_auto_20240603_1327.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.11 on 2024-06-03 10:27

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
('home', '0023_alter_capalertpage_info'),
]

operations = [
migrations.RenameField(
model_name='capalertpage',
old_name='identifier',
new_name='guid'
)
]
Loading

0 comments on commit 5381938

Please sign in to comment.