Example #1
0
def link_google_account(google_id: str, access_token: str, refresh_token: str,
                        expires_at: str) -> Tuple[dict, Optional[Error]]:
    with open_pg() as conn:
        with open_cursor(conn) as cur:
            cur.execute(
                "select google_id "
                "from   users "
                "where  google_id = %s", (google_id, ))
            if cur.fetchone() is None:
                return {}, Error(
                    400,
                    f"Google account `{google_id}` does not match the registered account."
                )
            cur.execute(
                "update users set "
                "google_access_token = %s,"
                "google_refresh_token = %s,"
                "google_token_expires_at = %s "
                "where google_id = %s",
                (encrypt(access_token, PASSWORD),
                 encrypt(refresh_token, PASSWORD) if refresh_token else None,
                 expires_at, google_id))
            cur.execute("select * "
                        "from   users "
                        "where  google_id = %s", (google_id, ))
            user = cur.fetchone()
    if user is None:
        return {}, Error(
            500,
            "User information could not be saved due to an unexpected error.")
    return dict(user), None
Example #2
0
def link_twitter_account(twitter_id: str, twitter_name: str, access_toke: str,
                         access_secret: str) -> Tuple[dict, Optional[Error]]:
    with open_pg() as conn:
        with open_cursor(conn) as cur:
            cur.execute(
                "select twitter_name "
                "from   users "
                "where  twitter_name = %s", (twitter_name, ))
            if cur.fetchone() is None:
                return {}, Error(
                    400,
                    f"Twitter account `{twitter_name}` does not match the registered account."
                )
            cur.execute(
                "update users set "
                "twitter_id = %s,"
                "twitter_name = %s,"
                "twitter_access_token = %s,"
                "twitter_access_token_secret = %s "
                "where twitter_name = %s",
                (twitter_id, twitter_name, encrypt(access_toke, PASSWORD),
                 encrypt(access_secret, PASSWORD), twitter_name))
            cur.execute("select * "
                        "from   users "
                        "where  twitter_id = %s", (twitter_id, ))
            user = cur.fetchone()
        if user is None:
            return {}, Error(
                500,
                "User information could not be saved due to an unexpected error."
            )
    return dict(user), None
Example #3
0
def fetch_twitter_info(user_id: str) -> Tuple[dict, Optional[Error]]:
    with open_pg() as conn:
        with open_cursor(conn) as cur:
            cur.execute(
                "select twitter_id,"
                "       twitter_name,"
                "       twitter_access_token,"
                "       twitter_access_token_secret,"
                "       twitter_latest_id "
                "from   users "
                "where  user_id = %s", (user_id, ))
            twitter = cur.fetchone()
            if twitter is None:
                return {}, Error(404, f"User {user_id} does not exist.")
            if twitter["twitter_id"] is None:
                return {}, Error(
                    403, f"User {user_id} is not linked to Twitter account.")
    twitter_info = {
        "id": twitter["twitter_id"],
        "name": twitter["twitter_name"],
        "access_token": decrypt(twitter["twitter_access_token"], PASSWORD),
        "access_secret": decrypt(twitter["twitter_access_token_secret"],
                                 PASSWORD),
        "latest_id": twitter["twitter_latest_id"],
    }
    return twitter_info, None
Example #4
0
def sign_up(user_name: str, google: str,
            twitter: str) -> Tuple[dict, Optional[Error]]:
    user_id = google.split("@")[0]
    with open_pg() as conn:
        with open_cursor(conn) as cur:
            cur.execute(
                "select user_id "
                "from   users "
                "where  user_id = %s or twitter_name = %s", (user_id, twitter))
            if cur.fetchone() is not None:
                return {}, Error(
                    400, f"User `{user_id}` (or `{twitter}`) already exists.")
            cur.execute(
                "insert into users "
                "(user_id, user_name, google_id, twitter_name) "
                "values (%s, %s, %s, %s)",
                (user_id, user_name, google, twitter))
            cur.execute("select * "
                        "from   users "
                        "where  user_id = %s", (user_id, ))
            user = cur.fetchone()
    if user is None:
        return {}, Error(
            500,
            "User information could not be saved due to an unexpected error.")
    return dict(user), None
Example #5
0
def get_weather(lat: int = None, lng: int = None) -> HTTPResponse:
    if lat is None or lng is None:
        lat, lng, err = get_validation(request, "lat", "lng")
        if err:
            return err.response
    if not float_check(lat, 90):
        return Error(400,
                     "lat must be a real number between -90 and 90").response
    if not float_check(lng, 180):
        return Error(400,
                     "lng must be a real number between -180 and 180").response
    weather_get_url = f"http://api.openweathermap.org/data/2.5/weather?APPID={WEATHER_API_KEY}&lat={lat}&lon={lng}"
    req = requests.get(weather_get_url)
    if req.status_code != 200:
        return Error(req.status_code, req.json()).response
    body = req.json()

    weather_id = body['weather'][0]['id']
    weather = WEATHER_TABLE.get(weather_id)
    return json_response(
        200, {
            "weather": weather["main_ja"],
            "icon_url":
            f"http://openweathermap.org/img/wn/{weather['icon']}@2x.png",
            "temp": int(body["main"]["temp"] - 273.15),
            "humid": body["main"]["humidity"]
        })
Example #6
0
def get_map(q: str = None) -> HTTPResponse:
    *_, err = get_validation(request)
    if err:
        return err.response
    if q is None:
        q = request.params.q
    if q == "":
        return Error(400, "parameter `q` is required.").response
    client = googlemaps.Client(key=MAP_API_KEY)
    req = client.places(q)
    if req['status'] != 'OK':
        return Error(400,
                     f"Google Maps API returns `{req['status']}`").response
    if len(req["results"]) != 1:
        return Error(
            500,
            f"Invalid number of result ({len(req['results'])}) are returned."
        ).response
    result = req["results"][0]
    body = {}
    photos = result.get("photos")
    if photos:
        body["photo_url"] = (
            f"https://maps.googleapis.com/maps/api/place/photo"
            f"?maxwidth={PHOTO_WIDTH}"
            f"&photoreference={photos[0]['photo_reference']}"
            f"&key={MAP_API_KEY}")
    body["latitude"] = result["geometry"]["location"]["lat"]
    body["longitude"] = result["geometry"]["location"]["lng"]
    return json_response(200, body)
Example #7
0
def get_twitter_today_detail() -> HTTPResponse:
    user = request.get_cookie("user_id")  # , secret=PASSWORD)
    q = request.params.q
    *_, err = get_validation(request)
    if err:
        return err.response
    if user is None:
        return Error(400, "parameter `user` is required").response()
    twitter, err = fetch_twitter_info(user)
    if err:
        return err.response
    oauth = OAuth1Session(CK, CS, twitter["access_token"], twitter["access_secret"])
    res, new_tweets = get_new_tweets(oauth, twitter["latest_id"])
    if res.status_code == 401 and res.json()["errors"][0]["code"] == 89:
        return Error(401, "The registered token is invalid. It may have expired. Please re-login.").response
    elif res.status_code != 200:
        return json_response(res.status_code, res.json())
    body = update_tweets(user, new_tweets)
    hashtags = list(set(hstg for tw in body for hstg in tw["hashtags"]))
    detail = {
        "event": [],
        "morning": [],
        "breakfast": [],
        "lunch": [],
        "dinner": [],
        "night": []
    }
    for h in sorted(hashtags):
        detail[h] = []
    detail["other"] = []
    used = set()
    for idx, tw in enumerate(body):
        if sum([t in tw["text"] for t in MORNING]) > 0:
            detail["morning"].append(tw)
            used.add(idx)
        if sum([t in tw["text"] for t in NIGHT]) > 0:
            detail["night"].append(tw)
            used.add(idx)
        if sum([t in tw["text"] for t in BREAKFAST]) > 0:
            detail["breakfast"].append(tw)
            used.add(idx)
        if sum([t in tw["text"] for t in LUNCH]) > 0:
            detail["lunch"].append(tw)
            used.add(idx)
        if sum([t in tw["text"] for t in DINNER]) > 0:
            detail["dinner"].append(tw)
            used.add(idx)
        if len(tw["hashtags"]) > 0:
            for hs in tw["hashtags"]:
                detail[hs].append(tw)
                used.add(idx)
        if idx not in used:
            detail["other"].append(tw)
    if q != "":
        detail = detail.get(q, {})
    return json_response(200, detail)
Example #8
0
def fetch_user_info(username: str,
                    social: str) -> Tuple[dict, Optional[Error]]:
    if social == "id":
        sql = "select * from users where user_id = %s"
    elif social == "google":
        sql = "select * from users where google_id = %s"
    elif social == "twitter":
        sql = "select * from users where twitter_name = %s"
    else:
        return {}, Error(400,
                         "The field `social` must be id, google or twitter.")
    with open_pg() as conn:
        with open_cursor(conn) as cur:
            cur.execute(sql, (username, ))
            user = cur.fetchone()
            if user is None:
                return {}, Error(404, f"User {username} does not exist.")
    return dict(user), None
Example #9
0
def fetch_google_token(user_id: str) -> Tuple[dict, Optional[Error]]:
    with open_pg() as conn:
        with open_cursor(conn) as cur:
            cur.execute(
                "select google_id, google_access_token, google_refresh_token, google_token_expires_at "
                "from   users "
                "where  user_id = %s", (user_id, ))
            token = cur.fetchone()
            if token is None:
                return {}, Error(404, f"User {user_id} does not exist.")
            if token["google_access_token"] is None:
                return {}, Error(
                    403, f"User {user_id} is not linked to Google account.")
    google_token = {
        "id": token["google_id"],
        "access_token": decrypt(token.get("google_access_token"), PASSWORD),
        "refresh_token": decrypt(token.get("google_refresh_token"), PASSWORD),
        "expires_at": token.get("google_token_expires_at")
    }
    return google_token, None
Example #10
0
def get_events_today() -> HTTPResponse:
    user = request.get_cookie("user_id", secret=PASSWORD)
    if user is None:
        return Error(400, "parameter `user` is required").response
    token, err = fetch_google_token(user)
    if err:
        return err.response
    if float(token.get("expires_at")) < datetime.now().timestamp():
        token, err = refresh_token_flow(user, token.get("refresh_token"))
        if err:
            return err.response
    today = datetime.now(timezone("Asia/Tokyo")).date()
    params = {
        "orderBy":
        "startTime",
        "singleEvents":
        True,
        "timeMin":
        datetime(today.year, today.month, today.day, 0, 0, 0, 0,
                 timezone("Asia/Tokyo")).isoformat(),
        "timeMax":
        datetime(today.year, today.month, today.day + 1, 0, 0, 0, 0,
                 timezone("Asia/Tokyo")).isoformat()
    }
    header = {"Authorization": f"Bearer {token['access_token']}"}
    req = requests.get(CALENDAR_EP + token["id"] + "/events",
                       params=params,
                       headers=header)
    if req.status_code != 200:
        return json_response(req.status_code, req.json())
    result = req.json().get("items")
    body = []
    for item in result:
        location = item.get("location")
        body.append({
            "title":
            item.get("summary"),
            "start":
            datetime_object(item.get("start", {}).get("dateTime")),
            "end":
            datetime_object(item.get("end", {}).get("dateTime")),
            "location": {
                "name": location
            },
            "link":
            item.get("htmlLink"),
        })
        if location is not None:
            map_info, err = get_map(location)
            if err is None:
                body[-1]["location"]["photo"] = map_info["photo_url"]
                body[-1]["location"]["latitude"] = map_info["latitude"]
                body[-1]["location"]["longitude"] = map_info["longitude"]
    return json_response(200, body)
Example #11
0
def get_twitter_today() -> HTTPResponse:
    user = request.get_cookie("user_id")  # , secret=PASSWORD)
    q = request.params.q
    *_, err = get_validation(request)
    if err:
        return err.response
    if user is None:
        return Error(400, "parameter `user` is required").response
    twitter, err = fetch_twitter_info(user)
    if err:
        return err.response
    oauth = OAuth1Session(CK, CS, twitter["access_token"], twitter["access_secret"])
    res, new_tweets = get_new_tweets(oauth, twitter["latest_id"])
    if res.status_code == 401 and res.json()["errors"][0]["code"] == 89:
        return Error(401, "The registered token is invalid. It may have expired. Please re-login.").response
    elif res.status_code != 200:
        return json_response(res.status_code, res.json())
    body = update_tweets(user, new_tweets)
    if q is not None:
        body = [b for b in body if q in b["text"]]
    return json_response(200, body)
Example #12
0
def refresh_token(user_id: str, token: str,
                  expires: int) -> Tuple[dict, Optional[Error]]:
    with open_pg() as conn:
        with open_cursor(conn) as cur:
            cur.execute(
                "select google_id "
                "from   users "
                "where  user_id = %s", (user_id, ))
            if cur.fetchone() is None:
                return {}, Error(404, f"User {user_id} does not exist.")
            cur.execute(
                "update users set "
                "google_access_token = %s,"
                "google_token_expires_at = %s "
                "where user_id = %s",
                (encrypt(token, PASSWORD),
                 datetime.now().timestamp() + expires, user_id))
            cur.execute(
                "select google_id, google_access_token, google_refresh_token, google_token_expires_at "
                "from   users "
                "where  user_id = %s", (user_id, ))
            user = cur.fetchone()
            if user is None:
                return {}, Error(
                    500,
                    "User information could not be saved due to an unexpected error."
                )
            token = {
                "id":
                user["google_id"],
                "access_token":
                decrypt(user.get("google_access_token"), PASSWORD),
                "refresh_token":
                decrypt(user.get("google_refresh_token"), PASSWORD),
                "expires_at":
                user.get("google_token_expires_at")
            }
            return token, None
Example #13
0
def refresh_token_flow(user: str, token: str) -> Tuple[dict, Optional[Error]]:
    data = {
        "refresh_token": token,
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET,
        "grant_type": "refresh_token"
    }
    req = requests.post(REFRESH_EP,
                        data=json.dumps(data).encode("utf-8"),
                        headers=JSON_HEADER)
    result = req.json()
    if req.status_code != 200:
        return {}, Error(req.status_code, result)
    return refresh_token(user, result["access_token"], result["expires_in"])
Example #14
0
def get_map(q: str) -> Tuple[dict, Optional[Error]]:
    if q == "":
        return {}, Error(400, "parameter `q` is required.")
    client = googlemaps.Client(key=MAP_API_KEY)
    req = client.places(q)
    if req['status'] != 'OK':
        return {}, Error(400, f"Google Maps API returns `{req['status']}`")
    if len(req["results"]) != 1:
        return {}, Error(
            500,
            f"Invalid number of result ({len(req['results'])}) are returned.")
    result = req["results"][0]
    body = {}
    photos = result.get("photos")
    if photos:
        body["photo_url"] = (
            f"https://maps.googleapis.com/maps/api/place/photo"
            f"?maxwidth={PHOTO_WIDTH}"
            f"&photoreference={photos[0]['photo_reference']}"
            f"&key={MAP_API_KEY}")
    body["latitude"] = result["geometry"]["location"]["lat"]
    body["longitude"] = result["geometry"]["location"]["lng"]
    return body, None
Example #15
0
def post_login() -> HTTPResponse:
    *_, err = post_validation(request)
    if err:
        return err.response
    body = request.json
    google = body.get("google")
    if google:
        user, err = fetch_user_info(google, "google")
        if err:
            return err.response
    else:
        twitter = body.get("twitter")
        if twitter is not None:
            user, err = fetch_user_info(twitter, "twitter")
            if err:
                return err.response
        else:
            return Error(400, "Either google or twitter is required.").response
    return json_response(200, user, user["user_id"])