2017-09-16 18:55:19 +02:00
# -*- coding: utf-8 -*-
import json
import os
from collections import OrderedDict
from gluon import current
from gluon . html import *
from gluon . storage import Storage
from gluon . languages import lazyT
from s3 import FS , s3_str , s3_truncate , s3_utc
def config ( settings ) :
"""
Template settings for CAP : Common Alerting Protocol
"""
T = current . T
2019-12-20 17:53:39 +01:00
## Deprecated because such edits to the title should happen in the 000_config.py file
## specific to the demo deployment and not here because if you change here it affect any
## developments and commits to git etc - nuwan at sahanafoundation dot org
#settings.base.system_name = T("Sahana Alerting and Messaging Broker")
#settings.base.system_name_short = T("SAMBRO")
##
2017-09-16 18:55:19 +02:00
# Pre-Populate
2020-04-14 13:55:43 +02:00
settings . base . prepopulate . append ( " SAMBRO " )
2019-12-20 17:53:39 +01:00
settings . base . prepopulate_demo + = ( " SAMBRO/Demo " , )
2017-09-16 18:55:19 +02:00
# Theme (folder to use for views/layout.html)
#settings.base.theme = "SAMBRO"
# The Registration functionality shouldn't be visible to the Public
#settings.security.registration_visible = True
settings . auth . registration_requires_approval = True
# Link Users to Organisations
settings . auth . registration_requests_organisation = True
# GeoNames username
2017-09-30 22:57:10 +02:00
settings . gis . geonames_username = " trendspotter "
2018-02-12 13:28:43 +01:00
settings . gis . simplify_tolerance = 0
2017-09-16 18:55:19 +02:00
# =========================================================================
# System Settings
# -------------------------------------------------------------------------
# Security Policy
# http://eden.sahanafoundation.org/wiki/S3/S3AAA#System-widePolicy
# 1: Simple (default): Global as Reader, Authenticated as Editor
# 2: Editor role required for Update/Delete, unless record owned by session
# 3: Apply Controller ACLs
# 4: Apply both Controller & Function ACLs
# 5: Apply Controller, Function & Table ACLs
# 6: Apply Controller, Function, Table ACLs and Entity Realm
# 7: Apply Controller, Function, Table ACLs and Entity Realm + Hierarchy
# 8: Apply Controller, Function, Table ACLs, Entity Realm + Hierarchy and Delegations
settings . security . policy = 4 # Controller-Function ACLs
# Record Approval
settings . auth . record_approval = True
# cap_alert record requires approval before sending
settings . auth . record_approval_required_for = ( " cap_alert " , )
# Don't auto-approve so that can save draft
settings . auth . record_approval_manual = ( " cap_alert " , )
# =========================================================================
# Module Settings
# -------------------------------------------------------------------------
# CAP Settings
# Uncomment this according to country profile
#settings.cap.restrict_fields = True
# -------------------------------------------------------------------------
# Notifications
# Template for the subject line in update notifications
#settings.msg.notify_subject = "%s $s %s" % (T("SAHANA"), T("Alert Notification"))
# Notifications format
settings . msg . notify_email_format = " html "
# Filename for FTP
# Characters not allowed are [\ / : * ? " < > | % .]
# https://en.wikipedia.org/wiki/Filename
# http://docs.attachmate.com/reflection/ftp/15.6/guide/en/index.htm?toc.htm?6503.htm
settings . sync . upload_filename = " $s- %s " % ( " recent_alert " )
# Whether to tweet alerts
settings . cap . post_to_twitter = True
# Whether to post alerts in facebook?
settings . cap . post_to_facebook = True
# ALlow RSS to use links of entry if link fails
settings . cap . rss_use_links = True
# SAMBRO supports ack workflow
settings . cap . use_ack = True
# -------------------------------------------------------------------------
# L10n (Localization) settings
languages = OrderedDict ( [
2018-03-14 21:25:20 +01:00
( " cs " , " Czech " ) ,
2017-09-16 18:55:19 +02:00
( " en-US " , " English " ) ,
] )
settings . cap . languages = languages
settings . L10n . languages = languages
# Translate the cap_area name
settings . L10n . translate_cap_area = True
# Date Format
#settings.L10n.date_format = "%a, %d %B %Y"
# Time Format
settings . L10n . time_format = " % H: % M: % S "
2017-09-18 22:29:17 +02:00
# PDF font
2019-04-13 20:49:19 +02:00
settings . L10n . pdf_export_font = [ ' Helvetica ' , ' Helvetica-Bold ' ]
2017-09-18 22:29:17 +02:00
2017-09-16 18:55:19 +02:00
# -------------------------------------------------------------------------
# Messaging
# Parser
settings . msg . parser = " SAMBRO "
# -------------------------------------------------------------------------
# Organisations
# Enable the use of Organisation Branches
settings . org . branches = True
# -------------------------------------------------------------------------
def customise_msg_rss_channel_resource ( r , tablename ) :
# @ToDo: We won't be able to automate this as we have 2 sorts, so will need the user to select manually
# Can we add a component for the parser for S3CSV imports?
s3db = current . s3db
def onaccept ( form ) :
# Normal onaccept
s3db . msg_channel_onaccept ( form )
db = current . db
table = db . msg_rss_channel
form_vars = form . vars
record_id = form_vars . get ( " id " , None )
form_type = form_vars . get ( " type " , None )
type = current . request . get_vars . get ( " type " , None )
query = ( table . id == record_id )
if type == " cap " or form_type == " cap " :
fn = " parse_rss_2_cap "
db ( query ) . update ( type = " cap " )
else :
fn = " parse_rss_2_cms "
db ( query ) . update ( type = " cms " )
channel_id = db ( query ) . select ( table . channel_id ,
limitby = ( 0 , 1 ) ) . first ( ) . channel_id
# Link to Parser
table = s3db . msg_parser
parser_id = table . insert ( channel_id = channel_id , function_name = fn , enabled = True )
s3db . msg_parser_enable ( parser_id )
2019-12-20 17:53:39 +01:00
run_async = current . s3task . run_async
2017-09-16 18:55:19 +02:00
# Poll
2019-12-20 17:53:39 +01:00
run_async ( " msg_poll " , args = [ " msg_rss_channel " , channel_id ] )
2017-09-16 18:55:19 +02:00
# Parse
2019-12-20 17:53:39 +01:00
run_async ( " msg_parse " , args = [ channel_id , fn ] )
2017-09-16 18:55:19 +02:00
s3db . configure ( tablename ,
create_onaccept = onaccept ,
)
settings . customise_msg_rss_channel_resource = customise_msg_rss_channel_resource
# -------------------------------------------------------------------------
def customise_msg_rss_channel_controller ( * * attr ) :
s3 = current . response . s3
2019-12-20 17:53:39 +01:00
channel_type = current . request . get_vars . get ( " type " , None )
if channel_type == " cap " :
2017-09-16 18:55:19 +02:00
# CAP RSS Channel
s3 . filter = ( FS ( " type " ) == " cap " )
s3 . crud_strings [ " msg_rss_channel " ] = Storage (
label_create = T ( " Add CAP Feed " ) ,
title_display = T ( " CAP Feed " ) ,
title_list = T ( " CAP Feeds " ) ,
title_update = T ( " Edit CAP Feed " ) ,
label_list_button = T ( " List CAP Feeds " ) ,
label_delete_button = T ( " Delete CAP Feed " ) ,
msg_record_created = T ( " CAP Feed created " ) ,
msg_record_modified = T ( " CAP Feed modified " ) ,
msg_record_deleted = T ( " CAP Feed deleted " ) ,
msg_list_empty = T ( " No CAP Feed to show " ) )
else :
# CMS RSS Channel
s3 . filter = ( FS ( " type " ) == " cms " )
# Custom postp
standard_postp = s3 . postp
def custom_postp ( r , output ) :
# Call standard postp
if callable ( standard_postp ) :
output = standard_postp ( r , output )
if r . interactive and isinstance ( output , dict ) :
# Modify Open Button
2019-12-20 17:53:39 +01:00
if channel_type == " cap " :
2017-09-16 18:55:19 +02:00
# CAP RSS Channel
table = r . table
query = ( table . deleted == False )
rows = current . db ( query ) . select ( table . id ,
table . enabled ,
)
restrict_e = [ str ( row . id ) for row in rows if not row . enabled ]
restrict_d = [ str ( row . id ) for row in rows if row . enabled ]
2019-12-20 17:53:39 +01:00
s3 . actions = [ { " label " : s3_str ( T ( " Open " ) ) ,
" _class " : " action-btn edit " ,
" url " : URL ( args = [ " [id] " , " update " ] ,
vars = { " type " : " cap " } ,
) ,
} ,
{ " label " : s3_str ( T ( " Delete " ) ) ,
" _class " : " delete-btn " ,
" url " : URL ( args = [ " [id] " , " delete " ] ,
vars = { " type " : " cap " } ,
) ,
} ,
{ " label " : s3_str ( T ( " Subscribe " ) ) ,
" _class " : " action-btn " ,
" url " : URL ( args = [ " [id] " , " enable " ] ,
vars = { " type " : " cap " } ,
) ,
" restrict " : restrict_e ,
} ,
{ " label " : s3_str ( T ( " Unsubscribe " ) ) ,
" _class " : " action-btn " ,
" url " : URL ( args = [ " [id] " , " disable " ] ,
vars = { " type " : " cap " } ,
) ,
" restrict " : restrict_d
} ,
]
2017-09-16 18:55:19 +02:00
if not current . s3task . _is_alive ( ) :
# No Scheduler Running
2019-12-20 17:53:39 +01:00
s3 . actions . append ( { " label " : s3_str ( T ( " Poll " ) ) ,
" _class " : " action-btn " ,
" url " : URL ( args = [ " [id] " , " poll " ] ,
vars = { " type " : " cap " } ,
) ,
" restrict " : restrict_d ,
} )
2017-09-16 18:55:19 +02:00
if " form " in output and current . auth . s3_has_role ( " ADMIN " ) :
# Modify Add Button
add_btn = A ( T ( " Add CAP Feed " ) ,
2019-12-20 17:53:39 +01:00
_class = " action-btn " ,
_href = URL ( args = [ " create " ] ,
vars = { " type " : " cap " } ,
) ,
2017-09-16 18:55:19 +02:00
)
output [ " showadd_btn " ] = add_btn
return output
s3 . postp = custom_postp
return attr
settings . customise_msg_rss_channel_controller = customise_msg_rss_channel_controller
# -------------------------------------------------------------------------
def customise_msg_twitter_channel_resource ( r , tablename ) :
s3db = current . s3db
def onaccept ( form ) :
# Normal onaccept
s3db . msg_channel_onaccept ( form )
_id = form . vars . id
db = current . db
table = db . msg_twitter_channel
channel_id = db ( table . id == _id ) . select ( table . channel_id ,
limitby = ( 0 , 1 ) ) . first ( ) . channel_id
# Link to Parser
table = s3db . msg_parser
_id = table . insert ( channel_id = channel_id , function_name = " parse_tweet " , enabled = True )
s3db . msg_parser_enable ( _id )
2019-12-20 17:53:39 +01:00
run_async = current . s3task . run_async
2017-09-16 18:55:19 +02:00
# Poll
2019-12-20 17:53:39 +01:00
run_async ( " msg_poll " , args = [ " msg_twitter_channel " , channel_id ] )
2017-09-16 18:55:19 +02:00
# Parse
2019-12-20 17:53:39 +01:00
run_async ( " msg_parse " , args = [ channel_id , " parse_tweet " ] )
2017-09-16 18:55:19 +02:00
s3db . configure ( tablename ,
create_onaccept = onaccept ,
)
settings . customise_msg_twitter_channel_resource = customise_msg_twitter_channel_resource
# -------------------------------------------------------------------------
def customise_org_organisation_resource ( r , tablename ) :
s3 = current . response . s3
crud_strings_branch = Storage (
label_create = T ( " Add Branch " ) ,
title_display = T ( " Branch Details " ) ,
title_list = T ( " Branches " ) ,
title_update = T ( " Edit Branch " ) ,
title_upload = T ( " Import Branches " ) ,
label_list_button = T ( " List Branches " ) ,
label_delete_button = T ( " Delete Branch " ) ,
msg_record_created = T ( " Branch added " ) ,
msg_record_modified = T ( " Branch updated " ) ,
msg_record_deleted = T ( " Branch deleted " ) ,
msg_list_empty = T ( " No Branches currently registered " ) )
if r . component_name == " branch " :
# Make sure branch uses same form as organisation because we need CAP OID
r . component . actuate = " replace "
s3 . crud_strings [ tablename ] = crud_strings_branch
if r . method == " hierarchy " :
s3 . crud_strings [ tablename ] = crud_strings_branch
from s3 import S3SQLCustomForm , S3SQLInlineComponent , S3SQLInlineLink
crud_form = S3SQLCustomForm ( " name " ,
" acronym " ,
S3SQLInlineLink ( " organisation_type " ,
field = " organisation_type_id " ,
label = T ( " Type " ) ,
multiple = False ,
#widget = "hierarchy",
) ,
S3SQLInlineComponent (
" tag " ,
label = T ( " CAP OID " ) ,
multiple = False ,
fields = [ ( " " , " value " ) ] ,
filterby = dict ( field = " tag " ,
options = " cap_oid " ,
) ,
) ,
" website " ,
" comments " ,
)
current . s3db . configure ( " org_organisation " ,
crud_form = crud_form ,
)
settings . customise_org_organisation_resource = customise_org_organisation_resource
# -------------------------------------------------------------------------
def customise_pr_person_resource ( r , tablename ) :
# On-delete option
current . s3db . pr_person_id . attr . ondelete = " SET NULL "
settings . customise_pr_person_resource = customise_pr_person_resource
# -------------------------------------------------------------------------
def customise_pr_contact_controller ( * * attr ) :
s3 = current . response . s3
# Custom prep
standard_prep = s3 . prep
def custom_prep ( r ) :
# Call standard prep
if callable ( standard_prep ) :
result = standard_prep ( r )
else :
result = True
table = r . table
table . priority . writable = False
table . priority . readable = False
table . comments . writable = False
table . comments . readable = False
return result
s3 . prep = custom_prep
return attr
settings . customise_pr_contact_controller = customise_pr_contact_controller
# -------------------------------------------------------------------------
def customise_cap_alert_resource ( r , tablename ) :
T = current . T
db = current . db
s3db = current . s3db
def onapprove ( record ) :
# Normal onapprove
2019-12-20 17:53:39 +01:00
s3db . cap_alert_onapprove ( record )
2017-09-16 18:55:19 +02:00
2019-12-20 17:53:39 +01:00
run_async = current . s3task . run_async
2017-09-16 18:55:19 +02:00
# Sync FTP Repository
2019-12-20 17:53:39 +01:00
run_async ( " cap_ftp_sync " )
2017-09-16 18:55:19 +02:00
# @ToDo: Check for LEFT join when required
# this is ok for now since every Alert should have an Info & an Area
alert_id = int ( record [ " id " ] )
table = s3db . cap_alert
itable = s3db . cap_info
atable = s3db . cap_area
query = ( table . id == alert_id ) & \
( table . deleted != True ) & \
( itable . alert_id == table . id ) & \
( itable . deleted != True ) & \
( atable . alert_id == table . id ) & \
( atable . deleted != True )
resource = s3db . resource ( " cap_alert " , filter = query )
# Fields to extract
fields = resource . list_fields ( key = " notify_fields " )
# Extract the data
data = resource . select ( fields ,
raw_data = True )
# Single row as we are filtering for particular alert_id
arow = data [ " rows " ] [ 0 ]
# Create attachment
cap_document_id = _get_or_create_attachment ( alert_id )
if record [ " scope " ] != " Private " and data [ " numrows " ] > 0 :
# Google Cloud Messaging
stable = s3db . pr_subscription
ctable = s3db . pr_contact
query = ( stable . pe_id == ctable . pe_id ) & \
( ctable . contact_method == " GCM " ) & \
( ctable . value != None ) & \
( ctable . deleted != True ) & \
( stable . deleted != True ) & \
( stable . method . like ( " %G CM % " ) )
rows = db ( query ) . select ( ctable . value )
if len ( rows ) :
registration_ids = [ s3_str ( row . value ) for row in rows ]
title = get_email_subject ( arow , system = False )
2019-12-20 17:53:39 +01:00
run_async ( " msg_gcm " , args = [ title ,
" %s / %s " % ( s3_str ( arow [ " cap_info.web " ] ) , " profile " ) ,
s3_str ( get_formatted_value ( arow [ " cap_info.headline " ] ,
system = False ) ) ,
json . dumps ( registration_ids ) ,
] )
2017-09-16 18:55:19 +02:00
# Twitter Post
if settings . get_cap_post_to_twitter ( ) :
try :
import tweepy
except ImportError :
current . log . debug ( " tweepy module needed for sending tweets " )
else :
2019-12-20 17:53:39 +01:00
url = " %s / %s " % ( arow [ " cap_info.web " ] , " profile " )
try :
from pyshorteners import Shortener
except ImportError :
pass
else :
try :
url = Shortener ( ' Tinyurl ' , timeout = 3 ) . short ( url )
except :
pass
2017-09-16 18:55:19 +02:00
twitter_text = \
( """ %(status)s Alert: %(headline)s
% ( sender ) s : % ( sender_name ) s
2019-12-20 17:53:39 +01:00
% ( website ) s : % ( Website ) s """ ) % { " status " : s3_str(T(arow[ " cap_alert.status " ])),
2017-09-16 18:55:19 +02:00
" headline " : s3_str ( get_formatted_value ( arow [ " cap_info.headline " ] ,
system = False ) ) ,
" sender " : s3_str ( T ( " Sender " ) ) ,
" sender_name " : s3_str ( get_formatted_value ( arow [ " cap_info.sender_name " ] ,
system = False ) ) ,
" website " : s3_str ( T ( " Website " ) ) ,
2019-12-20 17:53:39 +01:00
" Website " : s3_str ( url ) ,
2017-09-16 18:55:19 +02:00
}
try :
# @ToDo: Handle the multi-message nicely?
# @ToDo: Send resource url with tweet
2019-12-20 17:53:39 +01:00
current . msg . send_tweet ( text = s3_str ( twitter_text ) ,
alert_id = alert_id ,
)
except tweepy . error . TweepError as e :
2017-09-16 18:55:19 +02:00
current . log . debug ( " Sending tweets failed: %s " % e )
# Facebook Post
if settings . get_cap_post_to_facebook ( ) :
# @ToDo: post resources too?
content = get_facebook_content ( arow )
try :
2019-12-20 17:53:39 +01:00
current . msg . post_to_facebook ( text = content ,
alert_id = alert_id ,
)
except Exception as e :
2017-09-16 18:55:19 +02:00
current . log . debug ( " Posting Alert to Facebook failed: %s " % e )
addresses = record [ " addresses " ]
if len ( addresses ) :
# First Responders
gtable = s3db . pr_group
mtable = s3db . pr_group_membership
ptable = s3db . pr_person
send_by_pe_id = current . msg . send_by_pe_id
get_user_id = current . auth . s3_get_user_id
query_ = ( gtable . id == mtable . group_id ) & \
( mtable . person_id == ptable . id ) & \
( gtable . deleted != True ) & \
( mtable . deleted != True ) & \
( ptable . deleted != True )
count = len ( addresses )
if count == 1 :
query = query_ & ( gtable . id == addresses [ 0 ] )
else :
query = query_ & ( gtable . id . belongs ( addresses ) )
rows = db ( query ) . select ( ptable . pe_id )
subject = get_email_subject ( arow , system = False )
if settings . get_cap_use_ack ( ) :
for row in rows :
ack_id = create_ack ( alert_id , get_user_id ( pe_id = row . pe_id ) )
email_content = " %s %s %s " % ( " <html> " ,
XML ( get_html_email_content ( arow ,
ack_id = ack_id ,
system = False ) ) ,
" </html> " )
sms_content = get_sms_content ( arow , ack_id = ack_id , system = False )
send_by_pe_id ( row . pe_id ,
subject ,
email_content ,
2019-12-20 17:53:39 +01:00
document_ids = cap_document_id ,
alert_id = alert_id ,
)
2017-09-16 18:55:19 +02:00
try :
2019-12-20 17:53:39 +01:00
send_by_pe_id ( row . pe_id ,
subject ,
sms_content ,
contact_method = " SMS " ,
alert_id = alert_id ,
)
2017-09-16 18:55:19 +02:00
except ValueError :
current . log . error ( " No SMS Handler defined! " )
else :
html_content = get_html_email_content ( arow , system = False )
email_content = " %s %s %s " % ( " <html> " ,
XML ( html_content ) ,
" </html> " )
sms_content = get_sms_content ( a row , system = False )
for row in rows :
send_by_pe_id ( row . pe_id ,
subject ,
email_content ,
2019-12-20 17:53:39 +01:00
document_ids = cap_document_id ,
alert_id = alert_id ,
)
2017-09-16 18:55:19 +02:00
try :
2019-12-20 17:53:39 +01:00
send_by_pe_id ( row . pe_id ,
subject ,
sms_content ,
contact_method = " SMS " ,
alert_id = alert_id ,
)
2017-09-16 18:55:19 +02:00
except ValueError :
current . log . error ( " No SMS Handler defined! " )
s3db . configure ( tablename ,
onapprove = onapprove ,
)
settings . customise_cap_alert_resource = customise_cap_alert_resource
# -------------------------------------------------------------------------
def customise_cap_alert_controller ( * * attr ) :
s3 = current . response . s3
auth = current . auth
if not auth . user :
# For notifications for group
r = current . request
if not r . function == " public " :
if r . get_vars . format == " msg " :
# This is called by notification
# The request from web looks like r.extension
s3 . filter = ( FS ( " scope " ) != " Private " )
else :
auth . permission . fail ( )
# Custom prep
standard_prep = s3 . prep
def custom_prep ( r ) :
# Call standard prep
if callable ( standard_prep ) :
result = standard_prep ( r )
else :
result = True
if r . representation == " msg " :
# Notification
table = r . table
table . scope . represent = None
table . status . represent = None
table . msg_type . represent = None
itable = current . s3db . cap_info
itable . severity . represent = None
itable . urgency . represent = None
itable . certainty . represent = None
return result
s3 . prep = custom_prep
return attr
settings . customise_cap_alert_controller = customise_cap_alert_controller
# -------------------------------------------------------------------------
def customise_sync_repository_controller ( * * attr ) :
s3 = current . response . s3
# Custom prep
standard_prep = s3 . prep
def custom_prep ( r ) :
# Call standard prep
if callable ( standard_prep ) :
result = standard_prep ( r )
else :
result = True
if r . representation == " popup " :
table = r . table
table . apitype . default = " ftp "
table . apitype . readable = table . apitype . writable = False
table . synchronise_uuids . readable = \
table . synchronise_uuids . writable = False
table . uuid . readable = table . uuid . writable = False
return result
s3 . prep = custom_prep
return attr
settings . customise_sync_repository_controller = customise_sync_repository_controller
# -------------------------------------------------------------------------
def customise_pr_subscription_controller ( * * attr ) :
from s3 import S3CRUD
s3 = current . response . s3
s3db = current . s3db
auth = current . auth
stable = s3db . pr_subscription
has_role = auth . s3_has_role
list_fields = [ ( T ( " Filters " ) , " filter_id " ) ,
( T ( " Methods " ) , " method " ) ,
]
manage_recipient = current . request . get_vars [ " option " ] == " manage_recipient "
role_check = has_role ( " ADMIN " )
if manage_recipient and role_check :
# Admin based subscription
s3 . filter = ( stable . deleted != True ) & \
( stable . owned_by_group != None )
list_fields . insert ( 0 , ( T ( " People/Groups " ) , " pe_id " ) )
s3 . crud_strings [ " pr_subscription " ] . title_list = T ( " Admin Controlled Subscriptions " )
else :
# Self Subscription
s3 . filter = ( stable . deleted != True ) & \
( stable . owned_by_group == None ) & \
( stable . owned_by_user == auth . user . id )
s3 . crud_strings [ " pr_subscription " ] . title_list = T ( " Your Subscriptions " )
# Custom prep
standard_prep = s3 . prep
def custom_prep ( r ) :
from s3 import S3Represent
table = r . table
# Call standard prep
if callable ( standard_prep ) :
result = standard_prep ( r )
else :
result = True
MSG_CONTACT_OPTS = { " EMAIL " : T ( " EMAIL " ) ,
" SMS " : T ( " SMS " ) ,
" FTP " : T ( " FTP " ) ,
}
table . method . represent = S3Represent ( options = MSG_CONTACT_OPTS ,
multiple = True ,
) ,
if r . representation == " html " :
table . filter_id . represent = S3Represent ( \
options = pr_subscription_filter_row_options ( ) )
s3db . configure ( " pr_subscription " ,
list_fields = list_fields ,
list_orderby = " pe_id desc " ,
orderby = " pr_subscription.pe_id desc " ,
)
return result
s3 . prep = custom_prep
# Custom postp
standard_postp = s3 . postp
def custom_postp ( r , output ) :
# Call standard postp
if callable ( standard_postp ) :
output = standard_postp ( r , output )
if r . interactive and isinstance ( output , dict ) :
# Modify Open Button
if manage_recipient and role_check :
# Admin based subscription
S3CRUD . action_buttons ( r ,
update_url = URL ( c = " default " , f = " index " ,
args = [ " subscriptions " ] ,
vars = { " option " : " manage_recipient " ,
" subscription_id " : " [id] " }
) ,
delete_url = URL ( c = " pr " , f = " subscription " ,
args = [ " [id] " , " delete " ] ,
vars = { " option " : " manage_recipient " }
)
)
else :
# self subscription
url = URL ( c = " default " , f = " index " ,
args = [ " subscriptions " ] ,
vars = { " subscription_id " : " [id] " } )
S3CRUD . action_buttons ( r , update_url = url , read_url = url )
if " form " in output :
# Modify Add Button
if manage_recipient and role_check :
# Admin based subscription
add_btn = A ( T ( " Add Recipient to List " ) ,
_class = " action-btn " ,
_href = URL ( c = " default " , f = " index " ,
args = [ " subscriptions " ] ,
vars = { " option " : " manage_recipient " }
)
)
else :
# self subscription
add_btn = A ( T ( " Create Subscription " ) ,
_class = " action-btn " ,
_href = URL ( c = " default " , f = " index " , args = [ " subscriptions " ] )
)
output [ " showadd_btn " ] = add_btn
return output
s3 . postp = custom_postp
return attr
settings . customise_pr_subscription_controller = customise_pr_subscription_controller
# -----------------------------------------------------------------------------
def custom_msg_render ( resource , data , meta_data , format = None ) :
"""
Custom Method to pre - render the contents for the message template
@param resource : the S3Resource
@param data : the data returned from S3Resource . select
@param meta_data : the meta data for the notification
@param format : the contents format ( " text " or " html " )
"""
notify_on = meta_data [ " notify_on " ]
last_check_time = meta_data [ " last_check_time " ]
rows = data [ " rows " ]
output = { }
upd = [ ] # upd as the created alerts might be approved after some time, check is also done
db = current . db
atable = current . s3db . cap_alert
if format == " text " :
# For SMS
append_record = upd . append
for row in rows :
row_ = db ( atable . id == row [ " cap_alert.id " ] ) . select ( atable . approved_on ,
limitby = ( 0 , 1 ) ) . first ( )
if row_ and row_ . approved_on is not None :
if s3_utc ( row_ . approved_on ) > = last_check_time :
sms_content = get_sms_content ( row )
append_record ( sms_content )
if " upd " in notify_on and len ( upd ) :
output [ " upd " ] = len ( upd )
output [ " upd_records " ] = upd
else :
output [ " upd " ] = None
else :
# HTML emails
elements = [ ]
append = elements . append
append_record = upd . append
for row in rows :
row_ = db ( atable . id == row [ " cap_alert.id " ] ) . select ( atable . approved_on ,
limitby = ( 0 , 1 ) ) . first ( )
if row_ and row_ . approved_on is not None :
if s3_utc ( row_ . approved_on ) > = last_check_time :
content = get_html_email_content ( row )
container = DIV ( DIV ( content ) )
append ( container )
append ( BR ( ) )
append_record ( container )
if " upd " in notify_on and len ( upd ) :
output [ " upd " ] = len ( upd )
output [ " upd_records " ] = DIV ( * elements )
else :
output [ " upd " ] = None
output . update ( meta_data )
return output
settings . msg . notify_renderer = custom_msg_render
# -----------------------------------------------------------------------------
def custom_msg_notify_subject ( resource , data , meta_data ) :
"""
Custom Method to subject for the email
@param resource : the S3Resource
@param data : the data returned from S3Resource . select
@param meta_data : the meta data for the notification
"""
rows = data [ " rows " ]
2019-12-20 17:53:39 +01:00
subject = " %s %s " % ( settings . get_system_name_short ( ) ,
2017-09-16 18:55:19 +02:00
T ( " Alert Notification " ) )
if len ( rows ) == 1 :
# Since if there are more than one row, the single email has content
# for all rows
atable = current . s3db . cap_alert
2019-12-20 17:53:39 +01:00
row_ = current . db ( atable . id == rows [ 0 ] [ " cap_alert.id " ] ) . select ( atable . approved_on ,
limitby = ( 0 , 1 )
) . first ( )
2017-09-16 18:55:19 +02:00
if row_ and row_ . approved_on is not None :
2019-12-20 17:53:39 +01:00
if s3_utc ( row_ . approved_on ) > = meta_data [ " last_check_time " ] :
2017-09-16 18:55:19 +02:00
subject = get_email_subject ( rows [ 0 ] )
return subject
settings . msg . notify_subject = custom_msg_notify_subject
# -----------------------------------------------------------------------------
def custom_msg_notify_attachment ( resource , data , meta_data ) :
"""
Custom Method to get the document_ids to be sent as attachment
@param resource : the S3Resource
@param data : the data returned from S3Resource . select
@param meta_data : the meta data for the notification
"""
rows = data [ " rows " ]
document_ids = [ ]
dappend = document_ids . append
for row in rows :
alert_id = row [ " cap_alert.id " ]
document_id = _get_or_create_attachment ( alert_id )
dappend ( document_id )
return document_ids
settings . msg . notify_attachment = custom_msg_notify_attachment
2019-12-20 17:53:39 +01:00
# -----------------------------------------------------------------------------
def custom_msg_notify_send_data ( resource , data , meta_data ) :
"""
Custom Method to send data containing alert_id to the s3msg . send_by_pe_id
@param resource : the S3Resource
@param data : the data returned from S3Resource . select
@param meta_data : the meta data for the notification
"""
rows = data . rows
data = { }
if len ( rows ) == 1 :
row = rows [ 0 ]
if " cap_alert.id " in row :
try :
alert_id = int ( row [ " cap_alert.id " ] )
data [ " alert_id " ] = alert_id
except ValueError :
pass
return data
settings . msg . notify_send_data = custom_msg_notify_send_data
# -----------------------------------------------------------------------------
def msg_send_postprocess ( message_id , * * data ) :
"""
Custom function that links alert_id in cap module to message_id in
message module
"""
alert_id = data . get ( " alert_id " , None )
if alert_id and message_id :
current . s3db . cap_alert_message . insert ( alert_id = alert_id ,
message_id = message_id )
settings . msg . send_postprocess = msg_send_postprocess
2017-09-16 18:55:19 +02:00
# -------------------------------------------------------------------------
# Comment/uncomment modules here to disable/enable them
# @ToDo: Have the system automatically enable migrate if a module is enabled
# Modules menu is defined in modules/eden/menu.py
settings . modules = OrderedDict ( [
# Core modules which shouldn't be disabled
( " default " , Storage (
name_nice = T ( " Home " ) ,
restricted = False , # Use ACLs to control access to this module
access = None , # All Users (inc Anonymous) can see this module in the default menu & access the controller
module_type = None # This item is not shown in the menu
) ) ,
( " admin " , Storage (
name_nice = T ( " Administration " ) ,
#description = "Site Administration",
restricted = True ,
access = " |1| " , # Only Administrators can see this module in the default menu & access the controller
module_type = None # This item is handled separately for the menu
) ) ,
( " appadmin " , Storage (
name_nice = T ( " Administration " ) ,
#description = "Site Administration",
restricted = True ,
module_type = None # No Menu
) ) ,
( " errors " , Storage (
name_nice = T ( " Ticket Viewer " ) ,
#description = "Needed for Breadcrumbs",
restricted = False ,
module_type = None # No Menu
) ) ,
( " sync " , Storage (
name_nice = T ( " Synchronization " ) ,
#description = "Synchronization",
restricted = True ,
access = " |1| " , # Only Administrators can see this module in the default menu & access the controller
module_type = None # This item is handled separately for the menu
) ) ,
#("tour", Storage(
# name_nice = T("Guided Tour Functionality"),
# module_type = None,
#)),
( " translate " , Storage (
name_nice = T ( " Translation Functionality " ) ,
#description = "Selective translation of strings based on module.",
module_type = None ,
) ) ,
( " gis " , Storage (
name_nice = T ( " Mapping " ) ,
#description = "Situation Awareness & Geospatial Analysis",
restricted = True ,
module_type = 6 , # 6th item in the menu
) ) ,
( " pr " , Storage (
name_nice = T ( " Person Registry " ) ,
#description = "Central point to record details on People",
restricted = True ,
access = " |1| " , # Only Administrators can see this module in the default menu (access to controller is possible to all still)
module_type = 10
) ) ,
( " org " , Storage (
name_nice = T ( " Organizations " ) ,
#description = 'Lists "who is doing what & where". Allows relief agencies to coordinate their activities',
restricted = True ,
module_type = 10
) ) ,
# All modules below here should be possible to disable safely
#("hrm", Storage(
# name_nice = T("Staff"),
# #description = "Human Resources Management",
# restricted = True,
# module_type = 2,
#)),
( " cap " , Storage (
name_nice = T ( " Alerting " ) ,
#description = "Create & broadcast CAP alerts",
restricted = True ,
module_type = 1 ,
) ) ,
( " cms " , Storage (
name_nice = T ( " Content Management " ) ,
#description = "Content Management System",
restricted = True ,
module_type = 10 ,
) ) ,
( " doc " , Storage (
name_nice = T ( " Documents " ) ,
#description = "A library of digital resources, such as photos, documents and reports",
restricted = True ,
module_type = 10 ,
) ) ,
( " msg " , Storage (
name_nice = T ( " Messaging " ) ,
#description = "Sends & Receives Alerts via Email & SMS",
restricted = True ,
# The user-visible functionality of this module isn't normally required. Rather it's main purpose is to be accessed from other modules.
module_type = None ,
) ) ,
( " event " , Storage (
name_nice = T ( " Events " ) ,
#description = "Activate Events (e.g. from Scenario templates) for allocation of appropriate Resources (Human, Assets & Facilities).",
restricted = True ,
module_type = 10 ,
) ) ,
] )
# -------------------------------------------------------------------------
# Functions which are local to this Template
# -------------------------------------------------------------------------
def pr_subscription_filter_row_options ( ) :
"""
Build the options for the pr_subscription filter datatable from query
@ToDo complete this for locations
"""
db = current . db
s3db = current . s3db
auth = current . auth
has_role = auth . s3_has_role
stable = s3db . pr_subscription
ftable = s3db . pr_filter
if current . request . get_vars [ " option " ] == " manage_recipient " and \
( has_role ( " ALERT_EDITOR " ) or has_role ( " ALERT_APPROVER " ) ) :
2019-12-20 17:53:39 +01:00
# Admin based subscription
query = ( stable . deleted != True ) & \
( stable . owned_by_group != None )
2017-09-16 18:55:19 +02:00
else :
# Self Subscription
query = ( stable . deleted != True ) & \
( stable . owned_by_group == None ) & \
( stable . owned_by_user == auth . user . id )
left = ftable . on ( ftable . id == stable . filter_id )
rows = db ( query ) . select ( stable . filter_id ,
ftable . query ,
left = left )
2019-12-20 17:53:39 +01:00
filter_options = { }
2017-09-16 18:55:19 +02:00
if len ( rows ) > 0 :
T = current . T
etable = s3db . event_event_type
ptable = s3db . cap_warning_priority
from s3 import IS_ISO639_2_LANGUAGE_CODE
languages_dict = dict ( IS_ISO639_2_LANGUAGE_CODE . language_codes ( ) )
for row in rows :
event_type = None
priorities_id = [ ]
languages = [ ]
filters = json . loads ( row . pr_filter . query )
filters = [ filter for filter in filters if filter [ 1 ] is not None ]
if len ( filters ) > 0 :
for filter in filters :
# Get the prefix
prefix = s3_str ( filter [ 0 ] ) . strip ( " [] " )
# Get the value for prefix
values = filter [ 1 ] . split ( " , " )
if prefix == " event_type_id__belongs " :
event_type_id = s3_str ( values [ 0 ] )
row_ = db ( etable . id == event_type_id ) . select ( \
etable . name ,
limitby = ( 0 , 1 ) ) . first ( )
event_type = row_ . name
elif prefix == " info.priority__belongs " :
priorities_id = [ int ( s3_str ( value ) ) for value in values ]
rows_ = db ( ptable . id . belongs ( priorities_id ) ) . select ( ptable . name )
priorities = [ row_ . name for row_ in rows_ ]
elif prefix == " info.language__belongs " :
languages = [ s3_str ( languages_dict [ value ] ) for value in values ]
if event_type is not None :
display_text = " <b> %s :</b> %s " % ( T ( " Event Type " ) , event_type )
else :
display_text = " <b> %s :</b> %s " % ( T ( " Event Type " ) , T ( " No filter " ) )
if len ( priorities_id ) > 0 :
display_text = " %s <br/><b> %s </b>: %s " % ( display_text , T ( " Priorities " ) , " , " . join ( priorities ) )
else :
display_text = " %s <br/><b> %s :</b> %s " % ( display_text , T ( " Priorities " ) , T ( " No filter " ) )
if len ( languages ) > 0 :
display_text = " %s <br/><b> %s :</b> %s " % ( display_text , T ( " Languages " ) , " , " . join ( languages ) )
else :
display_text = " %s <br/><b> %s :</b> %s " % ( display_text , T ( " Languages " ) , T ( " No filter " ) )
filter_options [ row [ " pr_subscription.filter_id " ] ] = display_text
else :
filter_options [ row [ " pr_subscription.filter_id " ] ] = T ( " No filters " )
2019-12-20 17:53:39 +01:00
return filter_options
2017-09-16 18:55:19 +02:00
# -------------------------------------------------------------------------
def get_html_email_content ( row , ack_id = None , system = True ) :
"""
prepare the content for html email
@param row : the row from which the email will be constructed
@param ack_id : cap_alert_ack . id for including the acknowledgement link
@param system : is this system notification email or email for first responders
"""
itable = current . s3db . cap_info
event_type_id = row [ " cap_info.event_type_id " ]
priority_id = row [ " cap_info.priority " ]
response_type = row [ " _row " ] [ " cap_info.response_type " ] if system else row [ " cap_info.response_type " ]
instruction = row [ " _row " ] [ " cap_info.instruction " ] if system else row [ " cap_info.instruction " ]
description = row [ " _row " ] [ " cap_info.description " ] if system else row [ " cap_info.description " ]
status = row [ " cap_alert.status " ]
msg_type = row [ " cap_alert.msg_type " ]
2019-12-20 17:53:39 +01:00
url = " %s / %s " % ( row [ " cap_info.web " ] , " profile " )
try :
from pyshorteners import Shortener
except ImportError :
pass
else :
try :
url = Shortener ( ' Tinyurl ' , timeout = 3 ) . short ( url )
except :
pass
2017-09-16 18:55:19 +02:00
if event_type_id and event_type_id != current . messages [ " NONE " ] :
if not isinstance ( event_type_id , lazyT ) and \
not isinstance ( event_type_id , DIV ) :
event_type = itable . event_type_id . represent ( event_type_id )
else :
event_type = event_type_id
else :
event_type = T ( " None " )
if priority_id and priority_id != current . messages [ " NONE " ] :
if not isinstance ( priority_id , lazyT ) and \
not isinstance ( priority_id , DIV ) :
priority = itable . priority . represent ( priority_id )
else :
priority = priority_id
else :
priority = T ( " Alert " )
email_content = TAG [ " " ] ( HR ( ) , BR ( ) ,
B ( s3_str ( " %s %s %s " % ( T ( status . upper ( ) ) ,
T ( status . upper ( ) ) ,
T ( status . upper ( ) ) ) ) )
if status != " Actual " else " " ,
BR ( ) if status != " Actual " else " " ,
BR ( ) if status != " Actual " else " " ,
2019-12-20 17:53:39 +01:00
A ( T ( " VIEW ALERT ON THE WEB " ) , _href = s3_str ( url ) ) ,
2017-09-16 18:55:19 +02:00
BR ( ) , BR ( ) ,
B ( s3_str ( " %s %s %s %s " % ( T ( row [ " cap_alert.scope " ] ) ,
T ( status ) ,
T ( " Alert " ) if msg_type != " Alert " else " " ,
s3_str ( msg_type )
) ) ) ,
H2 ( T ( s3_str ( get_formatted_value ( row [ " cap_info.headline " ] ,
system = system ) ) ) ) ,
BR ( ) ,
XML ( " %(label)s : %(identifier)s " %
{ " label " : B ( T ( " ID " ) ) ,
" identifier " : s3_str ( row [ " cap_alert.identifier " ] )
} ) ,
BR ( ) , BR ( ) ,
T ( """ %(priority)s message %(message_type)s in effect for %(area_description)s """ ) % \
{ " priority " : s3_str ( priority ) ,
" message_type " : s3_str ( msg_type ) ,
" area_description " : s3_str ( get_formatted_value ( row [ " cap_area.name " ] ,
system = system ) ) ,
} ,
BR ( ) , BR ( ) ,
T ( " This %(severity)s %(event_type)s is %(urgency)s and is %(certainty)s " ) % \
{ " severity " : s3_str ( row [ " cap_info.severity " ] ) ,
" event_type " : s3_str ( event_type ) ,
" urgency " : s3_str ( row [ " cap_info.urgency " ] ) ,
" certainty " : s3_str ( row [ " cap_info.certainty " ] ) ,
} ,
BR ( ) , BR ( ) ,
T ( """ Message %(identifier)s : %(event_type)s ( %(category)s ) issued by %(sender_name)s sent at %(date)s from %(source)s """ ) % \
{ " identifier " : s3_str ( row [ " cap_alert.identifier " ] ) ,
" event_type " : s3_str ( event_type ) ,
" category " : s3_str ( get_formatted_value ( row [ " cap_info.category " ] ,
represent = itable . category . represent ,
system = system ) ) ,
" sender_name " : s3_str ( get_formatted_value ( row [ " cap_info.sender_name " ] ,
system = system ) ) ,
" date " : s3_str ( get_formatted_value ( row [ " cap_alert.sent " ] ,
represent = current . s3db . cap_alert . sent . represent ,
system = system ) ) ,
" source " : s3_str ( row [ " cap_alert.source " ] ) ,
} ,
BR ( ) ,
BR ( ) if description else " " ,
XML ( " %(label)s : %(alert_description)s " %
{ " label " : B ( T ( " Alert Description " ) ) ,
" alert_description " : s3_str ( get_formatted_value ( description ,
system = False ,
ul = True ) ) ,
} )
if description else " " ,
BR ( ) if not isinstance ( description , list ) else " " ,
BR ( ) if response_type else " " ,
2019-12-20 17:53:39 +01:00
XML ( T ( " %(label)s : %(response_type)s " ) %
2017-09-16 18:55:19 +02:00
{ " label " : B ( T ( " Expected Response " ) ) ,
" response_type " : s3_str ( get_formatted_value ( response_type ,
represent = itable . response_type . represent ,
system = False ,
ul = True ) ) ,
} )
if response_type else " " ,
BR ( ) if not isinstance ( response_type , list ) else " " ,
BR ( ) if instruction else " " ,
XML ( T ( " %(label)s : %(instruction)s " ) %
{ " label " : B ( T ( " Instructions " ) ) ,
" instruction " : s3_str ( get_formatted_value ( instruction ,
system = False ,
ul = True ) ) ,
} )
if instruction else " " ,
BR ( ) if not isinstance ( instruction , list ) else " " ,
BR ( ) ,
T ( " Alert is effective from %(effective)s and expires on %(expires)s " ) % \
{ " effective " : s3_str ( get_formatted_value ( row [ " cap_info.effective " ] ,
represent = itable . effective . represent ,
system = system ) ) ,
" expires " : s3_str ( get_formatted_value ( row [ " cap_info.expires " ] ,
represent = itable . expires . represent ,
system = system ) ) ,
} ,
BR ( ) , BR ( ) ,
T ( " For more details visit %(url)s or contact %(contact)s " ) % \
2019-12-20 17:53:39 +01:00
{ " url " : s3_str ( url ) ,
2017-09-16 18:55:19 +02:00
" contact " : s3_str ( get_formatted_value ( row [ " cap_info.contact " ] ,
system = system ) ) ,
} ,
BR ( ) , BR ( ) ,
T ( " To acknowledge the alert, use the following link: %(ack_link)s " ) % \
{ " ack_link " : " %s %s " % ( current . deployment_settings . get_base_public_url ( ) ,
URL ( c = " cap " , f = " alert_ack " , args = [ ack_id , " update " ] ) ) ,
} if ack_id else " " ,
BR ( ) if ack_id else " " ,
BR ( ) if ack_id else " " ,
B ( s3_str ( " %s %s %s " % ( T ( status . upper ( ) ) ,
T ( status . upper ( ) ) ,
T ( status . upper ( ) ) ) ) )
if status != " Actual " else " " ,
)
return email_content
# -------------------------------------------------------------------------
def get_email_subject ( row , system = True ) :
"""
2019-12-20 17:53:39 +01:00
Prepare the subject for Email
2017-09-16 18:55:19 +02:00
"""
itable = current . s3db . cap_info
event_type_id = row [ " cap_info.event_type_id " ]
msg_type = T ( row [ " cap_alert.msg_type " ] )
if event_type_id and event_type_id != current . messages [ " NONE " ] :
if not isinstance ( event_type_id , lazyT ) and \
not isinstance ( event_type_id , DIV ) :
event_type = itable . event_type_id . represent ( event_type_id )
else :
event_type = event_type_id
else :
event_type = T ( " None " )
subject = " [ %s ] %s %s " % ( get_formatted_value ( row [ " cap_info.sender_name " ] ,
system = system ) ,
event_type ,
msg_type )
# RFC 2822
return s3_str ( s3_truncate ( subject , length = 78 ) )
# -------------------------------------------------------------------------
def get_sms_content ( row , ack_id = None , system = True ) :
"""
2019-12-20 17:53:39 +01:00
Prepare the content for SMS
2017-09-16 18:55:19 +02:00
@param row : the row from which the sms will be constructed
@param ack_id : cap_alert_ack . id for including the acknowledgement link
@param system : is this system notification email or email for first responders
"""
itable = current . s3db . cap_info
event_type_id = row [ " cap_info.event_type_id " ]
priority_id = row [ " cap_info.priority " ]
2019-12-20 17:53:39 +01:00
url = " %s / %s " % ( row [ " cap_info.web " ] , " profile " )
try :
from pyshorteners import Shortener
except ImportError :
pass
else :
try :
url = Shortener ( ' Tinyurl ' , timeout = 3 ) . short ( url )
except :
pass
2017-09-16 18:55:19 +02:00
if not isinstance ( event_type_id , lazyT ) and \
not isinstance ( event_type_id , DIV ) :
event_type = itable . event_type_id . represent ( event_type_id )
else :
event_type = event_type_id
if priority_id and priority_id != current . messages [ " NONE " ] :
if not isinstance ( priority_id , lazyT ) and \
not isinstance ( priority_id , DIV ) :
priority = itable . priority . represent ( priority_id )
else :
priority = priority_id
else :
priority = T ( " Unknown " )
if ack_id :
sms_body = \
T ( """ %(status)s %(message_type)s for %(area_description)s with %(priority)s priority %(event_type)s issued by %(sender_name)s at %(date)s (ID: %(identifier)s ) \n To acknowledge the alert, click: %(ack_link)s \n \n """ ) % \
{ " status " : s3_str ( row [ " cap_alert.status " ] ) ,
" message_type " : s3_str ( row [ " cap_alert.msg_type " ] ) ,
" area_description " : s3_str ( get_formatted_value ( row [ " cap_area.name " ] ,
system = system ) ) ,
" priority " : s3_str ( priority ) ,
" event_type " : s3_str ( event_type ) ,
" sender_name " : s3_str ( get_formatted_value ( row [ " cap_info.sender_name " ] ,
system = system ) ) ,
" date " : s3_str ( row [ " cap_alert.sent " ] ) ,
" identifier " : s3_str ( row [ " cap_alert.identifier " ] ) ,
" ack_link " : " %s %s " % ( current . deployment_settings . get_base_public_url ( ) ,
URL ( c = " cap " , f = " alert_ack " , args = [ ack_id , " update " ] ) ) ,
}
else :
sms_body = \
T ( """ %(status)s %(message_type)s for %(area_description)s with %(priority)s priority %(event_type)s issued by %(sender_name)s at %(date)s (ID: %(identifier)s ). \n View Alert in web at %(profile)s \n \n """ ) % \
{ " status " : s3_str ( row [ " cap_alert.status " ] ) ,
" message_type " : s3_str ( row [ " cap_alert.msg_type " ] ) ,
" area_description " : s3_str ( get_formatted_value ( row [ " cap_area.name " ] ,
system = system ) ) ,
" priority " : s3_str ( priority ) ,
" event_type " : s3_str ( event_type ) ,
" sender_name " : s3_str ( get_formatted_value ( row [ " cap_info.sender_name " ] ,
system = system ) ) ,
" date " : s3_str ( row [ " cap_alert.sent " ] ) ,
" identifier " : s3_str ( row [ " cap_alert.identifier " ] ) ,
2019-12-20 17:53:39 +01:00
" profile " : s3_str ( url ) ,
2017-09-16 18:55:19 +02:00
}
return s3_str ( sms_body )
# -------------------------------------------------------------------------
def get_facebook_content ( row , system = False ) :
"""
prepare the content for facebook post
"""
itable = current . s3db . cap_info
event_type_id = row [ " cap_info.event_type_id " ]
priority_id = row [ " cap_info.priority " ]
response_type = row [ " cap_info.response_type " ]
instruction = row [ " cap_info.instruction " ]
description = row [ " cap_info.description " ]
2019-12-20 17:53:39 +01:00
url = " %s / %s " % ( row [ " cap_info.web " ] , " profile " )
try :
from pyshorteners import Shortener
try :
url = Shortener ( ' Tinyurl ' , timeout = 3 ) . short ( url )
except :
pass
except ImportError :
pass
2017-09-16 18:55:19 +02:00
if event_type_id and event_type_id != current . messages [ " NONE " ] :
if not isinstance ( event_type_id , lazyT ) :
event_type = itable . event_type_id . represent ( event_type_id )
else :
event_type = event_type_id
else :
event_type = T ( " None " )
if priority_id and priority_id != current . messages [ " NONE " ] :
if not isinstance ( priority_id , lazyT ) :
priority = itable . priority . represent ( priority_id )
else :
priority = priority_id
else :
priority = T ( " Alert " )
facebook_content = [
T ( " %(scope)s %(status)s Alert " ) % \
{ " scope " : s3_str ( row [ " cap_alert.scope " ] ) ,
" status " : s3_str ( row [ " cap_alert.status " ] ) ,
} ,
T ( ( s3_str ( get_formatted_value ( row [ " cap_info.headline " ] ,
system = system ) ) ) ) ,
T ( " ID: %(identifier)s " ) % { " identifier " : s3_str ( row [ " cap_alert.identifier " ] ) } ,
T ( """ %(priority)s message %(message_type)s in effect for %(area_description)s """ ) % \
{ " priority " : s3_str ( priority ) ,
" message_type " : s3_str ( row [ " cap_alert.msg_type " ] ) ,
" area_description " : s3_str ( get_formatted_value ( row [ " cap_area.name " ] ,
system = system ) ) ,
} ,
T ( " This %(severity)s %(event_type)s is %(urgency)s and is %(certainty)s " ) % \
{ " severity " : s3_str ( row [ " cap_info.severity " ] ) ,
" event_type " : s3_str ( event_type ) ,
" urgency " : s3_str ( row [ " cap_info.urgency " ] ) ,
" certainty " : s3_str ( row [ " cap_info.certainty " ] ) ,
} ,
T ( """ Message %(identifier)s : %(event_type)s ( %(category)s ) issued by %(sender_name)s sent at %(date)s from %(source)s """ ) % \
{ " identifier " : s3_str ( row [ " cap_alert.identifier " ] ) ,
" event_type " : s3_str ( event_type ) ,
" category " : s3_str ( get_formatted_value ( row [ " cap_info.category " ] ,
represent = itable . category . represent ,
system = system ) ) ,
" sender_name " : s3_str ( get_formatted_value ( row [ " cap_info.sender_name " ] ,
system = system ) ) ,
" date " : s3_str ( get_formatted_value ( row [ " cap_alert.sent " ] ,
represent = current . s3db . cap_alert . sent . represent ,
system = system ) ) ,
" source " : s3_str ( row [ " cap_alert.source " ] ) ,
} ,
T ( " Alert Description: %(alert_description)s " ) % \
{ " alert_description " : s3_str ( get_formatted_value ( description ,
system = system ) ) ,
} if description else " " ,
T ( " Expected Response: %(response_type)s " ) % \
{ " response_type " : s3_str ( get_formatted_value ( response_type ,
represent = itable . response_type . represent ,
system = system ) ) ,
} if response_type else " " ,
T ( " Instruction: %(instruction)s " ) % \
{ " instruction " : s3_str ( get_formatted_value ( instruction , system = system ) ) }
if instruction else " " ,
T ( " Alert is effective from %(effective)s and expires on %(expires)s " ) % \
{ " effective " : s3_str ( get_formatted_value ( row [ " cap_info.effective " ] ,
represent = itable . effective . represent ,
system = system ) ) ,
" expires " : s3_str ( get_formatted_value ( row [ " cap_info.expires " ] ,
represent = itable . expires . represent ,
system = system ) ) ,
} ,
T ( " For more details visit %(url)s or contact %(contact)s " ) % \
2019-12-20 17:53:39 +01:00
{ " url " : s3_str ( url ) ,
2017-09-16 18:55:19 +02:00
" contact " : s3_str ( get_formatted_value ( row [ " cap_info.contact " ] , system = system ) ) ,
}
if row [ " cap_info.contact " ] else
T ( " For more details visit %(url)s " ) % \
2019-12-20 17:53:39 +01:00
{ " url " : s3_str ( url ) }
2017-09-16 18:55:19 +02:00
]
return " \n \n " . join ( s3_str ( item ) for item in facebook_content if item != " " )
# -------------------------------------------------------------------------
def create_ack ( alert_id , user_id ) :
"""
Create a specific acknowledgement
@param alert_id : The particular alert ID for acknowledging
@param user_id : The user ID who owns the record
@todo : use location where the alert is targeted for
"""
ack_data = { " alert_id " : alert_id ,
" owned_by_user " : int ( user_id ) ,
}
ack_table = current . s3db . cap_alert_ack
ack_id = ack_table . insert ( * * ack_data )
current . auth . s3_set_record_owner ( ack_table , ack_id )
# Uncomment this when there is onaccept hook
#s3db.onaccept(ack_table, dict(id=ack_id))
return ack_id
# -------------------------------------------------------------------------
def get_formatted_value ( value ,
represent = None ,
system = True ,
ul = False ) :
""" For non-system notification returns the formatted represented value
"""
if not value :
return None
else :
if system :
# For system notification value is already properly formatted for representation
return value
else :
if isinstance ( value , list ) :
nvalue = [ ]
for value_ in value :
if value_ :
if represent :
nvalue . append ( represent ( value_ ) )
else :
nvalue . append ( value_ )
if len ( nvalue ) :
if ul :
nvalue = UL ( nvalue )
else :
nvalue = " , " . join ( nvalue )
else :
return None
else :
if represent :
nvalue = represent ( value )
else :
nvalue = value
return nvalue
# -------------------------------------------------------------------------
def _get_or_create_attachment ( alert_id ) :
2019-12-20 17:53:39 +01:00
"""
2017-09-16 18:55:19 +02:00
Retrieve the CAP attachment for the alert_id if present
else creates CAP file as attachment to be sent with the email
returns the document_id for the CAP file
"""
s3db = current . s3db
rtable = s3db . cap_resource
dtable = s3db . doc_document
query = ( rtable . alert_id == alert_id ) & \
( rtable . mime_type == " cap " ) & \
( rtable . deleted != True ) & \
( dtable . doc_id == rtable . doc_id ) & \
( dtable . deleted != True )
row = current . db ( query ) . select ( dtable . id , limitby = ( 0 , 1 ) ) . first ( )
if row and row . id :
return row . id
request = current . request
auth = current . auth
path_join = os . path . join
# Create the cap_resource table
record = { " alert_id " : alert_id ,
" resource_desc " : T ( " CAP XML File " ) ,
" mime_type " : " cap " # Hard coded to separate from attachment from user
}
resource_id = rtable . insert ( * * record )
record [ " id " ] = resource_id
s3db . update_super ( rtable , record )
doc_id = record [ " doc_id " ]
auth . s3_set_record_owner ( rtable , resource_id )
auth . s3_make_session_owner ( rtable , resource_id )
s3db . onaccept ( " cap_resource " , record , method = " create " )
resource = s3db . resource ( " cap_alert " )
resource . add_filter ( FS ( " id " ) == alert_id )
cap_xml = resource . export_xml ( stylesheet = path_join ( request . folder ,
" static " ,
" formats " ,
" cap " ,
" export.xsl " ) ,
pretty_print = True )
file_path = path_join ( request . folder ,
" uploads " ,
" %s _ %s .xml " % ( " cap_alert " , str ( alert_id ) ) )
file = open ( file_path , " w+ " )
file . write ( cap_xml )
file . close ( )
# Create doc_document record
dtable = s3db . doc_document
file = open ( file_path , " a+ " )
document_id = dtable . insert ( * * { " file " : file , " doc_id " : doc_id } )
file . close ( )
os . remove ( file_path )
return document_id
# END =========================================================================