Exemplo n.º 1
0
    def RetrieveAuthorizationToken(self, req, level):
        from tapiriik.services import Service

        #  might consider a real OAuth client
        code = req.GET.get("code")
        params = {
            "grant_type":
            "authorization_code",
            "code":
            code,
            "client_id":
            RUNKEEPER_CLIENT_ID,
            "client_secret":
            RUNKEEPER_CLIENT_SECRET,
            "redirect_uri":
            WEB_ROOT + reverse("oauth_return", kwargs={"service": "runkeeper"})
        }

        response = requests.post(
            "https://runkeeper.com/apps/token",
            data=urllib.parse.urlencode(params),
            headers={"Content-Type": "application/x-www-form-urlencoded"})
        if response.status_code != 200:
            raise APIException("Invalid code")
        token = response.json()["access_token"]

        # This used to check with GetServiceRecordWithAuthDetails but that's hideously slow on an unindexed field.
        uid = self._getUserId(
            ServiceRecord({"Authorization": {
                "Token": token
            }}))  # meh

        return (uid, {"Token": token})
Exemplo n.º 2
0
    def RetrieveAuthorizationToken(self, req, level):
        code = req.GET.get("code")
        params = {
            "grant_type":
            "authorization_code",
            "code":
            code,
            "client_id":
            STRAVA_CLIENT_ID,
            "client_secret":
            STRAVA_CLIENT_SECRET,
            "redirect_uri":
            WEB_ROOT + reverse("oauth_return", kwargs={"service": "strava"})
        }

        self._globalRateLimit()
        response = requests.post("https://www.strava.com/oauth/token",
                                 data=params)
        if response.status_code != 200:
            raise APIException("Invalid code")
        data = response.json()

        authorizationData = {"OAuthToken": data["access_token"]}
        # Retrieve the user ID, meh.
        self._globalRateLimit()
        id_resp = requests.get("https://www.strava.com/api/v3/athlete",
                               headers=self._apiHeaders(
                                   ServiceRecord(
                                       {"Authorization": authorizationData})))
        return (id_resp.json()["id"], authorizationData)
Exemplo n.º 3
0
    def RetrieveAuthorizationToken(self, req, level):
        #  might consider a real OAuth client
        code = req.GET.get("code")
        params = {
            "code": code,
            "client_id": PULSSTORY_CLIENT_ID,
            "client_secret": PULSSTORY_CLIENT_SECRET
        }

        response = requests.post(
            self.URLBase + "/ExternalSyncAPI/GenerateToken",
            data=urllib.parse.urlencode(params),
            headers={"Content-Type": "application/x-www-form-urlencoded"})
        if response.status_code != 200:
            raise APIException("Invalid code")

        token = response.json()["access_token"]

        # This used to check with GetServiceRecordWithAuthDetails but that's hideously slow on an unindexed field.
        uid = self._getUserId(
            ServiceRecord({"Authorization": {
                "Token": token
            }}))  # meh

        return (uid, {"Token": token})
Exemplo n.º 4
0
    def PollPartialSyncTrigger(self, multiple_index):
        # TODO: ensure the appropriate users are connected
        # GET http://connect.garmin.com/proxy/userprofile-service/connection/pending to get ID
        #  [{"userId":6244126,"displayName":"tapiriik-sync-ulukhaktok","fullName":"tapiriik sync ulukhaktok","profileImageUrlSmall":null,"connectionRequestId":1904086,"requestViewed":true,"userRoles":["ROLE_CONNECTUSER"],"userPro":false}]
        # PUT http://connect.garmin.com/proxy/userprofile-service/connection/accept/1904086
        # ...later...
        # GET http://connect.garmin.com/proxy/activitylist-service/activities/comments/subscriptionFeed?start=1&limit=10

        # First, accept any pending connections
        watch_user_key = sorted(list(GARMIN_CONNECT_USER_WATCH_ACCOUNTS.keys()))[multiple_index]
        watch_user = GARMIN_CONNECT_USER_WATCH_ACCOUNTS[watch_user_key]
        session = self._get_session(email=watch_user["Username"], password=watch_user["Password"], skip_cache=True)

        # Then, check for users with new activities
        self._rate_limit()
        watch_activities_resp = session.get("http://connect.garmin.com/proxy/activitylist-service/activities/subscriptionFeed?limit=1000")
        try:
            watch_activities = watch_activities_resp.json()
        except ValueError:
            raise Exception("Could not parse new activities list: %s %s" % (watch_activities_resp.status_code, watch_activities_resp.text))

        active_user_pairs = [(x["ownerDisplayName"], x["activityId"]) for x in watch_activities["activityList"]]
        active_user_pairs.sort(key=lambda x: x[1]) # Highest IDs last (so they make it into the dict, supplanting lower IDs where appropriate)
        active_users = dict(active_user_pairs)

        active_user_recs = [ServiceRecord(x) for x in db.connections.find({"ExternalID": {"$in": list(active_users.keys())}, "Service": "garminconnect"}, {"Config": 1, "ExternalID": 1, "Service": 1})]

        if len(active_user_recs) != len(active_users.keys()):
            logger.warning("Mismatch %d records found for %d active users" % (len(active_user_recs), len(active_users.keys())))

        to_sync_ids = []
        for active_user_rec in active_user_recs:
            last_active_id = active_user_rec.GetConfiguration()["WatchUserLastID"]
            this_active_id = active_users[active_user_rec.ExternalID]
            if this_active_id > last_active_id:
                to_sync_ids.append(active_user_rec.ExternalID)
                active_user_rec.SetConfiguration({"WatchUserLastID": this_active_id, "WatchUserKey": watch_user_key})

        self._rate_limit()
        pending_connections_resp = session.get("http://connect.garmin.com/proxy/userprofile-service/connection/pending")
        try:
            pending_connections = pending_connections_resp.json()
        except ValueError:
            logger.error("Could not parse pending connection requests: %s %s" % (pending_connections_resp.status_code, pending_connections_resp.text))
        else:
            valid_pending_connections_external_ids = [x["ExternalID"] for x in db.connections.find({"Service": "garminconnect", "ExternalID": {"$in": [x["displayName"] for x in pending_connections]}}, {"ExternalID": 1})]
            logger.info("Accepting %d, denying %d connection requests for %s" % (len(valid_pending_connections_external_ids), len(pending_connections) - len(valid_pending_connections_external_ids), watch_user_key))
            for pending_connect in pending_connections:
                if pending_connect["displayName"] in valid_pending_connections_external_ids:
                    self._rate_limit()
                    connect_resp = session.put("http://connect.garmin.com/proxy/userprofile-service/connection/accept/%s" % pending_connect["connectionRequestId"])
                    if connect_resp.status_code != 200:
                        logger.error("Error accepting request on watch account %s: %s %s" % (watch_user["Name"], connect_resp.status_code, connect_resp.text))
                else:
                    self._rate_limit()
                    ignore_resp = session.put("http://connect.garmin.com/proxy/userprofile-service/connection/decline/%s" % pending_connect["connectionRequestId"])


        return to_sync_ids
Exemplo n.º 5
0
    def RetrieveAuthorizationToken(self, req, level):
        from tapiriik.services import Service

        #  might consider a real OAuth client
        code = req.GET.get("code")
        params = {"grant_type": "authorization_code", "code": code, "client_id": RUNKEEPER_CLIENT_ID, "client_secret": RUNKEEPER_CLIENT_SECRET, "redirect_uri": WEB_ROOT + reverse("oauth_return", kwargs={"service": "runkeeper"})}

        response = requests.post("https://runkeeper.com/apps/token", data=urllib.parse.urlencode(params), headers={"Content-Type": "application/x-www-form-urlencoded"})
        if response.status_code != 200:
            raise APIException("Invalid code")
        token = response.json()["access_token"]

        # hacky, but also totally their fault for not giving the user id in the token req
        existingRecord = Service.GetServiceRecordWithAuthDetails(self, {"Token": token})
        if existingRecord is None:
            uid = self._getUserId(ServiceRecord({"Authorization": {"Token": token}}))  # meh
        else:
            uid = existingRecord.ExternalID

        return (uid, {"Token": token})
Exemplo n.º 6
0
    def RetrieveAuthorizationToken(self, req, level):
        from tapiriik.services import Service

        code = req.GET.get("code")
        params = {
            "grant_type":
            "authorization_code",
            "code":
            code,
            "client_id":
            MAPMYFITNESS_CLIENT_KEY,
            "client_secret":
            MAPMYFITNESS_CLIENT_SECRET,
            "redirect_uri":
            WEB_ROOT +
            reverse("oauth_return", kwargs={"service": "mapmyfitness"})
        }

        response = requests.post(
            "https://api.mapmyfitness.com/v7.1/oauth2/access_token",
            data=urlencode(params),
            headers={
                "Content-Type": "application/x-www-form-urlencoded",
                "api-key": MAPMYFITNESS_CLIENT_KEY
            })

        if response.status_code != 200:
            raise APIException("Invalid code")
        token = response.json()["access_token"]

        uid = self._getUserId(
            ServiceRecord({"Authorization": {
                "Token": token
            }}))

        return (uid, {"Token": token})
Exemplo n.º 7
0
    def PollPartialSyncTrigger(self, multiple_index):
        # TODO: ensure the appropriate users are connected
        # GET http://connect.garmin.com/modern/proxy/userprofile-service/connection/pending to get ID
        #  [{"userId":6244126,"displayName":"tapiriik-sync-ulukhaktok","fullName":"tapiriik sync ulukhaktok","profileImageUrlSmall":null,"connectionRequestId":1904086,"requestViewed":true,"userRoles":["ROLE_CONNECTUSER"],"userPro":false}]
        # PUT http://connect.garmin.com/proxy/userprofile-service/connection/accept/1904086
        # ...later...
        # GET http://connect.garmin.com/proxy/activitylist-service/activities/comments/subscriptionFeed?start=1&limit=10

        # First, accept any pending connections
        watch_user_key = sorted(list(GARMIN_CONNECT_USER_WATCH_ACCOUNTS.keys()))[multiple_index]
        watch_user = GARMIN_CONNECT_USER_WATCH_ACCOUNTS[watch_user_key]
        logger.debug("Initiating session for watch user %s", watch_user["Username"])
        sess_args = {
            "email": watch_user["Username"],
            "password": watch_user["Password"]
        }

        # These seems to fail with a 500 (talkking about a timeout) the first time, so keep trying.
        SERVER_ERROR_RETRIES = 10
        PAGE_SIZE = 100
        TOTAL_SIZE = 1000
        # Then, check for users with new activities
        watch_activities = []
        for i in range(1, TOTAL_SIZE, PAGE_SIZE):
            for x in range(SERVER_ERROR_RETRIES):
                logger.debug("Fetching activity list from %d - attempt %d", i, x)
                watch_activities_resp = self._request_with_reauth(
                    lambda session: session.get("https://connect.garmin.com/modern/proxy/activitylist-service/activities/subscriptionFeed",
                                                params={"limit": PAGE_SIZE, "start": i}),
                    **sess_args)
                if watch_activities_resp.status_code != 500:
                    break
            try:
                watch_activities += watch_activities_resp.json()["activityList"]
            except ValueError:
                raise Exception("Could not parse new activities list: %s %s" % (watch_activities_resp.status_code, watch_activities_resp.text))

        active_user_pairs = [(x["ownerDisplayName"], x["activityId"]) for x in watch_activities]
        active_user_pairs.sort(key=lambda x: x[1]) # Highest IDs last (so they make it into the dict, supplanting lower IDs where appropriate)
        active_users = dict(active_user_pairs)

        active_user_recs = [ServiceRecord(x) for x in db.connections.find({"ExternalID": {"$in": list(active_users.keys())}, "Service": "garminconnect"}, {"Config": 1, "ExternalID": 1, "Service": 1})]

        if len(active_user_recs) != len(active_users.keys()):
            logger.warning("Mismatch %d records found for %d active users" % (len(active_user_recs), len(active_users.keys())))

        to_sync_ids = []
        for active_user_rec in active_user_recs:
            last_active_id = active_user_rec.GetConfiguration()["WatchUserLastID"]
            this_active_id = active_users[active_user_rec.ExternalID]
            if this_active_id > last_active_id:
                to_sync_ids.append(active_user_rec.ExternalID)
                active_user_rec.SetConfiguration({"WatchUserLastID": this_active_id, "WatchUserKey": watch_user_key})

        for x in range(SERVER_ERROR_RETRIES):
            self._rate_limit()
            logger.debug("Fetching connection request list - attempt %d", x)
            pending_connections_resp = self._request_with_reauth(
                lambda session: session.get("https://connect.garmin.com/modern/proxy/userprofile-service/connection/pending"),
                **sess_args)
            if pending_connections_resp.status_code != 500:
                break
        try:
            pending_connections = pending_connections_resp.json()
        except ValueError:
            logger.error("Could not parse pending connection requests: %s %s" % (pending_connections_resp.status_code, pending_connections_resp.text))
        else:
            valid_pending_connections_external_ids = [x["ExternalID"] for x in db.connections.find({"Service": "garminconnect", "ExternalID": {"$in": [x["displayName"] for x in pending_connections]}}, {"ExternalID": 1})]
            logger.info("Accepting %d, denying %d connection requests for %s" % (len(valid_pending_connections_external_ids), len(pending_connections) - len(valid_pending_connections_external_ids), watch_user_key))
            for pending_connect in pending_connections:
                if pending_connect["displayName"] in valid_pending_connections_external_ids:
                    self._rate_limit()
                    connect_resp = self._request_with_reauth(
                        lambda session: session.put("https://connect.garmin.com/modern/proxy/userprofile-service/connection/accept/%s" % pending_connect["connectionRequestId"]),
                        **sess_args)
                    if connect_resp.status_code != 200:
                        logger.error("Error accepting request on watch account %s: %s %s" % (watch_user["Name"], connect_resp.status_code, connect_resp.text))
                else:
                    self._rate_limit()
                    self._request_with_reauth(
                        lambda session: session.put("https://connect.garmin.com/modern/proxy/userprofile-service/connection/decline/%s" % pending_connect["connectionRequestId"]),
                        **sess_args)

        return to_sync_ids