diff --git a/Orchestrator/ControlPanel/CP_Test.py b/Orchestrator/ControlPanel/CP_Test.py index c0b30172..6c3c893e 100644 --- a/Orchestrator/ControlPanel/CP_Test.py +++ b/Orchestrator/ControlPanel/CP_Test.py @@ -28,7 +28,25 @@ def CPRender(inGSettings): return lResultDict # Check in control panel, that process is runnning +# Test JSON generator when page init +def JSONGenerator(): + lJSONDict=[1,2,2,4,2,2,2] + return lJSONDict + +# Test JS when page init +def JSInitGenerator(): + lJSCheckVersion=""" + lT = 9; + lY="123"; + console.log(lT+1); + if (lT==9) { + alert(123) + } + """ + return lJSCheckVersion + #Orchestrator settings def SettingsUpdate(inGSettings): - inGSettings["ControlPanelDict"]["RobotList"].append({"RenderFunction": CPRender, "KeyStr": "TEST"}) + # New way to add CP defs in orchestrator - no gSettings.. + Orchestrator.OrchestratorWebCPUpdate(inGSettings=inGSettings,inCPKeyStr="TEST",inHTMLRenderDef=CPRender, inJSONGeneratorDef=JSONGenerator, inJSInitGeneratorDef=JSInitGenerator) return inGSettings \ No newline at end of file diff --git a/Orchestrator/OrchestratorSettings.py b/Orchestrator/OrchestratorSettings.py index 7583e82b..5f849d74 100644 --- a/Orchestrator/OrchestratorSettings.py +++ b/Orchestrator/OrchestratorSettings.py @@ -25,7 +25,7 @@ from pyOpenRPA.Orchestrator import SettingsTemplate # Import functionallity if __name__ == "__main__": # New init way - allow run as module -m PyOpenRPA.Orchestrator - from pyOpenRPA.Orchestrator import Orchestrator # Import orchestrator main + from pyOpenRPA import Orchestrator # Import orchestrator main gSettings = SettingsTemplate.Create(inModeStr="BASIC") # Create GSettings with basic configuration # TEST Add User ND - Add Login ND to superuser of the Orchestrator @@ -41,7 +41,7 @@ if __name__ == "__main__": # New init way - allow run as module -m PyOpenRPA.Orc # del lUACClientDict["pyOpenRPADict"]["CPKeyDict"] #lUACClientDict["pyOpenRPADict"]["CPKeyDict"]["VersionCheck"]=True #lUACClientDict["pyOpenRPADict"]["CPKeyDict"]["TEST"]=True - lUACClientDict["pyOpenRPADict"]["AgentKeyDict"]["DESKTOP----;ND"]=True + #lUACClientDict["pyOpenRPADict"]["AgentKeyDict"]["DESKTOP----;ND"]=True Orchestrator.OrchestratorUACUpdate(inGSettings=gSettings, inADLoginStr="ND", inADStr="", inADIsDefaultBool=True, inURLList=[], inRoleHierarchyAllowedDict=lUACClientDict) # TEST Add User IMaslov - Add Login IMaslov to superuser of the Orchestrator Orchestrator.OrchestratorUACUpdate(inGSettings=gSettings, inADLoginStr="IMaslov", inADStr="", inADIsDefaultBool=True, inURLList=[]) diff --git a/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py b/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py index 0d938842..64f123dd 100644 --- a/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py +++ b/Sources/pyOpenRPA/Orchestrator/BackwardCompatibility.py @@ -384,3 +384,10 @@ def Update(inGSettings): del inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"][lItemKeyTurple]["ControlPanelKeyAllowedList"] if lShowWarnBool: # Show only 1 warning per all run if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Convert CP allowed list to UAC Client hierarchy (consolidated)") # Log about compatibility + # Check if ControlPanelDict is active > convert to CPDict + if "ControlPanelDict" in inGSettings: + if "CPDict" not in inGSettings: inGSettings["CPDict"]={} + for lItemDict in inGSettings["ControlPanelDict"]["RobotList"]: + inGSettings["CPDict"][lItemDict["KeyStr"]]={"HTMLRenderDef":lItemDict["RenderFunction"], "JSONGeneratorDef":None, "JSInitGeneratorDef":None} + # Remove old structure ControlPanel + del inGSettings["ControlPanelDict"] \ No newline at end of file diff --git a/Sources/pyOpenRPA/Orchestrator/Orchestrator.py b/Sources/pyOpenRPA/Orchestrator/Orchestrator.py index b5c4bab7..7de222fd 100644 --- a/Sources/pyOpenRPA/Orchestrator/Orchestrator.py +++ b/Sources/pyOpenRPA/Orchestrator/Orchestrator.py @@ -205,6 +205,22 @@ def OrchestratorUACSuperTokenUpdate(inGSettings, inSuperTokenStr): {inSuperTokenStr:{"User":lLoginStr, "Domain":"", "TokenDatetime": datetime.datetime.now(), "FlagDoNotExpire":True}} ) +# OrchestratorWEB +# Add control panel HTML, JSON generator or JS when page init +def OrchestratorWebCPUpdate(inGSettings, inCPKeyStr, inHTMLRenderDef=None, inJSONGeneratorDef=None, inJSInitGeneratorDef=None): + # Create Struct if the re is current key + if inCPKeyStr not in inGSettings["CPDict"]: + inGSettings["CPDict"][inCPKeyStr] = {"HTMLRenderDef": None,"JSONGeneratorDef": None, "JSInitGeneratorDef": None} + # CASE HTMLRender + if inHTMLRenderDef is not None: + inGSettings["CPDict"][inCPKeyStr]["HTMLRenderDef"]=inHTMLRenderDef + # CASE JSONGenerator + if inJSONGeneratorDef is not None: + inGSettings["CPDict"][inCPKeyStr]["JSONGeneratorDef"] = inJSONGeneratorDef + # CASE JSInitGeneratorDef + if inJSInitGeneratorDef is not None: + inGSettings["CPDict"][inCPKeyStr]["JSInitGeneratorDef"] = inJSInitGeneratorDef + ## GSettings defs def GSettingsKeyListValueSet(inGSettings, inValue, inKeyList=[]): # Set value in GSettings by the key list lDict = inGSettings diff --git a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py index 4fa0f444..71e192ef 100644 --- a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py +++ b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py @@ -17,7 +17,40 @@ from . import SettingsTemplate # # # # # # # # # # # # # v 1.2.0 Functionallity # # # # # # # # # # # # -# Generate CP +# Generate JS when page init +def HiddenJSInitGenerate(inRequest, inGSettings): + dUAC = inRequest.UACClientCheck # Alias. + lUACCPTemplateKeyList=["pyOpenRPADict","CPKeyDict"] + lL = inGSettings["Logger"] # Alias for logger + lJSInitResultStr = "" + lRenderFunctionsRobotDict = inGSettings["CPDict"] + for lItemKeyStr in lRenderFunctionsRobotDict: + lItemDict = lRenderFunctionsRobotDict[lItemKeyStr] + lJSInitGeneratorDef = lItemDict.get("JSInitGeneratorDef",None) + lUACBool = dUAC(inRoleKeyList=lUACCPTemplateKeyList+[lItemKeyStr]) # Check if render function is applicable User Access Rights (UAC) + if lItemKeyStr=="VersionCheck": lUACBool=True # For backward compatibility for the old fron version which not reload page when new orch version is comming + if lUACBool: # Run function if UAC is TRUE + # JSONGeneratorDef + if lJSInitGeneratorDef is not None: # Call def (inRequest, inGSettings) or def (inGSettings) + lJSResult = None + lDEFSignature = signature(lJSInitGeneratorDef) # Get signature of the def + lDEFARGLen = len(lDEFSignature.parameters.keys()) # get count of the def args + try: + if lDEFARGLen == 1: # def (inGSettings) + lJSResult = lJSInitGeneratorDef(inGSettings) + elif lDEFARGLen == 2: # def (inRequest, inGSettings) + lJSResult = lJSInitGeneratorDef(inRequest, inGSettings) + elif lDEFARGLen == 0: # def () + lJSResult = lJSInitGeneratorDef() + if type(lJSResult) is str: + lJSInitResultStr += "; "+lJSResult # Add delimiter to some cases + else: + if lL: lL.warning(f"JSInitGenerator return bad type: {str(type(lJSResult))}, CP Key {lItemKeyStr}") + except Exception as e: + if lL: lL.exception(f"Error in control panel JSInitGeneratorDef. CP Key {lItemKeyStr}. Exception are below") + return lJSInitResultStr + +# Generate CP HTML + JSON # Return {"Key":{"",""}} def HiddenCPDictGenerate(inRequest, inGSettings): dUAC = inRequest.UACClientCheck # Alias. @@ -25,37 +58,61 @@ def HiddenCPDictGenerate(inRequest, inGSettings): lL = inGSettings["Logger"] # Alias for logger # Create result JSON lCPDict = {} - lRenderFunctionsRobotList = inGSettings["ControlPanelDict"]["RobotList"] - for lItem in lRenderFunctionsRobotList: - lUACBool = dUAC(inRoleKeyList=lUACCPTemplateKeyList+[lItem["KeyStr"]]) # Check if render function is applicable User Access Rights (UAC) - if lItem["KeyStr"]=="VersionCheck": lUACBool=True # For backward compatibility for the old fron version which not reload page when new orch version is comming - #if inGSettings["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True: - # lUserRights = inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"][(inRequest.OpenRPA["Domain"].upper(), inRequest.OpenRPA["User"].upper())] - # if len(lUserRights["ControlPanelKeyAllowedList"]) > 0 and lItem["KeyStr"] not in lUserRights["ControlPanelKeyAllowedList"]: - # lUACBool = False # UAC Check is not passed - False for user + lRenderFunctionsRobotDict = inGSettings["CPDict"] + for lItemKeyStr in lRenderFunctionsRobotDict: + lItemDict = lRenderFunctionsRobotDict[lItemKeyStr] + lItemHTMLRenderDef = lItemDict.get("HTMLRenderDef",None) + lItemJSONGeneratorDef = lItemDict.get("JSONGeneratorDef",None) + lUACBool = dUAC(inRoleKeyList=lUACCPTemplateKeyList+[lItemKeyStr]) # Check if render function is applicable User Access Rights (UAC) + if lItemKeyStr=="VersionCheck": lUACBool=True # For backward compatibility for the old fron version which not reload page when new orch version is comming if lUACBool: # Run function if UAC is TRUE - # Выполнить вызов и записать результат - # Call def (inRequest, inGSettings) or def (inGSettings) - lItemResultDict = None - lDEFSignature = signature(lItem["RenderFunction"]) # Get signature of the def - lDEFARGLen = len(lDEFSignature.parameters.keys()) # get count of the def args - try: - if lDEFARGLen == 1: # def (inGSettings) - lItemResultDict = lItem["RenderFunction"](inGSettings) - elif lDEFARGLen == 2: # def (inRequest, inGSettings) - lItemResultDict = lItem["RenderFunction"](inRequest, inGSettings) - elif lDEFARGLen == 0: # def () - lItemResultDict = lItem["RenderFunction"]() - # RunFunction - # lResultJSON["RenderRobotList"].append(lItemResultDict) - # Backward compatibility up to 1.2.0 - call HTML generator if result has no "HTMLStr" - if "HTMLStr" in lItemResultDict or "DataDict" in lItemResultDict: - lCPDict[lItem["KeyStr"]] = lItemResultDict # new version - else: - # Call backward compatibility HTML generator - lCPDict[lItem["KeyStr"]] = {"HTMLStr": Basic.HTMLControlPanelBC(inCPDict=lItemResultDict), "DataDict":{}} - except Exception as e: - if lL: lL.exception(f"Error in control panel. CP item {lItem}. Exception is below") + lCPItemDict = {"HTMLStr": None, "JSONDict":None} + # HTMLRenderDef + if lItemHTMLRenderDef is not None: # Call def (inRequest, inGSettings) or def (inGSettings) + lHTMLResult = None + lDEFSignature = signature(lItemHTMLRenderDef) # Get signature of the def + lDEFARGLen = len(lDEFSignature.parameters.keys()) # get count of the def args + try: + if lDEFARGLen == 1: # def (inGSettings) + lHTMLResult = lItemHTMLRenderDef(inGSettings) + elif lDEFARGLen == 2: # def (inRequest, inGSettings) + lHTMLResult = lItemHTMLRenderDef(inRequest, inGSettings) + elif lDEFARGLen == 0: # def () + lHTMLResult = lItemHTMLRenderDef() + # RunFunction + # Backward compatibility up to 1.2.0 - call HTML generator if result has no "HTMLStr" + if type(lHTMLResult) is str: + lCPItemDict["HTMLStr"] = lHTMLResult + elif "HTMLStr" in lHTMLResult or "JSONDict" in lHTMLResult: + lCPItemDict = lHTMLResult # new version + else: + # Call backward compatibility HTML generator + lCPItemDict["HTMLStr"] = Basic.HTMLControlPanelBC(inCPDict=lHTMLResult) + except Exception as e: + if lL: lL.exception(f"Error in control panel HTMLRenderDef. CP Key {lItemKeyStr}. Exception are below") + # JSONGeneratorDef + if lItemJSONGeneratorDef is not None: # Call def (inRequest, inGSettings) or def (inGSettings) + lJSONResult = None + lDEFSignature = signature(lItemJSONGeneratorDef) # Get signature of the def + lDEFARGLen = len(lDEFSignature.parameters.keys()) # get count of the def args + try: + if lDEFARGLen == 1: # def (inGSettings) + lJSONResult = lItemJSONGeneratorDef(inGSettings) + elif lDEFARGLen == 2: # def (inRequest, inGSettings) + lJSONResult = lItemJSONGeneratorDef(inRequest, inGSettings) + elif lDEFARGLen == 0: # def () + lJSONResult = lItemJSONGeneratorDef() + # RunFunction + # Backward compatibility up to 1.2.0 - call HTML generator if result has no "HTMLStr" + lType = type(lJSONResult) + if lType is str or lJSONResult is None or lType is int or lType is list or lType is dict or lType is bool or lType is float: + lCPItemDict["JSONDict"] = lJSONResult + else: + if lL: lL.warning(f"JSONGenerator return bad type: {str(type(lJSONResult))}, CP Key {lItemKeyStr}") + except Exception as e: + if lL: lL.exception(f"Error in control panel JSONGeneratorDef. CP Key {lItemKeyStr}. Exception are below") + # Insert CPItemDict in result CPDict + lCPDict[lItemKeyStr]=lCPItemDict return lCPDict # Return {"Key":{"",""}} @@ -141,6 +198,14 @@ def pyOpenRPA_ServerData(inRequest,inGSettings): inResponseDict["Body"] = bytes(message, "utf8") return lResult +# GET +# /pyOpenRPA/ServerJSInit return JavaScript to init on page +def pyOpenRPA_ServerJSInit(inRequest,inGSettings): + lResultStr = HiddenJSInitGenerate(inRequest=inRequest, inGSettings=inGSettings) + inResponseDict = inRequest.OpenRPAResponseDict + # Write content as utf-8 data + inResponseDict["Body"] = bytes(lResultStr, "utf8") + #v1.2.0 Send data container to the client from the server # /pyOpenRPA/ServerLog return {"HashStr" , "ServerLogList": ["row 1", "row 2"]} # Client: mGlobal.pyOpenRPA.ServerLogListHashStr @@ -313,6 +378,7 @@ def SettingsUpdate(inGlobalConfiguration): {"Method": "POST", "URL": "/Orchestrator/UserRoleHierarchyGet", "MatchType": "Equal","ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_UserRoleHierarchyGet, "ResponseContentType": "application/json"}, # New way of the v.1.2.0 functionallity (all defs by the URL from /pyOpenRPA/...) {"Method": "POST", "URL": "/pyOpenRPA/ServerData", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerData, "ResponseContentType": "application/json"}, + {"Method": "GET", "URL": "/pyOpenRPA/ServerJSInit", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerJSInit, "ResponseContentType": "application/javascript"}, {"Method": "POST", "URL": "/pyOpenRPA/ServerLog", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerLog, "ResponseContentType": "application/json"}, {"Method": "GET", "URL": "/pyOpenRPA/Screenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": pyOpenRPA_Screenshot, "ResponseContentType": "image/png"}, {"Method": "POST", "URL": "/pyOpenRPA/Processor", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Processor, "ResponseContentType": "application/json"}, diff --git a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py index 514ca494..fcd94d06 100644 --- a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py +++ b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py @@ -215,7 +215,7 @@ def __Create__(): "ExecuteBool": True, # Flag to execute thread processor "ThreadIdInt": None # Technical field - will be setup when processor init }, - "ControlPanelDict": { + "ControlPanelDict": { # Old structure > CPDict "RefreshSeconds": 5, # deprecated parameter "RobotList": [ #{ @@ -224,6 +224,9 @@ def __Create__(): #} ] }, + "CPDict": { + # "CPKey": {"HTMLRenderDef":None, "JSONGeneratorDef":None, "JSInitGeneratorDef":None} + }, # # # # # # # # # # # # # # "RobotRDPActive": { "RDPList": { diff --git a/Sources/pyOpenRPA/Orchestrator/Web/Index.js b/Sources/pyOpenRPA/Orchestrator/Web/Index.js index c9c29712..0b374983 100644 --- a/Sources/pyOpenRPA/Orchestrator/Web/Index.js +++ b/Sources/pyOpenRPA/Orchestrator/Web/Index.js @@ -391,6 +391,33 @@ $(document).ready(function() { }); } + /// v1.2.0 pyOpenRPA ServerJSInit + mGlobal.pyOpenRPA.ServerJSInitDef=function() { + try { + $.ajax({ + type: "GET", + headers: {}, + url: 'pyOpenRPA/ServerJSInit', + data: mGlobal.pyOpenRPA.ServerDataHashStr, + async: false, + success: function(lJSText) { + try { + eval(lJSText) + } + catch(error) { + console.log(error) + } + }, + dataType: "text", + error: function(jqXHR, textStatus, errorThrown ) { + console.log(textStatus) + } + }); + } + catch(error) { + console.log(error) + } + } /// v1.2.0 pyOpenRPA ServerData mGlobal.pyOpenRPA.ServerDataDict = null @@ -882,6 +909,7 @@ $(document).ready(function() { /// v1.2.0 pyOpenRPA Init defs + mGlobal.pyOpenRPA.ServerJSInitDef() // Recieve JS from server (if exist) and then call anothe url ServerData mGlobal.pyOpenRPA.ServerDataRefreshDef() // Init the refresh data def from server side mGlobal.pyOpenRPA.ServerLogListRefreshDef() // Init the refresh data def from the log window diff --git a/Sources/pyOpenRPA/Orchestrator/__init__.py b/Sources/pyOpenRPA/Orchestrator/__init__.py index f1e78842..5e488859 100644 --- a/Sources/pyOpenRPA/Orchestrator/__init__.py +++ b/Sources/pyOpenRPA/Orchestrator/__init__.py @@ -4,5 +4,6 @@ The pyOpenRPA package (from UnicodeLabs) """ from .Web import Basic +from .Orchestrator import * __all__ = [] __author__ = 'Ivan Maslov ' \ No newline at end of file diff --git a/changelog.md b/changelog.md index 0714dd28..483b8520 100644 --- a/changelog.md +++ b/changelog.md @@ -72,6 +72,16 @@ - Orc WEB: Create mGlobal.pyOpenRPA.ActivityListExecute({}) to test some activities from the front - Orc - add log about send activity to agent - Orc RoleHierarchy - support RDP, Support Agent + buttons +- Orc new structure for CP: "CPDict": { # "CPKey": {"HTMLRenderDef":None, "JSONGeneratorDef":None, "JSInitGeneratorDef":None}}, +- - Back: inGSettings["CPDict"][RobotKeyStr]["HTMLRenderDef"] > Front: mGlobal.pyOpenRPA.ServerDataDict.CPDict.RobotKeyStr.HTMLStr +- - Back: inGSettings["CPDict"][RobotKeyStr]["JSONGeneratorDef"] > Front: mGlobal.pyOpenRPA.ServerDataDict.CPDict.RobotKeyStr.JSONDict +- - CPDict > HTMLRenderDef > def (inGSettings); def (inRequest, inGSettings); def () +- - CPDict > JSONGeneratorDef > def (inGSettings); def (inRequest, inGSettings); def () +- - CPDict > JSInitGeneratorDef > def (inGSettings); def (inRequest, inGSettings); def () + Orc connect JSONGenerators to WEB Front (mGlobal.) +- Orc back: add new block: OrchestratorWeb +- - def OrchestratorWebCPUpdate(inGSettings, inCPKeyStr, inHTMLRenderDef=None, inJSONGeneratorDef=None, inJSInitGeneratorDef=None): # Add control panel HTML, JSON generator or JS when page init + [1.1.0] After 2 month test prefinal with new improovements (+RobotRDPActive in Orchestrator + Easy ControlPanelTemplate) Beta before 1.1.0 (new way of OpenRPA with improvements. Sorry, but no backward compatibility)/ Backward compatibility will start from 1.0.1