예제 #1
0
  def DoSearch(self, search_query, response_type):
    """Performs the coordinate search.

    Args:
     search_query: A string containing the search coordinates as
      entered by the user.
     response_type: Response type can be KML or JSONP, depending on the client.
    Returns:
     search_results: A KML/JSONP formatted string which contains search results.
    Raises:
     BadQueryException: if the search query is invalid.
    """
    coordinate_type = ""
    search_results = ""

    input_coordinates = []
    decimal_degrees_coordinates = []

    search_tokens = self.utils.SearchTokensFromString(search_query)
    self.logger.debug("coordinates: %s", ",".join(search_tokens))
    input_coordinates = self._transform.GetInputCoordinates(
        ",".join(search_tokens))
    number_of_coordinates = len(input_coordinates)

    if number_of_coordinates == 0:
      msg = "Incomplete search query %s submitted" % search_query
      self.logger.error(msg)
      raise exceptions.BadQueryException(msg)

    coordinate_type = self._transform.GetInputType(input_coordinates)

    self.logger.debug("Coordinate type is %s.", coordinate_type)

    if coordinate_type in self.coordinates_in_lat_lng_format_:
      reqd_num_of_coordinates = CoordinateSearch.NUM_OF_COORDS_IN_LAT_LNG_FORMAT
    else:
      reqd_num_of_coordinates = CoordinateSearch.NUM_OF_COORDS_IN_MGRS_FORMAT

    if number_of_coordinates > reqd_num_of_coordinates:
      self.logger.warning(
          "extra search parameters ignored: %s", ",".join(
              input_coordinates[reqd_num_of_coordinates:]))
      input_coordinates = input_coordinates[:reqd_num_of_coordinates]
    elif number_of_coordinates < reqd_num_of_coordinates:
      msg = "Incomplete search query %s submitted" % search_query
      self.logger.error(msg)
      raise exceptions.BadQueryException(msg)

    decimal_degrees_coordinates = self._transform.TransformToDecimalDegrees(
        coordinate_type, input_coordinates)

    search_results = self.ConstructResponse(
        response_type, decimal_degrees_coordinates)

    search_status = True if search_results else False

    return search_status, search_results
예제 #2
0
    def GetInputType(self, coordinates):
        """Check the coordinate type. Valid types are DD, DMS, DDM, UTM, MGRS.

    Args:
     coordinates: List containing latitude and longitude pair (both should be
      in same format).
    Returns:
     coordinate_type: coordinate type i.e., DD, DMS, DDM, UTM or MGRS.
    Raises:
     BadQueryException: for invalid coordinate type.
    """
        coordinate_type = ""
        pattern_matched = []

        for pattern, input_type in self._input_pattern_types:
            pattern_obj = re.compile(pattern)
            pattern_matched = [
                pattern_obj.match(z) is not None for z in coordinates
            ]

            if self.IsValidInputType(pattern_matched):
                coordinate_type = input_type
                break

        if not coordinate_type:
            msg = ("Invalid coordinate type. Supported formats are "
                   "DD, DMS, DDM, UTM and MGRS.")
            self._logger.error(msg)
            raise exceptions.BadQueryException(msg)

        return coordinate_type
예제 #3
0
  def HandleSearchRequest(self, environ):
    """Fetches the search tokens from form and performs the coordinate search.

    Args:
     environ: A list of environment variables as supplied by the
      WSGI interface to the coordinate search application interface.
    Returns:
     search_results: A KML/JSONP formatted string which contains search results.
    Raises:
     BadQueryException: if the search query is invalid.
    """
    search_results = ""

    # Fetch all the attributes provided by the user.
    parameters = self.utils.GetParameters(environ)
    response_type = self.utils.GetResponseType(environ)

    # Retrieve the function call back name for JSONP response.
    self.f_callback = self.utils.GetCallback(parameters)

    original_query = self.utils.GetValue(parameters, "q")

    if not original_query:
      msg = "Empty search query received."
      self.logger.error(msg)
      raise exceptions.BadQueryException(msg)

    search_status, search_results = self.DoSearch(original_query, response_type)

    if not search_status:
      folder_name = "Search returned no results."
      search_results = self.utils.NoSearchResults(
          folder_name, self._style, response_type, self.f_callback)

    return (search_results, response_type)
예제 #4
0
  def TransformToDecimalDegrees(self, coordinate_type, coordinates):
    """Performs a coordinate transformation from DMS, DDM, MGRS, UTM to DD.

    Args:
     coordinate_type: Format of coordinates, can be either of DD, DMS, DDM,
      UTM, MGRS.
     coordinates: List of coordinates in coordinate_type format.
    Returns:
     decimal_degrees_coordinates: List of coordinates in DD(Decimal Degrees)
      format.
    Raises:
     BadQueryException: if the coordinates are invalid.
    """

    conversion_status = False
    decimal_degrees_coordinates = []

    if coordinate_type == "DMS":
      conversion_status, decimal_degrees_coordinates = self.TransformDMSToDD(
          coordinates)
    elif coordinate_type == "DDM":
      conversion_status, decimal_degrees_coordinates = self.TransformDDMToDD(
          coordinates)
    elif coordinate_type == "MGRS":
      conversion_status, decimal_degrees_coordinates = self.TransformMGRSToDD(
          coordinates)
    elif coordinate_type == "UTM":
      conversion_status, decimal_degrees_coordinates = self.TransformUTMToDD(
          coordinates)
    elif coordinate_type == "DD":
      conversion_status, decimal_degrees_coordinates = self.TransformDDToDD(
          coordinates)
    else:
      self._logger.error(
          "Invalid type %s for coordinates %s.", coordinate_type, coordinates)

    self._logger.debug(
        "Transformation of %s to DD format %s",
        coordinates, ("successful" if conversion_status else "Failed"))

    if (not conversion_status or len(decimal_degrees_coordinates) != 2 or
        not self.IsValidCoordinatePair(
            float(decimal_degrees_coordinates[0]),
            float(decimal_degrees_coordinates[1]))):
      msg = "Couldn't transform coordinates: %s of type: %s" % (
          coordinates, coordinate_type)
      self._logger.error(msg)
      raise exceptions.BadQueryException(msg)

    return decimal_degrees_coordinates
    def HandleSearchRequest(self, environ):
        """Retrieves search tokens from form and performs the custom POI search.

    Args:
     environ: A list of environment variables as supplied by the
      WSGI interface to the custom POI search application interface.
    Returns:
     A XML/JSON formatted string with search results.
    Raises:
     BadQueryException: When all the mandatory parameters are not provided
     to the Google Places database.
    """
        # Retrieve "response_type", "location", "radius", "key" and
        # "callback" parameters from the form.
        parameters = self.utils.GetParameters(environ)
        response_type = self.utils.GetResponseType(environ)
        location = self.utils.GetValue(parameters, "location")
        radius = self.utils.GetValue(parameters, "radius")
        server_key = self.utils.GetValue(parameters, "key")

        # Default "callback" value is "handleSearchResults".
        f_callback = self.utils.GetCallback(parameters)

        if location and server_key and radius:
            output_type = self.GetOutputType(response_type)

            # Create Google Places database URL here.
            url = self._places_api_url % (output_type, location, radius,
                                          server_key)
            self.logger.debug("Google Places database URL is %s.", url)

            url_fetch = urllib2.urlopen(url)

            if response_type == "KML":
                return self.FormatKMLResponse(url_fetch)
            elif response_type == "JSONP":
                # Prepare a "jsonp" message as per the requirements of
                # GEE search services for maps.
                return "%s(%s);" % (f_callback,
                                    self.FormatJSONResponse(url_fetch))
        else:
            error = ("location, radius or key information not "
                     "received by the server.")
            raise exceptions.BadQueryException(error)
예제 #6
0
  def __ParseSQLResults(self, search_expression, poi_info, response_type, bbox):
    """Performs the poi search and returns the results.

    Args:
     search_expression: Normalized search expression.
     poi_info: Tuple containing sql_query, number of columns, style id
      and poi id as extracted from "poi_table" table of "gesearch" database.
     response_type: Either KML/JSONP, depending on the client.
     bbox: The bounding box string.
    Returns:
     poi_query_status: Whether data could be queried from "gepoi" database.
     poi_query_results: Query results as a list.
    Raises:
      psycopg2.pool.PoolError in case of error while getting a
          connection from the pool.
    """
    poi_query_status = False
    poi_query_results = []
    query_results = []
    poi_query = ""

    sql_query = poi_info[0]
    num_of_input_fields = poi_info[1]

    try:
      search_tokens = self.utils.SearchTokensFromString(search_expression)
    except Exception as e:
      raise exceptions.BadQueryException(
          "Couldn't parse search term. Error: %s" % e)

    self.logger.debug("Parsed search tokens: %s", search_tokens)
    params = ["%" + entry + "%" for entry in search_tokens]

    num_params = len(params)
    if num_params == 0:
      raise exceptions.BadQueryException("No search term.")

    if num_params > num_of_input_fields:
      params = params[:num_of_input_fields]
    elif num_params < num_of_input_fields:
      if num_params == 1:
        params.extend([params[0]] * (num_of_input_fields - num_params))
      else:
        params.extend(["^--IGNORE--"] * (num_of_input_fields - num_params))

    accum_func = self.utils.GetAccumFunc(response_type)

    # sql queries retrieved from "gesearch" database has "?" for
    # input arguments, but postgresql supports "%s".
    # Hence, replacing "?" with "%s".

    sql_stmt = sql_query.replace("?", "%s")

    # Extract the displayable and searchable POI fields from the POI
    # queries retrieved from "poi_table".
    matched = re.match(r"(\w*)\s*(Encode.*geom)(.*)(FROM.*)(WHERE )(\(.*\))",
                       sql_stmt)

    if matched:
      (sub_query1, unused_sub_query2,
       sub_query3, sub_query4, sub_query5, sub_query6) = matched.groups()
      # sub_query2 need to be replaced with a new query
      # as per the response_type.
      # PYLINT throws warning that sub_query2 has not been used, it's
      # not required and can be ignored.

      geom_stmt = "%s(the_geom) AS the_geom" % (accum_func)
      poi_query = "%s %s%s%s%s%s" % (sub_query1, geom_stmt, sub_query3,
                                     sub_query4, sub_query5, sub_query6)

      poi_query += " AND ( the_geom && %s )" % bbox

      # Displayable POI fields appear between SELECT and FROM
      # clause of the POI queries, as in below example.
      # SELECT ST_AsKML(the_geom) AS the_geom, "rpoly_", "fnode_"
      # FROM gepoi_7 WHERE ( lower("rpoly_") LIKE %s OR lower("name") LIKE %s ).

      # "rpoly_" and "fnode_" are display fields in the above example.
      display_fields = [field.replace("\"", "").strip()
                        for field in filter(len, sub_query3.split(","))]
      # Insert geom at the 0th index for easy retrieval.
      display_fields.insert(0, "geom")

      # Searchable POI fields appear after the WHERE
      # clause of the POI queries, as in below example.
      # SELECT ST_AsKML(the_geom) AS the_geom, "rpoly_", "fnode_"
      # FROM gepoi_7 WHERE ( lower("rpoly_") LIKE %s OR lower("name") LIKE %s ).

      # "rpoly_" and "name" are searchable fields in the above example.
      searchable_fields = [
          entry.strip().strip("OR").strip().strip("lower").strip("\\(\\)\"")
          for entry in filter(len, sub_query6.strip("\\(\\) ").split("LIKE %s"))
          ]

      # Insert geom at the 0th index for easy retrieval.
      searchable_fields.insert(0, "geom")

    if poi_query:
      poi_query_status, query_results = self.__RunPGSQLQuery(
          self._poi_pool, poi_query, params)

      # Create a map which will have the POI fields values
      # retrieved from the gepoi_X tables and
      # other information like displayable or searchable or both
      # based on the display and search labels retrieved above.

      # Some sample maps are as below.
      # 1) {
      #    'field_value': 'State Route 55',
      #    'field_name': 'name',
      #  'is_search_display': True,
      #   'is_searchable': True,
      #   'is_displayable': True
      #}

      # 2) {'field_value': '0',
      #    'field_name': 'rpoly_',
      #    'is_search_display': True,
      #    'is_searchable': True,
      #    'is_displayable': True}.

      # 3) {'field_value': '22395',
      #     'field_name': 'fnode_',
      #     'is_search_display': True,
      #     'is_searchable': True,
      #     'is_displayable': True}.

      # These maps would be used when creating the KML and JSONP responses
      # The different flags (is_displayable,is_searchable etc) allow for
      # easier retrieval of data based on our requirements.

      for entry in query_results:
        field_name_value = []

        for field_name, field_value in zip(display_fields, entry):
          temp = {}
          temp["field_name"] = field_name
          temp["field_value"] = field_value
          temp["is_searchable"] = (field_name in searchable_fields)
          # "is_displayable" is always True as we are iterating over
          # the display(only) POI fields.
          temp["is_displayable"] = True
          temp["is_search_display"] = (
              temp["is_displayable"] and temp["is_searchable"])
          field_name_value.append(temp)

        for field_name in searchable_fields:
          temp = {}
          if field_name not in display_fields:
            temp["field_name"] = field_name
            temp["field_value"] = ""
            # "is_searchable" is always True as we are iterating over
            # the search(only) POI fields.
            temp["is_searchable"] = True
            temp["is_displayable"] = (field_name in display_fields)
            temp["is_search_display"] = (
                temp["is_displayable"] and temp["is_searchable"])
            field_name_value.append(temp)

        poi_query_results.append(field_name_value)

    return poi_query_status, poi_query_results