def uninstall(self): # deregister models model.deregisterModel("occurrence", "_occurrence", "_action", "plugins.occurrence.models.action") model.deregisterModel("occurrence clean", "_occurrenceClean", "_action", "plugins.occurrence.models.action") model.deregisterModel("occurrenceUpdate", "_occurrenceUpdate", "_action", "plugins.occurrence.models.action") conduct._conduct().api_delete(query={"name": "occurrenceCore"}) trigger._trigger().api_delete(query={"name": "occurrenceCore"}) action._occurrenceClean().api_delete(query={"name": "occurrenceCore"}) return True
def deleteFlowLink(conductID, fromFlowID, toFlowID): conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: fromFlow = [x for x in conductObj.flow if x["flowID"] == fromFlowID] if len(fromFlow) > 0: fromFlow = fromFlow[0] for nextflow in fromFlow["next"]: if nextflow["flowID"] == toFlowID: if db.fieldACLAccess(api.g["sessionData"], conductObj.acl, "flow", "delete"): conductObj.flow[conductObj.flow.index( fromFlow)]["next"].remove(nextflow) conductObj.update(["flow"]) return {}, 200 return {}, 403 return {}, 404 else: return {}, 403
def run(self, data, persistentData, actionResult): answered = choice._choice().getAsClass(query={ "complete": False, "answerTime": { "$gt": 0 } }) for answeredItem in answered: answeredItem.complete = True c = conduct._conduct().getAsClass(id=answeredItem.conductID) if c and len(c) > 0: c = c[0] data = jimi.conduct.dataTemplate(data, keepEvent=True) data["flowData"] = answeredItem.data data["flowData"]["plugin"]["choice"] = True data["flowData"]["callingTriggerID"] = answeredItem.triggerID data["flowData"]["eventStats"] = { "first": True, "current": 1, "total": 1, "last": True } if answeredItem.answer: workers.workers.new( "trigger:{0}".format(answeredItem._id), c.triggerHandler, (answeredItem.flowID, data, False, True)) answeredItem.update(["complete"]) actionResult["result"] = True actionResult["rc"] = 0 return actionResult
def conductPage(conductID): conductObj = conduct._conduct().query(api.g["sessionData"], id=conductID)["results"] conductObj = conductObj[0] existingFlow = webui._flowData().query( query={"conductID": conductID})["results"] if len(existingFlow) == 1: existingFlow = existingFlow[0] flowData = existingFlow["flowData"] else: flowData = buildFlowData(conductObj["flow"]) if "acl" not in conductObj: conductObj["acl"] = {} return render_template("flow.html", conductID=conductObj["_id"], conductName=conductObj["name"], conductACL=conductObj["acl"], conductEnabled=conductObj["enabled"], content=conductObj, actions=action._action().query()["results"], triggers=trigger._trigger().query()["results"], flowData=flowData, CSRF=api.g["sessionData"]["CSRF"])
def getModelExtra(modelName): class_ = loadModel(modelName).classObject() if class_: results = _model().query( query={"className": class_.__name__})["results"] if len(results) == 1: results = results[0] results = class_().query( api.g["sessionData"], query={"classID": results["_id"]}, fields=["_id", "name", "classType", "lastUpdateTime"])["results"] if modelName == "action" or modelName == "trigger": for result in results: result["whereUsed"] = conduct._conduct().query( query={ "$or": [{ "flow.triggerID": { "$in": [result["_id"]] } }, { "flow.actionID": { "$in": [result["_id"]] } }] }, fields=["_id", "name"])["results"] return {"results": results}, 200 return {}, 404
def newFlow(conductID): conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: data = json.loads(api.request.data) # Get new UUID store within current conduct flow and return UUID newFlowID = str(uuid.uuid4()) flow = {"flowID": newFlowID, "next": []} # Creating new object of model type _class = model._model().getAsClass(api.g["sessionData"], id=data["classID"]) if _class: subtype = _class[0].name _class = _class[0].classObject() newFlowObjectID = _class().new(flow["flowID"]).inserted_id # Working out by bruteforce which type this is ( try and load it by parent class and check for error) - get on trigger if it does not exist will return None modelFlowObjectType = "action" if len(trigger._trigger().getAsClass(api.g["sessionData"], id=newFlowObjectID)) > 0: modelFlowObjectType = "trigger" modelFlowObject = _class().getAsClass(api.g["sessionData"], id=newFlowObjectID) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] else: return {}, 404 modelFlowObject.acl = { "ids": [{ "accessID": api.g["sessionData"]["primaryGroup"], "read": True, "write": True, "delete": True }] } modelFlowObject.update(["acl"], sessionData=api.g["sessionData"]) flow["type"] = modelFlowObjectType if subtype != "action" and subtype != "trigger": flow["subtype"] = subtype flow["{0}{1}".format(modelFlowObjectType, "ID")] = str(newFlowObjectID) # Adding UI position for cloned object webui._modelUI().new(conductID, conductObj.acl, flow["flowID"], data["x"], data["y"], modelFlowObject.name) # Appending new object to conduct conductObj.flow.append(flow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {}, 201 else: return {}, 403 return {}, 404
def install(self): # Register models model.registerModel("choice","_choice","_document","plugins.choice.models.choice",True) model.registerModel("choiceRequest","_requestChoice","_action","plugins.choice.models.action") model.registerModel("choiceTrigger","_choiceTrigger","_action","plugins.choice.models.action",True) c = conduct._conduct().new("choiceCore") c = conduct._conduct().getAsClass(id=c.inserted_id)[0] t = trigger._trigger().new("choiceCore") t = trigger._trigger().getAsClass(id=t.inserted_id)[0] a = action._choiceTrigger().new("choiceCore") a = action._choiceTrigger().getAsClass(id=a.inserted_id)[0] c.triggers = [t._id] flowTriggerID = str(uuid.uuid4()) flowActionID = str(uuid.uuid4()) c.flow = [ { "flowID" : flowTriggerID, "type" : "trigger", "triggerID" : t._id, "next" : [ {"flowID": flowActionID, "logic": True } ] }, { "flowID" : flowActionID, "type" : "action", "actionID" : a._id, "next" : [] } ] webui._modelUI().new(c._id,{ "ids":[ { "accessID":"0","delete": True,"read": True,"write": True } ] },flowTriggerID,0,0,"") webui._modelUI().new(c._id,{ "ids":[ { "accessID":"0","delete": True,"read": True,"write": True } ] },flowActionID,100,0,"") c.acl = { "ids":[ { "accessID":"0","delete": True,"read": True,"write": True } ] } c.enabled = True c.update(["triggers","flow","enabled","acl"]) t.acl = { "ids":[ { "accessID":"0","delete": True,"read": True,"write": True } ] } t.schedule = "60-90s" t.enabled = True t.update(["schedule","enabled","acl"]) a.acl = { "ids":[ { "accessID":"0","delete": True,"read": True,"write": True } ] } a.enabled = True a.update(["enabled","acl"]) return True
def getConductFlowProperties(conductID, flowID): conductObj = conduct._conduct().query(api.g["sessionData"], id=conductID)["results"] if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 flow = [x for x in conductObj["flow"] if x["flowID"] == flowID] if len(flow) == 1: flow = flow[0] formData = None if "type" in flow: if flow["type"] == "trigger": triggerObj = trigger._trigger().query( api.g["sessionData"], id=flow["triggerID"])["results"] if len(triggerObj) == 1: triggerObj = triggerObj[0] else: return {}, 404 _class = model._model().getAsClass(api.g["sessionData"], id=triggerObj["classID"]) if len(_class) == 1: _class = _class[0].classObject() else: return {}, 404 triggerObj = _class().getAsClass(api.g["sessionData"], id=triggerObj["_id"]) if len(triggerObj) == 1: triggerObj = triggerObj[0] else: return {}, 404 if "_properties" in dir(triggerObj): formData = triggerObj._properties().generate(triggerObj) else: formData = webui._properties().generate(triggerObj) elif flow["type"] == "action": actionObj = action._action().query( api.g["sessionData"], id=flow["actionID"])["results"] if len(actionObj) == 1: actionObj = actionObj[0] else: return {}, 404 _class = model._model().getAsClass(api.g["sessionData"], id=actionObj["classID"]) if len(_class) == 1: _class = _class[0].classObject() actionObj = _class().getAsClass(api.g["sessionData"], id=actionObj["_id"]) if len(actionObj) == 1: actionObj = actionObj[0] else: return {}, 404 if "_properties" in dir(actionObj): formData = actionObj._properties().generate(actionObj) else: formData = webui._properties().generate(actionObj) return {"formData": formData}, 200
def setConductFlowLogic(conductID, flowID, nextflowID): conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: flow = [x for x in conductObj.flow if x["flowID"] == flowID] data = json.loads(api.request.data) if len(flow) == 1: flow = flow[0] if "next" in flow: found = False for key, nextFlow in enumerate(flow["next"]): if type(nextFlow) is str: if nextFlow == nextflowID: nextFlow = {"flowID": nextflowID} found = True elif type(nextFlow) is dict: if nextFlow["flowID"] == nextflowID: found = True if found: if "true" == data["logic"].lower(): flow["next"][key] = { "flowID": nextFlow["flowID"], "logic": True } elif "false" == data["logic"].lower(): flow["next"][key] = { "flowID": nextFlow["flowID"], "logic": False } elif data["logic"].startswith("if"): flow["next"][key] = { "flowID": nextFlow["flowID"], "logic": data["logic"] } else: try: flow["next"][key] = { "flowID": nextFlow["flowID"], "logic": int(data["logic"]) } except ValueError: return {}, 403 conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {}, 200 else: return {}, 403 return {}, 404
def mainPage(): from system import install return render_template("main.html", conducts=conduct._conduct().query( api.g["sessionData"], query={"name": { "$exists": True }}, sort=[("name", 1)])["results"], version=install.installedVersion(), pluginPages=pluginPages)
def newConduct(): data = json.loads(api.request.data) if data["action"] == "new": class_ = model._model().getAsClass(api.g["sessionData"], query={"name": "conduct"}) if class_: class_ = class_[0] access, accessIDs, adminBypass = db.ACLAccess( api.g["sessionData"], class_.acl, "read") if access: conductID = str(conduct._conduct().new( data["name"]).inserted_id) return {"result": True, "conductID": conductID}, 201 return {}, 403
def debugItem(conductID, flowID): conductObj = conduct._conduct().query(api.g["sessionData"], id=conductID)["results"] if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 flow = [x for x in conductObj["flow"] if x["flowID"] == flowID] flow = flow[0] if "type" in flow: if flow["type"] == "trigger": return {"_id": flow["triggerID"]}, 200 elif flow["type"] == "action": return {"_id": flow["actionID"]}, 200 return {}, 404
def forceTrigger(conductID, flowID): conductObj = conduct._conduct().query(api.g["sessionData"], id=conductID)["results"] if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 flow = [x for x in conductObj["flow"] if x["flowID"] == flowID] flow = flow[0] data = json.loads(api.request.data) apiEndpoint = "scheduler/{0}/".format(flow["triggerID"]) helpers.apiCall("POST", apiEndpoint, { "action": "trigger", "events": data["events"] }, token=api.g["sessionToken"]) return {}, 200
def getConductFlowLogic(conductID, flowID, nextflowID): conductObj = conduct._conduct().query(api.g["sessionData"], id=conductID)["results"] if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 flow = [x for x in conductObj["flow"] if x["flowID"] == flowID] if len(flow) == 1: flow = flow[0] if "next" in flow: for nextFlow in flow["next"]: if type(nextFlow) is str: if nextflowID == nextFlow: return {"result": {"logic": True}}, 200 elif type(nextFlow) is dict: if nextflowID == nextFlow["flowID"]: return {"result": {"logic": nextFlow["logic"]}}, 200 return {}, 404
def getConductFlow(conductID, flowID): conductObj = conduct._conduct().query(api.g["sessionData"], id=conductID)["results"] if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 flow = [x for x in conductObj["flow"] if x["flowID"] == flowID] if len(flow) == 1: flow = flow[0] if "type" in flow: flowType = flow["type"] if "{0}{1}".format(flowType, "ID") in flow: result = { "type": flowType, "{0}{1}".format(flowType, "ID"): flow["{0}{1}".format(flowType, "ID")] } return {"result": result}, 200 return {}, 404
def newFlowLink(conductID, fromFlowID, toFlowID): conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: fromFlow = [x for x in conductObj.flow if x["flowID"] == fromFlowID][0] toFlow = [x for x in conductObj.flow if x["flowID"] == toFlowID][0] nextFlows = [x for x in fromFlow["next"] if x["flowID"] == toFlowID] if len(nextFlows) == 0: if toFlow["type"] != "trigger": fromFlow["next"].append({"flowID": toFlowID, "logic": True}) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {}, 201 else: return {}, 403 return {}, 200 else: return {}, 403
def deleteFlow(conductID, flowID): conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: flow = [x for x in conductObj.flow if x["flowID"] == flowID] if len(flow) == 1: flow = flow[0] for flowItemsValue in conductObj.flow: for nextflowValue in flowItemsValue["next"]: if nextflowValue["flowID"] == flowID: conductObj.flow[conductObj.flow.index( flowItemsValue)]["next"].remove(nextflowValue) conductObj.flow.remove(flow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {}, 200 else: return {}, 404
def dropExistingObject(conductID): conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: data = json.loads(api.request.data) if data["action"] == "drop": newFlowID = str(uuid.uuid4()) flow = { "flowID": newFlowID, "type": data["flowType"], "{0}{1}".format(data["flowType"], "ID"): data["_id"], "next": [] } modelFlowObject = None if data["flowType"] == "trigger": modelFlowObject = trigger._trigger().getAsClass( api.g["sessionData"], id=data["_id"])[0] elif data["flowType"] == "action": modelFlowObject = action._action().getAsClass( api.g["sessionData"], id=data["_id"])[0] if modelFlowObject: name = modelFlowObject.name else: name = flow["flowID"] webui._modelUI().new(conductID, conductObj.acl, flow["flowID"], data["x"], data["y"], name) conductObj.flow.append(flow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {}, 201 return {}, 404
def install(self): # Register models model.registerModel("occurrence", "_occurrence", "_action", "plugins.occurrence.models.action") model.registerModel("occurrence clean", "_occurrenceClean", "_action", "plugins.occurrence.models.action") model.registerModel("occurrenceUpdate", "_occurrenceUpdate", "_action", "plugins.occurrence.models.action") # Finding conduct foundConducts = conduct._conduct().query( query={"name": "occurrenceCore"})["results"] if len(foundConducts) == 0: # Install c = conduct._conduct().new("occurrenceCore") c = conduct._conduct().get(c.inserted_id) elif len(foundConducts) == 1: # Reinstall c = conduct._conduct().get(foundConducts[0]["_id"]) else: # Count invalid return False # Finding trigger foundTriggers = trigger._trigger().query( query={"name": "occurrenceCore"})["results"] if len(foundTriggers) == 0: # Install t = trigger._trigger().new("occurrenceCore") t = trigger._trigger().get(t.inserted_id) elif len(foundTriggers) == 1: # Reinstall t = trigger._trigger().get(foundTriggers[0]["_id"]) else: # Count invalid return False # Finding action foundActions = action._occurrenceClean().query( query={"name": "occurrenceCore"})["results"] if len(foundActions) == 0: # Install a = action._occurrenceClean().new("occurrenceCore") a = action._occurrenceClean().get(a.inserted_id) elif len(foundActions) == 1: # Reinstall a = action._occurrenceClean().get(foundActions[0]["_id"]) else: # Count invalid return False c.triggers = [t._id] flowTriggerID = str(uuid.uuid4()) flowActionID = str(uuid.uuid4()) c.flow = [{ "flowID": flowTriggerID, "type": "trigger", "triggerID": t._id, "next": [{ "flowID": flowActionID, "logic": True }] }, { "flowID": flowActionID, "type": "action", "actionID": a._id, "next": [] }] webui._modelUI().new( c._id, { "ids": [{ "accessID": "0", "delete": True, "read": True, "write": True }] }, flowTriggerID, 0, 0, "") webui._modelUI().new( c._id, { "ids": [{ "accessID": "0", "delete": True, "read": True, "write": True }] }, flowActionID, 100, 0, "") c.acl = { "ids": [{ "accessID": "0", "delete": True, "read": True, "write": True }] } c.enabled = True c.update(["triggers", "flow", "enabled", "acl"]) t.acl = { "ids": [{ "accessID": "0", "delete": True, "read": True, "write": True }] } t.schedule = "60-90s" t.enabled = True t.update(["schedule", "enabled", "acl"]) a.acl = { "ids": [{ "accessID": "0", "delete": True, "read": True, "write": True }] } a.enabled = True a.update(["enabled", "acl"]) # Hide Created Models temp = model._model().getAsClass(query={"name": "occurrence clean"}) if len(temp) == 1: temp = temp[0] temp.hidden = True temp.update(["hidden"]) return True
def getTriggerConducts(triggerID, sessionData): return conduct._conduct().getAsClass(query={ "flow.triggerID": triggerID, "enabled": True })
def conductFlowchartPoll(conductID): conductObj = conduct._conduct().query(api.g["sessionData"], id=conductID)["results"] if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 data = json.loads(api.request.data) flowchartOperators = data["operators"] flowchartLinks = data["links"] flowchartResponse = { "operators": { "delete": {}, "create": {}, "update": {} }, "links": { "delete": {}, "create": {}, "update": {} } } # Getting all UI flow details for flows in this conduct flows = [x for x in conductObj["flow"]] flowTriggers = [ db.ObjectId(x["triggerID"]) for x in flows if x["type"] == "trigger" ] flowActions = [ db.ObjectId(x["actionID"]) for x in flows if x["type"] == "action" ] flowsList = [x["flowID"] for x in flows] linksList = [] # For every refresh the entire flow object and UI is loaded from the database - this may need improvment for speed in future flowsUI = webui._modelUI().getAsClass(api.g["sessionData"], query={ "flowID": { "$in": flowsList }, "conductID": conductID }) actions = action._action().getAsClass(api.g["sessionData"], query={"_id": { "$in": flowActions }}) triggers = trigger._trigger().getAsClass( api.g["sessionData"], query={"_id": { "$in": flowTriggers }}) cache.globalCache.newCache("modelCache", sessionData=api.g["sessionData"]) for flow in flows: if "type" in flow: flowType = flow["type"] if "subtype" in flow: flowSubtype = flow["subtype"] else: flowSubtype = "" if "{0}{1}".format(flowType, "ID") in flow: objectID = "{0}{1}".format(flowType, "ID") flowID = flow["flowID"] # Default to create flowchartResponseType = "create" if flowID in flowchartOperators: # If it already exits then its an update flowchartResponseType = "update" # Setting position if it has changed since last pollTime foundFlowUI = False foundObject = False name = flow["flowID"] node = {} for flowUI in flowsUI: if flow["flowID"] == flowUI.flowID: foundFlowUI = True if flowchartResponseType == "create": node["x"] = flowUI.x node["y"] = flowUI.y node["shape"] = "box" node["widthConstraint"] = { "minimum": 125, "maximum": 125 } node["heightConstraint"] = { "minimum": 35, "maximum": 35 } node["borderWidth"] = 1.5 node["font"] = {"multi": True} elif flowUI.x != flowchartOperators[flowID]["node"][ "x"] or flowUI.y != flowchartOperators[flowID][ "node"]["y"]: node["x"] = flowUI.x node["y"] = flowUI.y if flow["type"] == "trigger": for t in triggers: if flow["triggerID"] == t._id: name = t.name modeClass = cache.globalCache.get( "modelCache", t.classID, model.getClassObject, sessionData=api.g["sessionData"])[0] color = None if t.enabled: color = "#7cbeeb" duration = t.maxDuration if duration == 0: duration = 60 if ((t.startCheck != 0) and (t.startCheck + duration > time.time())): color = "green" if ((t.startCheck != 0) and (t.startCheck + duration < time.time())): color = "red" if not t.enabled: color = "gray" label = "<b>{0}</b>\n{1}".format( t.name, modeClass.name) if flowchartResponseType == "create": node["label"] = label node["color"] = {"background": color} else: if color != flowchartOperators[flowID][ "node"]["color"]: node["color"] = { "background": color } if label != flowchartOperators[flowID][ "node"]["label"]: node["label"] = label foundObject = True break elif flow["type"] == "action": for a in actions: if flow["actionID"] == a._id: name = a.name modeClass = cache.globalCache.get( "modelCache", a.classID, model.getClassObject, sessionData=api.g["sessionData"])[0] color = None if a.enabled: color = "#7cbeeb" if not a.enabled: color = "gray" label = "<b>{0}</b>\n{1}".format( a.name, modeClass.name) if flowchartResponseType == "create": node["label"] = label node["color"] = {"background": color} else: if color != flowchartOperators[flowID][ "node"]["color"]: node["color"] = { "background": color } if label != flowchartOperators[flowID][ "node"]["label"]: node["label"] = label foundObject = True break if node: if not foundObject: node["label"] = "Unknown Object" node["color"] = {"background": "black"} flowchartResponse["operators"][ flowchartResponseType][flowID] = { "_id": flow[objectID], "flowID": flowID, "flowType": flowType, "flowSubtype": flowSubtype, "name": name, "node": node } break if not foundFlowUI: node["x"] = 0 node["y"] = 0 node["shape"] = "box" node["widthConstraint"] = {"minimum": 125, "maximum": 125} node["heightConstraint"] = {"minimum": 35, "maximum": 35} node["borderWidth"] = 1.5 node["label"] = "Unknown Object" node["color"] = {"background": "black"} flowchartResponse["operators"][flowchartResponseType][ flowID] = { "_id": flow[objectID], "flowID": flowID, "flowType": flowType, "flowSubtype": flowSubtype, "node": node } # Do any links need to be created for nextFlow in flow["next"]: linkName = "{0}->{1}".format(flowID, nextFlow["flowID"]) linksList.append(linkName) if linkName not in flowchartLinks: flowchartResponse["links"]["create"][linkName] = { "from": flowID, "to": nextFlow["flowID"], "logic": nextFlow["logic"] } #Updates (for logic for now) << needs to be readded but using same as node with color value set from server #flowchartResponse["links"]["update"][linkName] = { "from" : flowID, "to" : nextFlow["flowID"], "logic" : nextFlow["logic"] } # Checking for deleted operators for flowchartOperator in flowchartOperators: if flowchartOperator not in flowsList: flowchartResponse["operators"]["delete"][flowchartOperator] = { "flowID": flowchartOperator } # Checking for deleted links for flowchartLink in flowchartLinks: if flowchartLink not in linksList: flowchartResponse["links"]["delete"][flowchartLink] = { "linkName": flowchartLink } return flowchartResponse, 200
def getConductFlowCodify(conductID): def generateFlow(currentFlow, flowDict, triggers, actions): flowCode = "" processQueue = [] indentLevel = 0 logic = None while True: if currentFlow: obj = None if currentFlow["type"] == "trigger": for t in triggers: if flow["triggerID"] == t._id: obj = t break for nextFlow in currentFlow["next"]: processQueue.append({ "flowID": nextFlow["flowID"], "indentLevel": indentLevel + 1, "logic": nextFlow["logic"] }) elif currentFlow["type"] == "action": for a in actions: if currentFlow["actionID"] == a._id: obj = a break for nextFlow in currentFlow["next"]: processQueue.append({ "flowID": nextFlow["flowID"], "indentLevel": indentLevel + 1, "logic": nextFlow["logic"] }) if obj: classObj = _class = model._model().getAsClass( api.g["sessionData"], id=obj.classID) classObj = classObj[0] blacklist = [ "_id", "acl", "classID", "workerID", "startCheck", "nextCheck", "lastUpdateTime", "lastCheck" ] members = [ attr for attr in dir(obj) if not callable(getattr(obj, attr)) and not "__" in attr and attr ] params = [] for member in members: if member not in blacklist: value = getattr(obj, member) if type(value) == str: value = "\"{0}\"".format(value) params.append("{0}={1}".format(member, value)) if currentFlow["type"] == "action": flowCode += "\r\n{0}logic({1})->{2}({3})".format( ("\t" * indentLevel), logic, classObj.name, ",".join(params)) else: if len(flowCode) > 0: flowCode += "\r\n{0}{1}({2})".format( ("\t" * indentLevel), classObj.name, ",".join(params)) else: flowCode = "{0}({1})".format( classObj.name, ",".join(params)) if len(processQueue) == 0: break else: nextFlowID = processQueue[-1]["flowID"] indentLevel = processQueue[-1]["indentLevel"] logic = processQueue[-1]["logic"] processQueue.pop() if nextFlowID in flowDict: currentFlow = flowDict[nextFlowID] else: currentFlow = None return flowCode conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 # Getting all UI flow details for flows in this conduct flows = [x for x in conductObj.flow] flowDict = {} for flow in flows: flowDict[flow["flowID"]] = flow flowTriggers = [ db.ObjectId(x["triggerID"]) for x in flows if x["type"] == "trigger" ] flowActions = [ db.ObjectId(x["actionID"]) for x in flows if x["type"] == "action" ] actions = action._action().getAsClass(api.g["sessionData"], query={"_id": { "$in": flowActions }}) triggers = trigger._trigger().getAsClass( api.g["sessionData"], query={"_id": { "$in": flowTriggers }}) flowCode = "" for flow in flows: if flow["type"] == "trigger": flowCode += generateFlow(flow, flowDict, triggers, actions) return render_template("blank.html", content=flowCode, CSRF=api.g["sessionData"]["CSRF"]), 200
def saveConduct(conductID): data = json.loads(api.request.data) conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 if data["action"] == "new": access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: # Get new UUID store within current conduct flow and return UUID newFlowID = str(uuid.uuid4()) flow = {"flowID": newFlowID, "next": []} conductObj.flow.append(flow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {"result": True, "flowID": newFlowID}, 201 else: return {}, 403 # Clone an existing object into a new object if data["action"] == "clone": access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: flow = [ x for x in conductObj.flow if x["flowID"] == data["operatorId"] ] if len(flow) == 1: flow = flow[0] data = json.loads(api.request.data) modelFlowObject = None # Check if the modelType and object are unchanged if "type" in flow: if flow["type"] == "trigger": modelFlowObject = trigger._trigger().getAsClass( api.g["sessionData"], id=flow["{0}{1}".format(flow["type"], "ID")]) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] modelFlowObjectType = "trigger" if flow["type"] == "action": modelFlowObject = action._action().getAsClass( api.g["sessionData"], id=flow["{0}{1}".format(flow["type"], "ID")]) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] modelFlowObjectType = "action" # Was it possible to load an existing object if modelFlowObject: # Create new flowItem newFlowID = str(uuid.uuid4()) flow = { "flowID": newFlowID, "type": flow["type"], "next": [] } # New object required _class = model._model().getAsClass( api.g["sessionData"], id=modelFlowObject.classID) if _class: _class = _class[0].classObject() # Bug exists as name value is not requried by db class but is for core models - this could result in an error if new model is added that does not accept name within new function override newFlowObjectID = _class().new( flow["flowID"]).inserted_id # Working out by bruteforce which type this is ( try and load it by parent class and check for error) - get on trigger if it does not exist will return None modelFlowObjectClone = _class().getAsClass( api.g["sessionData"], id=newFlowObjectID) if len(modelFlowObjectClone) == 1: modelFlowObjectClone = modelFlowObjectClone[0] else: return {}, 404 # Setting values in cloned object members = [ attr for attr in dir(modelFlowObject) if not callable(getattr(modelFlowObject, attr)) and not "__" in attr and attr ] dontCopy = ["_id", "name"] updateList = [] for member in members: if member not in dontCopy: setattr(modelFlowObjectClone, member, getattr(modelFlowObject, member)) updateList.append(member) modelFlowObjectClone.update( updateList, sessionData=api.g["sessionData"]) # Set conduct flow to correct type and objectID flow["{0}{1}".format(flow["type"], "ID")] = str(newFlowObjectID) conductObj.flow.append(flow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {"result": True, "flowID": newFlowID}, 201 else: return {}, 403 # Add existing object to flow elif data["action"] == "existing": access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: newFlowID = str(uuid.uuid4()) flow = {"flowID": newFlowID, "next": []} if data["type"] == "trigger": flow["type"] = "trigger" flow["triggerID"] = data["triggerID"] elif data["type"] == "action": flow["type"] = "action" flow["actionID"] = data["actionID"] conductObj.flow.append(flow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {"result": True, "flowID": newFlowID}, 201 else: return {}, 403 elif data["action"] == "save": access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: flowData = data["flowData"] newFlowData = {} flowPopList = [] for flow in flowData['links']: if flow != "{}>{}".format( flowData['links'][flow]['fromOperator'], flowData['links'][flow]['toOperator']): newFlowData["{}>{}".format( flowData['links'][flow]['fromOperator'], flowData['links'][flow] ['toOperator'])] = flowData['links'][flow] flowPopList.append(flow) if len(newFlowData) > 0: flowData['links'].update(newFlowData, sessionData=api.g["sessionData"]) for popItem in flowPopList: flowData['links'].pop(popItem) poplistOperator = [] poplistLink = [] for operatorID in flowData["operators"]: operatorFound = None for flow in conductObj.flow: flowID = flow["flowID"] if operatorID == flowID: operatorFound = flowID connections = [] for link in flowData["links"]: if flowData["links"][link][ "fromOperator"] == flowID: connections.append( flowData["links"][link]["toOperator"]) for connection in connections: foundFlow = False for index, nextFlowID in enumerate(conductObj.flow[ conductObj.flow.index(flow)]["next"]): if type(nextFlowID) is dict: if connection == nextFlowID["flowID"]: foundFlow = True conductObj.flow[conductObj.flow.index( flow)]["next"][index] = { "flowID": connection, "logic": nextFlowID["logic"] } else: if connection == nextFlowID: foundFlow = True conductObj.flow[conductObj.flow.index( flow)]["next"][index] = { "flowID": connection, "logic": True } if not foundFlow: conductObj.flow[conductObj.flow.index( flow)]["next"].append({ "flowID": connection, "logic": True }) notUpdatedPopList = [] for nextFlowID in conductObj.flow[ conductObj.flow.index(flow)]["next"]: if nextFlowID["flowID"] not in connections: notUpdatedPopList.append(nextFlowID) for notUpdatedPopItem in notUpdatedPopList: del conductObj.flow[conductObj.flow.index(flow)][ "next"][conductObj.flow[conductObj.flow.index( flow)]["next"].index(notUpdatedPopItem)] if not operatorFound: for link in flowData["links"]: if flowData["links"][link][ "toOperator"] == operatorID or flowData[ "links"][link][ "fromOperator"] == operatorID: poplistLink.append(link) poplistOperator.append(operatorID) # Checking to ensure every flow that exists is also still within the flowData i.e. it has not been deleted poplistFlow = [] for flow in conductObj.flow: flowID = flow["flowID"] if len([x for x in flowData["operators"] if x == flowID]) == 0: poplistFlow.append(flow) # Deleting any items that were found within flowData but not in the conduct flow for pop in poplistOperator: del flowData["operators"][pop] for pop in poplistLink: del flowData["links"][pop] for pop in poplistFlow: del conductObj.flow[conductObj.flow.index(pop)] # checking if conduct has been enabled or name changed if "conductName" in data: conductObj.name = data["conductName"] if "conductEnabled" in data: conductObj.enabled = data["conductEnabled"] if "conductACL" in data: try: conductObj.acl = json.loads(data["conductACL"]) except: pass # Updating all possible updated values conductObj.update(["flow", "name", "enabled", "acl"], sessionData=api.g["sessionData"]) existingFlow = webui._flowData().query( query={"conductID": conductID})["results"] if len(existingFlow) > 0: existingFlow = existingFlow[0] existingFlow = webui._flowData().load(existingFlow["_id"]) existingFlow.flowData = flowData existingFlow.update(["flowData"], sessionData=api.g["sessionData"]) else: webui._flowData().new(conductID, flowData) return {"result": True, "flowData": flowData}, 201 return {"result": True, "flowData": flowData}, 200 else: return {}, 403 return {"result": False}, 404
def setConductFlow(conductID, flowID): # List of attributes that are prevented from updating - this needs to be made more dynamic and part of class design unsafeUpdateList = [ "_id", "classID", "lastCheck", "lastRun", "lastResult", "workerID", "startCheck" ] conductObj = conduct._conduct().query(api.g["sessionData"], id=conductID)["results"] conductObj = conductObj[0] conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductObj["_id"]) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 flow = [x for x in conductObj.flow if x["flowID"] == flowID] if len(flow) == 1: flow = flow[0] data = json.loads(api.request.data) modelFlowObject = None # Check if the modelType and object are unchanged if "type" in flow: if flow["type"] == "trigger": modelFlowObject = trigger._trigger().getAsClass( api.g["sessionData"], id=flow["{0}{1}".format(flow["type"], "ID")]) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] modelFlowObjectType = "trigger" if flow["type"] == "action": modelFlowObject = action._action().getAsClass( api.g["sessionData"], id=flow["{0}{1}".format(flow["type"], "ID")]) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] modelFlowObjectType = "action" # Was it possible to load an existing object if modelFlowObject: # Check that the object model is still the same if modelFlowObject.classID == data["newClassID"]: # Get flow object correct class _class = model._model().getAsClass( api.g["sessionData"], id=modelFlowObject.classID) if len(_class) == 1: _class = _class[0] _class = _class.classObject() else: return {}, 404 modelFlowObject = _class().getAsClass( api.g["sessionData"], id=modelFlowObject._id) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] else: return {}, 404 else: modelFlowObject = None # New object required if not modelFlowObject: _class = model._model().getAsClass(api.g["sessionData"], id=data["newClassID"]) if _class: _class = _class[0].classObject() # Bug exists as name value is not requried by db class but is for core models - this could result in an error if new model is added that does not accept name within new function override newFlowObjectID = _class().new(flow["flowID"]).inserted_id # Working out by bruteforce which type this is ( try and load it by parent class and check for error) - get on trigger if it does not exist will return None modelFlowObjectType = "action" if len(trigger._trigger().getAsClass(api.g["sessionData"], id=newFlowObjectID)) > 0: modelFlowObjectType = "trigger" modelFlowObject = _class().getAsClass(api.g["sessionData"], id=newFlowObjectID) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] else: return {}, 404 modelFlowObject.acl = { "ids": [{ "accessID": api.g["sessionData"]["primaryGroup"], "read": True, "write": True, "delete": True }] } modelFlowObject.update(["acl"]) # Set conduct flow to correct type and objectID flow["type"] = modelFlowObjectType flow["{0}{1}".format(modelFlowObjectType, "ID")] = str(newFlowObjectID) conductObj.update(["flow"], sessionData=api.g["sessionData"]) # Updating new or existing modeFlowObject if modelFlowObject: updateItemsList = [] changeLog = {} # Getting schema information so types can be set correctly class_ = model._model().getAsClass(api.g["sessionData"], id=modelFlowObject.classID) if class_: _class = modelFlowObject # Builds list of permitted ACL access, accessIDs, adminBypass = db.ACLAccess( api.g["sessionData"], _class.acl, "write") if access: for dataKey, dataValue in data.items(): fieldAccessPermitted = True # Checking if sessionData is permitted field level access if _class.acl and not adminBypass: fieldAccessPermitted = db.fieldACLAccess( api.g["sessionData"], _class.acl, dataKey, "write") if fieldAccessPermitted: # Change update database entry _id if dataKey not in unsafeUpdateList: if hasattr(_class, dataKey): changeLog[dataKey] = {} changeLog[dataKey][ "currentValue"] = getattr( _class, dataKey) if type(getattr(_class, dataKey)) is str: if dataValue: if _class.setAttribute( dataKey, str(dataValue), sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) elif type(getattr(_class, dataKey)) is int: try: if _class.setAttribute( dataKey, int(dataValue), sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) except ValueError: if _class.setAttribute( dataKey, 0, sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) elif type(getattr(_class, dataKey)) is float: try: if _class.setAttribute( dataKey, float(dataValue), sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) except ValueError: if _class.setAttribute( dataKey, 0, sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) elif type(getattr(_class, dataKey)) is bool: if _class.setAttribute( dataKey, bool(dataValue), sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) elif type(getattr( _class, dataKey)) is dict or type( getattr(_class, dataKey)) is list: if dataValue: if _class.setAttribute( dataKey, json.loads(dataValue), sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) # Commit back to database if updateItemsList: _class.update(updateItemsList, sessionData=api.g["sessionData"]) # Adding audit record if "_id" in api.g["sessionData"]: audit._audit().add( "model", "update", { "_id": api.g["sessionData"]["_id"], "objects": helpers.unicodeEscapeDict(changeLog) }) else: audit._audit().add("model", "update", { "objects": helpers.unicodeEscapeDict(changeLog) }) return {"type": modelFlowObjectType}, 200 else: return {}, 403 return {}, 404
def updateFlow(conductID, flowID): conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 flow = [x for x in conductObj.flow if x["flowID"] == flowID] if len(flow) == 1: flow = flow[0] data = json.loads(api.request.data) if data["action"] == "update": access, accessIDs, adminBypass = db.ACLAccess( api.g["sessionData"], conductObj.acl, "write") if access: if "x" in data and "y" in data: try: x = int(data["x"]) y = int(data["y"]) except: return {}, 403 flowUI = webui._modelUI().getAsClass(api.g["sessionData"], query={ "flowID": flow["flowID"], "conductID": conductID }) if len(flowUI) == 1: flowUI = flowUI[0] if "x" in data and "y" in data: flowUI.x = x flowUI.y = y flowUI.update(["x", "y"], sessionData=api.g["sessionData"]) if "title" in data: flowUI.title = data["title"] flowUI.update(["title"], sessionData=api.g["sessionData"]) return {}, 200 else: webui._modelUI().new(conductID, conductObj.acl, flow["flowID"], x, y) return {}, 201 elif data["action"] == "copy": access, accessIDs, adminBypass = db.ACLAccess( api.g["sessionData"], conductObj.acl, "write") if access: flow = [ x for x in conductObj.flow if x["flowID"] == data["operatorId"] ] if len(flow) == 1: flow = flow[0] newFlowID = str(uuid.uuid4()) newFlow = { "flowID": newFlowID, "type": flow["type"], "{0}{1}".format(flow["type"], "ID"): flow["{0}{1}".format(flow["type"], "ID")], "next": [] } flowUI = webui._modelUI().getAsClass(api.g["sessionData"], query={ "flowID": flow["flowID"], "conductID": conductID })[0] webui._modelUI().new(conductID, conductObj.acl, newFlow["flowID"], data["x"], data["y"], flowUI.title) conductObj.flow.append(newFlow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {}, 201 elif data["action"] == "clone": access, accessIDs, adminBypass = db.ACLAccess( api.g["sessionData"], conductObj.acl, "write") if access: flow = [ x for x in conductObj.flow if x["flowID"] == data["operatorId"] ] if len(flow) == 1: flow = flow[0] data = json.loads(api.request.data) modelFlowObject = None # Check if the modelType and object are unchanged if "type" in flow: if flow["type"] == "trigger": modelFlowObject = trigger._trigger().getAsClass( api.g["sessionData"], id=flow["{0}{1}".format(flow["type"], "ID")]) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] modelFlowObjectType = "trigger" if flow["type"] == "action": modelFlowObject = action._action().getAsClass( api.g["sessionData"], id=flow["{0}{1}".format(flow["type"], "ID")]) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] modelFlowObjectType = "action" # Was it possible to load an existing object if modelFlowObject: # Create new flowItem newFlowID = str(uuid.uuid4()) flow = { "flowID": newFlowID, "type": flow["type"], "next": [] } # New object required _class = model._model().getAsClass( api.g["sessionData"], id=modelFlowObject.classID) if _class: _class = _class[0].classObject() # Bug exists as name value is not requried by db class but is for core models - this could result in an error if new model is added that does not accept name within new function override newFlowObjectID = _class().new( flow["flowID"]).inserted_id # Working out by bruteforce which type this is ( try and load it by parent class and check for error) - get on trigger if it does not exist will return None modelFlowObjectClone = _class().getAsClass( api.g["sessionData"], id=newFlowObjectID) if len(modelFlowObjectClone) == 1: modelFlowObjectClone = modelFlowObjectClone[ 0] else: return {}, 404 # Setting values in cloned object members = [ attr for attr in dir(modelFlowObject) if not callable( getattr(modelFlowObject, attr)) and not "__" in attr and attr ] dontCopy = ["_id", "name"] updateList = [] for member in members: if member not in dontCopy: setattr( modelFlowObjectClone, member, getattr(modelFlowObject, member)) updateList.append(member) modelFlowObjectClone.update( updateList, sessionData=api.g["sessionData"]) # Set conduct flow to correct type and objectID flow["{0}{1}".format( flow["type"], "ID")] = str(newFlowObjectID) conductObj.flow.append(flow) # Adding UI position for cloned object flowUI = webui._modelUI().getAsClass( api.g["sessionData"], query={ "flowID": flowID, "conductID": conductID })[0] webui._modelUI().new( conductID, conductObj.acl, flow["flowID"], data["x"], data["y"], "Copy - {0}".format(flowUI.title)) conductObj.update( ["flow"], sessionData=api.g["sessionData"]) return {"result": True}, 201 return {}, 404
def run(self, data, persistentData, actionResult): now = int(time.time()) conductsCache = {} foundOccurrenceCache = {} # Finding occurrences that have expired their lull time foundOccurrences = occurrence._occurrence().query(query={ "lullTime": { "$lt": now }, "lullTimeExpired": { "$lt": 1 } })["results"] foundOccurrencesIDs = [] for foundOccurrence in foundOccurrences: # Adding IDs of found occurrences to the delete list as they are now cleared foundOccurrencesIDs.append(db.ObjectId(foundOccurrence["_id"])) # Notifiying clears if foundOccurrence["occurrenceFlowID"] not in foundOccurrenceCache: tempOccurrence = _occurrence().load( foundOccurrence["occurrenceActionID"]) foundOccurrenceCache[foundOccurrence["occurrenceFlowID"]] = { "triggerID": None, "conducts": [] } if tempOccurrence.enabled: conducts = conduct._conduct().query( query={ "flow.actionID": tempOccurrence._id, "flow.flowID": foundOccurrence["occurrenceFlowID"], "enabled": True })["results"] foundOccurrenceCache[foundOccurrence["occurrenceFlowID"]][ "exitCodeMode"] = { "actionID": tempOccurrence._id, "conducts": conducts } conducts = foundOccurrenceCache[foundOccurrence[ "occurrenceFlowID"]]["exitCodeMode"]["conducts"] data = conduct.dataTemplate() data["flowData"]["trigger_id"] = tempOccurrence._id data["flowData"]["clearOccurrence"] = True # If occurrence contains the orgnial data var and event then apply it to the data passsed to clear if "data" in foundOccurrence: data["flowData"]["event"] = foundOccurrence["data"]["event"] data["flowData"]["var"] = foundOccurrence["data"]["var"] for conduct_ in conducts: loadedConduct = None if conduct_["classID"] not in conductsCache: # Dynamic loading for classType model _class = model._model().get( conduct_["classID"]).classObject() if _class: loadedConduct = _class().load(conduct_["_id"]) conductsCache[conduct_["classID"]] = loadedConduct else: logging.debug( "Cannot locate occurrence by ID, occurrenceID='{0}'" .format(foundOccurrence["occurrenceFlowID"]), 6) else: loadedConduct = conductsCache[conduct_["classID"]] if loadedConduct: try: cache.globalCache.delete("occurrenceCacheMatch", foundOccurrence["match"]) eventStat = { "first": True, "current": 0, "total": 1, "last": True } tempData = conduct.copyData(data) tempData["flowData"]["eventStats"] = eventStat loadedConduct.triggerHandler( foundOccurrence["occurrenceFlowID"], tempData, flowIDType=True) except Exception as e: pass # Error handling is needed here # Deleting expired occurrences if len(foundOccurrencesIDs) > 0: foundOccurrences = occurrence._occurrence().api_delete( query={"_id": { "$in": foundOccurrencesIDs }}) logging.debug( "Occurrences cleared, result='{0}'".format(foundOccurrences), 7) activeOccurrences = occurrence._occurrence()._dbCollection.aggregate([{ "$project": { "triggerID": { "$toObjectId": '$triggerID' }, "lastLullCheck": 1, "lullTime": 1 } }, { "$lookup": { "from": "triggers", "localField": "triggerID", "foreignField": "_id", "as": "triggers" } }, { "$unwind": "$triggers" }, { "$match": { "lullTime": { "$lt": now }, "$expr": { "$gt": ["$triggers.lastCheck", "$lastLullCheck"] } } }]) updateOccurrenceIDs = [] for activeOccurrence in activeOccurrences: updateOccurrenceIDs.append(activeOccurrence["_id"]) # Increment all with expired lullTime if len(updateOccurrenceIDs) > 0: incrementedOccurrences = occurrence._occurrence().api_update( query={"_id": { "$in": updateOccurrenceIDs }}, update={ "$inc": { "lullTimeExpired": -1 }, "$set": { "lastLullCheck": int(time.time()) } }) logging.debug( "Occurrences incremented, result='{0}'".format( incrementedOccurrences), 7) actionResult["result"] = True actionResult["rc"] = 0 return actionResult