Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of git://github.com/flavour/eden

  • Loading branch information...
commit 5f3c28e4eeefb3b00ce2b7f9a46318b5738ad8ab 2 parents f2434de + 31a7f69
Fran Boon authored
Showing with 1,347 additions and 714 deletions.
  1. +97 −2 controllers/project.py
  2. +5 −6 modules/eden/asset.py
  3. +4 −9 modules/eden/gis.py
  4. +2 −6 modules/eden/hrm.py
  5. +20 −20 modules/eden/inv.py
  6. +3 −7 modules/eden/member.py
  7. +21 −20 modules/eden/org.py
  8. +9 −6 modules/eden/pr.py
  9. +189 −91 modules/eden/project.py
  10. +65 −7 modules/eden/stats.py
  11. +13 −9 modules/eden/vulnerability.py
  12. +27 −40 modules/s3/s3aaa.py
  13. +14 −4 modules/s3/s3crud.py
  14. +30 −6 modules/s3/s3forms.py
  15. +69 −56 modules/s3/s3import.py
  16. +1 −1  modules/s3/s3search.py
  17. +3 −2 modules/s3/s3widgets.py
  18. +2 −2 modules/tests/project/create_project.py
  19. +1 −1  modules/unit_tests/eden/pr.py
  20. +47 −4 modules/unit_tests/s3/s3aaa.py
  21. +127 −31 private/templates/IFRC/project_activity_type.csv
  22. +67 −27 private/templates/IFRC/project_theme.csv
  23. +100 −100 private/templates/IFRC_Demo/project_location.csv
  24. +10 −7 static/formats/s3csv/cr/shelter.xsl
  25. +10 −7 static/formats/s3csv/hrm/person.xsl
  26. +10 −7 static/formats/s3csv/inv/warehouse.xsl
  27. +10 −7 static/formats/s3csv/member/person.xsl
  28. +10 −7 static/formats/s3csv/org/office.xsl
  29. +10 −7 static/formats/s3csv/org/organisation.xsl
  30. +1 −1  static/formats/s3csv/project/activity.xsl
  31. +37 −2 static/formats/s3csv/project/activity_type.xsl
  32. +1 −1  static/formats/s3csv/project/beneficiary_type.csv
  33. +1 −0  static/formats/s3csv/project/beneficiary_type.xsl
  34. +3 −3 static/formats/s3csv/project/location.xsl
  35. +35 −1 static/formats/s3csv/project/theme.xsl
  36. +10 −7 static/formats/s3csv/scenario/scenario.xsl
  37. +203 −118 static/scripts/S3/S3.js
  38. +69 −68 static/scripts/S3/S3.min.js
  39. +11 −14 static/scripts/S3/s3.search.js
99 controllers/project.py
View
@@ -101,8 +101,17 @@ def postp(r, output):
# Pre-process
def prep(r):
+ table = s3db.project_project
+
# Location Filter
s3db.gis_location_filter(r)
+
+ # Filter Themes based on Sector
+ if r.record:
+ sector_ids = r.record.sector_id
+ else:
+ sector_ids = []
+ set_project_multi_theme_id_requires(sector_ids)
if r.interactive:
if not r.component:
@@ -138,6 +147,10 @@ def prep(r):
(ttable.tag == "ISO2")
countries = db(query).select(ttable.value)
settings.gis.countries = [c.value for c in countries]
+
+ # Filter Activity Type based on Sector
+ set_project_multi_activity_type_id_requires(sector_ids)
+ #@ToDo: Do this for project_activity too.
elif r.component_name == "task":
r.component.table.milestone_id.requires = IS_NULL_OR(IS_ONE_OF(db,
"project_milestone.id",
@@ -228,6 +241,77 @@ def postp(r, output):
"project", # Need to specify as sometimes we come via index()
rheader=rheader,
csv_template="project")
+# -----------------------------------------------------------------------------
+def set_project_multi_theme_id_requires(sector_ids):
+ """
+ Filters the multi_theme_id based on the sector_id
+ """
+
+ table = s3db.project_project
+ ttable = s3db.project_theme
+ tstable = s3db.project_theme_sector
+
+ # All themes linked to the projects sectors or to no sectors
+ rows = db().select(ttable.id,
+ tstable.sector_id,
+ left=tstable.on(ttable.id == tstable.theme_id))
+ theme_ids = [row.project_theme.id for row in rows
+ if not row.project_theme_sector.sector_id or
+ row.project_theme_sector.sector_id[0] in sector_ids]
+ table.multi_theme_id.requires = IS_NULL_OR(
+ IS_ONE_OF(db,
+ "project_theme.id",
+ s3db.project_theme_represent,
+ filterby="id",
+ filter_opts=theme_ids,
+ sort=True,
+ multiple=True
+ )
+ )
+
+# -----------------------------------------------------------------------------
+def set_project_multi_activity_type_id_requires(sector_ids):
+ """
+ Filters the multi_activity_type_id based on the sector_id
+ """
+
+ # @ToDo: merge with set_project_multi_theme_id_requires?
+ table = s3db.project_location
+ attable = s3db.project_activity_type
+ atstable = s3db.project_activity_type_sector
+
+ # All activity_types linked to the projects sectors or to no sectors
+ rows = db().select(attable.id,
+ atstable.sector_id,
+ left=atstable.on(attable.id == atstable.activity_type_id))
+ activity_type_ids = [row.project_activity_type.id for row in rows
+ if not row.project_activity_type_sector.sector_id or
+ row.project_activity_type_sector.sector_id[0] in sector_ids]
+ table.multi_activity_type_id.requires = IS_NULL_OR(
+ IS_ONE_OF(db,
+ "project_activity_type.id",
+ s3db.project_activity_type_represent,
+ filterby="id",
+ filter_opts=activity_type_ids,
+ sort=True,
+ multiple=True
+ )
+ )
+
+# -----------------------------------------------------------------------------
+def project_multi_theme_id_widget():
+ """
+ Used by the project controller to return dynamically generated
+ multi_theme_id widget based on sector_id
+ """
+ ptable = s3db.project_project
+ sector_ids = [int(id) for id in request.vars.sector_ids.split(",") if id]
+ value = [int(id) for id in request.vars.value.split(",") if id]
+
+ set_project_multi_theme_id_requires(sector_ids)
+ widget = ptable.multi_theme_id.widget(ptable.multi_theme_id,
+ value)
+ return widget
# =============================================================================
def status():
@@ -275,7 +359,7 @@ def organisation():
(T("Basic Details"), None),
(T("Projects"), "project"),
(T("Contacts"), "human_resource"),
- ]
+ ]
rheader = lambda r: s3db.org_rheader(r, tabs)
return s3_rest_controller("org", resourcename,
rheader=rheader)
@@ -373,7 +457,13 @@ def location():
# Pre-process
def prep(r):
if r.interactive:
- if r.component is not None:
+ if r.record and r.record.project_id:
+ sector_ids = ptable[r.record.project_id].sector_id
+ else:
+ sector_ids = []
+ set_project_multi_activity_type_id_requires(sector_ids)
+
+ if r.component:
if r.component_name == "document":
doc_table = s3db.doc_document
doc_table.organisation_id.readable = False
@@ -452,6 +542,11 @@ def represent(record, field):
return s3_rest_controller(interactive_report=True,
rheader=s3db.project_rheader,
csv_template="location")
+# -----------------------------------------------------------------------------
+def demographic_data():
+ """ RESTful CRUD controller """
+
+ return s3db.stats_demographic_data_controller()
# -----------------------------------------------------------------------------
def community_contact():
11 modules/eden/asset.py
View
@@ -162,6 +162,7 @@ def model(self):
'Field':'site_id',
'FieldResource':'site',
'FieldPrefix':'org',
+ 'FieldID':'site_id'
})
})'''),),
# This is a component, so needs to be a super_link
@@ -344,7 +345,10 @@ def model(self):
#"L2",
#"L3",
"comments",
- ])
+ ],
+ realm_components = ["log", "presence"],
+ update_realm = True,
+ )
# Log as component of Assets
add_component("asset_log", asset_asset="asset_id")
@@ -576,11 +580,6 @@ def asset_onaccept(form):
vars = form.vars
atable = db.asset_asset
- # Update asset realm_entity and components' realm_entity
- auth.set_realm_entity(atable, vars, force_update=True)
- auth.set_component_realm_entity(atable, vars,
- update_components = ["log", "presence"])
-
site_id = vars.get("site_id", None)
if site_id:
asset_id = vars.id
13 modules/eden/gis.py
View
@@ -1369,10 +1369,7 @@ def model(self):
onvalidation=self.gis_config_onvalidation,
onaccept=self.gis_config_onaccept,
create_next=URL(args=["[id]", "layer_entity"]),
- # @ToDo: Not currently allowing delete, but with some
- # restrictions, we could.
- #delete_onaccept=self.gis_config_ondelete,
- update_ondelete=self.gis_config_ondelete,
+ ondelete=self.gis_config_ondelete,
subheadings = {
T("Map Settings"): "zoom",
T("Form Settings"): "default_location_id",
@@ -1683,16 +1680,14 @@ def gis_config_onaccept(form):
# -------------------------------------------------------------------------
@staticmethod
- def gis_config_ondelete(form):
+ def gis_config_ondelete(row):
"""
If the currently-active config was deleted, clear the cache
"""
- record_id = form.record_id
s3 = current.response.s3
- if s3.gis.config:
- gis_config_id = s3.gis.config.id
- if record_id == gis_config_id:
+ if s3.gis.config and \
+ s3.gis.config.id == row.id:
s3.gis.config = None
# -------------------------------------------------------------------------
8 modules/eden/hrm.py
View
@@ -472,6 +472,8 @@ def model(self):
),
create_next = hrm_url,
update_next = hrm_url,
+ realm_components = ["presence"],
+ update_realm = True,
)
# ---------------------------------------------------------------------
@@ -3262,9 +3264,6 @@ def hrm_human_resource_onaccept(form):
# Affiliation, record ownership and component ownership
s3db.pr_update_affiliations(htable, record)
- auth.set_realm_entity(htable, record, force_update=True)
- auth.set_component_realm_entity(htable, vars,
- update_components = ["presence"])
# Realm_entity for the pr_person record
ptable = s3db.pr_person
@@ -3278,9 +3277,6 @@ def hrm_human_resource_onaccept(form):
auth.set_realm_entity(ptable, person,
entity = entity,
force_update = True)
- auth.set_component_realm_entity(ptable, person,
- entity = entity,
- update_components = ["presence"])
site_id = record.site_id
site_contact = record.site_contact
40 modules/eden/inv.py
View
@@ -286,7 +286,26 @@ def model(self):
#"location_id$L4",
"phone1",
"email"
- ])
+ ],
+ realm_components = ["contact_emergency",
+ "physical_description",
+ "config",
+ "image",
+ "req",
+ "send",
+ "human_resource_site",
+ "note",
+ "contact",
+ "role",
+ "asset",
+ "commit",
+ "inv_item",
+ "document",
+ "recv",
+ "address",
+ ],
+ update_realm = True,
+ )
# ---------------------------------------------------------------------
# Pass variables back to global scope (s3db.*)
@@ -341,25 +360,6 @@ def inv_warehouse_onaccept(form):
# Affiliation, record ownership and component ownership
s3db.pr_update_affiliations(wtable, vars)
- auth.set_realm_entity(wtable, vars, force_update=True)
- auth.set_component_realm_entity(wtable, vars,
- update_components = ["contact_emergency",
- "physical_description",
- "config",
- "image",
- "req",
- "send",
- "human_resource_site",
- "note",
- "contact",
- "role",
- "asset",
- "commit",
- "inv_item",
- "document",
- "recv",
- "address",
- ])
# ---------------------------------------------------------------------
@staticmethod
10 modules/eden/member.py
View
@@ -265,7 +265,9 @@ def member_type_opts():
"location_id$L2",
"location_id$L3",
"location_id$L4",
- ])
+ ],
+ update_realm=True,
+ )
# ---------------------------------------------------------------------
# Pass variables back to global scope (s3db.*)
@@ -338,8 +340,6 @@ def member_onaccept(form):
# Affiliation, record ownership and component ownership
s3db.pr_update_affiliations(mtable, record)
- auth.set_realm_entity(mtable, record, force_update=True)
- auth.set_component_realm_entity(mtable, record)
# realm_entity for the pr_person record
person_id = record.person_id
@@ -352,10 +352,6 @@ def member_onaccept(form):
auth.set_realm_entity(ptable, person,
entity = entity,
force_update = True)
- auth.set_component_realm_entity(ptable, person,
- entity = entity,
- update_components = [])
-
# Update the location ID from the Home Address
atable = s3db.pr_address
41 modules/eden/org.py
View
@@ -687,6 +687,7 @@ def model(self):
return Storage(
org_sector_id=sector_id,
org_sector_opts=self.org_sector_opts,
+ org_sector_represent = self.org_sector_represent,
org_organisation_type_id=organisation_type_id,
org_organisation_id=organisation_id,
)
@@ -1024,9 +1025,9 @@ def org_branch_duplicate(item):
def org_branch_onvalidation(form):
"""
Prevent an Organisation from being a Branch of itself
+ - this is for interactive forms, imports are caught in .xsl
"""
- # @ToDo: This ctaches manual creation but need to catch Imports somehow
vars = form.request_vars
if vars and \
vars.branch_id and \
@@ -1915,7 +1916,25 @@ def model(self):
#"location_id$L4",
"phone1",
"email"
- ])
+ ],
+ realm_components=["contact_emergency",
+ "config",
+ "image",
+ "req",
+ "send",
+ "human_resource_site",
+ "note",
+ "contact",
+ "role",
+ "asset",
+ "commit",
+ "inv_item",
+ "document",
+ "recv",
+ "address",
+ ],
+ update_realm=True,
+ )
if current.deployment_settings.get_org_summary():
add_component("org_office_summary",
@@ -1997,24 +2016,6 @@ def org_office_onaccept(form):
# Affiliation, record ownership and component ownership
s3db.pr_update_affiliations(otable, vars)
- auth.set_realm_entity(otable, vars, force_update=True)
- auth.set_component_realm_entity(otable, vars,
- update_components = ["contact_emergency",
- "config",
- "image",
- "req",
- "send",
- "human_resource_site",
- "note",
- "contact",
- "role",
- "asset",
- "commit",
- "inv_item",
- "document",
- "recv",
- "address",
- ])
if current.deployment_settings.get_org_summary():
15 modules/eden/pr.py
View
@@ -536,7 +536,7 @@ def model(self):
pr_gender = S3ReusableField("gender", "integer",
requires = IS_IN_SET(pr_gender_opts, zero=None),
default = 1,
- label = T("Gender"),
+ label = T("Sex"),
represent = lambda opt: \
pr_gender_opts.get(opt, UNKNOWN_OPT))
@@ -747,7 +747,8 @@ def model(self):
search_method=pr_person_search,
deduplicate=self.person_deduplicate,
main="first_name",
- extra="last_name"
+ extra="last_name",
+ realm_components = ["presence"],
)
person_id_comment = pr_person_comment(
@@ -2511,7 +2512,7 @@ def model(self):
super_entity = "sit_situation",
onvalidation = self.presence_onvalidation,
onaccept = self.presence_onaccept,
- delete_onaccept = self.presence_onaccept,
+ ondelete = self.presence_onaccept,
list_fields = ["id",
"datetime",
"location_id",
@@ -2612,9 +2613,11 @@ def presence_onaccept(form):
elif hasattr(form, "vars"):
id = form.vars.id
else:
+ # e.g. Row like for delete
id = form.id
- presence = db(table.id == id).select(table.ALL, limitby=(0,1)).first()
+ presence = db(table.id == id).select(table.ALL,
+ limitby=(0, 1)).first()
if not presence:
return
else:
@@ -2660,7 +2663,7 @@ def presence_onaccept(form):
if not presence.closed:
- # Re-open the last persistant presence if no closing event
+ # Re-open the last persistent presence if no closing event
query = this_entity & is_present
presence = db(query).select(table.ALL, orderby=~table.datetime, limitby=(0,1)).first()
if presence and presence.closed:
@@ -2669,7 +2672,7 @@ def presence_onaccept(form):
if not db(query).count():
db(table.id == presence.id).update(closed=False)
- # Re-open the last missing if no later persistant presence
+ # Re-open the last missing if no later persistent presence
query = this_entity & is_missing
presence = db(query).select(table.ALL, orderby=~table.datetime, limitby=(0,1)).first()
if presence and presence.closed:
280 modules/eden/project.py
View
@@ -83,12 +83,14 @@ class S3ProjectModel(S3Model):
names = ["project_status",
"project_theme",
+ "project_theme_sector",
"project_theme_id",
"project_theme_opts",
"project_hazard",
"project_hfa_opts",
"project_project",
"project_activity_type",
+ "project_activity_type_sector",
"project_project_id",
"project_multi_activity_type_id",
]
@@ -229,6 +231,45 @@ def model(self):
# Projects
add_component("project_theme_percentage", project_theme="theme_id")
+ crud_form = s3forms.S3SQLCustomForm(
+ "name",
+ # Project Organisations
+ s3forms.S3SQLInlineComponent(
+ "theme_sector",
+ label=T("Theme Sectors"),
+ fields=["sector_id"],
+ ),
+ )
+
+ configure(tablename,
+ crud_form=crud_form)
+
+ # ---------------------------------------------------------------------
+ # Theme - Sector Link Table
+ #
+ tablename = "project_theme_sector"
+ location = current.session.s3.location_filter
+ if location:
+ filterby = "location_id"
+ filter_opts = (location, None)
+ else:
+ filterby = None
+ filter_opts = (None,)
+ table = define_table(tablename,
+ theme_id(),
+ self.org_sector_id(
+ label = "",
+ requires=IS_ONE_OF(db, "org_sector.id",
+ self.org_sector_represent,
+ sort=True,
+ filterby=filterby,
+ filter_opts=filter_opts),
+ ),
+ *s3_meta_fields())
+
+ add_component(tablename, project_theme="theme_id")
+ add_component(tablename, org_sector="sector_id")
+
# ---------------------------------------------------------------------
# Hazard
# @ToDo: Move to link table to move to S3ProjectDRRModel
@@ -300,7 +341,6 @@ def model(self):
label = org_label,
requires = self.org_organisation_requires(updateable=True,
required=True),
- widget = None,
),
Field("name", unique = True,
label = T("Name"),
@@ -344,12 +384,6 @@ def model(self):
readable = False if multi_budgets else True,
writable = False if multi_budgets else True,
),
- sector_id(
- readable = use_sectors,
- writable = use_sectors,
- widget = lambda f, v: \
- CheckboxesWidgetS3.widget(f, v, cols=3),
- ),
countries_id(
readable = mode_3w,
writable = mode_3w
@@ -358,11 +392,29 @@ def model(self):
readable = mode_drr,
writable = mode_drr
),
+ sector_id(
+ readable = use_sectors,
+ writable = use_sectors,
+ widget = lambda f, v: \
+ CheckboxesWidgetS3.widget(f, v, cols=3),
+ ),
multi_theme_id(
readable = mode_3w and \
not theme_percentages,
writable = mode_3w and \
not theme_percentages,
+ script = SCRIPT('''
+$(document).ready(function(){
+ S3FilterFieldChange({
+ 'FilterField':'sector_id',
+ 'Field':'multi_theme_id',
+ 'Widget':'multi_theme_id_widget',
+ 'FieldResource':'theme',
+ 'url':S3.Ap.concat('/project/project_multi_theme_id_widget?sector_ids='),
+ 'GetWidgetHTML':true,
+ 'FilterOnLoad':false,
+ })
+})'''),
),
Field("hfa", "list:integer",
label = T("HFA Priorities"),
@@ -540,8 +592,21 @@ def model(self):
aggregate="count",
totals=True
)
- )
- )
+ ),
+ realm_components = ["human_resource",
+ "task",
+ "organisation",
+ "activity",
+ "annual_budget",
+ "beneficiary",
+ "location",
+ "milestone",
+ "theme_percentage",
+ "document",
+ "image",
+ ],
+ update_realm=True,
+ )
# Reusable Field
project_id = S3ReusableField("project_id", table,
@@ -698,14 +763,48 @@ def model(self):
CheckboxesWidgetS3.widget(f, v, cols=3),
ondelete = "RESTRICT")
+ crud_form = s3forms.S3SQLCustomForm(
+ "name",
+ # Project Organisations
+ s3forms.S3SQLInlineComponent(
+ "activity_type_sector",
+ label=T("Activity Type Sectors"),
+ fields=["sector_id"],
+ ),
+ )
+
+ configure(tablename,
+ crud_form=crud_form)
+
+ # ---------------------------------------------------------------------
+ # Activity Type - Sector Link Table
+ #
+ tablename = "project_activity_type_sector"
+ table = define_table(tablename,
+ activity_type_id(),
+ self.org_sector_id(
+ label = "",
+ requires=IS_ONE_OF(db, "org_sector.id",
+ self.org_sector_represent,
+ sort=True,
+ filterby=filterby,
+ filter_opts=filter_opts),
+ ),
+ *s3_meta_fields())
+
+ add_component(tablename, project_activity_type="activity_type_id")
+ add_component(tablename, org_sector="sector_id") # Doesn't Work???
+
# ---------------------------------------------------------------------
# Pass variables back to global scope (s3db.*)
#
return dict(
project_project_id = project_id,
project_multi_activity_type_id = multi_activity_type_id,
+ project_activity_type_represent = self.project_activity_type_represent,
project_theme_id = theme_id,
project_hfa_opts = project_hfa_opts,
+ project_theme_represent = project_theme_represent,
project_theme_opts = self.project_theme_opts,
)
@@ -751,21 +850,6 @@ def project_project_onaccept(form):
ptable = db.project_project
otable = db.project_organisation
vars = form.vars
- # Update asset realm_entity and components' realm_entity
- auth.set_realm_entity(ptable, vars, force_update=True)
- auth.set_component_realm_entity(ptable, vars,
- update_components = ["human_resource",
- "task",
- "organisation",
- "activity",
- "annual_budget",
- "beneficiary",
- "location",
- "milestone",
- "theme_percentage",
- "document",
- "image",
- ])
lead_role = current.deployment_settings.get_project_organisation_lead_role()
@@ -1141,7 +1225,7 @@ class S3Project3WModel(S3Model):
names = ["project_beneficiary_type",
"project_beneficiary",
"project_location",
- "project_community_contact",
+ "project_location_contact",
"project_organisation",
"project_organisation_roles",
"project_organisation_lead_role",
@@ -1190,13 +1274,6 @@ def model(self):
readable = theme_percentages,
writable = False,
),
- # @ToDo: This duplicates the data in gis_location
- # - move to stats_demographic_data
- Field("population", "integer",
- label = T("Population")),
- # @ToDo: Replace with a 'family size' value & auto-calculate?
- Field("number_families", "integer",
- label = T("Number of Families")),
s3_comments(),
*s3_meta_fields())
@@ -1403,7 +1480,7 @@ def model(self):
add_component("pr_person",
project_location=Storage(
name="contact",
- link="project_community_contact",
+ link="project_location_contact",
joinby="project_location_id",
key="person_id",
actuate="hide",
@@ -1412,7 +1489,7 @@ def model(self):
# ---------------------------------------------------------------------
# Project Community Contact Person
#
- tablename = "project_community_contact"
+ tablename = "project_location_contact"
table = define_table(tablename,
project_location_id(),
person_id(widget=S3AddPersonWidget(controller="pr"),
@@ -1420,7 +1497,7 @@ def model(self):
comment=None),
*s3_meta_fields())
- table.virtualfields.append(S3ProjectCommunityContactVirtualFields())
+ table.virtualfields.append(S3ProjectLocationContactVirtualFields())
# CRUD Strings
ADD_CONTACT = T("Add Contact")
@@ -1483,9 +1560,12 @@ def model(self):
#
tablename = "project_beneficiary_type"
table = define_table(tablename,
+ super_link("parameter_id", "stats_parameter"),
Field("name", length=128, unique=True,
requires = IS_NOT_IN_DB(db,
"project_beneficiary_type.name")),
+ s3_comments("description",
+ label = T("Description")),
*s3_meta_fields())
# Field configuration?
@@ -1509,32 +1589,50 @@ def model(self):
# Search Method?
- # Resource Configuration?
+ # Resource Configuration
+ configure(tablename,
+ super_entity = "stats_parameter",
+ )
+
# Reusable Field
- beneficiary_type_id = S3ReusableField("beneficiary_type_id", table,
- requires = IS_NULL_OR(
- IS_ONE_OF(db, "project_beneficiary_type.id",
- self.project_beneficiary_type_represent)),
- represent = self.project_beneficiary_type_represent,
- label = T("Beneficiary Type"),
- comment = S3AddResourceLink(c="project",
+ beneficiary_type_param_id = S3ReusableField("parameter_id", table,
+ sortby="name",
+ requires = IS_ONE_OF(db, "stats_parameter.parameter_id",
+ self.stats_parameter_represent,
+ orderby="stats_parameter.name",
+ filterby = "instance_type",
+ filter_opts = ["project_beneficiary_type"],
+ sort=True),
+ represent = self.stats_parameter_represent,
+ label = T("Beneficiary Type"),
+ comment = S3AddResourceLink(c="project",
f="beneficiary_type",
+ vars = dict(child = "parameter_id"),
title=ADD_BNF_TYPE,
tooltip=T("Please record Beneficiary according to the reporting needs of your project")),
- ondelete = "CASCADE")
+ ondelete = "CASCADE"
+ )
# ---------------------------------------------------------------------
# Project Beneficiary
#
tablename = "project_beneficiary"
table = define_table(tablename,
+ # Link Fields
# populated automatically
project_id(readable=False,
writable=False),
- #activity_id(comment=None),
project_location_id(comment=None),
- beneficiary_type_id(empty=False),
+
+ # stats_data Fields
+ super_link("data_id", "stats_data"),
+ beneficiary_type_param_id(),
+ # populated automatically
+ self.gis_location_id(readable = False,
+ writable = False),
+ self.stats_group_id(readable = False,
+ writable = False),
Field("value", "double",
label = T("Quantity"),
requires = IS_INT_IN_RANGE(0, 99999999),
@@ -1576,7 +1674,7 @@ def model(self):
report_fields=[
#"activity_id",
"project_location_id",
- (T("Beneficiary Type"), "beneficiary_type_id"),
+ (T("Beneficiary Type"), "parameter_id"),
"project_id",
(T("Year"), "year"),
"project_id$multi_hazard_id",
@@ -1660,6 +1758,7 @@ def beneficiary_L1_opts():
return od
configure(tablename,
+ super_entity = "stats_data",
onaccept=self.project_beneficiary_onaccept,
deduplicate=self.project_beneficiary_deduplicate,
report_options=Storage(
@@ -1670,8 +1769,8 @@ def beneficiary_L1_opts():
label=T("Project")
),
S3SearchOptionsWidget(
- field="beneficiary_type_id",
- name="beneficiary_type_id",
+ field="parameter_id",
+ name="parameter_id",
label=T("Beneficiary Type")
),
# @ToDo: These do now work - no results are returned
@@ -1691,11 +1790,11 @@ def beneficiary_L1_opts():
],
rows=report_fields,
cols=report_fields,
- facts=["number"],
+ facts=["value"],
methods=["sum"],
defaults=Storage( rows="beneficiary.project_id",
- cols="beneficiary.beneficiary_type_id",
- fact="beneficiary.number",
+ cols="beneficiary.parameter_id",
+ fact="beneficiary.value",
aggregate="sum",
totals=True
)
@@ -1871,20 +1970,24 @@ def project_beneficiary_represent(id, row=None):
# ---------------------------------------------------------------------
@staticmethod
def project_beneficiary_onaccept(form):
- """ Record creation post-processing """
+ """
+ Update project_beneficiary project & location from project_location_id
+ """
db = current.db
btable = db.project_beneficiary
- ctable = db.project_location
+ ltable = db.project_location
record_id = form.vars.id
query = (btable.id == record_id) & \
- (ctable.id == btable.project_location_id)
- project_location = db(query).select(ctable.project_id,
+ (ltable.id == btable.project_location_id)
+ project_location = db(query).select(ltable.project_id,
+ ltable.location_id,
limitby=(0, 1)).first()
if project_location:
db(btable.id == record_id).update(
- project_id=project_location.project_id
+ project_id = project_location.project_id,
+ location_id = project_location.location_id
)
return
@@ -1897,13 +2000,13 @@ def project_beneficiary_deduplicate(item):
return
data = item.data
- if "beneficiary_type_id" in data and \
+ if "parameter_id" in data and \
"project_location_id" in data:
# Match beneficiary by type and activity_id
table = item.table
- beneficiary_type_id = data.beneficiary_type_id
+ parameter_id = data.parameter_id
project_location_id = data.project_location_id
- query = (table.beneficiary_type_id == beneficiary_type_id) & \
+ query = (table.parameter_id == parameter_id) & \
(table.project_location_id == project_location_id)
duplicate = current.db(query).select(table.id,
limitby=(0, 1)).first()
@@ -4499,13 +4602,16 @@ def year(self):
date = project.date
if not end_date:
end_date = project.end_date
- if not date or not end_date:
+ if not date and not end_date:
+ return []
+ elif not date or not end_date:
return [date.year or end_date.year]
- return [year for year in xrange(date.year, end_date.year + 1)]
+ else:
+ return [year for year in xrange(date.year, end_date.year + 1)]
# =============================================================================
-class S3ProjectCommunityContactVirtualFields:
- """ Virtual fields for the project_community_contact table """
+class S3ProjectLocationContactVirtualFields:
+ """ Virtual fields for the project_location_contact table """
extra_fields = ["person_id"]
@@ -4517,7 +4623,7 @@ def email(self):
ctable = s3db.pr_contact
try:
- person_id = self.project_community_contact.person_id
+ person_id = self.project_location_contact.person_id
except AttributeError:
return "-"
@@ -4536,7 +4642,7 @@ def sms(self):
ctable = s3db.pr_contact
try:
- person_id = self.project_community_contact.person_id
+ person_id = self.project_location_contact.person_id
except AttributeError:
return "-"
@@ -4765,13 +4871,17 @@ def project_rheader(r, tabs=[]):
if r.representation != "html":
# RHeaders only used in interactive views
return None
- record = r.record
- if record is None:
- # List or Create form: rheader makes no sense here
+
+ # Need to use this as otherwise demographic_data?viewing=project_location.x
+ # doesn't have an rheader
+ tablename, record = s3_rheader_resource(r)
+ if not record:
return None
-
- table = r.table
+ s3db = current.s3db
+ table = s3db.table(tablename)
+
resourcename = r.name
+
T = current.T
auth = current.auth
settings = current.deployment_settings
@@ -4817,32 +4927,22 @@ def project_rheader(r, tabs=[]):
if settings.has_module("vol"):
append((T("Volunteers"), "human_resource", dict(group="volunteer")))
- rheader_tabs = s3_rheader_tabs(r, tabs)
-
- tbl = TABLE()
- append = tbl.append
- fields = ["code", "name", "organisation_id", "countries_id", "start_date", "end_date"]
- for field in fields:
- _field = table[field]
- if _field.readable and record[field]:
- represent = _field.represent(record[field]) if _field.represent else record[field]
- append(TR(
- TH("%s: " % _field.label),
- represent
- ))
-
- rheader = DIV(tbl, rheader_tabs)
+ rheader_fields = [["code", "name"], ["organisation_id", "countries_id"], ["start_date", "end_date"]]
+ rheader = S3ResourceHeader(rheader_fields, tabs)(r)
- elif resourcename == "location":
+ elif resourcename in ["location","demographic_data"]:
tabs = [(T("Details"), None),
(T("Beneficiaries"), "beneficiary"),
+ (T("Demographics"), "demographic_data/"),
(T("Contact People"), "contact"),
]
rheader_fields = []
if record.project_id is not None:
rheader_fields.append(["project_id"])
rheader_fields.append(["location_id"])
- rheader = S3ResourceHeader(rheader_fields, tabs)(r)
+ rheader = S3ResourceHeader(rheader_fields, tabs)(r,
+ record = record,
+ table = table)
elif resourcename == "framework":
tabs = [(T("Details"), None),
@@ -4867,9 +4967,6 @@ def project_rheader(r, tabs=[]):
rheader = S3ResourceHeader(rheader_fields, tabs)(r)
elif resourcename == "task":
- db = current.db
- s3db = current.s3db
-
# Tabs
tabs = [(T("Details"), None)]
append = tabs.append
@@ -4886,6 +4983,7 @@ def project_rheader(r, tabs=[]):
rheader_tabs = s3_rheader_tabs(r, tabs)
# RHeader
+ db = current.db
ptable = s3db.project_project
ltable = s3db.project_task_project
query = (ltable.deleted == False) & \
72 modules/eden/stats.py
View
@@ -31,6 +31,7 @@
"S3StatsDemographicModel",
"S3StatsGroupModel",
"stats_parameter_represent",
+ "stats_demographic_data_controller",
]
from gluon import *
@@ -70,8 +71,9 @@ def model(self):
vulnerability_indicator = T("Vulnerability Indicator"),
vulnerability_aggregated_indicator = T("Vulnerability Aggregated Indicator"),
stats_demographic = T("Demographic"),
+ project_beneficiary_type = T("Project Beneficiary Type"),
#survey_question_type = T("Survey Question Type"),
- #project_beneficary_type = T("Project Beneficiary Type"),
+
#climate_parameter = T("Climate Parameter"),
)
@@ -83,6 +85,7 @@ def model(self):
Field("description",
label = T("Description")),
)
+ table.instance_type.readable = True
# Reusable Field
param_id = S3ReusableField("parameter_id", table,
@@ -103,7 +106,7 @@ def model(self):
vulnerability_data = T("Vulnerability Data"),
stats_demographic_data = T("Demographic Data"),
#survey_answer = T("Survey Answer"),
- #project_beneficary = T("Project Beneficiary"),
+ project_beneficiary = T("Project Beneficiary"),
#climate_data = T("Climate Data"),
)
@@ -118,14 +121,15 @@ def model(self):
),
Field("value", "double",
label = T("Value")),
- Field("date", "date",
- label = T("Date")),
+ s3_date(),
+ s3_date("date_end",
+ label = T("End Date")),
self.stats_group_id(),
Field("approved_by", "integer",
default = None)
)
- self.configure("stats_data",
+ self.configure(tablename,
onapprove = self.stats_data_onapprove,
requires_approval = True,
)
@@ -861,11 +865,11 @@ def stats_demographic_duplicate(item):
if duplicate:
item.id = duplicate.id
item.method = item.METHOD.UPDATE
-
+
# =============================================================================
class S3StatsGroupModel(S3Model):
"""
- Table to hold the group details of the different stats records
+ Tables to hold the group details of the different stats records
"""
names = ["stats_group_type",
@@ -1109,6 +1113,60 @@ def stats_parameter_represent(id, row=None):
except:
return current.messages.UNKNOWN_OPT
+# =============================================================================
+def stats_demographic_data_controller():
+ """
+ Function to be called from controller functions to display all
+ requests as a tab for a site.
+ """
+
+ vars = current.request.vars
+
+ output = dict()
+
+ if "viewing" not in vars:
+ return output
+ else:
+ viewing = vars.viewing
+ if "." in viewing:
+ tablename, id = viewing.split(".", 1)
+ else:
+ return output
+
+ s3db = current.s3db
+ table = s3db[tablename]
+ location_id = current.db(table.id == id).select(table.location_id,
+ limitby=(0, 1)
+ ).first().location_id
+
+ s3 = current.response.s3
+ dtable = s3db.stats_demographic_data
+
+ field = dtable.location_id
+ s3.filter = (field == location_id)
+ field.default = location_id
+ field.readable = False
+ field.writable = False
+
+ dtable.group_id.readable = False
+ dtable.group_id.writable = False
+
+ # Post-process
+ def postp(r, output):
+ if r.representation == "html":
+ output["title"] = s3.crud_strings[tablename].title_display
+ return output
+ s3.postp = postp
+
+ if tablename == "project_location":
+ rheader = s3db.project_rheader
+ else:
+ rheader = None
+
+ output = current.rest_controller("stats", "demographic_data",
+ rheader=rheader)
+
+ return output
# =============================================================================
def stats_group_type_represent(id, row=None):
22 modules/eden/vulnerability.py
View
@@ -140,13 +140,13 @@ def model(self):
table = define_table(tablename,
super_link("data_id", "stats_data"),
self.stats_param_id(
- label = T("Indicator"),
- requires = IS_ONE_OF(db, "stats_parameter.parameter_id",
- self.stats_parameter_represent,
- filterby="instance_type",
- filter_opts=["vulnerability_indicator"],
- orderby="stats_parameter.name",
- sort=True)
+ label = T("Indicator"),
+ requires = IS_ONE_OF(db, "stats_parameter.parameter_id",
+ self.stats_parameter_represent,
+ filterby="instance_type",
+ filter_opts=["vulnerability_indicator"],
+ orderby="stats_parameter.name",
+ sort=True)
),
self.gis_location_id(
widget = S3LocationAutocompleteWidget(),
@@ -154,8 +154,12 @@ def model(self):
),
Field("value", "double",
label = T("Value")),
- Field("date", "date",
- label = T("Date")),
+ s3_date(),
+ # Unused but needed for the stats_data SE
+ Field("date_end", "date",
+ readable=False,
+ writable=False
+ ),
self.stats_group_id(),
*s3_meta_fields()
)
67 modules/s3/s3aaa.py
View
@@ -3385,7 +3385,7 @@ def s3_clear_session_ownership(self, table=None, record_id=None):
return
# -------------------------------------------------------------------------
- def s3_update_record_owner(self, table, record, **fields):
+ def s3_update_record_owner(self, table, record, update=False, **fields):
"""
Update the ownership for a record
@@ -3411,7 +3411,29 @@ def s3_update_record_owner(self, table, record, **fields):
if key in ownership_fields:
data[key] = fields[key]
if data:
- success = current.db(table._id == record_id).update(**data)
+ s3db = current.s3db
+ db = current.db
+
+ # Update record
+ q = (table._id == record_id)
+ success = db(q).update(**data)
+
+ # Update realm-components
+ if success and update and REALM in data:
+ rc = s3db.get_config(table, "realm_components", [])
+ resource = s3db.resource(table, components=rc)
+ realm = {REALM:data[REALM]}
+ for component in resource.components.values():
+ ctable = component.table
+ if REALM not in ctable.fields:
+ continue
+ query = component.get_join() & q
+ rows = db(query).select(ctable._id)
+ ids = list(set([row[ctable._id] for row in rows]))
+ if ids:
+ db(ctable._id.belongs(ids)).update(**realm)
+
+ # Update super-entity
self.update_shared_fields(table, record, **data)
else:
return None
@@ -3548,7 +3570,7 @@ def s3_set_record_owner(self,
entity=entity)
data[REALM] = realm_entity
- self.s3_update_record_owner(table, row, **data)
+ self.s3_update_record_owner(table, row, update=force_update, **data)
return
# -------------------------------------------------------------------------
@@ -3648,8 +3670,8 @@ def set_realm_entity(self, table, records, entity=0, force_update=False):
realm_entity = self.get_realm_entity(table, row,
entity=realm_entity)
data = {REALM:realm_entity}
- db(q).update(**data)
- self.update_shared_fields(table, record_id, **data)
+ self.s3_update_record_owner(table, row,
+ update=force_update, **data)
return
@@ -3716,41 +3738,6 @@ def get_realm_entity(self, table, record, entity=0):
return realm_entity
# -------------------------------------------------------------------------
- def set_component_realm_entity(self, table, record, entity=0,
- force_update=True,
- update_components=[]):
- """
- Update the realm entity for a record and it's components
-
- @param table: the table
- @param record: the record (as Row or dict)
- @param entity: the entity (pe_id)
- """
-
- s3db = current.s3db
-
- if not entity:
- entity = self.get_realm_entity(table, record)
-
- # Find Record Components
- resource = s3db.resource(table, components = update_components)
- components = resource.components
-
- # Update Components
- for component in components:
- c = components[component]
- if not c:
- continue
- query = c.get_join() & (table._id == record.id)
- rows = current.db(query).select(c.table.id)
- self.set_realm_entity(c.table, rows, entity,
- force_update=force_update)
- # @ToDo: Check if we need to update component Super Links
-
- # Update Super Links
- s3db.update_super(table, record)
-
- # -------------------------------------------------------------------------
def update_shared_fields(self, table, record, **data):
"""
Update the shared fields in data in all super-entity rows linked
18 modules/s3/s3crud.py
View
@@ -2000,6 +2000,7 @@ def _postprocess_embedded(self, form,
db = current.db
s3db = current.s3db
+ auth = current.auth
request = current.request
T = current.T
@@ -2029,8 +2030,13 @@ def _postprocess_embedded(self, form,
else:
form.errors.update(_form.errors)
return
- # Super-entity update
+ # Update super-entity links
s3db.update_super(table, dict(id=selected))
+ # Update realm
+ update_realm = s3db.get_config(table, "update_realm")
+ if update_realm:
+ auth.set_realm_entity(table, selected,
+ force_update=True)
# Onaccept
onaccept = get_config("update_onaccept") or \
get_config("onaccept")
@@ -2048,10 +2054,14 @@ def _postprocess_embedded(self, form,
return
if selected:
# Update post_vars and form.vars
- request.post_vars.update({key:str(selected)})
- form.vars.update({key:selected})
- # Super-entity update
+ request.post_vars[key] = str(selected)
+ form.request_vars[key] = str(selected)
+ form.vars[key] = selected
+ # Update super-entity links
s3db.update_super(table, dict(id=selected))
+ # Set record owner
+ auth.s3_set_record_owner(table, selected)
+ auth.s3_make_session_owner(table, selected)
# Onaccept
onaccept = get_config("create_onaccept") or \
get_config("onaccept")
36 modules/s3/s3forms.py
View
@@ -409,6 +409,8 @@ def process(self, form, vars,
@todo: describe arguments
"""
+ s3db = current.s3db
+
manager = current.manager
audit = manager.audit
table = self.table
@@ -423,9 +425,9 @@ def process(self, form, vars,
if link and link.postprocess:
postprocess = link.postprocess
if isinstance(onvalidation, list):
- onvalidation.append(postprocess)
+ onvalidation.insert(0, postprocess)
elif onvalidation is not None:
- onvalidation = [onvalidation, postprocess]
+ onvalidation = [postprocess, onvalidation]
else:
onvalidation = [postprocess]
@@ -454,7 +456,7 @@ def process(self, form, vars,
vars = form.vars
# Update super entity links
- current.s3db.update_super(table, vars)
+ s3db.update_super(table, vars)
# Update component link
if link and link.postprocess is None:
@@ -463,11 +465,17 @@ def process(self, form, vars,
resource.update_link(master, vars)
if vars.id:
+ auth = current.auth
if record_id is None:
- # Set record ownership
- auth = current.auth
+ # Set record owner
auth.s3_set_record_owner(table, vars.id)
auth.s3_make_session_owner(table, vars.id)
+ else:
+ # Update realm
+ update_realm = s3db.get_config(table, "update_realm")
+ if update_realm:
+ auth.set_realm_entity(table, vars,
+ force_update=True)
# Store session vars
self.resource.lastid = str(vars.id)
manager.store_session(prefix, name, vars.id)
@@ -954,9 +962,15 @@ def _accept(self, record_id, data, alias=None, format=None):
if accept_id:
if record_id is None:
- # Set record ownership
+ # Set record owner
auth.s3_set_record_owner(table, accept_id)
auth.s3_make_session_owner(table, accept_id)
+ else:
+ # Update realm
+ update_realm = s3db.get_config(table, "update_realm")
+ if update_realm:
+ auth.set_realm_entity(table, vars,
+ force_update=True)
# Store session vars
component.lastid = str(accept_id)
@@ -1682,7 +1696,14 @@ def accept(self, form, master_id=None, format=None):
if success:
audit("update", prefix, name,
record=record_id, representation=format)
+ # Update super entity links
s3db.update_super(table, values)
+ # Update realm
+ update_realm = s3db.get_config(table, "update_realm")
+ if update_realm:
+ auth.set_realm_entity(table, vars,
+ force_update=True)
+ # Onaccept
manager.onaccept(table, Storage(vars=values),
method="update")
else:
@@ -1712,8 +1733,11 @@ def accept(self, form, master_id=None, format=None):
audit("create", prefix, name,
record=record_id, representation=format)
values[table._id.name] = record_id
+ # Update super entity link
s3db.update_super(table, values)
+ # Set record owner
auth.s3_set_record_owner(table, record_id)
+ # onaccept
manager.onaccept(table, Storage(vars=values),
method="create")
else:
125 modules/s3/s3import.py
View
@@ -1834,6 +1834,9 @@ def parse(self,
# -------------------------------------------------------------------------
def deduplicate(self):
+ """
+ Detect whether this is an update or a new record
+ """
RESOLVER = "deduplicate"
@@ -1873,18 +1876,11 @@ def authorize(self):
if not self.table:
return False
- manager = current.manager
-
prefix = self.tablename.split("_", 1)[0]
- if prefix in manager.PROTECTED:
+ if prefix in current.manager.PROTECTED:
return False
- authorize = manager.permit
- if authorize:
- self.permitted = False
- else:
- self.permitted = True
-
+ # Determine the method
self.method = self.METHOD.CREATE
if self.id:
@@ -1899,13 +1895,18 @@ def authorize(self):
if self.original:
self.method = self.METHOD.UPDATE
+ # Set self.id
if self.method == self.METHOD.CREATE:
self.id = 0
+ # Authorization
+ authorize = current.auth.s3_has_permission
if authorize:
self.permitted = authorize(self.method,
self.tablename,
record_id=self.id)
+ else:
+ self.permitted = True
return self.permitted
@@ -1921,11 +1922,13 @@ def validate(self):
self.accepted = False
return False
- form = Storage()
- form.method = self.method
- form.vars = self.data
+ form = Storage(method = self.method,
+ vars = self.data,
+ request_vars = self.data)
+
if self.id:
form.vars.id = self.id
+
form.errors = Storage()
tablename = self.tablename
key = "%s_onvalidation" % self.method
@@ -1975,6 +1978,9 @@ def commit(self, ignore_errors=False):
_debug("Committing item %s" % self)
+ METHOD = self.METHOD
+ POLICY = self.POLICY
+
db = current.db
s3db = current.s3db
xml = current.xml
@@ -2024,12 +2030,13 @@ def commit(self, ignore_errors=False):
self.skip = True
return ignore_errors
- _debug("Method: %s" % self.method)
+ method = self.method
+ _debug("Method: %s" % method)
# Check if import method is allowed in strategy
if not isinstance(self.strategy, (list, tuple)):
self.strategy = [self.strategy]
- if self.method not in self.strategy:
+ if method not in self.strategy:
_debug("Method not in strategy - skip")
self.error = manager.ERROR.NOT_PERMITTED
self.skip = True
@@ -2037,7 +2044,7 @@ def commit(self, ignore_errors=False):
this = self.original
if not this and self.id and \
- self.method in (self.METHOD.UPDATE, self.METHOD.DELETE):
+ method in (METHOD.UPDATE, METHOD.DELETE):
query = (table.id == self.id)
this = db(query).select(limitby=(0, 1)).first()
this_mtime = None
@@ -2063,7 +2070,7 @@ def commit(self, ignore_errors=False):
self.conflict = True
if self.conflict and \
- self.method in (self.METHOD.UPDATE, self.METHOD.DELETE):
+ method in (METHOD.UPDATE, METHOD.DELETE):
_debug("Conflict: %s" % self)
if self.job.onconflict:
self.job.onconflict(self)
@@ -2073,15 +2080,30 @@ def commit(self, ignore_errors=False):
else:
data = Storage()
+ if isinstance(self.update_policy, dict):
+ def update_policy(f):
+ setting = self.update_policy
+ p = setting.get(f,
+ setting.get("__default__", POLICY.THIS))
+ if p not in POLICY:
+ return POLICY.THIS
+ return p
+ else:
+ def update_policy(f):
+ p = self.update_policy
+ if p not in POLICY:
+ return POLICY.THIS
+ return p
+
# Update existing record
- if self.method == self.METHOD.UPDATE:
+ if method == METHOD.UPDATE:
if this:
if "deleted" in this and this.deleted:
- policy = self._get_update_policy(None)
- if policy == self.POLICY.NEWER and \
+ policy = update_policy(None)
+ if policy == POLICY.NEWER and \
this_mtime and this_mtime > self.mtime or \
- policy == self.POLICY.MASTER and \
+ policy == POLICY.MASTER and \
(this_mci == 0 or self.mci != 1):
self.skip = True
return True
@@ -2098,13 +2120,13 @@ def commit(self, ignore_errors=False):
del data[f]
continue
remove = False
- policy = self._get_update_policy(f)
- if policy == self.POLICY.THIS:
+ policy = update_policy(f)
+ if policy == POLICY.THIS:
remove = True
- elif policy == self.POLICY.NEWER:
+ elif policy == POLICY.NEWER:
if this_mtime and this_mtime > self.mtime:
remove = True
- elif policy == self.POLICY.MASTER:
+ elif policy == POLICY.MASTER:
if this_mci == 0 or self.mci != 1:
remove = True
if remove:
@@ -2143,7 +2165,7 @@ def commit(self, ignore_errors=False):
self.committed = True
# Create new record
- elif self.method == self.METHOD.CREATE:
+ elif method == METHOD.CREATE:
# Do not apply field policy to UID and MCI
UID = xml.UID
@@ -2154,8 +2176,8 @@ def commit(self, ignore_errors=False):
del data[MCI]
for f in data:
- policy = self._get_update_policy(f)
- if policy == self.POLICY.MASTER and self.mci != 1:
+ policy = update_policy(f)
+ if policy == POLICY.MASTER and self.mci != 1:
del data[f]
if len(data) or self.components or self.references:
@@ -2183,18 +2205,18 @@ def commit(self, ignore_errors=False):
return True
# Delete local record
- elif self.method == self.METHOD.DELETE:
+ elif method == METHOD.DELETE:
if this:
if this.deleted:
self.skip = True
- policy = self._get_update_policy(None)
- if policy == self.POLICY.THIS:
+ policy = update_policy(None)
+ if policy == POLICY.THIS:
self.skip = True
- elif policy == self.POLICY.NEWER and \
+ elif policy == POLICY.NEWER and \
(this_mtime and this_mtime > self.mtime):
self.skip = True
- elif policy == self.POLICY.MASTER and \
+ elif policy == POLICY.MASTER and \
(this_mci == 0 or self.mci != 1):
self.skip = True
else:
@@ -2214,27 +2236,36 @@ def commit(self, ignore_errors=False):
_debug("Success: %s, id=%s %sd" % (self.tablename, self.id,
self.skip and "skippe" or \
- self.method))
+ method))
return True
# Audit + onaccept on successful commits
if self.committed:
form = Storage()
- form.method = self.method
+ form.method = method
form.vars = self.data
tablename = self.tablename
prefix, name = tablename.split("_", 1)
if self.id:
form.vars.id = self.id
if manager.audit is not None:
- manager.audit(self.method, prefix, name,
+ manager.audit(method, prefix, name,
form=form,
record=self.id,
representation="xml")
+ # Update super entity links
s3db.update_super(table, form.vars)
- if self.method == self.METHOD.CREATE:
+ if method == METHOD.CREATE:
+ # Set record owner
current.auth.s3_set_record_owner(table, self.id)
- key = "%s_onaccept" % self.method
+ elif method == METHOD.UPDATE:
+ # Update realm
+ update_realm = s3db.get_config(table, "update_realm")
+ if update_realm:
+ current.auth.set_realm_entity(table, self.id,
+ force_update=True)
+ # Onaccept
+ key = "%s_onaccept" % method
onaccept = s3db.get_config(tablename, key,
s3db.get_config(tablename, "onaccept"))
if onaccept:
@@ -2259,28 +2290,10 @@ def commit(self, ignore_errors=False):
_debug("Success: %s, id=%s %sd" % (self.tablename, self.id,
self.skip and "skippe" or \
- self.method))
+ method))
return True
# -------------------------------------------------------------------------
- def _get_update_policy(self, field):
- """
- Get the update policy for a field (if the item will
- update an existing record)
-
- @param field: the name of the field
- """
-
- if isinstance(self.update_policy, dict):
- r = self.update_policy.get(field,
- self.update_policy.get("__default__", self.POLICY.THIS))
- else:
- r = self.update_policy
- if not r in self.POLICY.values():
- r = self.POLICY.THIS
- return r
-
- # -------------------------------------------------------------------------
def _resolve_references(self):
"""
Resolve the references of this item (=look up all foreign
2  modules/s3/s3search.py
View
@@ -272,7 +272,7 @@ def widget(self,
self.name = attr._name
# Search Autocomplete - Display current value
- attr["_value"] = vars.get(self.name, value)
+ attr["_value"] = vars.get(self.name, value) if vars else value
return INPUT(**attr)
5 modules/s3/s3widgets.py
View
@@ -3385,7 +3385,8 @@ def s3_grouped_checkboxes_widget(field,
letters_options[letter].append((val, label))
widget = DIV(_class=attributes.pop("_class",
- "s3-grouped-checkboxes-widget"))
+ "s3-grouped-checkboxes-widget"),
+ _name = "%s_widget" % field.name)
input_index = 0
group_index = 0
@@ -3419,7 +3420,7 @@ def s3_grouped_checkboxes_widget(field,
widget.append(DIV(group_label,
_id="%s-group-label-%s" % (field.name,
group_index),
- _class="s3-grouped-checkboxes-widget-label"))
+ _class="s3-grouped-checkboxes-widget-label expanded"))
group_field = field
# Can give Unicode issues:
4 modules/tests/project/create_project.py
View
@@ -112,7 +112,7 @@ def test_project001_create_project(self):
)
self.create("project_beneficiary",
- [( "beneficiary_type_id",
+ [( "parameter_id",
"Teachers",
"option"),
( "value",
@@ -126,7 +126,7 @@ def test_project001_create_project(self):
self.browser.find_element_by_id("show-add-btn").click()
self.create("project_beneficiary",
- [( "beneficiary_type_id",
+ [( "parameter_id",
"Pupils",
"option"),
( "value",
2  modules/unit_tests/eden/pr.py
View
@@ -450,7 +450,7 @@ def testOnValidation(self):
f = S3SavedSearch.pr_saved_search_onvalidation
def testFriendlyQuery(self):
- app = request.application
+ app = current.request.application
f = S3SavedSearch.friendly_string_from_field_query
result = f(
51 modules/unit_tests/s3/s3aaa.py
View
@@ -3196,7 +3196,8 @@ def setUp(self):
# Create a dummy record
ftable = s3db.org_office
- office = Storage(name="Ownership Test Office")
+ office = Storage(organisation_id=self.org_id,
+ name="Ownership Test Office")
office_id = ftable.insert(**office)
office.update(id=office_id)
s3db.update_super(ftable, office)
@@ -3285,6 +3286,48 @@ def testSetRealmEntityWithRecord(self):
self.assertEqual(record.realm_entity, 5)
# -------------------------------------------------------------------------
+ def testSetRealmEntityWithRealmComponent(self):
+ """ Test whether the realm entity of the component updates automatically """
+
+ s3db = current.s3db
+ auth = current.auth
+ settings = current.deployment_settings
+
+ realm_components = s3db.get_config("org_organisation",
+ "realm_components", "none")
+ s3db.configure("org_organisation",
+ realm_components = ["office"])
+
+ try:
+ otable = s3db.org_organisation
+ ftable = s3db.org_office
+
+ settings.auth.realm_entity = self.realm_entity
+
+ record = otable[self.org_id]
+ record.update_record(realm_entity = None)
+ record = ftable[self.office_id]
+ record.update_record(realm_entity = None)
+
+ record = otable[self.org_id]
+ auth.set_realm_entity(otable, record, force_update=True)
+
+ tname = "org_organisation"
+ self.assertEqual(self.owned_record, (tname, record.id))
+
+ record = otable[self.org_id]
+ self.assertEqual(record.realm_entity, 5)
+
+ record = ftable[self.office_id]
+ self.assertEqual(record.realm_entity, 5)
+ finally:
+ if realm_components != "none":
+ s3db.configure("org_organisation",
+ realm_components=realm_components)
+ else:
+ s3db.clear_config("org_organisation", "realm_components")
+
+ # -------------------------------------------------------------------------
def testSetRealmEntityWithRecordID(self):
""" Test the realm entity can be set for a record ID """
@@ -3383,7 +3426,7 @@ def testSetRealmEntityWithQueryAndOverrideNone(self):
self.assertEqual(record.realm_entity, None)
# -------------------------------------------------------------------------
- def testUpdateSuperRealm(self):
+ def testUpdateSharedFields(self):
""" Test that realm entity gets set in super-entity """
s3db = current.s3db
@@ -3398,11 +3441,11 @@ def testUpdateSuperRealm(self):
site_id = row["site_id"]
- auth.update_super_realm(ftable, self.office_id, realm_entity=None)
+ auth.update_shared_fields(ftable, self.office_id, realm_entity=None)
site = stable[site_id]
self.assertEqual(site["realm_entity"], None)
- auth.update_super_realm(ftable, self.office_id, realm_entity=row["realm_entity"])
+ auth.update_shared_fields(ftable, self.office_id, realm_entity=row["realm_entity"])
site = stable[site_id]
self.assertEqual(site["realm_entity"], row["realm_entity"])
158 private/templates/IFRC/project_activity_type.csv
View
@@ -1,31 +1,127 @@
-"Name"
-"Advocacy"
-"Awareness raising"
-"BDRT (Branch disaster response teams)"
-"Capacity Building"
-"CDRT (Community disaster response teams)"
-"Children's Education"
-"Climate change mitigation"
-"Climate change preparednes"
-"Community Based Health and First Aid (CBHFA)"
-"Community organisation"
-"Contingency planning"
-"DM Planning"
-"Early warning"
-"Evacuation drills"
-"Food security "
-"Hygiene promotion"
-"IDRL"
-"IEC Materials"
-"Livelihoods"
-"Logistics"
-"Mainstreaming DRR"
-"NDRT (National disaster response teams)"
-"Nutrition"
-"Risk transfer"
-"Sanitation"
-"School Safety"
-"Small scale mitigation"
-"Tools & Equipment"
-"VCA (Vulnerability and Capacity Assessment)"
-"Water Supply"
+Name,Sector:Health,Sector:DRR,Sector:OD,Sector:WatSan,Notes
+Auxiliary role,,Yes,,,
+Climate change awareness ,,Yes,,,
+"Climate change mainstreaming, ",,Yes,,,
+Coastal conservation ,,Yes,,,
+Community disaster awareness,,Yes,,,
+Community early warning systems,,Yes,,,
+Education & advocacy,,Yes,,,
+"Financial risk sharing (community funds, etc.), ",,Yes,,,
+Insurance ,,Yes,,,
+"legislation/IDRL, ",,Yes,,,
+Logistics & warehouses,,Yes,,,
+National DM planning ,,Yes,,,
+Provision of tools and equipment,,Yes,,,
+RDRT (Regional disaster response teams),,Yes,,,
+"School safety and children education,",,Yes,,,
+"Simulation small scale mitigation, ",,Yes,,,
+"Staff/volunteer capacity building, (does this mean volunteering development guidelines??)",,Yes,,,
+Tree and mangrove planting ,,Yes,,,
+Volunteering in emergencies guidelines/toolkit,,Yes,,,
+Vulnerability and Capacity Assessments,,Yes,,,
+Advocacy,Yes,,,,
+Behaviour change communication,Yes,,,,
+Better programming initiative guidance,Yes,,,,DRR
+Blood banking,Yes,,,,
+Club 25 / Pledge 25,Yes,,,,
+Community action planning,Yes,,,,DRR
+Community health committees,Yes,,,,
+Community health initiative/projects,Yes,,,,
+Community health risk assessments,Yes,,,,
+Community mobilisation,Yes,,,,
+Community preparedness,Yes,,,,
+Contingency planning/preparedness planning,Yes,,,,
+Coordination and partnerships,Yes,,,,
+Disease prevention,Yes,,,,
+"Distribution of prevention items � such as condoms, mosquito nets, soap",Yes,,,,
+Donor recruitment,Yes,,,,
+Feeding programmes,Yes,,,,
+First Aid,Yes,,,,
+Food supplementation,Yes,,,,
+"Health awareness, promotion",Yes,,,,
+Health facilities - construction and operation,Yes,,,,
+"Health policy, strategy development",Yes,,,,
+Immunisation campaigns,Yes,,,,
+Infant and young child feeding,Yes,,,,
+Knowledge management ,Yes,,,,
+Medical supplies and equipment,Yes,,,,
+Mobile health units,Yes,,,,
+Monitoring and evaluation,Yes,,,,
+Nutritional assessments,Yes,,,,
+Organisational preparedness � NHQ and branches,Yes,,,,
+Peer support,Yes,,,,
+Project assessments and planning,Yes,,,,
+Psychosocial support (tools/guidelines/trainings in cross-cultural contexts),Yes,,,,
+Referral,Yes,,,,
+Risk management and quality assurance,Yes,,,,
+School-based activities,Yes,,,,
+Situation monitoring/community surveillance,Yes,,,,
+Staff capacity building,Yes,,,,
+"Stockpiling, prepositioning of supplies",Yes,,,,
+Tools and guidelines development,Yes,,,,
+Training of community/first responders ,Yes,,,,
+Training of master trainers/trainers,Yes,,,,
+Vector control,Yes,,,,
+Volunteer capacity building - training and mobilisation,Yes,,,,
+Volunteer training,Yes,,,,
+Volunteering in pandemic emergency situations (Jim had shared guidelines earlier?),Yes,,,,
+Branch planning,,,Yes,,
+Capacity building of governance,,,Yes,,
+Capacity building of management staff,,,Yes,,
+"Database development (vol, member, donors)",,,Yes,,
+Policy development,,,Yes,,
+"Resource Mobilisation (fundraising, income generation, in-kind support, partnership) ",,,Yes,,
+School RC units development,,,Yes,,
+SOPs and guidelines development,,,Yes,,
+Strategy development,,,Yes,,
+Training ,,,Yes,,
+Volunteer insurance,,,Yes,,
+Volunteer recognition,,,Yes,,
+Volunteer recruitment (normal and ViE too),,,Yes,,
+Volunteer training,,,Yes,,
+Youth leadership development,,,Yes,,
+Catchment protection,,,,Yes,
+Clean-up campaign,,,,Yes,
+"Construction of water supply systems (gravity-fed, shallow wells, boreholes)",,,,Yes,
+Desluding ,,,,Yes,
+Emergency householdwater treatment and storage,,,,Yes,
+Emergency water supply,,,,Yes,
+Hand washing facilities and demonstration,,,,Yes,
+Installation of rainwater harvesting systems,,,,Yes,
+latrine construction (emergency and permanent),,,,Yes,
+Participatory Hygiene and Sanitation Transformation,,,,Yes,
+Planning and construction of drainage systems ,,,,Yes,
+Solid waste management,,,,Yes,
+Spraying of vectors,,,,Yes,
+Training and capacity building,,,,Yes,
+Water testing,,,,Yes,
+Advocacy,,,,,
+Awareness raising,,,,,
+BDRT (Branch disaster response teams),,,,,DRR
+Capacity Building,,,,,
+CDRT (Community disaster response teams),,,,,DRR
+Children's Education,,,,,
+Climate change mitigation,,,,,
+Climate change preparedness,,,,,DRR
+Community Based Health and First Aid (CBHFA),,,,,
+Community organisation,,,,,DRR
+Contingency planning,,,,,DRR
+DM Planning,,,,,
+Early warning,,,,,
+Evacuation drills,,,,,DRR
+Food security ,,,,,
+Hygiene promotion,,,,,
+IDRL,,,,,
+IEC Materials,,,,,"Development/dissemination WatSan,DRR"
+Livelihoods,,,,,
+Logistics,,,,,
+Mainstreaming DRR,,,,,DRR
+NDRT (National disaster response teams),,,,,DRR
+Nutrition,,,,,
+Risk transfer,,,,,
+Sanitation,,,,,
+School Safety,,,,,
+Small scale mitigation,,,,,
+Tools & Equipment,,,,,
+VCA (Vulnerability and Capacity Assessment),,,,,
+Water Supply,,,,,
94 private/templates/IFRC/project_theme.csv
View
@@ -1,27 +1,67 @@
-"Name","Comments"
-"Capacity Development","training and development, institutional strengthening, institutional learning"
-"Civil Society/NGOs","civic action, collective community action, community-based organization (CBO) action, grassroots action, integrative DRR, non-governmental organization (NGO) action"
-"Climate Change","adaptation to climate change, sustainable development"
-"Community-based DRR","local knowledge, local risk mapping"
-"Complex Emergency","multiple hazard crisis, humanitarian crisis, conflict"
-"Critical Infrastructure","communications systems, health facilities, 'lifelines', power and energy, emergency evacuation shelters, financial infrastructure, schools, transportation, waste disposal, water supplies"
-"Disaster Risk Management","civil protection, contingency and emergency planning, early recovery, preparedness"
-"Early Warning","risk knowledge, monitoring and warning service, risk communication, response capability, disaster preparedness, risk modelling"
-"Economics of DRR","cost benefit analysis, disaster risk financing, financial effects of disasters, poverty and disaster risk, risk sharing, socio-economic impacts of disasters"
-"Education & School Safety","learning, safe schools"
-"Environment","sustainable development, environmental degradation, ecosystems and environmental management"
-"Gender","gendered vulnerability, gender-sensitive disaster risk management"
-"GIS & Mapping","geographic information systems, hazard exposure mapping, vulnerability mapping, risk mapping"
-"Governance","disaster risk reduction policy and legislation, National Platform for disaster risk reduction, Regional Platforms for disaster risk reduction"
-"Health & Health Facilities","capacity of health practitioners, mental health"
-"Information Management","disaster databases, disaster information, disaster risk information portals, ICT"
-"Media","disaster reporting, disaster information dissemination"
-"Private-public Partnerships","corporate social responsibility, private sector engagement in DRR"
-"Recovery","building back better, long-term recovery and reconstruction, rehabilitation, shelter"
-"Risk Identification & Assessment","risk assessment, loss data, disaster risk management"
-"Risk Transfer & Insurance","disaster insurance, contingency funding, micro-insurance, post-disaster loans, risk financing, risk insurance, risk sharing, pooling"
-"Social Impacts & Resilience","coping capacity, loss absorption, loss acceptance, psychosocial support, social vulnerability, trauma prevention"
-"Structural Safety","building codes, building standards, building materials, construction, retrofitting"
-"Urban Risk & Planning","urban planning, urban management"
-"Vulnerable Populations",
-"Water","drinking water, freshwater, irrigation, potable water, water and sanitation, water resource management"
+Name,Comments,Sector:Health,Sector:DRR,Sector:OD,Sector:WatSan,Notes
+CBDRM ,,,Yes,,,
+Climate Change Adaptation and Mitigation,,,Yes,,,
+Early Warning Systems,,,Yes,,,
+Gender and DM sensitisation guidelines,,,Yes,,,
+Infrastructure Development,,,Yes,,,
+Partnerships ,,,Yes,,,
+Risk transfer mechanism ,,,Yes,,,
+Urban Risk Management,,,Yes,,,
+Blood donation and services,,Yes,,,,
+"Communicable diseases (including emerging and re-emerging diseases, vaccine preventable diseases, HIV, TB)",,Yes,,,,
+Community health,,Yes,,,,
+Emergency health,,Yes,,,,
+Epidemic preparedness/pandemic preparedness,,Yes,,,,
+"Maternal, newborn and child health",,Yes,,,,
+Medical services,,Yes,,,,
+Non-communicable diseases,,Yes,,,,
+Nutrition,,Yes,,,,
+Psychosocial support,,Yes,,,,
+Road safety,,Yes,,,,
+School health,,Yes,,,,
+Sexual and reproductive health,,Yes,,,,
+Branch Capacity development ,,,,Yes,,
+Communication capacity building,,,,Yes,,
+Financial system development,,,,Yes,,
+Gender sensitisation and guidelines,,,,Yes,,
+Human Resource development ,,,,Yes,,
+IT � Digital Divide,,,,Yes,,
+Member base development,,,,Yes,,
+PMER development,,,,Yes,,
+Programme planning and management ,,,,Yes,,
+"RM (fundraising, income generation, in-kind support, partnership)",,,,Yes,,
+Social inclusion/ diversity/ violence prevention,,,,Yes,,
+Volunteer and staff Management or HR,,,,Yes,,
+Youth Development,,,,Yes,,
+Drainage,,,,,Yes,
+Excreta Disposal,,,,,Yes,
+Hygiene promotion,,,,,Yes,
+Solid Waste Management,,,,,Yes,
+Vector Control,,,,,Yes,
+Water Supply,,,,,Yes,
+Capacity Development,"training and development, institutional strengthening, institutional learning",,,,,DRR
+Civil Society/NGOs,"civic action, collective community action, community-based organization (CBO) action, grassroots action, integrative DRR, non-governmental organization (NGO) action",,,,,
+Climate Change,"adaptation to climate change, sustainable development",,,,,
+Community-based DRR,"local knowledge, local risk mapping",,,,,
+Complex Emergency,"multiple hazard crisis, humanitarian crisis, conflict",,,,,
+Critical Infrastructure,"communications systems, health facilities, 'lifelines', power and energy, emergency evacuation shelters, financial infrastructure, schools, transportation, waste disposal, water supplies",,,,,
+Disaster Risk Management,"civil protection, contingency and emergency planning, early recovery, preparedness",,,,,
+Early Warning,"risk knowledge, monitoring and warning service, risk communication, response capability, disaster preparedness, risk modelling",,,,,
+Economics of DRR,"cost benefit analysis, disaster risk financing, financial effects of disasters, poverty and disaster risk, risk sharing, socio-economic impacts of disasters",,,,,
+Education & School Safety,"learning, safe schools",,,,,
+Environment,"sustainable development, environmental degradation, ecosystems and environmental management",,,,,
+Gender,"gendered vulnerability, gender-sensitive disaster risk management",,,,,
+GIS & Mapping,"geographic information systems, hazard exposure mapping, vulnerability mapping, risk mapping",,,,,
+Governance,"disaster risk reduction policy and legislation, National Platform for disaster risk reduction, Regional Platforms for disaster risk reduction",,,,,
+Health & Health Facilities,"capacity of health practitioners, mental health",,,,,
+Information Management,"disaster databases, disaster information, disaster risk information portals, ICT",,,,,
+Media,"disaster reporting, disaster information dissemination",,,,,
+Private-public Partnerships,"corporate social responsibility, private sector engagement in DRR",,,,,
+Recovery,"building back better, long-term recovery and reconstruction, rehabilitation, shelter",,,,,
+Risk Identification & Assessment,"risk assessment, loss data, disaster risk management",,,,,DRR
+Risk Transfer & Insurance,"disaster insurance, contingency funding, micro-insurance, post-disaster loans, risk financing, risk insurance, risk sharing, pooling",,,,,
+Social Impacts & Resilience,"coping capacity, loss absorption, loss acceptance, psychosocial support, social vulnerability, trauma prevention",,,,,
+Structural Safety,"building codes, building standards, building materials, construction, retrofitting",,,,,
+Urban Risk & Planning,"urban planning, urban management",,,,,
+Vulnerable Populations,,,,,,
+Water,"drinking water, freshwater, irrigation, potable water, water and sanitation, water resource management",HHH,EEE,LLL,PPP,
200 private/templates/IFRC_Demo/project_location.csv
View
@@ -1,100 +1,100 @@
-Project Name,Activities,Country,L1,L2,L3,L4,Lat,Lon,ContactPerson,Comments,Beneficiaries:Individuals,Beneficiaries:Families,Beneficiaries:Pupils,Beneficiaries:Teachers,Beneficiaries:Men,Beneficiaries:Women
-Community Based Disaster Management,"Community organisation, Capacity Building, CDRT (Community disaster response teams)",Timor-Leste,Baucau,Laga,Soba,Soba,-8.47342,126.59791,"Donato,Urbana,donato.urbana@gmail.com,",,152,,,,,
-Community Based Disaster Management,"Community organisation, Capacity Building, CDRT (Community disaster response teams)",Timor-Leste,Bobonaro,Bobonaro,Lourba,Zobelis,-9.01786,125.35333,"Joana,Arriaga,joana.arriaga@yahoo.com,",,421,,,,,
-Community Based Disaster Management,"Community organisation, Capacity Building, CDRT (Community disaster response teams)",Timor-Leste,Liquiçá,Liquiçá,Dato,Nunturi,-8.64709,125.34227,"Francisco,Hendrigue Pinto,francisco.hendriguepinto@hotmail.com,",,453,,,,,
-Community Based Disaster Management,"Community organisation, Capacity Building, CDRT (Community disaster response teams)",Timor-Leste,Oecusse,Passabe,Abani,Ato,-9.47556,124.34222,"Sergio,Polido,sergio.polido@gmail.com,",,386,,,,,
-Community Based Disaster Management,"Community organisation, Capacity Building, CDRT (Community disaster response teams)",Timor-Leste,Ainaro,Maubisse,Manetu,Maulau,-8.87917,125.66389,"Ercia,Licinia,ercia.licinia@yahoo.com,",,407,,,,,
-Community Based Disaster Management,"Community organisation, Capacity Building, CDRT (Community disaster response teams)",Timor-Leste,Oecusse,Nitibe,Usi-Taco,Nitibe,-9.34499,124.22979,"Telma,Antonio Belo,telma.antoniobelo@hotmail.com,",,211,,,,,
-Community Based Disaster Management,"Community organisation, Capacity Building, CDRT (Community disaster response teams)",Timor-Leste,Manatuto,Laclubar,Funar,Batamac,-8.75332,125.9,"Durcelina,Vidigal dos Santos,durcelina.vidigaldossantos@gmail.com,",,164,,,,,
-Community Based Disaster Management,"Community organisation, Capacity Building, CDRT (Community disaster response teams)",Timor-Leste,Ermera,Letefoho,Ducurai,Hatulete,-8.86284,125.4945,"Tomas,Clara,tomas.clara@yahoo.com,",,177,,,,,
-Community Based Sanitation Infrastructure improvement,"Water Supply, Community organisation",Timor-Leste,Dili,Vera Cruz,Vila Verde,Vila Verde,-8.5579,125.56633,"Vidiana,Pedro Pinto,vidiana.pedropinto@hotmail.com,",,,169,,,,
-Community Based Sanitation Infrastructure improvement,"Water Supply, Community organisation",Timor-Leste,Viqueque,Uatucarbau,Afaloicai,Bahatata,-8.64917,126.65131,"Abril,da Costa Belo,abril.dacostabelo@gmail.com,",,,279,,,,
-Community Based Sanitation Infrastructure improvement,"Water Supply, Community organisation",Timor-Leste,Viqueque,Watulari,Afaloicai,Siquilari,-8.74964,126.52186,"Augusto,de Deus Gomes,augusto.dedeusgomes@yahoo.com,",,,135,,,,
-Community Based Sanitation Infrastructure improvement,"Water Supply, Community organisation",Timor-Leste,Lautém,Lospalos,Fuiloro,Sentral,-8.52188,126.99469,"Graciano,Helena,graciano.helena@hotmail.com,",,,78,,,,
-Community Based Sanitation Infrastructure improvement,"Water Supply, Community organisation",Timor-Leste,Liquiçá,Liquiçá,Darulete,Fahate,-8.66992,125.34759,"Domingos,Nunes,domingos.nunes@gmail.com,",,,70,,,,
-Community Based Sanitation Infrastructure improvement,"Water Supply, Community organisation",Timor-Leste,Oecusse,Passabe,Abani,Fot,-9.4698,124.34225,"Abelito,Cardoso,abelito.cardoso@yahoo.com,",,,112,,,,
-Community Based Sanitation Infrastructure improvement,"Water Supply, Community organisation",Timor-Leste,Ermera,Railaco,Taraso,Datoleo,-8.65719,125.48918,"Agapito,Pereira,agapito.pereira@hotmail.com,",,,274,,,,
-Community Based Sanitation Infrastructure improvement,"Water Supply, Community organisation",Timor-Leste,Ainaro,Hatu-Udo,Foho-ai-Lico,Aimorbada,-9.17228,125.64499,"Acacio,Ojeda,acacio.ojeda@gmail.com,",,,174,,,,
-Community Based Sanitation Infrastructure improvement,"Water Supply, Community organisation",Timor-Leste,Dili,Atauro,Atauro Vila/Maumeta,Atauro,-8.26642,125.59909,"Natalino,da Costa Lopes,natalino.dacostalopes@yahoo.com,",,,222,,,,
-Community Based Sanitation Infrastructure improvement,"Water Supply, Community organisation",Timor-Leste,Ainaro,Maubisse,Manetu,Maulau,-8.87917,125.66389,"Isabel,de Oliveira,isabel.deoliveira@hotmail.com,",,,165,,,,
-Community School Building Renewal,School Safety,Timor-Leste,Lautém,Lautém,Pairara,Puno,-8.42927,126.93611,"Beatriz,Sevinate,beatriz.sevinate@gmail.com,",,,,312,24,,
-Community School Building Renewal,School Safety,Timor-Leste,Manatuto,Laclubar,Funar,Batamac,-8.75332,125.9,"Marcelino,Roleto,marcelino.roleto@yahoo.com,",,,,320,32,,
-Community School Building Renewal,School Safety,Timor-Leste,Baucau,Quelicai,Lelalai,Uabuu,-8.64559,126.50566,"Marcelo,Jose,marcelo.jose@hotmail.com,",,,,143,13,,
-Community School Building Renewal,School Safety,Timor-Leste,Ainaro,Hatu-Udo,Leolima,Nonuboka,-9.13307,125.59534,"Justiano,Freitas,justiano.freitas@gmail.com,",,,,920,23,,
-Community School Building Renewal,School Safety,Timor-Leste,Covalima,Suai,Debos,Asumaten,-9.31861,125.26101,"Soraia,de Fatima,soraia.defatima@yahoo.com,",,,,648,24,,
-Community School Building Renewal,School Safety,Timor-Leste,Manufahi,Same,Daisua,Lesulau,-9.08097,125.68315,"Lucio,Chilro,lucio.chilro@hotmail.com,",,,,2254,46,,
-Community School Building Renewal,School Safety,Timor-Leste,Viqueque,Ossu,Loi-Huno,Buanurak,-8.83085,126.37455,"Cláudia,Caldeira,cláudia.caldeira@gmail.com,",,,,576,32,,
-Community School Building Renewal,School Safety,Timor-Leste,Manufahi,Alas,Mahaquidan,Wedauberek,-9.12083,125.85278,"Adriana,Uva,adriana.uva@yahoo.com,",,,,228,12,,
-Community School Building Renewal,School Safety,Timor-Leste,Manufahi,Turiscai,Liurai,Binimalo,-8.83166,125.72915,"Elly ,Boavida,elly.boavida@hotmail.com,",,,,465,31,,
-Community School Building Renewal,School Safety,Timor-Leste,Aileu,Laulara,Fatisi,Sabereke,-8.64573,125.5267,"Orlando,Godinho ,orlando.godinho@gmail.com,",,,,1600,50,,
-Community School Building Renewal,School Safety,Timor-Leste,Covalima,Maucatar,Ogues,Oges,-9.26491,125.21452,"Yakobus,Adevinha,yakobus.adevinha@yahoo.com,",,,,585,13,,
-Fishing Livelihoods Improvement,"Livelihoods, Capacity Building",Timor-Leste,Bobonaro,Lolotoe,Gildapil,Gildapil,-9.12149,125.21228,"Abrao,Cabecinhas,abrao.cabecinhas@hotmail.com,",,,,,,29,
-Fishing Livelihoods Improvement,"Livelihoods, Capacity Building",Timor-Leste,Liquiçá,Maubara,Vatuvou,Watubau,-8.64984,125.26259,"Mariana,Elo,mariana.elo@gmail.com,",,,,,,12,
-Fishing Livelihoods Improvement,"Livelihoods, Capacity Building",Timor-Leste,Aileu,Aileu Vila,Suco Liurai,Maurusa,-8.74522,125.51559,"Andreia,Pinto Soares,andreia.pintosoares@yahoo.com,",,,,,,19,
-Fishing Livelihoods Improvement,"Livelihoods, Capacity Building",Timor-Leste,Bobonaro,Bobonaro,Bobonaro,Lepo,-9.04311,125.35841,"Maria,Ximenes,maria.ximenes@hotmail.com,",,,,,,13,
-Fishing Livelihoods Improvement,"Livelihoods, Capacity Building",Timor-Leste,Baucau,Laga,Atelari,Auraba,-8.55694,126.69167,"Mariano,Baros,mariano.baros@gmail.com,",,,,,,24,
-Fishing Livelihoods Improvement,"Livelihoods, Capacity Building",Timor-Leste,Bobonaro,Cailaco,Meligo,Daulelo,-8.87854,125.23523,"Apolonius,Palat,apolonius.palat@yahoo.com,",,,,,,40,
-Fishing Livelihoods Improvement,"Livelihoods, Capacity Building",Timor-Leste,Ermera,Hatolia,Coliate-Leotelo,Martulete,-8.82309,125.37867,"Aleixo,Hugo,aleixo.hugo@hotmail.com,",,,,,,12,
-Fishing Livelihoods Improvement,"Livelihoods, Capacity Building",Timor-Leste,Oecusse,Oesilo,Bobometo,Oenoa,-9.32601,124.37428,"Erculano,Magno Freitas,erculano.magnofreitas@gmail.com,",,,,,,14,
-Fishing Livelihoods Improvement,"Livelihoods, Capacity Building",Timor-Leste,Lautém,Lautém,Maina I,Daulaturo,-8.39538,126.91078,"Vanessa,Duarte,vanessa.duarte@yahoo.com,",,,,,,18,
-Fishing Livelihoods Improvement,"Livelihoods, Capacity Building",Timor-Leste,Baucau,Baucau,Triloca,Angkasabaru,-8.49578,126.36563,"Eduarda,Rente,eduarda.rente@hotmail.com,",,,,,,26,
-Road Safety Campaign,Advocacy,Timor-Leste,Covalima,Suai,Beco,Haemanu,-9.25387,125.34518,"Jessica,Bosco Soares,jessica.boscosoares@gmail.com,",,,,1188,27,,
-Road Safety Campaign,Advocacy,Timor-Leste,Manatuto,Barique/Natarbora,Aubeon,Buburlolon,-8.98212,126.06151,"Manuel,Moniz,manuel.moniz@yahoo.com,",,,,484,44,,
-Road Safety Campaign,Advocacy,Timor-Leste,Liquiçá,Maubara,Vatuvou,Lisalara,-8.64304,125.22638,"Marito,de Jesus Alves,marito.dejesusalves@hotmail.com,",,,,792,33,,
-Road Safety Campaign,Advocacy,Timor-Leste,Ermera,Hatolia,Ailelo,Lukulaulau,-8.81806,125.30833,"Martinho,Pascoela,martinho.pascoela@gmail.com,",,,,420,15,,
-Road Safety Campaign,Advocacy,Timor-Leste,Ainaro,Maubisse,Maubisse,Rileko,-8.83205,125.59131,"Leonito,M. Pereira,leonito.m.pereira@yahoo.com,",,,,448,16,,
-Road Safety Campaign,Advocacy,Timor-Leste,Viqueque,Watulari,Uaitame,Naidala,-8.8037,126.54842,"Antonio,Liub,antonio.liub@hotmail.com,",,,,420,42,,
-Road Safety Campaign,Advocacy,Timor-Leste,Bobonaro,Cailaco,Purugoa,Sabarakalara,-8.85638,125.2235,"Afonso,da Silva,afonso.dasilva@gmail.com,",,,,1760,40,,
-Road Safety Campaign,Advocacy,Timor-Leste,Ainaro,Ainaro,Ainaro,Kertapati,-8.98464,125.50353,"Liliana,Pala,liliana.pala@yahoo.com,",,,,1015,35,,
-Road Safety Campaign,Advocacy,Timor-Leste,Liquiçá,Maubara,Vatuvou,Samanaro,-8.63013,125.25124,"Margarida,Rilo,margarida.rilo@hotmail.com,",,,,616,44,,
-Road Safety Campaign,Advocacy,Timor-Leste,Lautém,Tutuala,Tutuala,Loro,-8.39909,127.25094,"Agusto,Rogerio,agusto.rogerio@gmail.com,",,,,989,23,,
-Water Supply Enhancement,Water Supply,Timor-Leste,Manatuto,Barique/Natarbora,Abat Oan,Ranac,-8.97295,126.06049,"Januario,Bercamns,januario.bercamns@yahoo.com,",,360,,,,,
-Water Supply Enhancement,Water Supply,Timor-Leste,Viqueque,Uatucarbau,Uani Uma,Uaniuma,-8.75577,126.68472,"Marcus,da Costa Mariz,marcus.dacostamariz@hotmail.com,",,149,,,,,
-Water Supply Enhancement,Water Supply,Timor-Leste,Dili,Nain Feto,Acadiru Hun,Nubadak,-8.55194,125.58944,"Abel,Marques,abel.marques@gmail.com,",,498,,,,,
-Water Supply Enhancement,Water Supply,Timor-Leste,Covalima,Maucatar,Ogues,Ogues,-9.29206,125.23198,"Diana,de Almeida,diana.dealmeida@yahoo.com,",,264,,,,,
-Water Supply Enhancement,Water Supply,Timor-Leste,Ainaro,Ainaro