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})
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)
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})
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
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})
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})
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