def account_setconfig(req): if not req.user: return HttpResponse(status=403) data = json.loads(req.body.decode("utf-8")) if data["sync_skip_before"] and len(data["sync_skip_before"]): data["sync_skip_before"] = dateutil.parser.parse( data["sync_skip_before"]) User.SetConfiguration(req.user, data) Sync.SetNextSyncIsExhaustive(req.user, True) return HttpResponse()
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"])) Sync.SetNextSyncIsExhaustive(req.user, True) # e.g. if they opted to sync private activities. return HttpResponse()
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 ConnectService(user, serviceRecord): from tapiriik.services import Service, UserExceptionType existingUser = db.users.find_one({ "_id": { '$ne': ObjectId(user["_id"]) }, "ConnectedServices.ID": ObjectId(serviceRecord._id) }) if "ConnectedServices" not in user: user["ConnectedServices"] = [] delta = False if existingUser is not None: # merge merge merge # Don't let the user end up with two services of the same type, ever # It's not fully supported, plus it's caused all sorts of trauma in the past. # Note that this will discard the new serviceRecord connection if an existing one exists on the other account # ...which isn't the end of the world, compared to screwing around asking the user which they wanted to keep. for to_merge_service in existingUser["ConnectedServices"]: if len([ x for x in user["ConnectedServices"] if x["Service"] == to_merge_service["Service"] ]) == 0: user["ConnectedServices"].append(to_merge_service) # There's got to be some 1-liner to do this merge if "Payments" in existingUser: if "Payments" not in user: user["Payments"] = [] user["Payments"] += existingUser["Payments"] if "Promos" in existingUser: if "Promos" not in user: user["Promos"] = [] user["Promos"] += existingUser["Promos"] if "ExternalPayments" in existingUser: if "ExternalPayments" not in user: user["ExternalPayments"] = [] user["ExternalPayments"] += existingUser["ExternalPayments"] if "FlowExceptions" in existingUser: if "FlowExceptions" not in user: user["FlowExceptions"] = [] user["FlowExceptions"] += existingUser["FlowExceptions"] user["Email"] = user["Email"] if "Email" in user and user[ "Email"] is not None else ( existingUser["Email"] if "Email" in existingUser else None) user["NonblockingSyncErrorCount"] = ( user["NonblockingSyncErrorCount"] if "NonblockingSyncErrorCount" in user and user["NonblockingSyncErrorCount"] is not None else 0 ) + (existingUser["NonblockingSyncErrorCount"] if "NonblockingSyncErrorCount" in existingUser and existingUser["NonblockingSyncErrorCount"] is not None else 0) user["BlockingSyncErrorCount"] = ( user["BlockingSyncErrorCount"] if "BlockingSyncErrorCount" in user and user["BlockingSyncErrorCount"] is not None else 0 ) + (existingUser["BlockingSyncErrorCount"] if "BlockingSyncErrorCount" in existingUser and existingUser["BlockingSyncErrorCount"] is not None else 0) user["SyncExclusionCount"] = ( user["SyncExclusionCount"] if "SyncExclusionCount" in user and user["SyncExclusionCount"] is not None else 0) + ( existingUser["SyncExclusionCount"] if "SyncExclusionCount" in existingUser and existingUser["SyncExclusionCount"] is not None else 0) user[ "Created"] = user["Created"] if user["Created"] < existingUser[ "Created"] else existingUser["Created"] if "AncestorAccounts" not in user: user["AncestorAccounts"] = [] user["AncestorAccounts"] += existingUser["AncestorAccounts"] if "AncestorAccounts" in existingUser else [] user["AncestorAccounts"] += [existingUser["_id"]] user["Timezone"] = user["Timezone"] if "Timezone" in user and user[ "Timezone"] else (existingUser["Timezone"] if "Timezone" in existingUser else None) user["CreationIP"] = user[ "CreationIP"] if "CreationIP" in user and user[ "CreationIP"] else (existingUser["CreationIP"] if "CreationIP" in existingUser else None) existing_config = existingUser[ "Config"] if "Config" in existingUser else {} existing_config.update(user["Config"] if "Config" in user else {}) user["Config"] = existing_config delta = True db.users.remove({"_id": existingUser["_id"]}) else: if serviceRecord._id not in [ x["ID"] for x in user["ConnectedServices"] ]: # we might be connecting a second account for the same service for duplicateConn in [ x for x in user["ConnectedServices"] if x["Service"] == serviceRecord.Service.ID ]: dupeRecord = User.GetConnectionRecord( user, serviceRecord.Service.ID ) # this'll just pick the first connection of type, but we repeat the right # of times anyways Service.DeleteServiceRecord(dupeRecord) # We used to call DisconnectService() here, but the results of that call were getting overwritten, which was unfortunate. user["ConnectedServices"] = [ x for x in user["ConnectedServices"] if x["Service"] != serviceRecord.Service.ID ] user["ConnectedServices"].append({ "Service": serviceRecord.Service.ID, "ID": serviceRecord._id }) delta = True db.users.update({"_id": user["_id"]}, user) if delta or ( hasattr(serviceRecord, "SyncErrors") and len(serviceRecord.SyncErrors) > 0 ): # also schedule an immediate sync if there is an outstanding error (i.e. user reconnected) db.connections.update( {"_id": serviceRecord._id}, { "$pull": { "SyncErrors": { "UserException.Type": UserExceptionType.Authorization } } } ) # Pull all auth-related errors from the service so they don't continue to see them while the sync completes. db.connections.update( {"_id": serviceRecord._id}, { "$pull": { "SyncErrors": { "UserException.Type": UserExceptionType.RenewPassword } } } ) # Pull all auth-related errors from the service so they don't continue to see them while the sync completes. Sync.SetNextSyncIsExhaustive( user, True ) # exhaustive, so it'll pick up activities from newly added services / ones lost during an error if hasattr(serviceRecord, "SyncErrors") and len(serviceRecord.SyncErrors) > 0: Sync.ScheduleImmediateSync(user)
def diag_user(req, user): try: userRec = db.users.find_one({"_id": ObjectId(user)}) except: userRec = None if not userRec: searchOpts = [{"Payments.Txn": user}, {"Payments.Email": user}] try: searchOpts.append({"AncestorAccounts": ObjectId(user)}) searchOpts.append({"ConnectedServices.ID": ObjectId(user)}) except: pass # Invalid format for ObjectId userRec = db.users.find_one({"$or": searchOpts}) if not userRec: searchOpts = [{"ExternalID": user}] try: searchOpts.append({"ExternalID": int(user)}) except: pass # Not an int svcRec = db.connections.find_one({"$or": searchOpts}) if svcRec: userRec = db.users.find_one( {"ConnectedServices.ID": svcRec["_id"]}) if userRec: return redirect("diagnostics_user", user=userRec["_id"]) if not userRec: return render(req, "diag/error_user_not_found.html") delta = True # Easier to set this to false in the one no-change case. if "sync" in req.POST: Sync.ScheduleImmediateSync(userRec, req.POST["sync"] == "Full") elif "unlock" in req.POST: db.users.update({"_id": ObjectId(user)}, {"$unset": { "SynchronizationWorker": None }}) elif "lock" in req.POST: db.users.update({"_id": ObjectId(user)}, {"$set": { "SynchronizationWorker": 1 }}) elif "hostrestrict" in req.POST: host = req.POST["host"] if host: db.users.update({"_id": ObjectId(user)}, {"$set": { "SynchronizationHostRestriction": host }}) else: db.users.update( {"_id": ObjectId(user)}, {"$unset": { "SynchronizationHostRestriction": None }}) elif "substitute" in req.POST: req.session["substituteUserid"] = user return redirect("dashboard") elif "svc_setauth" in req.POST and len(req.POST["authdetails"]): db.connections.update( {"_id": ObjectId(req.POST["id"])}, {"$set": { "Authorization": json.loads(req.POST["authdetails"]) }}) elif "svc_unlink" in req.POST: from tapiriik.services import Service from tapiriik.auth import User svcRec = Service.GetServiceRecordByID(req.POST["id"]) try: Service.DeleteServiceRecord(svcRec) except: pass try: User.DisconnectService(svcRec) except: pass elif "svc_marksync" in req.POST: db.connections.update( {"_id": ObjectId(req.POST["id"])}, {"$addToSet": { "SynchronizedActivities": req.POST["uid"] }}, multi=False) elif "svc_clearexc" in req.POST: db.connections.update({"_id": ObjectId(req.POST["id"])}, {"$unset": { "ExcludedActivities": 1 }}) elif "svc_clearacts" in req.POST: db.connections.update({"_id": ObjectId(req.POST["id"])}, {"$unset": { "SynchronizedActivities": 1 }}) Sync.SetNextSyncIsExhaustive(userRec, True) else: delta = False if delta: return redirect("diagnostics_user", user=user) return render(req, "diag/user.html", {"user": userRec})
def diag_user(req, user): try: userRec = db.users.find_one({"_id": ObjectId(user)}) except: userRec = None if not userRec: searchOpts = [{"Payments.Txn": user}, {"Payments.Email": user}] try: searchOpts.append({"AncestorAccounts": ObjectId(user)}) searchOpts.append({"ConnectedServices.ID": ObjectId(user)}) except: pass # Invalid format for ObjectId userRec = db.users.find_one({"$or": searchOpts}) if not userRec: searchOpts = [{"ExternalID": user}] try: searchOpts.append({"ExternalID": int(user)}) except: pass # Not an int svcRec = db.connections.find_one({"$or": searchOpts}) if svcRec: userRec = db.users.find_one( {"ConnectedServices.ID": svcRec["_id"]}) if userRec: return redirect("diagnostics_user", user=userRec["_id"]) if not userRec: return render(req, "diag/error_user_not_found.html") delta = True # Easier to set this to false in the one no-change case. if "sync" in req.POST: Sync.ScheduleImmediateSync(userRec, req.POST["sync"] == "Full") elif "unlock" in req.POST: db.users.update({"_id": ObjectId(user)}, {"$unset": { "SynchronizationWorker": None }}) elif "lock" in req.POST: db.users.update({"_id": ObjectId(user)}, {"$set": { "SynchronizationWorker": 1 }}) elif "requeue" in req.POST: db.users.update({"_id": ObjectId(user)}, {"$unset": { "QueuedAt": None }}) elif "hostrestrict" in req.POST: host = req.POST["host"] if host: db.users.update({"_id": ObjectId(user)}, {"$set": { "SynchronizationHostRestriction": host }}) else: db.users.update( {"_id": ObjectId(user)}, {"$unset": { "SynchronizationHostRestriction": None }}) elif "substitute" in req.POST: req.session["substituteUserid"] = user return redirect("dashboard") elif "svc_setauth" in req.POST and len(req.POST["authdetails"]): db.connections.update( {"_id": ObjectId(req.POST["id"])}, {"$set": { "Authorization": json.loads(req.POST["authdetails"]) }}) elif "svc_setconfig" in req.POST and len(req.POST["config"]): db.connections.update( {"_id": ObjectId(req.POST["id"])}, {"$set": { "Config": json.loads(req.POST["config"]) }}) elif "svc_unlink" in req.POST: from tapiriik.services import Service from tapiriik.auth import User svcRec = Service.GetServiceRecordByID(req.POST["id"]) try: Service.DeleteServiceRecord(svcRec) except: pass try: User.DisconnectService(svcRec) except: pass elif "svc_marksync" in req.POST: db.connections.update( {"_id": ObjectId(req.POST["id"])}, {"$addToSet": { "SynchronizedActivities": req.POST["uid"] }}, multi=False) elif "svc_clearexc" in req.POST: db.connections.update({"_id": ObjectId(req.POST["id"])}, {"$unset": { "ExcludedActivities": 1 }}) elif "svc_clearacts" in req.POST: db.connections.update({"_id": ObjectId(req.POST["id"])}, {"$unset": { "SynchronizedActivities": 1 }}) Sync.SetNextSyncIsExhaustive(userRec, True) elif "svc_toggle_poll_sub" in req.POST: from tapiriik.services import Service svcRec = Service.GetServiceRecordByID(req.POST["id"]) svcRec.SetPartialSyncTriggerSubscriptionState( not svcRec.PartialSyncTriggerSubscribed) elif "svc_toggle_poll_trigger" in req.POST: from tapiriik.services import Service svcRec = Service.GetServiceRecordByID(req.POST["id"]) db.connections.update({"_id": ObjectId(req.POST["id"])}, { "$set": { "TriggerPartialSync": not getattr(svcRec, "TriggerPartialSync", False) } }) elif "svc_tryagain" in req.POST: from tapiriik.services import Service svcRec = Service.GetServiceRecordByID(req.POST["id"]) db.connections.update({"_id": ObjectId(req.POST["id"])}, {"$pull": { "SyncErrors": { "Scope": "activity" } }}) act_recs = db.activity_records.find_one({"UserID": ObjectId(user)}) for act in act_recs["Activities"]: if "FailureCounts" in act and svcRec.Service.ID in act[ "FailureCounts"]: del act["FailureCounts"][svcRec.Service.ID] db.activity_records.save(act_recs) else: delta = False if delta: return redirect("diagnostics_user", user=user) return render(req, "diag/user.html", {"diag_user": userRec})
def ConnectService(user, serviceRecord): from tapiriik.services import Service, UserExceptionType existingUser = db.users.find_one({ "_id": { '$ne': ObjectId(user["_id"]) }, "ConnectedServices.ID": ObjectId(serviceRecord._id) }) if "ConnectedServices" not in user: user["ConnectedServices"] = [] delta = False if existingUser is not None: # merge merge merge user["ConnectedServices"] += existingUser["ConnectedServices"] if "Payments" in existingUser: if "Payments" not in user: user["Payments"] = [] user["Payments"] += existingUser["Payments"] if "FlowExceptions" in existingUser: if "FlowExceptions" not in user: user["FlowExceptions"] = [] user["FlowExceptions"] += existingUser["FlowExceptions"] user["Email"] = user["Email"] if "Email" in user and user[ "Email"] is not None else ( existingUser["Email"] if "Email" in existingUser else None) user["NonblockingSyncErrorCount"] = ( user["NonblockingSyncErrorCount"] if "NonblockingSyncErrorCount" in user and user["NonblockingSyncErrorCount"] is not None else 0 ) + (existingUser["NonblockingSyncErrorCount"] if "NonblockingSyncErrorCount" in existingUser and existingUser["NonblockingSyncErrorCount"] is not None else 0) user["BlockingSyncErrorCount"] = ( user["BlockingSyncErrorCount"] if "BlockingSyncErrorCount" in user and user["BlockingSyncErrorCount"] is not None else 0 ) + (existingUser["BlockingSyncErrorCount"] if "BlockingSyncErrorCount" in existingUser and existingUser["BlockingSyncErrorCount"] is not None else 0) user["SyncExclusionCount"] = ( user["SyncExclusionCount"] if "SyncExclusionCount" in user and user["SyncExclusionCount"] is not None else 0) + ( existingUser["SyncExclusionCount"] if "SyncExclusionCount" in existingUser and existingUser["SyncExclusionCount"] is not None else 0) user[ "Created"] = user["Created"] if user["Created"] < existingUser[ "Created"] else existingUser["Created"] if "AncestorAccounts" not in user: user["AncestorAccounts"] = [] user["AncestorAccounts"] += existingUser["AncestorAccounts"] if "AncestorAccounts" in existingUser else [] user["AncestorAccounts"] += [existingUser["_id"]] user["Timezone"] = user["Timezone"] if user[ "Timezone"] else existingUser["Timezone"] delta = True db.users.remove({"_id": existingUser["_id"]}) else: if serviceRecord._id not in [ x["ID"] for x in user["ConnectedServices"] ]: # we might be connecting a second account for the same service for duplicateConn in [ x for x in user["ConnectedServices"] if x["Service"] == serviceRecord.Service.ID ]: dupeRecord = User.GetConnectionRecord( user, serviceRecord.Service.ID ) # this'll just pick the first connection of type, but we repeat the right # of times anyways Service.DeleteServiceRecord(dupeRecord) # We used to call DisconnectService() here, but the results of that call were getting overwritten, which was unfortunate. user["ConnectedServices"] = [ x for x in user["ConnectedServices"] if x["Service"] != serviceRecord.Service.ID ] user["ConnectedServices"].append({ "Service": serviceRecord.Service.ID, "ID": serviceRecord._id }) delta = True db.users.update({"_id": user["_id"]}, user) if delta or ( hasattr(serviceRecord, "SyncErrors") and len(serviceRecord.SyncErrors) > 0 ): # also schedule an immediate sync if there is an outstanding error (i.e. user reconnected) db.connections.update( {"_id": serviceRecord._id}, { "$pull": { "SyncErrors": { "UserException.Type": UserExceptionType.Authorization } } } ) # Pull all auth-related errors from the service so they don't continue to see them while the sync completes. Sync.SetNextSyncIsExhaustive( user, True ) # exhaustive, so it'll pick up activities from newly added services / ones lost during an error if hasattr(serviceRecord, "SyncErrors") and len(serviceRecord.SyncErrors) > 0: Sync.ScheduleImmediateSync(user)
def diag_user(req, user): userRec = db.users.find_one({"_id": ObjectId(user)}) if not userRec: userRec = db.users.find_one({"AncestorAccounts": ObjectId(user)}) if userRec: return redirect("diagnostics_user", user=userRec["_id"]) if not userRec: return render(req, "diag/error_user_not_found.html") delta = False if "sync" in req.POST: Sync.ScheduleImmediateSync(userRec, req.POST["sync"] == "Full") delta = True elif "unlock" in req.POST: db.users.update({"_id": ObjectId(user)}, {"$unset": { "SynchronizationWorker": None }}) delta = True elif "lock" in req.POST: db.users.update({"_id": ObjectId(user)}, {"$set": { "SynchronizationWorker": 1 }}) delta = True elif "substitute" in req.POST: req.session["substituteUserid"] = user return redirect("dashboard") elif "svc_setauth" in req.POST and len(req.POST["authdetails"]): db.connections.update( {"_id": ObjectId(req.POST["id"])}, {"$set": { "Authorization": json.loads(req.POST["authdetails"]) }}) delta = True elif "svc_unlink" in req.POST: from tapiriik.services import Service from tapiriik.auth import User svcRec = Service.GetServiceRecordByID(req.POST["id"]) try: Service.DeleteServiceRecord(svcRec) except: pass try: User.DisconnectService(svcRec) except: pass delta = True elif "svc_marksync" in req.POST: from tapiriik.services import Service from tapiriik.auth import User db.connections.update( {"_id": ObjectId(req.POST["id"])}, {"$addToSet": { "SynchronizedActivities": req.POST["uid"] }}, multi=False) delta = True elif "svc_clearexc" in req.POST: from tapiriik.services import Service from tapiriik.auth import User db.connections.update({"_id": ObjectId(req.POST["id"])}, {"$unset": { "ExcludedActivities": 1 }}) delta = True elif "svc_clearacts" in req.POST: from tapiriik.services import Service from tapiriik.auth import User db.connections.update({"_id": ObjectId(req.POST["id"])}, {"$unset": { "SynchronizedActivities": 1 }}) Sync.SetNextSyncIsExhaustive(userRec, True) delta = True if delta: return redirect("diagnostics_user", user=user) return render(req, "diag/user.html", {"user": userRec})