Skip to content
Browse files

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

  • Loading branch information...
2 parents 4428342 + 0d2b8cd commit 7eaf3af4facd82d0538b47b8b42d9afadd654fe2 @flavour committed Apr 16, 2012
View
99 controllers/hrm.py
@@ -250,28 +250,81 @@ def hrm_map_popup(r):
"""
output = TABLE()
+ append = output.append
# Edit button
- output.append(TR(TD(A(T("Edit"),
- _target="_blank",
- _id="edit-btn",
- _href=URL(args=[r.id, "update"])))))
+ append(TR(TD(A(T("Edit"),
+ _target="_blank",
+ _id="edit-btn",
+ _href=URL(args=[r.id, "update"])))))
# First name, last name
- output.append(TR(TD(B("%s:" % T("Name"))),
- TD(s3_fullname(r.record.person_id))))
+ append(TR(TD(B("%s:" % T("Name"))),
+ TD(s3_fullname(r.record.person_id))))
# Job Title
if r.record.job_title:
- output.append(TR(TD(B("%s:" % r.table.job_title.label)),
- TD(r.record.job_title)))
+ append(TR(TD(B("%s:" % r.table.job_title.label)),
+ TD(r.record.job_title)))
# Organization (better with just name rather than Represent)
- table = s3db.org_organisation
- query = (table.id == r.record.organisation_id)
- name = db(query).select(table.name,
- limitby=(0, 1)).first().name
- output.append(TR(TD(B("%s:" % r.table.organisation_id.label)),
- TD(name)))
+ # @ToDo: Make this configurable - some deployments will only see
+ # their staff so this is a meaningless field
+ #table = s3db.org_organisation
+ #query = (table.id == r.record.organisation_id)
+ #name = db(query).select(table.name,
+ # limitby=(0, 1)).first().name
+ #append(TR(TD(B("%s:" % r.table.organisation_id.label)),
+ # TD(name)))
+
+ # Components link to the Person record
+ person_id = r.record.person_id
+
+ # Skills
+ table = s3db.hrm_competency
+ stable = s3db.hrm_skill
+ query = (table.person_id == person_id) & \
+ (table.skill_id == stable.id)
+ skills = db(query).select(stable.name)
+ if skills:
+ vals = [skill.name for skill in skills]
+ if len(skills) > 1:
+ represent = ", ".join(vals)
+ else:
+ represent = len(vals) and vals[0] or ""
+ append(TR(TD(B("%s:" % T("Skills"))),
+ TD(represent)))
+
+ # Certificates
+ table = s3db.hrm_certification
+ ctable = s3db.hrm_certificate
+ query = (table.person_id == person_id) & \
+ (table.certificate_id == ctable.id)
+ certificates = db(query).select(ctable.name)
+ if certificates:
+ vals = [cert.name for cert in certificates]
+ if len(certificates) > 1:
+ represent = ", ".join(vals)
+ else:
+ represent = len(vals) and vals[0] or ""
+ append(TR(TD(B("%s:" % T("Certificates"))),
+ TD(represent)))
+
+ # Trainings
+ table = s3db.hrm_training
+ etable = s3db.hrm_training_event
+ ctable = s3db.hrm_course
+ query = (table.person_id == person_id) & \
+ (table.training_event_id == etable.id) & \
+ (etable.course_id == ctable.id)
+ trainings = db(query).select(ctable.name)
+ if trainings:
+ vals = [train.name for train in trainings]
+ if len(trainings) > 1:
+ represent = ", ".join(vals)
+ else:
+ represent = len(vals) and vals[0] or ""
+ append(TR(TD(B("%s:" % T("Trainings"))),
+ TD(represent)))
if r.record.location_id:
table = s3db.gis_location
@@ -282,12 +335,12 @@ def hrm_map_popup(r):
# City
# Street address
if location.addr_street:
- output.append(TR(TD(B("%s:" % table.addr_street.label)),
- TD(location.addr_street)))
+ append(TR(TD(B("%s:" % table.addr_street.label)),
+ TD(location.addr_street)))
# Mobile phone number
ptable = s3db.pr_person
ctable = s3db.pr_contact
- query = (ptable.id == r.record.person_id) & \
+ query = (ptable.id == person_id) & \
(ctable.pe_id == ptable.pe_id)
contacts = db(query).select(ctable.contact_method,
ctable.value)
@@ -298,24 +351,24 @@ def hrm_map_popup(r):
elif contact.contact_method == "SMS":
mobile_phone = contact.value
if mobile_phone:
- output.append(TR(TD(B("%s:" % msg.CONTACT_OPTS.get("SMS"))),
- TD(mobile_phone)))
+ append(TR(TD(B("%s:" % msg.CONTACT_OPTS.get("SMS"))),
+ TD(mobile_phone)))
# Office number
if r.record.site_id:
table = s3db.org_office
query = (table.site_id == r.record.site_id)
office = db(query).select(table.phone1,
limitby=(0, 1)).first()
if office and office.phone1:
- output.append(TR(TD(B("%s:" % T("Office Phone"))),
- TD(office.phone1)))
+ append(TR(TD(B("%s:" % T("Office Phone"))),
+ TD(office.phone1)))
else:
# @ToDo: Support other Facility Types (Hospitals & Shelters)
pass
# Email address (as hyperlink)
if email:
- output.append(TR(TD(B("%s:" % msg.CONTACT_OPTS.get("EMAIL"))),
- TD(A(email, _href="mailto:%s" % email))))
+ append(TR(TD(B("%s:" % msg.CONTACT_OPTS.get("EMAIL"))),
+ TD(A(email, _href="mailto:%s" % email))))
return output
View
8 controllers/pr.py
@@ -410,9 +410,11 @@ def presence():
def pentity():
"""
RESTful CRUD controller
- - used by AutocompleteWidget
+ - limited to just search.json for use in Autocompletes
"""
+ response.s3.prep = lambda r: r.representation == "json" and \
+ r.method == "search"
return s3_rest_controller()
# -----------------------------------------------------------------------------
@@ -436,10 +438,6 @@ def tooltip():
return dict()
# -----------------------------------------------------------------------------
-def guide():
- return dict()
-
-# -----------------------------------------------------------------------------
def person_duplicates():
""" Handle De-duplication of People
View
4 models/zzz_1st_roles.py
@@ -124,6 +124,10 @@ def parseACL(_acl):
dict(t="pr_person", uacl=acl.NONE, oacl=acl.READ|acl.UPDATE),
# But need to be able to add/edit addresses
dict(c="pr", f="person", uacl=acl.CREATE, oacl=acl.READ|acl.UPDATE),
+ # And access the Autocompletes
+ dict(c="pr", f="person_search", uacl=acl.READ),
+ dict(c="pr", f="pentity", uacl=acl.READ),
+ dict(c="msg", f="search", uacl=acl.READ),
# Authenticated users can see the Supply Catalogue
dict(c="supply", uacl=acl.READ|acl.CREATE, oacl=default_oacl),
uid=sysroles.AUTHENTICATED,
View
2 modules/eden/event.py
@@ -91,7 +91,7 @@ def model(self):
Field("name", notnull=True, # Name could be a code
length=64, # Mayon compatiblity
label=T("Name")),
- #Field("code", # e.g. to link to WebEOC
+ #Field("code", # e.g. to link to WebEOC or GLIDE (http://glidenumber.net/glide/public/about.jsp)
# length=64, # Mayon compatiblity
# label=T("Code")),
countries_id(
View
21 modules/eden/irs.py
@@ -272,6 +272,24 @@ def model(self):
requires = IS_NULL_OR(IS_UTC_DATETIME())
),
location_id(),
+ # Very basic Impact Assessment
+ Field("affected", "integer",
+ label=T("Number of People Affected"),
+ represent = lambda val: val or T("unknown"),
+ ),
+ Field("dead", "integer",
+ label=T("Number of People Dead"),
+ represent = lambda val: val or T("unknown"),
+ ),
+ Field("injured", "integer",
+ label=T("Number of People Injured"),
+ represent = lambda val: val or T("unknown"),
+ ),
+ # Probably too much to try & capture
+ #Field("missing", "integer",
+ # label=T("Number of People Missing")),
+ #Field("displaced", "integer",
+ # label=T("Number of People Displaced")),
Field("verified", "boolean", # Ushahidi-compatibility
# We don't want these visible in Create forms
# (we override in Update forms in controller)
@@ -407,6 +425,9 @@ def model(self):
"datetime",
"location_id",
#"organisation_id",
+ "affected",
+ "dead",
+ "injured",
"verified",
"message",
])
View
12 modules/eden/msg.py
@@ -95,8 +95,12 @@ def model(self):
represent = lambda direction: \
(direction and ["In"] or ["Out"])[0],
label = T("Direction")),
- Field("is_parsed", "boolean", default = False),
- Field("reply", "text"),
+ Field("is_parsed", "boolean", default = False,
+ represent = lambda status: \
+ (status and ["Parsed"] or ["Not Parsed"])[0],
+ label = T("Parsing Status")),
+ Field("reply", "text" ,
+ label = T("Reply")),
*s3.meta_fields())
self.configure(tablename,
@@ -112,7 +116,9 @@ def model(self):
"actionable",
"actioned",
#"actioned_comments",
- #"priority"
+ #"priority",
+ "is_parsed",
+ "reply"
])
# Components
View
42 modules/eden/survey.py
@@ -2037,23 +2037,40 @@ def seriesMap(r, **attr):
else:
seriesList = [series_id]
pqstn_name = None
+ pqstn = {}
if "post_vars" in request and len(request.post_vars) > 0:
if "pqstn_name" in request.post_vars:
pqstn_name = request.post_vars.pqstn_name
+ if pqstn_name == None:
+ pqstn = survey_getPriorityQuestionForSeries(series_id)
+ pqstn_name = pqstn["name"]
feature_queries = []
bounds = {}
+ # Build the drop down list of priority questions
+ allQuestions = survey_getAllQuestionsForSeries(series_id)
+ numericTypeList = ("Numeric")
+ numericQuestions = survey_get_series_questions_of_type(allQuestions,
+ numericTypeList)
+ numQstns = []
+ for question in numericQuestions:
+ numQstns.append(question["name"])
+
+ form = FORM(_id="mapQstnForm")
+ table = TABLE()
+
+ priorityQstn = SELECT(numQstns, _name="pqstn_name",
+ value=pqstn_name)
+
# Set up the legend
for series_id in seriesList:
series_name = survey_getSeriesName(series_id)
response_locations = getLocationList(series_id)
- if pqstn_name == None:
- pqstn = survey_getPriorityQuestionForSeries(series_id)
- else:
- pqstn = survey_getQuestionFromName(pqstn_name,
- series_id)
+ if pqstn == {} and pqstn_name:
+ for question in numericQuestions:
+ if pqstn_name == question["name"]:
+ pqstn = question
if pqstn != {}:
- pqstn_name = pqstn["name"]
pqstn_id = pqstn["qstn_id"]
answers = survey_getAllAnswersForQuestionInSeries(pqstn_id,
series_id)
@@ -2133,19 +2150,6 @@ def seriesMap(r, **attr):
#collapsed = True,
catalogue_layers = True,
)
- allQuestions = survey_getAllQuestionsForSeries(series_id)
- numericTypeList = ("Numeric")
- numericQuestions = survey_get_series_questions_of_type(allQuestions,
- numericTypeList)
- numQstns = []
- for question in numericQuestions:
- numQstns.append(question["name"])
-
- form = FORM(_id="mapQstnForm")
- table = TABLE()
-
- priorityQstn = SELECT(numQstns, _name="pqstn_name",
- value=pqstn_name)
series = INPUT(_type="hidden",
_id="selectSeriesID",
_name="series",
View
21 modules/s3/s3crud.py
@@ -1939,6 +1939,7 @@ def ssp_filter(self, table, fields, left=[]):
@param left: list of left joins
"""
+ db = current.db
vars = self.request.get_vars
resource = self.resource
@@ -1964,14 +1965,17 @@ def ssp_filter(self, table, fields, left=[]):
# Old DAL version?
join = [j for j in left if j.table._tablename == tn]
if not join:
- left.append(current.db[tn].on(field == current.db[tn].id))
+ left.append(db[tn].on(field == db[tn].id))
else:
- join[0].query = (join[0].query) | (field == current.db[tn].id)
+ try:
+ join[0].second = (join[0].second) | (field == db[tn].id)
+ except:
+ join[0].query = (join[0].query) | (field == db[tn].id)
if isinstance(field.sortby, (list, tuple)):
- flist.extend([current.db[tn][f] for f in field.sortby])
+ flist.extend([db[tn][f] for f in field.sortby])
else:
- if field.sortby in current.db[tn]:
- flist.append(current.db[tn][field.sortby])
+ if field.sortby in db[tn]:
+ flist.append(db[tn][field.sortby])
else:
flist.append(field)
@@ -2029,6 +2033,7 @@ def ssp_orderby(self, resource, fields, left=[]):
@param left: list of left joins
"""
+ db = current.db
vars = self.request.get_vars
table = resource.table
tablename = table._tablename
@@ -2064,15 +2069,15 @@ def direction(i):
# Old DAL version?
join = [j for j in left if j.table._tablename == tn]
if not join:
- left.append(current.db[tn].on(c == current.db[tn].id))
+ left.append(db[tn].on(c == db[tn].id))
else:
try:
join[0].query = (join[0].second) | \
- (c == current.db[tn].id)
+ (c == db[tn].id)
except:
# Old DAL version?
join[0].query = (join[0].query) | \
- (c == current.db[tn].id)
+ (c == db[tn].id)
if not isinstance(c.sortby, (list, tuple)):
orderby.append("%s.%s%s" % (tn, c.sortby, direction(i)))
else:
View
27 modules/s3/s3report.py
@@ -38,11 +38,13 @@
__all__ = ["S3Cube"]
import sys
+import datetime
import gluon.contrib.simplejson as json
from gluon import current
from gluon.storage import Storage
from gluon.html import *
+from s3rest import S3TypeConverter
from s3crud import S3CRUD
from s3search import S3Search
from s3utils import s3_truncate
@@ -1191,7 +1193,7 @@ def _totals(values, layers, append=None):
for layer in layers:
f, m = layer
value = values[layer]
-
+
if m == "list":
value = value and len(value) or 0
if not len(totals) and append is not None:
@@ -1216,6 +1218,29 @@ def _represent(lfields, field, value, default="-"):
if field in lfields:
lfield = lfields[field]
if lfield.field:
+ f = lfield.field
+ ftype = str(f.type)
+ if ftype not in ("string", "text") and \
+ isinstance(value, basestring):
+ # pyvttbl converts col/row headers into unicode,
+ # but represent may need the original data type,
+ # hence try to convert it back here:
+ convert = S3TypeConverter.convert
+ try:
+ if ftype == "boolean":
+ value = convert(bool, value)
+ elif ftype == "integer":
+ value = convert(int, value)
+ elif ftype == "float":
+ value = convert(float, value)
+ elif ftype == "date":
+ value = convert(datetime.date, value)
+ elif ftype == "time":
+ value = convert(datetime.time, value)
+ elif ftype == "datetime":
+ value = convert(datetime.datetime, value)
+ except TypeError, ValueError:
+ pass
return manager.represent(lfield.field, value,
strip_markup=True)
if value is None:
View
41 modules/s3/s3rest.py
@@ -37,7 +37,8 @@
"S3Request",
"S3Resource",
"S3ResourceFilter",
- "S3FieldSelector"]
+ "S3FieldSelector",
+ "S3TypeConverter"]
import sys
import datetime
@@ -4715,27 +4716,27 @@ def __init__(self, resource, id=None, uid=None, filter=None, vars=None):
# Add the subqueries and filters for this component
if alias in cquery:
- self.add_filter(cquery[alias])
+ [self.add_filter(q) for q in cquery[alias]]
if alias in cvfltr:
- self.add_filter(cvfltr[alias])
+ [self.add_filter(f) for f in cvfltr[alias]]
if resource.link is not None:
# If this component has a link table, add the subqueries
# and filters for the link table
lname = resource.link.alias
if lname in cquery:
- self.add_filter(cquery[lname])
+ [self.add_filter(q) for q in cquery[lname]]
if lname in cvfltr:
- self.add_filter(cvfltr[lname])
+ [self.add_filter(f) for f in cvfltr[lname]]
elif resource.linked is not None:
# Otherwise, if this is a linktable, add the subqueries
# and filters for the linked table
cname = resource.linked.alias
if cname in cquery:
- self.add_filter(cquery[cname])
+ [self.add_filter(q) for q in cquery[cname]]
if cname in cvfltr:
- self.add_filter(cvfltr[cname])
+ [self.add_filter(f) for f in cvfltr[cname]]
# Master resource query -----------------------------------------------
else:
@@ -5797,6 +5798,24 @@ def convert(cls, a, b):
if b is None:
return None
+ if type(a) is type:
+ if a in (str, unicode):
+ return cls._str(b)
+ if a is int:
+ return cls._int(b)
+ if a is bool:
+ return cls._bool(b)
+ if a is long:
+ return cls._long(b)
+ if a is float:
+ return cls._float(b)
+ if a is datetime.datetime:
+ return cls._datetime(b)
+ if a is datetime.date:
+ return cls._date(b)
+ if a is datetime.time:
+ return cls._time(b)
+ raise TypeError
if type(b) is type(a) or isinstance(b, type(a)):
return b
if isinstance(a, (list, tuple)):
@@ -5898,8 +5917,12 @@ def _datetime(b):
elif isinstance(b, basestring):
manager = current.manager
xml = manager.xml
- tfmt = xml.ISOFORMAT
- (y,m,d,hh,mm,ss,t0,t1,t2) = time.strptime(v, tfmt)
+ try:
+ tfmt = xml.ISOFORMAT
+ (y,m,d,hh,mm,ss,t0,t1,t2) = time.strptime(b, tfmt)
+ except ValueError:
+ tfmt = "%Y-%m-%d %H:%M:%S"
+ (y,m,d,hh,mm,ss,t0,t1,t2) = time.strptime(b, tfmt)
return datetime.datetime(y,m,d,hh,mm,ss)
else:
raise TypeError
View
4 modules/s3/s3search.py
@@ -1468,6 +1468,8 @@ def search_interactive(self, r, **attr):
# We have some features returned
map_popup = gis.show_map(
feature_queries=feature_queries,
+ catalogue_layers=True,
+ legend=True,
toolbar=True,
collapsed=True,
bbox=bounds,
@@ -1482,6 +1484,8 @@ def search_interactive(self, r, **attr):
# Added by search widget onClick in s3.dataTables.js
#add_polygon = True,
#add_polygon_active = True,
+ catalogue_layers=True,
+ legend=True,
toolbar=True,
collapsed=True,
#search = True,
View
2 private/prepopulate/demo/IFRC/auth_roles.csv
@@ -1,5 +1,7 @@
"uid","role"," description","controller","function","table","uacl","oacl","org","facility","hidden","system","protected"
+"AUTHENTICATED","Authenticated",,"pr","pentity",,"READ",,,,,,
"AUTHENTICATED","Authenticated",,"pr","person_search",,"READ",,,,,,
+"AUTHENTICATED","Authenticated",,"msg","search",,"READ",,,,,,
"AUTHENTICATED","Authenticated",,"org","office",,"READ",,,,,,
"AUTHENTICATED","Authenticated",,"inv","warehouse",,"READ",,,,,,
"ASSET_EDIT","Assets Editor","Can see/edit all Asset records belonging to this Organisation & all it's Facilities. Cannot control access permissions.","asset",,,"ALL",,,,,,
View
8 private/prepopulate/demo/IFRC/gis_layer_feature.csv
@@ -1,10 +1,10 @@
"Name","Description","Module","Resource","Symbology","Marker","GPS Marker","Popup Label","Popup Fields","REST Filter","Filter Field","Filter Value","Trackable","Folder","Visible","Enabled"
"Incidents",,"irs","ireport","IFRC","incident","Danger Area","Incident Report","name/category",,,,,,"False"
"Offices","All Active Offices","org","office","IFRC","office","Building","Office","name/organisation_id","office.type=NONE,1,2,3,4&office.obsolete=False",,,,,"False"
-"Project Communities",,"project","activity","IFRC","activity",,"Project Community","name/location_id/multi_activity_type_id",,,,,,"False"
-"Staff","All Active Staff","hrm","human_resource","IFRC","staff","Contact, Dreadlocks","Staff","person_id/job_title/organisation_id","human_resource.type=1&human_resource.status=1","type",1,True,,"False"
-"Volunteers","All Active Volunteers","hrm","human_resource","IFRC","volunteer","Contact, Dreadlocks","Volunteer","person_id/job_title/organisation_id","human_resource.type=2&human_resource.status=1","type",2,True,,"False"
-"Members","All Active Members","member","membership","IFRC","member","Contact, Dreadlocks","Member","person_id/type/organisation_id","membership.end_date=NONE","end_date",NONE,True,,"False"
+"Project Communities",,"project","activity","IFRC","activity",,"Project Community","name/multi_activity_type_id",,,,,,"False"
+"Staff","All Active Staff","hrm","human_resource","IFRC","staff","Contact, Dreadlocks","Staff","person_id/job_title","human_resource.type=1&human_resource.status=1","type",1,True,,"False"
+"Volunteers","All Active Volunteers","hrm","human_resource","IFRC","volunteer","Contact, Dreadlocks","Volunteer","person_id/job_title","human_resource.type=2&human_resource.status=1","type",2,True,,"False"
+"Members","All Active Members","member","membership","IFRC","member","Contact, Dreadlocks","Member","person_id/type","membership.end_date=NONE","end_date",NONE,True,,"False"
"Warehouses","All Active Warehouses","org","office","IFRC","warehouse","Building","Warehouse","name/organisation_id","office.type=5&office.obsolete=False","type",5,,,"False"
"Assets",,"asset","asset","IFRC","asset",,"Asset","item_id/number",,,,True,,"False"
"Stock Items","Used for Search Results","inv","inv_item","IFRC","",,"Stock Item","item_id/site_id/quantity/item_pack_id/expiry_date",,,,,,"False","False"
View
2 private/prepopulate/demo/IFRC/gis_layer_google.csv
@@ -2,7 +2,7 @@
"Google Maps","Streets","maps","True",,
"Google Maps","Streets","maps","True","True","TL"
"Google Hybrid","Streets over Satellite imagery","hybrid","False",,
-"Google Satellite","Satellite imagery","satellite","False",,
+"Google Satellite","Satellite imagery","satellite","True",,
"Google Terrain","Streets over topography","terrain","False",,
"Google MapMaker","Community additions to streets. This is much more detailed than normal Google in some locations. It is incompatioble with Streetview.","mapmaker","False",,
"Google MapMapker Hybrid","Community additions to streets overlaid over Satellite imagery. This is much more detailed than normal Google in some locations. It is incompatioble with Streetview.","mapmakerhybrid","False",,
View
2 static/formats/s3csv/irs/ireport.csv
@@ -1 +1 @@
-Name,Category,Message,Date,Expiry,Country,State,District,City,Lat,Lon,Image,URL
+Name,Category,Message,Date,Expiry,Country,State,District,City,Lat,Lon,Image,URL,Affected,Dead,Injured
View
6 static/formats/s3csv/irs/ireport.xsl
@@ -31,6 +31,9 @@
Lon..................float...........Longitude (Decimal Degrees)
Image................string..........doc_image.url
URL..................string..........doc_document.url
+ Affected.............integer.........irs_ireport.affected
+ Dead.................integer.........irs_ireport.dead
+ Injured..............integer.........irs_ireport.injured
*********************************************************************** -->
<xsl:output method="xml"/>
@@ -65,6 +68,9 @@
<data field="message"><xsl:value-of select="col[@field='Message']"/></data>
<data field="datetime"><xsl:value-of select="col[@field='Date']"/></data>
<data field="expiry"><xsl:value-of select="col[@field='Expiry']"/></data>
+ <data field="affected"><xsl:value-of select="col[@field='Affected']"/></data>
+ <data field="dead"><xsl:value-of select="col[@field='Dead']"/></data>
+ <data field="injured"><xsl:value-of select="col[@field='Injured']"/></data>
<!-- Link to Location -->
<xsl:call-template name="LocationReference"/>
View
62 static/scripts/S3/s3.gis.layers.js
@@ -223,6 +223,39 @@ function addDraftLayer() {
map.addLayer(S3.gis.draftLayer);
}
+/**
+ * Class: OpenLayers.Strategy.AttributeCluster
+ * Strategy for vector feature clustering based on feature attributes.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy.Cluster>
+ */
+OpenLayers.Strategy.AttributeCluster = OpenLayers.Class(OpenLayers.Strategy.Cluster, {
+ /**
+ * the attribute to use for comparison
+ */
+ attribute: null,
+ /**
+ * Method: shouldCluster
+ * Determine whether to include a feature in a given cluster.
+ *
+ * Parameters:
+ * cluster - {<OpenLayers.Feature.Vector>} A cluster.
+ * feature - {<OpenLayers.Feature.Vector>} A feature.
+ *
+ * Returns:
+ * {Boolean} The feature should be included in the cluster.
+ */
+ shouldCluster: function(cluster, feature) {
+ var cc_attrval = cluster.cluster[0].attributes[this.attribute];
+ var fc_attrval = feature.attributes[this.attribute];
+ var superProto = OpenLayers.Strategy.Cluster.prototype;
+ return cc_attrval === fc_attrval &&
+ superProto.shouldCluster.apply(this, arguments);
+ },
+ CLASS_NAME: "OpenLayers.Strategy.AttributeCluster"
+});
+
// GeoJSON
// Used also by internal Feature Layers, Feature Queries & GeoRSS feeds
function addGeoJSONLayer(layer) {
@@ -410,8 +443,17 @@ function addGeoJSONLayer(layer) {
},
fill: function(feature) {
if (feature.cluster) {
- // fillColor for Clustered Point
- var color = '#8087ff';
+ if (feature.cluster[0].attributes.colour) {
+ // Use colour from features
+ var color = feature.cluster[0].attributes.colour;
+ if ( color.indexOf('#') == -1) {
+ // gis_layer_theme
+ color = '#' + color;
+ }
+ } else {
+ // default fillColor for Clustered Point
+ var color = '#8087ff';
+ }
} else if (feature.attributes.colour) {
// Use colour from feature
var color = feature.attributes.colour;
@@ -426,9 +468,18 @@ function addGeoJSONLayer(layer) {
return color;
},
stroke: function(feature) {
- // strokeColor for Clustered Point
if (feature.cluster) {
- var color = '#2b2f76';
+ if (feature.cluster[0].attributes.colour) {
+ // Use colour from features
+ var color = feature.cluster[0].attributes.colour;
+ if ( color.indexOf('#') == -1) {
+ // gis_layer_theme
+ color = '#' + color;
+ }
+ } else {
+ // default strokeColor for Clustered Point
+ var color = '#2b2f76';
+ }
} else if (feature.attributes.colour) {
// Use colour from feature
var color = feature.attributes.colour;
@@ -492,7 +543,8 @@ function addGeoJSONLayer(layer) {
// }
//}
}),
- new OpenLayers.Strategy.Cluster({
+ new OpenLayers.Strategy.AttributeCluster({
+ attribute: 'colour',
distance: cluster_distance,
threshold: cluster_threshold
})
View
7 static/scripts/S3/s3.gis.min.js
@@ -25,12 +25,13 @@ if(S3.gis.layers_features)for(i=0;i<S3.gis.layers_features.length;i++)addGeoJSON
function addBingLayers(){var a=S3.gis.Bing,b=a.ApiKey,c;if(a.Aerial){c=new OpenLayers.Layer.Bing({key:b,type:"Aerial",name:a.Aerial.name,layer_id:a.Aerial.id});map.addLayer(c);Bing.Base=="aerial"&&map.setBaseLayer(c)}if(a.Road){c=new OpenLayers.Layer.Bing({key:b,type:"Road",name:a.Road.name,layer_id:a.Road.id});map.addLayer(c);Bing.Base=="road"&&map.setBaseLayer(c)}if(a.Hybrid){c=new OpenLayers.Layer.Bing({key:b,type:"AerialWithLabels",name:a.Hybrid.name,layer_id:a.Hybrid.id});map.addLayer(c);Bing.Base==
"hybrid"&&map.setBaseLayer(c)}}function addCoordinateGrid(){map.addLayer(new OpenLayers.Layer.cdauth.CoordinateGrid(null,{name:S3.gis.CoordinateGrid.name,shortName:"grid",visibility:S3.gis.CoordinateGrid.visibility,layer_id:S3.gis.CoordinateGrid.id}))}
function addDraftLayer(){var a=S3.gis.marker_url+S3.gis.marker_default,b=S3.gis.marker_default_height,c=S3.gis.marker_default_width,d=OpenLayers.Util.extend({},OpenLayers.Feature.Vector.style["default"]);d.graphicOpacity=1;d.graphicWidth=c;d.graphicHeight=b;d.graphicXOffset=-(c/2);d.graphicYOffset=-b;d.externalGraphic=a;S3.gis.draftLayer=new OpenLayers.Layer.Vector(S3.i18n.gis_draft_layer,{style:d,displayInLayerSwitcher:false});S3.gis.draftLayer.setVisibility(true);map.addLayer(S3.gis.draftLayer)}
+OpenLayers.Strategy.AttributeCluster=OpenLayers.Class(OpenLayers.Strategy.Cluster,{attribute:null,shouldCluster:function(a,b){var c=OpenLayers.Strategy.Cluster.prototype;return a.cluster[0].attributes[this.attribute]===b.attributes[this.attribute]&&c.shouldCluster.apply(this,arguments)},CLASS_NAME:"OpenLayers.Strategy.AttributeCluster"});
function addGeoJSONLayer(a){var b=a.name,c=a.url;if(void 0!=a.marker_image)var d=S3.gis.marker_url+a.marker_image,f=a.marker_height,e=a.marker_width;else d="";var g=void 0!=a.refresh?a.refresh:900;if(void 0!=a.dir){var h=a.dir;$.inArray(h,S3.gis.dirs)==-1&&S3.gis.dirs.push(h)}else h="";var j=void 0!=a.visibility?a.visibility:true,l=void 0!=a.opacity?a.opacity:1,m=void 0!=a.cluster_distance?a.cluster_distance:S3.gis.cluster_distance,o=void 0!=a.cluster_threshold?a.cluster_threshold:S3.gis.cluster_threshold,
k=void 0!=a.projection?a.projection:4326,k=4326==k?S3.gis.proj4326:new OpenLayers.Projection("EPSG:"+k),l=new OpenLayers.Style({label:"${label}",labelAlign:"cm",pointRadius:"${radius}",fillColor:"${fill}",fillOpacity:l,strokeColor:"${stroke}",strokeWidth:2,strokeOpacity:l,graphicWidth:"${graphicWidth}",graphicHeight:"${graphicHeight}",graphicXOffset:"${graphicXOffset}",graphicYOffset:"${graphicYOffset}",graphicOpacity:l,graphicName:"${graphicName}",externalGraphic:"${externalGraphic}"},{context:{graphicWidth:function(a){return a.cluster?
"":a.attributes.marker_width?a.attributes.marker_width:e},graphicHeight:function(a){return a.cluster?"":a.attributes.marker_height?a.attributes.marker_height:f},graphicXOffset:function(a){return a.cluster?"":a.attributes.marker_width?-(a.attributes.marker_width/2):-(e/2)},graphicYOffset:function(a){return a.cluster?"":a.attributes.marker_height?-a.attributes.marker_height:-f},graphicName:function(a){return a.cluster?"circle":a.attributes.shape?a.attributes.shape:"circle"},externalGraphic:function(a){return a.cluster?
-"":a.attributes.marker_url?a.attributes.marker_url:d},radius:function(a){return a.cluster?Math.min(a.attributes.count/2,8)+10:a.attributes.size?a.attributes.size:10},fill:function(a){if(a.cluster)a="#8087ff";else if(a.attributes.colour){a=a.attributes.colour;a.indexOf("#")==-1&&(a="#"+a)}else a="#f5902e";return a},stroke:function(a){if(a.cluster)a="#2b2f76";else if(a.attributes.colour){a=a.attributes.colour;a.indexOf("#")==-1&&(a="#FFFFFF")}else a="#f5902e";return a},label:function(a){var b="";if(a.cluster&&
-a.attributes.count>1)b=a.attributes.count;return b}}}),l=new OpenLayers.StyleMap({"default":l,select:{fillColor:"#ffdc33",strokeColor:"#ff9933"}}),a=new OpenLayers.Layer.Vector(b,{dir:h,projection:k,strategies:[new OpenLayers.Strategy.BBOX({ratio:1.5}),new OpenLayers.Strategy.Refresh({force:true,interval:g*1E3}),new OpenLayers.Strategy.Cluster({distance:m,threshold:o})],layer_id:a.id,legendURL:d,styleMap:l,protocol:new OpenLayers.Protocol.HTTP({url:c,format:S3.gis.format_geojson})});a.setVisibility(j);
-a.events.on({featureselected:onGeojsonFeatureSelect,featureunselected:onFeatureUnselect,loadstart:showThrobber,loadend:hideThrobber,loadcancel:hideThrobber});map.addLayer(a);S3.gis.layers_all.push(a)}
+"":a.attributes.marker_url?a.attributes.marker_url:d},radius:function(a){return a.cluster?Math.min(a.attributes.count/2,8)+10:a.attributes.size?a.attributes.size:10},fill:function(a){if(a.cluster)if(a.cluster[0].attributes.colour){a=a.cluster[0].attributes.colour;a.indexOf("#")==-1&&(a="#"+a)}else a="#8087ff";else if(a.attributes.colour){a=a.attributes.colour;a.indexOf("#")==-1&&(a="#"+a)}else a="#f5902e";return a},stroke:function(a){if(a.cluster)if(a.cluster[0].attributes.colour){a=a.cluster[0].attributes.colour;
+a.indexOf("#")==-1&&(a="#"+a)}else a="#2b2f76";else if(a.attributes.colour){a=a.attributes.colour;a.indexOf("#")==-1&&(a="#FFFFFF")}else a="#f5902e";return a},label:function(a){var b="";if(a.cluster&&a.attributes.count>1)b=a.attributes.count;return b}}}),l=new OpenLayers.StyleMap({"default":l,select:{fillColor:"#ffdc33",strokeColor:"#ff9933"}}),a=new OpenLayers.Layer.Vector(b,{dir:h,projection:k,strategies:[new OpenLayers.Strategy.BBOX({ratio:1.5}),new OpenLayers.Strategy.Refresh({force:true,interval:g*
+1E3}),new OpenLayers.Strategy.AttributeCluster({attribute:"colour",distance:m,threshold:o})],layer_id:a.id,legendURL:d,styleMap:l,protocol:new OpenLayers.Protocol.HTTP({url:c,format:S3.gis.format_geojson})});a.setVisibility(j);a.events.on({featureselected:onGeojsonFeatureSelect,featureunselected:onFeatureUnselect,loadstart:showThrobber,loadend:hideThrobber,loadcancel:hideThrobber});map.addLayer(a);S3.gis.layers_all.push(a)}
function addGoogleLayers(){var a=S3.gis.Google,b;if(a.MapMaker||a.MapMakerHybrid){if(a.Satellite){b=new OpenLayers.Layer.Google(a.Satellite.name,{type:G_SATELLITE_MAP,sphericalMercator:true,layer_id:a.Satellite.id});map.addLayer(b);a.Base=="satellite"&&map.setBaseLayer(b)}if(a.Maps){b=new OpenLayers.Layer.Google(a.Maps.name,{type:G_NORMAL_MAP,sphericalMercator:true,layer_id:a.Maps.id});map.addLayer(b);a.Base=="maps"&&map.setBaseLayer(b)}if(a.Hybrid){b=new OpenLayers.Layer.Google(a.Hybrid.name,{type:G_HYBRID_MAP,
sphericalMercator:true,layer_id:a.Hybrid.id});map.addLayer(b);a.Base=="maps"&&map.setBaseLayer(b)}if(a.Terrain){b=new OpenLayers.Layer.Google(a.Terrain.name,{type:G_PHYSICAL_MAP,sphericalMercator:true,layer_id:a.Terrain.id});map.addLayer(b);a.Base=="terrain"&&map.setBaseLayer(b)}if(a.MapMaker){b=new OpenLayers.Layer.Google(a.MapMaker.name,{type:G_MAPMAKER_NORMAL_MAP,sphericalMercator:true,layer_id:b.id});map.addLayer(b);a.Base=="mapmaker"&&map.setBaseLayer(b)}if(a.MapMakerHybrid){b=new OpenLayers.Layer.Google(a.MapMakerHybrid.name,
{type:G_MAPMAKER_HYBRID_MAP,sphericalMercator:true,layer_id:b.id});map.addLayer(b);a.Base=="mapmakerhybrid"&&map.setBaseLayer(b)}}else{if(a.Satellite){b=new OpenLayers.Layer.Google(a.Satellite.name,{type:"satellite",numZoomLevels:22,layer_id:a.Satellite.id});map.addLayer(b);a.Base=="satellite"&&map.setBaseLayer(b)}if(a.Maps){b=new OpenLayers.Layer.Google(a.Maps.name,{numZoomLevels:20,layer_id:a.Maps.id});map.addLayer(b);a.Base=="maps"&&map.setBaseLayer(b)}if(a.Hybrid){b=new OpenLayers.Layer.Google(a.Hybrid.name,
View
20 tests/unit_tests/modules/s3/s3rest.py
@@ -469,6 +469,26 @@ def testComponentFilterConstruction3(self):
self.assertEqual(rfilter.left, Storage())
rows = component.sqltable(as_rows=True)
+ def testComponentFilterConstruction4(self):
+
+ resource = s3mgr.define_resource("pr", "person",
+ id=1,
+ components=["competency"],
+ filter=(s3base.S3FieldSelector("competency.id") == 1))
+
+ component = resource.components["competency"]
+ query = component.get_query()
+ self.assertEqual(str(query), "((((hrm_competency.deleted <> 'T') AND "
+ "((hrm_competency.owned_by_organisation IS NULL) OR "
+ "(hrm_competency.owned_by_organisation IN (3)))) AND "
+ "((((pr_person.deleted <> 'T') AND "
+ "((pr_person.owned_by_organisation IS NULL) OR "
+ "(pr_person.owned_by_organisation IN (3)))) AND "
+ "(pr_person.id = 1)) AND "
+ "(hrm_competency.id = 1))) AND "
+ "((hrm_competency.person_id = pr_person.id) AND "
+ "(hrm_competency.deleted <> 'T')))")
+
def testGetLeftJoins(self):
q = (s3base.S3FieldSelector("organisation_id$name") == "test") & \

0 comments on commit 7eaf3af

Please sign in to comment.
Something went wrong with that request. Please try again.