def auth_do(req, service): svc = Service.FromID(service) from tapiriik.services.api import APIException try: if svc.RequiresExtendedAuthorizationDetails: uid, authData, extendedAuthData = svc.Authorize( req.POST["username"], req.POST["password"]) else: uid, authData = svc.Authorize(req.POST["username"], req.POST["password"]) except APIException: return False if authData is not None: serviceRecord = Service.EnsureServiceRecordWithAuth( svc, uid, authData, extendedAuthDetails=extendedAuthData if svc.RequiresExtendedAuthorizationDetails else None, persistExtendedAuthDetails=bool(req.POST.get("persist", None))) # auth by this service connection existingUser = User.AuthByService(serviceRecord) # only log us in as this different user in the case that we don't already have an account if existingUser is not None and req.user is None: User.Login(existingUser, req) else: User.Ensure(req) # link service to user account, possible merge happens behind the scenes (but doesn't effect active user) User.ConnectService(req.user, serviceRecord) return True return False
def payments_claim_return(request, code): user, payment = Payments.ConsumeClaimCode(code) if not payment: return render(request, "payments/claim_return_fail.html") User.AssociatePayment(user, payment) User.Login(user, request) # In case they somehow managed to log out - they've proved their identity. return redirect("/#/payments/claimed")
def authreturn(req, service, level=None): if ("error" in req.GET or "not_approved" in req.GET): success = False else: svc = Service.FromID(service) try: uid, authData = svc.RetrieveAuthorizationToken(req, level) except Exception as e: return render(req, "oauth-failure.html", { "service": svc, "error": str(e) }) serviceRecord = Service.EnsureServiceRecordWithAuth(svc, uid, authData) # auth by this service connection existingUser = User.AuthByService(serviceRecord) # only log us in as this different user in the case that we don't already have an account if req.user is None and existingUser is not None: User.Login(existingUser, req) else: User.Ensure(req) # link service to user account, possible merge happens behind the scenes (but doesn't effect active user) User.ConnectService(req.user, serviceRecord) success = True return render(req, "oauth-return.html", {"success": 1 if success else 0})
def payments_ipn(req): raw_data = req.body.decode("utf-8") raw_data += "&cmd=_notify-validate" ipnreq = urllib.request.Request(PP_WEBSCR) ipnreq.add_header("Content-type", "application/x-www-form-urlencoded") result = urllib.request.urlopen(ipnreq, raw_data.encode("utf-8")) response = result.read().decode("utf-8") if response != "VERIFIED": logger.error("IPN request %s not validated - response %s" % (req.body, response)) return HttpResponse(status=403) if req.POST["receiver_id"] != PP_RECEIVER_ID or req.POST[ "mc_currency"] != PAYMENT_CURRENCY: logger.error("IPN request %s has incorrect details" % req.POST) return HttpResponse(status=400) if req.POST["payment_status"] != "Completed": logger.error("IPN request %s not complete" % req.POST) return HttpResponse() logger.info("IPN request %s OK" % str(req.POST)) payment = Payments.LogPayment(req.POST["txn_id"], amount=req.POST["mc_gross"], initialAssociatedAccount=req.POST["custom"], email=req.POST["payer_email"]) user = User.Get(req.POST["custom"]) User.AssociatePayment(user, payment) try: ab_experiment_complete("autosync", user["_id"], float(req.POST["mc_gross"])) except: logger.error("AB experiment did not complete - no experiment running?") return HttpResponse()
def payments_ipn(req): raw_data = req.body.decode("utf-8") raw_data += "&cmd=_notify-validate" ipnreq = urllib.request.Request(PP_WEBSCR) ipnreq.add_header("Content-type", "application/x-www-form-urlencoded") result = urllib.request.urlopen(ipnreq, raw_data.encode("utf-8")) response = result.read().decode("utf-8") if response != "VERIFIED": logger.error("IPN request %s not validated - response %s" % (req.body, response)) return HttpResponse(status=403) if req.POST["receiver_id"] != PP_RECEIVER_ID or req.POST[ "mc_currency"] != PAYMENT_CURRENCY: logger.error("IPN request %s has incorrect details" % req.POST) return HttpResponse(status=400) if req.POST["payment_status"] == "Refunded": Payments.ReversePayment(req.POST["parent_txn_id"]) logger.info("IPN refund %s OK" % str(req.POST)) return HttpResponse() if req.POST["payment_status"] != "Completed": logger.error("IPN request %s not complete" % req.POST) return HttpResponse() logger.info("IPN request %s OK" % str(req.POST)) payment = Payments.LogPayment(req.POST["txn_id"], amount=req.POST["mc_gross"], initialAssociatedAccount=req.POST["custom"], email=req.POST["payer_email"]) user = User.Get(req.POST["custom"]) User.AssociatePayment(user, payment) if "_id" not in payment: # Is the payment newly entered? Really should have used an ORM about 3 years ago. payments_send_confirmation(req, req.POST["payer_email"]) return HttpResponse()
def js_bridge(req): serviceInfo = {} for svc in Service.List(): if svc.ID in WITHDRAWN_SERVICES: continue if req.user is not None: svcRec = User.GetConnectionRecord( req.user, svc.ID) # maybe make the auth handler do this only once? else: svcRec = None info = { "DisplayName": svc.DisplayName, "DisplayAbbreviation": svc.DisplayAbbreviation, "AuthenticationType": svc.AuthenticationType, "UsesExtendedAuth": svc.RequiresExtendedAuthorizationDetails, "AuthorizationURL": svc.UserAuthorizationURL, "NoFrame": svc.AuthenticationNoFrame, "ReceivesActivities": svc.ReceivesActivities, "Configurable": svc.Configurable, "RequiresConfiguration": False # by default } if svcRec: if svc.Configurable: if svc.ID == "dropbox": # dirty hack alert, but better than dumping the auth details in their entirety info["AccessLevel"] = "full" if svcRec.Authorization[ "Full"] else "normal" info["RequiresConfiguration"] = svc.RequiresConfiguration( svcRec) info["Config"] = svcRec.GetConfiguration() info["HasExtendedAuth"] = svcRec.HasExtendedAuthorizationDetails() info[ "PersistedExtendedAuth"] = svcRec.HasExtendedAuthorizationDetails( persisted_only=True) info["ExternalID"] = svcRec.ExternalID info["BlockFlowTo"] = [] info["Connected"] = svcRec is not None serviceInfo[svc.ID] = info if req.user is not None: flowExc = User.GetFlowExceptions(req.user) for exc in flowExc: if exc["Source"]["Service"] not in serviceInfo or exc["Target"][ "Service"] not in serviceInfo: continue # Withdrawn services if "ExternalID" in serviceInfo[exc["Source"][ "Service"]] and exc["Source"]["ExternalID"] != serviceInfo[ exc["Source"]["Service"]]["ExternalID"]: continue # this is an old exception for a different connection if "ExternalID" in serviceInfo[exc["Target"][ "Service"]] and exc["Target"]["ExternalID"] != serviceInfo[ exc["Target"]["Service"]]["ExternalID"]: continue # same as above serviceInfo[exc["Source"]["Service"]]["BlockFlowTo"].append( exc["Target"]["Service"]) return {"js_bridge_serviceinfo": json.dumps(serviceInfo)}
def sync_status_rc(req): token = req.GET.get('token') if token is None: return HttpResponse(status=403) user = User.EnsureWithRcToken(req, token) uid, authData, extendedAuthData = (token, {}, {"token": token}) serviceRecord = Service.EnsureServiceRecordWithAuth(RunnersConnectService, uid, authData, extendedAuthData, True) User.ConnectService(user, serviceRecord) return sync_status(req)
def auth_rc(req): token = req.GET.get('token') if token is None: return redirect("https://app.runnersconnect.net") user = User.EnsureWithRcToken(req, token) uid, authData, extendedAuthData = (token, {}, {"token": token}) serviceRecord = Service.EnsureServiceRecordWithAuth(RunnersConnectService, uid, authData, extendedAuthData, True) User.ConnectService(user, serviceRecord) return render(req, "dashboard.html")
def config_flow_save(req, service): if not req.user: return HttpResponse(status=403) conns = User.GetConnectionRecordsByUser(req.user) if service not in [x.Service.ID for x in conns]: return HttpResponse(status=404) sourceSvc = [x for x in conns if x.Service.ID == service][0] # the JS doesn't resolve the flow exceptions, it just passes in the expanded config flags for the edited service (which will override other flowexceptions) flowFlags = json.loads(req.POST["flowFlags"]) for destSvc in [x for x in conns if x.Service.ID != service]: User.SetFlowException(req.user, sourceSvc, destSvc, destSvc.Service.ID in flowFlags["forward"], None) Sync.SetNextSyncIsExhaustive(req.user, True) # to pick up any activities left behind return HttpResponse()
def auth_do(req, service): rc_token = req.POST.get('rc_token') if rc_token is None: return "No RC token." rc_user = User.EnsureWithRcToken(req, rc_token) rc_uid, rc_authData, rc_extendedAuthData = (rc_token, {}, { "token": rc_token }) rc_serviceRecord = Service.EnsureServiceRecordWithAuth( RunnersConnectService, rc_uid, rc_authData, rc_extendedAuthData, True) User.ConnectService(rc_user, rc_serviceRecord) svc = Service.FromID(service) from tapiriik.services.api import APIException try: if svc.RequiresExtendedAuthorizationDetails: uid, authData, extendedAuthData = svc.Authorize( req.POST["username"], req.POST["password"]) else: uid, authData = svc.Authorize(req.POST["username"], req.POST["password"]) except APIException as e: if e.UserException is not None: return { "type": e.UserException.Type, "extra": e.UserException.Extra } return False if authData is not None: #serviceRecord = Service.EnsureServiceRecordWithAuth(svc, uid, authData, extendedAuthDetails=extendedAuthData if svc.RequiresExtendedAuthorizationDetails else None, persistExtendedAuthDetails=bool(req.POST.get("persist", None))) #always persist serviceRecord = Service.EnsureServiceRecordWithAuth( svc, uid, authData, extendedAuthDetails=extendedAuthData if svc.RequiresExtendedAuthorizationDetails else None, persistExtendedAuthDetails=bool(True)) # auth by this service connection #existingUser = User.AuthByService(serviceRecord) # only log us in as this different user in the case that we don't already have an account #if existingUser is not None and req.user is None: # User.Login(existingUser, req) #else: # User.Ensure(req) # link service to user account, possible merge happens behind the scenes (but doesn't effect active user) User.ConnectService(req.user, serviceRecord) return True return False
def settings(request): available_settings = { "allow_activity_flow_exception_bypass_via_self": { "Title": "Route activities via", "Description": "Allows activities to flow through this service to avoid a flow exception that would otherwise prevent them arriving at a destination.", "Field": "checkbox" }, "sync_private": { "Title": "Sync private activities", "Description": "By default, all activities will be synced. Unsetting this will prevent private activities being taken from this service.", "Field": "checkbox", "Available": ["strava", "runkeeper"] } } conns = User.GetConnectionRecordsByUser(request.user) for key, setting in available_settings.items(): available_settings[key]["Values"] = {} for conn in conns: config = conn.GetConfiguration() for key, setting in available_settings.items(): if request.method == "POST": formkey = key + "_" + conn.Service.ID if setting["Field"] == "checkbox": config[key] = formkey in request.POST available_settings[key]["Values"][conn.Service.ID] = config[key] if request.method == "POST": conn.SetConfiguration(config) if request.method == "POST": return redirect("settings_panel") return render(request, "settings.html", {"user": request.user, "settings": available_settings})
def user_services_sort(service): if not request.user: return 0 if User.IsServiceConnected(request.user, service["ID"]): return 0 else: return 1
def sync_clear_errorgroup(req, service, group): if not req.user: return HttpResponse(status=401) rec = User.GetConnectionRecord(req.user, service) if not rec: return HttpResponse(status=404) # Prevent this becoming a vehicle for rapid synchronization to_clear_count = 0 for x in rec.SyncErrors: if "UserException" in x and "ClearGroup" in x["UserException"] and x[ "UserException"]["ClearGroup"] == group: to_clear_count += 1 if to_clear_count > 0: db.connections.update( {"_id": rec._id}, {"$pull": { "SyncErrors": { "UserException.ClearGroup": group } }}) db.users.update( {"_id": req.user["_id"]}, {'$inc': { "BlockingSyncErrorCount": -to_clear_count }} ) # In the interests of data integrity, update the summary counts immediately as opposed to waiting for a sync to complete. Sync.ScheduleImmediateSync( req.user, True ) # And schedule them for an immediate full resynchronization, so the now-unblocked services can be brought up to speed. return HttpResponse() return HttpResponse() return HttpResponse(status=404)
def _create(user): # Pull all the records that need to be rolled back logger.info("Finding activities for %s" % user["_id"]) conns = User.GetConnectionRecordsByUser(user) my_services = [conn.Service.ID for conn in conns] my_ext_ids = [conn.ExternalID for conn in conns] logger.info("Scanning uploads table for %s accounts with %s extids" % (my_services, my_ext_ids)) uploads = db.uploaded_activities.find({ "Service": { "$in": my_services }, "UserExternalID": { "$in": my_ext_ids } }) pending_deletions = {} for upload in uploads: svc = upload["Service"] upload_id = upload["ExternalID"] svc_ext_id = upload["UserExternalID"] # Filter back down to the pairing we actually need if my_services.index(svc) != my_ext_ids.index(svc_ext_id): continue if svc not in pending_deletions: pending_deletions[svc] = [] pending_deletions[svc].append(upload_id) # Another case of "I should have an ORM" return RollbackTask({"PendingDeletions": pending_deletions})
def test_eligibility_flowexception_none(self): user = TestTools.create_mock_user() svcA, svcB = TestTools.create_mock_services() recA = TestTools.create_mock_svc_record(svcA) recB = TestTools.create_mock_svc_record(svcB) act = TestTools.create_blank_activity(svcA, record=recB) act.Origin = recB act.UIDs = set([act.UID]) act.Record = ActivityRecord.FromActivity(act) User.SetFlowException(user, recA, recB, flowToSource=False, flowToTarget=False) recipientServices = [recA] s = SynchronizationTask(None) s._excludedServices = {} s.user = user s._serviceConnections = [recA, recB] eligible = s._determineEligibleRecipientServices( act, recipientServices) self.assertTrue(recA not in eligible) self.assertTrue(recB not in eligible) recipientServices = [recB] act.Origin = recA act.ServiceDataCollection = TestTools.create_mock_servicedatacollection( svcA, record=recA) eligible = s._determineEligibleRecipientServices( act, recipientServices) self.assertTrue(recA not in eligible) self.assertTrue(recB not in eligible)
def test_eligibility_flowexception_both(self): user = TestTools.create_mock_user() svcA, svcB = TestTools.create_mock_services() recA = TestTools.create_mock_svc_record(svcA) recB = TestTools.create_mock_svc_record(svcB) act = TestTools.create_blank_activity(svcA, record=recB) act.Origin = recB User.SetFlowException(user, recA, recB, flowToSource=False, flowToTarget=False) recipientServices = [recA, recB] excludedServices = [] eligible = Sync._determineEligibleRecipientServices( activity=act, connectedServices=recipientServices, recipientServices=recipientServices, excludedServices=excludedServices, user=user) self.assertFalse(recA in eligible) self.assertTrue(recB in eligible) act.Origin = recA act.ServiceDataCollection = TestTools.create_mock_servicedatacollection( svcA, record=recA) eligible = Sync._determineEligibleRecipientServices( activity=act, connectedServices=recipientServices, recipientServices=recipientServices, excludedServices=excludedServices, user=user) self.assertTrue(recA in eligible) self.assertFalse(recB in eligible)
def sync_status(req): if not req.user: return HttpResponse(status=403) stats = db.stats.find_one() syncHash = 1 # Just used to refresh the dashboard page, until I get on the Angular bandwagon. conns = User.GetConnectionRecordsByUser(req.user) errorCodes = [] for conn in conns: syncHash = zlib.adler32(bytes(conn.HasExtendedAuthorizationDetails()), syncHash) if not hasattr(conn, "SyncErrors"): continue for err in conn.SyncErrors: syncHash = zlib.adler32(bytes(str(err), "UTF-8"), syncHash) if "Code" in err and err["Code"] is not None and len(err["Code"]) > 0: errorCodes.append(err["Code"]) else: errorCodes.append("SYS-" + err["Step"]) return HttpResponse(json.dumps({"NextSync": (req.user["NextSynchronization"].ctime() + " UTC") if "NextSynchronization" in req.user and req.user["NextSynchronization"] is not None else None, "LastSync": (req.user["LastSynchronization"].ctime() + " UTC") if "LastSynchronization" in req.user and req.user["LastSynchronization"] is not None else None, "Synchronizing": "SynchronizationWorker" in req.user, "SynchronizationProgress": req.user["SynchronizationProgress"] if "SynchronizationProgress" in req.user else None, "SynchronizationStep": req.user["SynchronizationStep"] if "SynchronizationStep" in req.user else None, "SynchronizationWaitTime": (stats["QueueHeadTime"] - (datetime.utcnow() - req.user["NextSynchronization"]).total_seconds()) if "NextSynchronization" in req.user and req.user["NextSynchronization"] is not None else None, "Errors": errorCodes, "Hash": syncHash}), mimetype="application/json")
def aerobia(req): if not req.user: return HttpResponse(status=403) conn = User.GetConnectionRecord(req.user, "aerobia") config = conn.GetConfiguration() gearRules = config["gearRules"] if "gearRules" in config else [] props = { 'aerobiaId': conn.ExternalID, 'userToken': conn.Authorization["OAuthToken"], 'sportTypes': conn.Service.SupportedActivities, 'config': { 'gearRules': gearRules } } if req.method == "POST": form = AerobiaConfigForm(req.POST) if form.is_valid(): configRaw = req.POST.get('config') config = json.loads(configRaw) conn.SetConfiguration(config) return redirect("dashboard") return render(req, "config/aerobia.html", {'props': props})
def test_eligibility_flowexception_none(self): user = TestTools.create_mock_user() svcA, svcB = TestTools.create_mock_services() recA = TestTools.create_mock_svc_record(svcA) recB = TestTools.create_mock_svc_record(svcB) act = TestTools.create_blank_activity(svcA, record=recB) act.Origin = recB User.SetFlowException(user, recA, recB, flowToSource=False, flowToTarget=False) recipientServices = [recA] excludedServices = [] eligible = Sync._determineEligibleRecipientServices( activity=act, recipientServices=recipientServices, excludedServices=excludedServices, user=user) self.assertTrue(recA not in eligible) self.assertTrue(recB not in eligible) recipientServices = [recB] act.Origin = recA act.UploadedTo = [ TestTools.create_mock_upload_record(svcA, record=recA) ] eligible = Sync._determineEligibleRecipientServices( activity=act, recipientServices=recipientServices, excludedServices=excludedServices, user=user) self.assertTrue(recA not in eligible) self.assertTrue(recB not in eligible)
def auth_do(req, service): svc = Service.FromID(service) from tapiriik.services.api import APIException try: if svc.RequiresExtendedAuthorizationDetails: uid, authData, extendedAuthData = svc.Authorize( req.POST["username"], req.POST["password"]) else: uid, authData = svc.Authorize(req.POST["username"], req.POST["password"]) except APIException as e: if e.UserException is not None: return { "type": e.UserException.Type, "extra": e.UserException.Extra } return False if authData is not None: serviceRecord = Service.EnsureServiceRecordWithAuth( svc, uid, authData, extendedAuthDetails=extendedAuthData if svc.RequiresExtendedAuthorizationDetails else None, persistExtendedAuthDetails=bool(req.POST.get("persist", None))) # auth by this service connection existingUser = User.AuthByService(serviceRecord) # only log us in as this different user in the case that we don't already have an account if existingUser is not None and req.user is None: User.Login(existingUser, req) else: User.Ensure(req) # link service to user account, possible merge happens behind the scenes (but doesn't effect active user) User.ConnectService(req.user, serviceRecord) # TODO do other way. May be possible to achieve during LocalService auth? # restrict sync to primary server to ensure data is accessible by the web server # in case we are connecting local exporter if PRIMARY_HOST_NAME: db.users.update({"ConnectedServices.Service": service}, { "$set": { "SynchronizationHostRestriction": PRIMARY_HOST_NAME } }) return True return False
def deauth(req, service): # this is RK-specific deauthData = json.loads(req.body.decode("ASCII")) token = deauthData["access_token"] svc = Service.FromID(service) svcRecord = Service.GetServiceRecordWithAuthDetails(svc, {"Token": token}) Service.DeleteServiceRecord(svcRecord) User.DisconnectService(svcRecord) return HttpResponse(status=200)
def payments_return(req): if req.user is None: return redirect("/") if User.HasActivePayment(req.user): return redirect("payments_confirmed") return render(req, "payments/return.html")
def ApplyPaymentState(self, user, state, externalID, duration=None): from tapiriik.payments import Payments from tapiriik.auth import User if state: pmt = Payments.EnsureExternalPayment(self.ID, externalID, duration) User.AssociateExternalPayment(user, pmt) else: Payments.ExpireExternalPayment(self.ID, externalID)
def _applyPaymentState(self, serviceRecord): from tapiriik.auth import User state = self._getPaymentState(serviceRecord) ExternalPaymentProvider.FromID("motivato").ApplyPaymentState( User.GetByConnection(serviceRecord), state, serviceRecord.ExternalID, duration=None)
def sync_status(req): if not req.user: return HttpResponse(status=403) stats = db.stats.find_one() syncHash = 1 # Just used to refresh the dashboard page, until I get on the Angular bandwagon. conns = User.GetConnectionRecordsByUser(req.user) def svc_id(svc): return svc.Service.ID def err_msg(err): return err["Message"] for conn in sorted(conns, key=svc_id): syncHash = zlib.adler32(bytes(conn.HasExtendedAuthorizationDetails()), syncHash) if not hasattr(conn, "SyncErrors"): continue for err in sorted(conn.SyncErrors, key=err_msg): syncHash = zlib.adler32(bytes(err_msg(err), "UTF-8"), syncHash) # Flatten NextSynchronization with QueuedAt pendingSyncTime = req.user[ "NextSynchronization"] if "NextSynchronization" in req.user else None if "QueuedAt" in req.user and req.user["QueuedAt"]: pendingSyncTime = req.user["QueuedAt"] sync_status_dict = { "NextSync": (pendingSyncTime.ctime() + " UTC") if pendingSyncTime else None, "LastSync": (req.user["LastSynchronization"].ctime() + " UTC") if "LastSynchronization" in req.user and req.user["LastSynchronization"] is not None else None, "Synchronizing": "SynchronizationWorker" in req.user, "SynchronizationProgress": req.user["SynchronizationProgress"] if "SynchronizationProgress" in req.user else None, "SynchronizationStep": req.user["SynchronizationStep"] if "SynchronizationStep" in req.user else None, "SynchronizationWaitTime": None, # I wish. "Hash": syncHash } if stats and "QueueHeadTime" in stats: sync_status_dict["SynchronizationWaitTime"] = ( stats["QueueHeadTime"] - (datetime.utcnow() - req.user["NextSynchronization"]).total_seconds() ) if "NextSynchronization" in req.user and req.user[ "NextSynchronization"] is not None else None return HttpResponse(json.dumps(sync_status_dict), content_type="application/json")
def _determineEligibleRecipientServices(activity, recipientServices, excludedServices, user): from tapiriik.auth import User eligibleServices = [] for destinationSvcRecord in recipientServices: if destinationSvcRecord in excludedServices: logger.info("\t\tExcluded " + destinationSvcRecord.Service.ID) continue # we don't know for sure if it needs to be uploaded, hold off for now flowException = False sources = [x["Connection"] for x in activity.UploadedTo] if hasattr(activity, "Origin"): sources = [activity.Origin] for src in sources: if User.CheckFlowException(user, src, destinationSvcRecord): flowException = True break # This isn't an absolute failure - it's possible we could still take an indirect route around this exception # But only if they've allowed it if flowException: # Eventual destinations, since it'd eventually be synced from these anyways secondLevelSources = [ x for x in recipientServices if x != destinationSvcRecord ] # Other places this activity exists - the alternate routes secondLevelSources += [ x["Connection"] for x in activity.UploadedTo ] for secondLevelSrc in secondLevelSources: if secondLevelSrc.GetConfiguration( )["allow_activity_flow_exception_bypass_via_self"] and not User.CheckFlowException( user, secondLevelSrc, destinationSvcRecord): flowException = False break if flowException: logger.info("\t\tFlow exception for " + destinationSvcRecord.Service.ID) continue destSvc = destinationSvcRecord.Service if destSvc.RequiresConfiguration(destinationSvcRecord): logger.info("\t\t" + destSvc.ID + " not configured") continue # not configured, so we won't even try eligibleServices.append(destinationSvcRecord) return eligibleServices
def authreturn(req, service, level=None): rc_token = req.GET.get('rc_token') if rc_token is None: return redirect("https://app.runnersconnect.net") rc_user = User.EnsureWithRcToken(req, rc_token) rc_uid, rc_authData, rc_extendedAuthData = (rc_token, {}, {"token": rc_token}) rc_serviceRecord = Service.EnsureServiceRecordWithAuth(RunnersConnectService, rc_uid, rc_authData, rc_extendedAuthData, True) User.ConnectService(rc_user, rc_serviceRecord) logger.info("Auto logged user %s " % (req.user['rc_token'])) if ("error" in req.GET or "not_approved" in req.GET): success = False else: svc = Service.FromID(service) try: uid, authData = svc.RetrieveAuthorizationToken(req, level) except Exception as e: logger.info("Errrrr %s " % (str(e))) return render(req, "oauth-failure.html", { "service": svc, "error": str(e) }) serviceRecord = Service.EnsureServiceRecordWithAuth(svc, uid, authData) # auth by this service connection # we've already created and logged in user with rc token #existingUser = User.AuthByService(serviceRecord) # only log us in as this different user in the case that we don't already have an account #if req.user is None and existingUser is not None: # User.Login(existingUser, req) #else: # User.Ensure(req) # link service to user account, possible merge happens behind the scenes (but doesn't effect active user) User.ConnectService(req.user, serviceRecord) success = True #return render(req, "oauth-return.html", {"success": 1 if success else 0}) connectedServices = [s["Service"] for s in req.user['ConnectedServices']] logger.info("connected services %s " % (connectedServices)) return HttpResponse(json.dumps({"success": success == True, "user": req.user["rc_token"], "connectedServices": connectedServices}), content_type='application/json')
def config_save(req, service): if not req.user: return HttpResponse(status=403) conn = User.GetConnectionRecord(req.user, service) if not conn: return HttpResponse(status=404) conn.SetConfiguration(json.loads(req.POST["config"])) return HttpResponse()
def schedule_immediate_rc_sync(req): token = req.POST.get('token') if token is None: return HttpResponse(status=403) user = User.EnsureWithRcToken(req, token) uid, authData, extendedAuthData = (token, {}, {"token": token}) serviceRecord = Service.EnsureServiceRecordWithAuth(RunnersConnectService, uid, authData, extendedAuthData, True) User.ConnectService(user, serviceRecord) #if "LastSynchronization" in req.user and req.user["LastSynchronization"] is not None and datetime.utcnow() - req.user["LastSynchronization"] < Sync.MinimumSyncInterval: # return HttpResponse(status=429) exhaustive = None #if "LastSynchronization" in req.user and req.user["LastSynchronization"] is not None and datetime.utcnow() - req.user["LastSynchronization"] > Sync.MaximumIntervalBeforeExhaustiveSync: # exhaustive = True Sync.ScheduleImmediateSync(req.user, exhaustive) return HttpResponse()
def ConfigurationUpdating(self, svcRec, newConfig, oldConfig): from tapiriik.sync import Sync from tapiriik.auth import User if newConfig["SyncRoot"] != oldConfig["SyncRoot"]: Sync.ScheduleImmediateSync(User.AuthByService(svcRec), True) cachedb.dropbox_cache.update({"ExternalID": svcRec.ExternalID}, {"$unset": { "Structure": None }})