Exemple #1
0
def children(request):
    """ Implement the "/geo/api/location/children" API call.
    """
    loc_code = get_param(request, "location")

    if loc_code != None:
        # We've been asked to generate a list of all children of the given
        # location.
        try:
            location = Location.objects.get(code=loc_code)
        except Location.DoesNotExist:
            return error_response(code=400,
                                  message="Missing or invalid location code",
                                  callback=get_param(request, "callback"))

        children = []
        for child in location.children.all():
            children.append(child.code)

        results = json.dumps({'children' : children})

        callback = get_param(request, "callback")
        if callback != None:
            results = callback + "(" + results + ")" # Add JSONP callback.

        return HttpResponse(results, mimetype="application/json")

    # If we get here, we don't have a parent location -> assemble a list of all
    # the top-level (country) locations.

    countryLevel = Level.objects.get(level=1)

    countries = []
    for country in Location.objects.filter(level=countryLevel):
        countries.append(country.code)

    results = json.dumps({'children' : countries})

    callback = get_param(request, "callback")
    if callback != None:
        results = callback + "(" + results + ")" # Add JSONP callback.

    return HttpResponse(results, mimetype="application/json")
Exemple #2
0
def locate(request):
    """ Implement the "/locate" API call.
    """
    if request.method == "GET":
        params = request.GET
    elif request.method == "POST":
        params = request.POST
    else:
        params = {}

    code,response = geolocator.geolocate(params)

    if code == 200:
        # We got a normal response -> bundle it up and return it to the caller.
        response = json.dumps(response)
        if "callback" in params:
            # Wrap the response in a JSONP callback function.
            response = params['callback'] + "(" + response + ")"
        return HttpResponse(response, mimetype="application/json")
    else:
        # We got an error response -> return the error back to the caller.
        return error_response(code, response, params.get("callback"))
Exemple #3
0
def parents(request):
    """ Implement the "parents" API call.
    """
    loc_code = get_param(request, "location")

    try:
        location = Location.objects.get(code=loc_code)
    except Location.DoesNotExist:
        return error_response(code=400,
                              message="Missing or invalid location code",
                              callback=get_param(request, "callback"))

    parents = []
    for parent in location.parents.all():
        parents.append(parent.code)

    results = json.dumps({'parents' : parents})

    callback = get_param(request, "callback")
    if callback != None:
        results = callback + "(" + results + ")" # Add JSONP callback.

    return HttpResponse(results, mimetype="application/json")
Exemple #4
0
def main(request):
    """ Respond to the "/" URL.

        This is the main entry point for the tableau_api application.
    """
    # Extract our CGI parameters.

    location = get_param(request, "location")
    if location == None:
        return error_response(code=400,
                              message="Missing 'location' parameter.",
                              callback=get_param(request, "callback"))

    name = get_param(request, "name")

    ok = True # initially.
    width = get_param(request, "width")
    if width == None:
        ok = False
    else:
        try:
            width = int(width)
        except ValueError:
            ok = False

    if ok:
        if width < 10 or width > 2000:
            ok = False

    if not ok:
        return error_response(code=400,
                              message="Missing or invalid 'width' parameter.",
                              callback=get_param(request, "callback"))

    ok = True # initially.
    height = get_param(request, "height")
    if height == None:
        ok = False
    else:
        try:
            height = int(height)
        except ValueError:
            ok = False

    if ok:
        if height < 10 or height > 2000:
            ok = False

    if not ok:
        return error_response(code=400,
                              message="Missing or invalid 'height' parameter.",
                              callback=get_param(request, "callback"))

    # See which tableau we need to generate.

    tableau = tableauGenerator.select_tableau(location, name)
    if tableau == None:
        return error_response(code=500, message="No tableau found.",
                              callback=get_param(request, "callback"))

    # See if this tableau already exists in the tableau cache for the requested
    # size.  If so, we can use the cached JSON data directly.

    if tableauCache != None:
        json_data = tableauCache.get(tableau.id, width, height)
    else:
        json_data = None # No cache module -> nothing is cached.

    # If we didn't have a cache entry for this tableau and size, we have to
    # generate it.

    if json_data == None:
        try:
            generated_tableau = tableauGenerator.generate_tableau(tableau,
                                                                  width,
                                                                  height)
        except:
            # Something went wrong.  Print the traceback into the Django log
            # and return an error message back to the caller.
            traceback.print_exc()
            return error_response(code=500, message="Internal server error.",
                                  callback=get_param(request, "callback"))

        json_data = json.dumps({'tableau' : generated_tableau})

        # If we have a tableau cache, save the generated tableau into the cache
        # so that we can retrieve it quickly next time.

        if tableauCache != None:
            tableauCache.save(tableau.id, width, height, json_data)

    # Finally, return the results back to the caller.

    callback = get_param(request, "callback")
    if callback != None:
        json_data = callback + "(" + json_data + ")" # Add JSONP callback.

    return HttpResponse(json_data, mimetype="application/json")
Exemple #5
0
def search_by_latlong(request):
    """ Implement the "latlong" API call.
    """
    # Process our CGI parameters.

    try:
        latitude = float(request.GET["lat"])
    except:
        return error_response(
            code=400, message="Missing or invalid 'lat' parameter.", callback=get_param(request, "callback")
        )

    try:
        longitude = float(request.GET["long"])
    except:
        return error_response(
            code=400, message="Missing or invalid 'long' parameter.", callback=get_param(request, "callback")
        )

    try:
        strategy = request.GET["strategy"]
    except KeyError:
        return error_response(
            code=400, message="Missing 'strategy' parameter.", callback=get_param(request, "callback")
        )

    if strategy == "all":
        pass
    elif strategy == "level":
        try:
            levels_param = request.GET["levels"]
        except KeyError:
            return error_response(
                code=400, message="Missing 'levels' parameter.", callback=get_param(request, "callback")
            )

        levels = []  # List of desired Level objects.
        for level_name in levels_param.split(","):
            level = name_to_level(level_name)
            if level != None:
                levels.append(level)
            else:
                return error_response(
                    code=400, message="Unknown level: " + repr(level_name), callback=get_param(request, "callback")
                )
    elif strategy == "parent":
        try:
            loc_code = request.GET["location"]
        except KeyError:
            return error_response(
                code=400, message="Missing 'location' parameter.", callback=get_param(request, "callback")
            )

        if loc_code == "WORLD":
            location = None
        else:
            try:
                location = Location.objects.get(code=loc_code)
            except Location.DoesNotExist:
                return error_response(
                    code=400, message="Unknown location " + repr(loc_code), callback=get_param(request, "callback")
                )
    else:
        return error_response(
            code=400, message="Invalid strategy " + repr(strategy), callback=get_param(request, "callback")
        )

    # Calculate the matching locations, using the specified strategy.

    pt = Point(longitude, latitude, srid=4326)

    locations = []

    if strategy == "all":
        for outline in Outline.objects.filter(outline__bbcontains=pt):
            if outline.outline.contains(pt):
                locations.append(outline.location.code)
    elif strategy == "level":
        for level in levels:
            for outline in Outline.objects.filter(location__level=level, outline__bbcontains=pt):
                if outline.outline.contains(pt):
                    locations.append(outline.location.code)
    elif strategy == "parent":
        # Check the starting location's children.
        outlineIDs = []
        if location != None:
            for child in location.children.all():
                outline = get_outline(child)
                if outline != None:
                    outlineIDs.append(outline.id)
        else:
            # We're at the top level -> check the countries.
            for child in Location.objects.filter(level__level=1):
                outline = get_outline(child)
                if outline != None:
                    outlineIDs.append(outline.id)

        for outline in Outline.objects.filter(id__in=outlineIDs, outline__bbcontains=pt):
            if outline.outline.contains(pt):
                locations.append(outline.location.code)
                break

        if len(locations) == 0:
            # We didn't find a child location -> search for locations starting
            # at the same level as the parent, going up to the country level.
            if location != None:
                for level in range(location.level.level, 0, -1):
                    query = Outline.objects.filter(outline__bbcontains=pt, location__level__level=level)
                    for outline in query:
                        if outline.outline.contains(pt):
                            locations.append(outline.location.code)
                            break
                    if len(locations) > 0:
                        break  # Only find the first matching location.

    # Finally, return the found locations back to the caller.

    results = json.dumps({"locations": locations})

    callback = get_param(request, "callback")
    if callback != None:
        results = callback + "(" + results + ")"  # Add JSONP callback.

    return HttpResponse(results, mimetype="application/json")
Exemple #6
0
def search_by_name(request):
    """ Implement the "/name" API call.
    """
    # Extract our parameters.

    levels = []

    level_param = get_param(request, "level")
    if level_param != None:
        level = name_to_level(level_param)
        if level == None:
            return error_response(
                code=400, message="Unknown level: " + repr(level_param), callback=get_param(request, "callback")
            )
        levels.append(level)
    else:
        levels_param = get_param(request, "levels")
        if levels_param != None:
            for level_name in levels_param.split(","):
                level = name_to_level(level_name)
                if level == None:
                    return error_response(
                        code=400, message="Unknown level: " + repr(level_param), callback=get_param(request, "callback")
                    )
                levels.append(level)

    text = get_param(request, "text")

    if text == None:
        return error_response(code=400, message="Missing 'text' parameter.", callback=get_param(request, "callback"))
    if len(text) < 3:
        return error_response(code=400, message="'text' parameter too short.", callback=get_param(request, "callback"))

    type = get_param(request, "type")

    if type != None:
        type = type.lower()
        if not type in [
            "exact",
            "contains",
            "startswith",
            "endswith",
            "iexact",
            "icontains",
            "istartswith",
            "iendswith",
        ]:
            return error_response(
                code=400, message="Invalid 'type' parameter: " + repr(type), callback=get_param(request, "callback")
            )
    else:
        type = "istartswith"  # Default search type.

    # Perform the appropriate type of name-based search.

    args = {"name__" + str(type): text}
    if len(levels) > 0:
        args["level__in"] = levels

    query = Name.objects.filter(**args).order_by("level__level", "name")
    results = {}

    num_matches = query.count()
    results["numMatches"] = num_matches

    if num_matches <= 20:
        matches = []
        matched_locs = set()  # Used to only include each location once.

        for name in query:
            for loc_name in name.locationname_set.all():
                location = loc_name.location
                if location in matched_locs:
                    # Only include each location once.
                    continue

                matches.append(
                    {
                        "level": level_to_name(location.level),
                        "code": location.code,
                        "foundName": name.name,
                        "locationName": location.name,
                        "displayName": location.display_name,
                        "abbreviation": location.abbreviation,
                        "context": get_context(location),
                    }
                )

                matched_locs.add(location)

        results["locations"] = matches

    # Finally, return the results back to the caller.

    results = json.dumps(results)
    callback = get_param(request, "callback")
    if callback != None:
        results = callback + "(" + results + ")"  # Add JSONP callback.

    return HttpResponse(results, mimetype="application/json")
Exemple #7
0
def search_by_bbox(request):
    """ Implement the "bbox" API call.
    """
    # Extract our parameters.

    levels = []  # List of desired Level objects.

    levels_param = get_param(request, "levels")
    if levels_param != None:
        for level_name in levels_param.split(","):
            level = name_to_level(level_name)
            if level == None:
                return error_response(
                    code=400, message="Unknown level: " + repr(level_name), callback=get_param(request, "callback")
                )
            else:
                levels.append(level)

    minlat = get_param(request, "minlat")
    maxlat = get_param(request, "maxlat")
    minlong = get_param(request, "minlong")
    maxlong = get_param(request, "maxlong")

    try:
        minlat = float(minlat)
    except:
        return error_response(
            code=400, message="Invalid minlat: " + repr(minlat), callback=get_param(request, "callback")
        )

    try:
        maxlat = float(maxlat)
    except:
        return error_response(
            code=400, message="Invalid maxlat: " + repr(maxlat), callback=get_param(request, "callback")
        )

    try:
        minlong = float(minlong)
    except:
        return error_response(
            code=400, message="Invalid minlong: " + repr(minlong), callback=get_param(request, "callback")
        )

    try:
        maxlong = float(maxlong)
    except:
        return error_response(
            code=400, message="Invalid maxlong: " + repr(maxlong), callback=get_param(request, "callback")
        )

    # Create a Polygon geometry that encompasses the specified bounding box.

    bounds = Polygon.from_bbox((minlong, minlat, maxlong, maxlat))

    # Perform a spatial query to return all objects that *might* be in our
    # bounding box.  Note that, because of limitations in MySQL, we have to
    # then check each object individually.

    locations = []  # List of all location codes within our desired bounds.

    for outline in Outline.objects.filter(location__level__in=levels, outline__intersects=bounds):
        mpoly = outline.outline
        if mpoly.intersects(bounds):
            locations.append(outline.location.code)

    # Finally, return the results back to the caller.

    results = json.dumps({"locations": locations})

    callback = get_param(request, "callback")
    if callback != None:
        results = callback + "(" + results + ")"  # Add JSONP callback.

    return HttpResponse(results, mimetype="application/json")
Exemple #8
0
def outline(request):
    """ Implement the "outline" API call.
    """
    # Get the list of locations to return the outline for.

    locations = get_param(request, "locations")
    if locations == None:
        location = get_param(request, "location")
        if location == None:
            return error_response(code=400,
                                  message="Missing 'locations' or 'location'"
                                         +" parameter.",
                                  callback=get_param(request, "callback"))
        locations = [location]
    else:
        try:
            locations = json.loads(locations)
        except:
            return error_response(code=400,
                                  message="Invalid 'locations' parameter.",
                                  callback=get_param(request, "callback"))

    # Get the desired output format.

    format = get_param(request, "format")

    if format not in ["wkt", "gml", "geojson", "kml"]:
            return error_response(code=400,
                                  message="Missing or invalid 'format'"
                                         +" parameter: " + repr(format),
                                  callback=get_param(request, "callback"))

    # Extract the desired outlines.

    results = []
    for loc_code in locations:
        try:
            location = Location.objects.get(code=loc_code)
        except Location.DoesNotExist:
            return error_response(code=400,
                                  message="There is no location with code " +
                                          repr(loc_code),
                                  callback=get_param(request, "callback"))

        try:
            outline = Outline.objects.get(location=location)

            if True:
                orig_size = len(outline.outline.wkt)
                outline = outline.outline.simplify(0.3515/2, True)
                simplified_size = len(outline.wkt)
#                print "%d -> %d" % (orig_size, simplified_size)
            else:
                outline = outline.outline
        except Outline.DoesNotExist:
            outline = None

        result = {'location' : loc_code}
        if outline != None:
            if format == "wkt":
                result['outline'] = outline.wkt
            elif format == "gml":
                result['outline'] = outline.ogr.gml
            elif format == "geojson":
                result['outline'] = outline.geojson
            elif format == "kml":
                result['outline'] = outline.kml

        results.append(result)

    results = json.dumps({'outlines' : results})

    callback = get_param(request, "callback")
    if callback != None:
        results = callback + "(" + results + ")" # Add JSONP callback.

    return HttpResponse(results, mimetype="application/json")
Exemple #9
0
def get(request):
    """ Implement the "get" API call.
    """
    locations = get_param(request, "locations")
    if locations == None:
        location = get_param(request, "location")
        if location == None:
            return error_response(code=400,
                                  message="Missing 'locations' or 'location' "
                                         +"parameter.",
                                  callback=get_param(request, "callback"))
        locations = [location]
        has_multi = False
    else:
        try:
            locations = json.loads(locations)
        except:
            return error_response(code=400,
                                  message="Invalid 'locations' parameter.",
                                  callback=get_param(request, "callback"))
        has_multi = True

    results = []
    for loc_code in locations:
        try:
            location = Location.objects.get(code=loc_code)
        except Location.DoesNotExist:
            return error_response(code=400,
                                  message="Missing or invalid location code",
                                  callback=get_param(request, "callback"))

        loc_data = {}
        loc_data['code']         = location.code
        loc_data['level']        = level_to_name(location.level)
        loc_data['name']         = location.name
        loc_data['displayName']  = location.display_name
        loc_data['abbreviation'] = location.abbreviation
        loc_data['minZoomLat']   = float(location.min_zoom_lat)
        loc_data['maxZoomLat']   = float(location.max_zoom_lat)
        loc_data['minZoomLong']  = float(location.min_zoom_long)
        loc_data['maxZoomLong']  = float(location.max_zoom_long)
        loc_data['context']      = get_context(location)

        if location.population != None:
            loc_data['population'] = location.population

        if location.area != None:
            loc_data['area'] = location.area

        if location.averageIncome != None:
            loc_data['averageIncome'] = int(location.averageIncome)

        results.append(loc_data)

    if has_multi:
        results = json.dumps({'locations' : results})
    else:
        results = json.dumps({'location' : results[0]})

    callback = get_param(request, "callback")
    if callback != None:
        results = callback + "(" + results + ")" # Add JSONP callback.

    return HttpResponse(results, mimetype="application/json")