def before_request():
    uri = os.environ.get("MONGOLAB_URI", "mongodb://localhost/wtflunch")
    flask.g.dbc = pymongo.Connection(host=uri)
    dbname = pymongo.uri_parser.parse_uri(uri).get("database", "wtflunch")
    flask.g.db = flask.g.dbc[dbname]

    # Indexing.
    c = User.c()
    c.ensure_index("token")
    c.ensure_index("open_id")

    c = Proposal.c()
    c.ensure_index("accepted")
    c.ensure_index("date")
    c.ensure_index("user_id")
    c.ensure_index("short_url")

    # Redis database.
    flask.g.redis = redis.StrictRedis.from_url(
            os.environ.get("REDISTOGO_URL", "redis://localhost:6379"))
def main(rejectid=None, blackid=None):
    # Get the currently logged in user.
    user = current_user()

    # Get the acceptance model.
    # try:
    #     model = AcceptanceModel(*(user["model"]))
    # except (TypeError, KeyError):
    model = AcceptanceModel(0.3, 2.0, 1.0, 3.0)

    # Blacklist the proposal forever.
    if blackid is not None:
        if user is not None:
            proposal = Proposal.from_id(blackid)
            if proposal is not None:
                user.blacklist(proposal["id"])
                proposal.update_response(-2)

                # model.update(proposal.distance, proposal.rating,
                #              proposal.price, False, eta=0.02)
                # user.update_model(model.pars)
        else:
            rejectid = blackid

    # Reject the proposal for today.
    rediskey = "blacklist:"
    if user is None:
        h = flask.request.headers
        rediskey += h.get("X-Forwarded-For",
                          unicode(flask.request.remote_addr))
    else:
        rediskey += unicode(user._id)
    if rejectid is not None:
        proposal = Proposal.from_id(rejectid)
        if proposal is not None:
            # Update the model.
            # if user is not None:
            #     model.update(proposal.distance, proposal.rating,
            #                  proposal.price, False, eta=0.01)
            #     user.update_model(model.pars)

            # Cache the rejection.
            pipe = flask.g.redis.pipeline()
            pipe.sadd(rediskey, proposal["id"])
            pipe.expire(rediskey, 12 * 60 * 60)
            pipe.execute()

            if user is None:
                proposal.remove()
            else:
                proposal.update_response(0)

    print("model", model.pars)

    # Parse the location coordinates.
    a = flask.request.args
    if "longitude" in a and "latitude" in a:
        loc = np.array((a.get("longitude"), a.get("latitude")), dtype=float)
    else:
        return json.dumps({"code": 1,
                        "message": "You need to provide coordinates."}), 400

    # Find some yelp restaurant.
    data = get_listings(loc, model._sd2)

    if len(data) == 0:
        # We really couldn't find any results at all.
        return (json.dumps({"message":
            "We couldn't find any results. Maybe you should just stay home."}),
            404)

    # Loop over the list of suggestions and accept or reject stochastically.
    inds = np.arange(len(data))
    np.random.shuffle(inds)
    best = (0, None, None)
    for ind in inds:
        choice = data[ind]

        # Check the user blacklist.
        if user is not None:
            bl = user._doc.get("blacklist", [])
            if choice.id in bl:
                continue

        # Check the cached temporary blacklist.
        if flask.g.redis.sismember(rediskey, choice.id) != 0:
            continue

        # Get the aggregate user rating.
        n0, r0 = 5, choice.rating
        if r0 is not None:
            nratings = choice.likes
            rating = nratings * r0 / (n0 + nratings)
        else:
            rating = None

        # Compute the distance.
        cloc = choice.location
        x1 = lnglat2xyz(cloc["longitude"], cloc["latitude"])
        x2 = lnglat2xyz(*loc)
        dist = np.sqrt(2 * (rearth * rearth - np.dot(x1, x2)))

        # Compute the predictive acceptance probability.
        prob = model.predict(dist, rating, choice.price)

        # Check if you've already been there.
        v = None
        if user is not None:
            v = Proposal.c().find_one({"user_id": user._id,
                                       "accepted": {"$in": [2, -1]}})

        # Down weight the probability if you have been there.
        if v is not None:
            # HACKISH MAGIC.
            prob = 0.1 * prob

        print(dist, rating, choice.price, prob, choice.likes)
        if prob > best[0]:
            best = (prob, ind, dist)

        # Accept stochastically.
        if np.random.rand() <= prob:
            best = (prob, ind, dist)
            break

    if best[1] is None:
        # None of the restaurants had non-zero acceptance probability.
        return (json.dumps({"message":
            "We couldn't find any results. Maybe you should just stay home."}),
            404)

    choice = data[best[1]]

    # Try and get the directions.
    # l = choice.location
    # params = {
    #             "mode": "walking",
    #             "sensor": "false",
    #             "origin": "{1},{0}".format(*loc),
    #             "destination": "{latitude},{longitude}".format(**l)
    #         }
    # r = requests.get(google_directions_url, params=params)
    # resp = r.json()

    # Build the static map URL.
    map_params = {
            "size": "640x200",
            "zoom": 15,
            "scale": 2,
            "sensor": "false",
            "markers": "label:B|{latitude},{longitude}"
                       .format(**choice.location)
            }
    map_url = "http://maps.googleapis.com/maps/api/staticmap?" + \
              urllib.urlencode(map_params)

    result = {
        "id": choice.id,
        "name": choice.name,
        "address": choice.address,
        "url": choice.url,
        "rating": choice.rating,
        "price": choice.price,
        "categories": choice.categories,
        "checkins": choice.checkins,
        "users": choice.users,
        "likes": choice.likes,
        "probability": best[0],
        "distance": best[2],
        "map_url": map_url,
        "map_link": "http://maps.google.com/?q="
                    + urllib.quote(choice.address.encode("utf-8"))
    }

    # Save the proposal.
    if user is None:
        prop = Proposal.new(None, **result)
    else:
        prop = Proposal.new(user._id, **result)

    result["accept_url"] = flask.url_for(".accept", acceptid=prop._id)
    result["reject_url"] = flask.url_for(".main", rejectid=prop._id)
    result["blacklist_url"] = flask.url_for(".main", blackid=prop._id)

    return json.dumps(result)
def share_view(short_url):
    prop = Proposal.c().find_one({"short_url": short_url})
    if prop is not None:
        return flask.render_template("share.html", proposal=Proposal(prop))
    return flask.redirect(flask.url_for("index"))