699
702
# -----------------------------------------------------------------------------
700
def shn_search(r, **attr):
702
""" Search function, mostly used with the JSON representation
704
used as method handler for S3Resources
706
@todo: replace by a S3MethodHandler
710
deletable = attr.get("deletable", True)
711
main = attr.get("main", None)
712
extra = attr.get("extra", None)
716
# Filter Search list to just those records which user can read
717
query = shn_accessible_query("read", r.table)
719
# Filter search to items which aren't deleted
720
if "deleted" in r.table:
721
query = (r.table.deleted == False) & query
723
# Respect response.s3.filter
724
if response.s3.filter:
725
query = response.s3.filter & query
727
if r.representation in shn_interactive_view_formats:
729
shn_represent(r.table, r.prefix, r.name, deletable, main, extra)
730
search = t2.search(r.table, query=query)
731
#search = crud.search(r.table, query=query)[0]
733
# Check for presence of Custom View
734
shn_custom_view(r, "search.html")
737
title = s3.crud_strings.title_search
739
output = dict(search=search, title=title)
741
elif r.representation == "json":
746
# JQuery Autocomplete uses "q" instead of "value"
747
# JQueryUI Autocomplete uses "term" instead of "value"
748
value = _vars.value or _vars.term or _vars.q or None
750
if _vars.field and _vars.filter and value:
751
field = str.lower(_vars.field)
752
_field = _table[field]
755
if "field2" in _vars:
756
field2 = str.lower(_vars.field2)
759
if "field3" in _vars:
760
field3 = str.lower(_vars.field3)
763
if "parent" in _vars and _vars.parent:
764
if _vars.parent == "null":
767
parent = int(_vars.parent)
770
if "exclude_field" in _vars:
771
exclude_field = str.lower(_vars.exclude_field)
772
if "exclude_value" in _vars:
773
exclude_value = str.lower(_vars.exclude_value)
780
limit = int(_vars.limit or 0)
782
filter = _vars.filter
784
if field2 and field3:
785
# pr_person name search
787
value1, value2 = value.split(" ", 1)
788
query = query & ((_field.like("%" + value1 + "%")) & \
789
(_table[field2].like("%" + value2 + "%")) | \
790
(_table[field3].like("%" + value2 + "%")))
792
query = query & ((_field.like("%" + value + "%")) | \
793
(_table[field2].like("%" + value + "%")) | \
794
(_table[field3].like("%" + value + "%")))
796
elif exclude_field and exclude_value:
797
# gis_location hierarchical search
798
# Filter out poor-quality data, such as from Ushahidi
799
query = query & (_field.like("%" + value + "%")) & \
800
(_table[exclude_field] != exclude_value)
803
# gis_location hierarchical search
804
# NB Currently not used - we allow people to search freely across all the hierarchy
805
# SQL Filter is immediate children only so need slow lookup
806
#query = query & (_table.parent == parent) & \
807
# (_field.like("%" + value + "%"))
808
children = gis.get_children(parent)
809
children = children.find(lambda row: value in str.lower(row.name))
810
item = children.json()
814
# Normal single-field
815
query = query & (_field.like("%" + value + "%"))
819
item = db(query).select(limitby=(0, limit)).json()
821
item = db(query).select().json()
824
query = query & (_field == value)
826
# e.g. gis_location hierarchical search
827
query = query & (_table.parent == parent)
829
if _table == db.gis_location:
830
# Don't return unnecessary fields (WKT is large!)
831
item = db(query).select(_table.id, _table.uuid, _table.parent, _table.name, _table.level, _table.lat, _table.lon, _table.addr_street).json()
833
item = db(query).select().json()
836
query = query & (_field < value)
837
item = db(query).select().json()
840
query = query & (_field > value)
841
item = db(query).select().json()
844
item = s3xrc.xml.json_message(False, 400, "Unsupported filter! Supported filters: ~, =, <, >")
845
raise HTTP(400, body=item)
848
#item = s3xrc.xml.json_message(False, 400, "Search requires specifying Field, Filter & Value!")
849
#raise HTTP(400, body=item)
850
# Provide a simplified JSON output which is in the same format as the Search one
851
# (easier to parse than S3XRC & means no need for different parser for filtered/unfiltered)
852
if _table == db.gis_location:
853
# Don't return unnecessary fields (WKT is large!)
854
item = db(query).select(_table.id, _table.name, _table.level).json()
856
item = db(query).select().json()
858
response.view = "xml.html"
859
output = dict(item=item)
862
raise HTTP(501, body=BADFORMAT)
867
# -----------------------------------------------------------------------------
868
703
def shn_barchart (r, **attr):
870
705
""" Provide simple barcharts for resource attributes
1005
# Set method handlers
1006
s3xrc.set_handler("search", shn_search)
1007
s3xrc.set_handler("copy", shn_copy)
1008
s3xrc.set_handler("barchart", shn_barchart)
1010
840
# Parse and execute the request
1011
841
resource, r = s3xrc.parse_request(prefix, resourcename)
843
resource.set_handler("search", _s3xrc.S3Search(s3xrc))
844
resource.set_handler("copy", shn_copy)
845
resource.set_handler("barchart", shn_barchart)
1012
847
output = resource.execute_request(r, **attr)
1014
# Add default action buttons in list views
1015
849
if isinstance(output, dict) and not r.method or r.method=="search_simple":
1017
850
if response.s3.actions is None:
852
# Add default action buttons
1019
853
prefix, name, table, tablename = r.target()
1020
854
authorised = shn_has_permission("update", tablename)