- Tools.RobotRDPActive: ENG version included

- Tools.RobotRDPActive: Add Settings template in Utils
- Orchestrator: Auth template fix
- Tools.RobotRDPActive: Added logging
- Studio: Try to create support in IE (works - need test)
Signed-off-by: Ivan Maslov <Ivan.Maslov@UnicodeLabs.ru>
dev-linux
Ivan Maslov 5 years ago
parent ab193d6022
commit 4f6b4a8e75

@ -1,14 +1,4 @@
def SettingsUpdate(inDict):
#################################################
#General MethodMatchURL list (no domain/user)
lRuleMethodMatchURLBeforeList=[
{
"Method":"GET",
"MatchType":"Equal",
"URL":"/",
"FlagAccess": True
}
]
#Append to global list
inDict["Server"]["AccessUsers"]["RuleMethodMatchURLBeforeList"]=inDict["Server"]["AccessUsers"]["RuleMethodMatchURLBeforeList"]+lRuleMethodMatchURLBeforeList
##################################################

@ -1,5 +1,6 @@
import psutil
import datetime
import logging
def RenderRobotR01(inGlobalConfiguration):
#Subheader Variants
@ -81,7 +82,7 @@ def Settings():
"URL": "http://127.0.0.1:8081"
}
],
"AccessUsers": { #Defaul - all URL is blocked
"AccessUsers": { #Default - all URL is blocked
"FlagCredentialsAsk": True, #Turn on Authentication
"RuleDomainUserDict": {
#("DOMAIN", "USER"): { #upper case
@ -96,7 +97,7 @@ def Settings():
# ]
#}
},
"RuleMethodMatchURLBeforeList": [
"RuleMethodMatchURLBeforeList": [ #General MethodMatchURL list (no domain/user)
# {
# "Method":"GET|POST",
# "MatchType":"BeginWith|Contains|Equal|EqualCase",
@ -185,11 +186,28 @@ def Settings():
"r01/report.xlsx": "C:\\RPA\\R01_IntegrationOrderOut\\Data\\Reestr_otgruzok.xlsx"
}
},
"Logger": logging.getLogger("Orchestrator"),
"Storage": {
"Robot_R01_help": "Robot data storage in orchestrator env",
"Robot_R01": {}
}
}
#Создать файл логирования
# add filemode="w" to overwrite
if not os.path.exists("Reports"):
os.makedirs("Reports")
##########################
#Подготовка логгера Robot
#########################
mRobotLogger=mDict["Logger"]
mRobotLogger.setLevel(logging.INFO)
# create the logging file handler
mRobotLoggerFH = logging.FileHandler("Reports\ReportOrchestrator_"+datetime.datetime.now().strftime("%Y_%m_%d")+".log")
mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
mRobotLoggerFH.setFormatter(mRobotLoggerFormatter)
# add handler to logger object
mRobotLogger.addHandler(mRobotLoggerFH)
############################################
###################################
#Init .py files from Settings folder
####################################

@ -15,11 +15,6 @@ import copy
#from .Settings import Settings
import importlib
from importlib import util
#Создать файл логирования
# add filemode="w" to overwrite
if not os.path.exists("Reports"):
os.makedirs("Reports")
logging.basicConfig(filename="Reports\ReportRun_"+datetime.datetime.now().strftime("%Y_%m_%d__%H_%M_%S")+".log", level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
#Единый глобальный словарь (За основу взять из Settings.py)
global mGlobalDict
@ -51,6 +46,8 @@ lDaemonStartDateTime=datetime.datetime.now()
#Инициализация сервера
lThreadServer = Server.RobotDaemonServer("ServerThread", mGlobalDict)
lThreadServer.start()
#Logging
mGlobalDict["Logger"].info("Scheduler loop init")
#Вечный цикл
while True:
lCurrentDateTime = datetime.datetime.now()

@ -22,12 +22,14 @@ class RobotDaemonServer(Thread):
def run(self):
inServerAddress="";
inPort = mGlobalDict["Server"]["ListenPort"];
print('starting server..., port:'+str(inPort)+" inAddress:"+inServerAddress)
#print('starting server..., port:'+str(inPort)+" inAddress:"+inServerAddress)
# Server settings
# Choose port 8080, for port 80, which is normally used for a http server, you need root access
server_address = (inServerAddress, inPort)
httpd = HTTPServer(server_address, testHTTPServer_RequestHandler)
print('running server...')
#print('running server...')
# Logging
mGlobalDict["Logger"].info(f"Server init. Listen URL: {inServerAddress}, Listen port: {inPort}")
httpd.serve_forever()
#Authenticate function ()
@ -288,7 +290,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
self.wfile.write(inResponseDict["Body"])
def do_GET(self):
# Prepare result dict
lResponseDict = {"Headers": {}, "SetCookies":{}, "Body": "", "StatusCode": None}
lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": "", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
#####################################
#Do authentication
@ -300,6 +302,8 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
# Logging
mGlobalDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################

@ -9,6 +9,115 @@
crossorigin="anonymous"></script>
<script src="3rdParty/Semantic-UI-CSS-master/semantic.min.js"></script>
<script>
// Production steps of ECMA-262, Edition 6, 22.1.2.1
if (!Array.from) {
Array.from = (function () {
var toStr = Object.prototype.toString;
var isCallable = function (fn) {
return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
};
var toInteger = function (value) {
var number = Number(value);
if (isNaN(number)) { return 0; }
if (number === 0 || !isFinite(number)) { return number; }
return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
};
var maxSafeInteger = Math.pow(2, 53) - 1;
var toLength = function (value) {
var len = toInteger(value);
return Math.min(Math.max(len, 0), maxSafeInteger);
};
// The length property of the from method is 1.
return function from(arrayLike/*, mapFn, thisArg */) {
// 1. Let C be the this value.
var C = this;
// 2. Let items be ToObject(arrayLike).
var items = Object(arrayLike);
// 3. ReturnIfAbrupt(items).
if (arrayLike == null) {
throw new TypeError('Array.from requires an array-like object - not null or undefined');
}
// 4. If mapfn is undefined, then let mapping be false.
var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
var T;
if (typeof mapFn !== 'undefined') {
// 5. else
// 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
if (!isCallable(mapFn)) {
throw new TypeError('Array.from: when provided, the second argument must be a function');
}
// 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (arguments.length > 2) {
T = arguments[2];
}
}
// 10. Let lenValue be Get(items, "length").
// 11. Let len be ToLength(lenValue).
var len = toLength(items.length);
// 13. If IsConstructor(C) is true, then
// 13. a. Let A be the result of calling the [[Construct]] internal method
// of C with an argument list containing the single item len.
// 14. a. Else, Let A be ArrayCreate(len).
var A = isCallable(C) ? Object(new C(len)) : new Array(len);
// 16. Let k be 0.
var k = 0;
// 17. Repeat, while k < len (also steps a - h)
var kValue;
while (k < len) {
kValue = items[k];
if (mapFn) {
A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
} else {
A[k] = kValue;
}
k += 1;
}
// 18. Let putStatus be Put(A, "length", len, true).
A.length = len;
// 20. Return A.
return A;
};
}());
}
if (!Object.assign) {
Object.defineProperty(Object, 'assign', {
enumerable: false,
configurable: true,
writable: true,
value: function(target, firstSource) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert first argument to object');
}
var to = Object(target);
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
if (nextSource === undefined || nextSource === null) {
continue;
}
var keysArray = Object.keys(Object(nextSource));
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
var nextKey = keysArray[nextIndex];
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
if (desc !== undefined && desc.enumerable) {
to[nextKey] = nextSource[nextKey];
}
}
}
return to;
}
});
}
var mGlobal={}
$(document)
.ready(function() {
@ -17,11 +126,8 @@
/////////////////////////////////////////////////////////////////
mGlobal.Settings={}
mGlobal.Settings.mUIOTreeHeight=450
mGlobal.GUIElement={}
mGlobal.GenerateUniqueID=function(inPrefix="ID") {
mGlobal.GenerateUniqueID=function(inPrefix) {
return inPrefix+Math.round(Math.random()*1000)+"-"+Math.round(Math.random()*10000)+"-"+Math.round(Math.random()*1000)
}
///Инициализация
@ -158,7 +264,7 @@
}
///Функция визуализации дерева
mGlobal.ElementTree.fRender = function(inElementsTreeDataArray,inBackendString="-")
mGlobal.ElementTree.fRender = function(inElementsTreeDataArray,inBackendString)
{
var lHTMLList=
'<b style="font-size:10px;" >Backend: '+inBackendString+'</b>\
@ -166,7 +272,7 @@
///Циклический обход списка
for (var i = 0; i< inElementsTreeDataArray.length;i++) {
///Добавить HTML код позиции
lHTMLList+=mGlobal.ElementTree.fItemGenerateHTML_JS(inElementsTreeDataArray[i])
lHTMLList+=mGlobal.ElementTree.fItemGenerateHTML_JS(inElementsTreeDataArray[i],[])
}
///Закрывающая список HTML
lHTMLList+="</div>"
@ -176,9 +282,9 @@
}
///Функция визуализации дерева
///Вызов создания вложенного листа, если имеется атрибут SpecificationChild
mGlobal.ElementTree.fItemGenerateHTML_JS = function(inItem,inParentSpecification=[]){
mGlobal.ElementTree.fItemGenerateHTML_JS = function(inItem,inParentSpecification){
///Генерация уникального кода для элемента
var lElementId = mGlobal.GenerateUniqueID()
var lElementId = mGlobal.GenerateUniqueID("ID")
//Добавить информацию об элементе в словарь JS
///Урезанная часть селектора (сделать, чтобы была без SpecificationChild)
var lSelectorLocal={};
@ -245,7 +351,7 @@
var lHTMLTree='<div class="ui list">'
var lResponseJSON=JSON.parse(lData)
for (i=0;i<lResponseJSON.Result.length;i++) {
var lElementId = mGlobal.GenerateUniqueID()
var lElementId = mGlobal.GenerateUniqueID("ID")
var lSubItemHandleId=lResponseJSON.Result[i].handle;
var lSubItemActionOnClick=' onclick="mGlobal.TreeLoadSubTree(\''+lElementId+'\');" '
var lSubItemActionOnRightClick=' onclick="mGlobal.ElementHighlightNew(\''+lElementId+'\');" '
@ -293,7 +399,7 @@
var lSpecificationArrayNew=[]
for (i=0;i<lSpecificationArray.length;i++) {
lSpecificationArrayNew.push(lSpecificationArray[i])
var lElementId = mGlobal.GenerateUniqueID()
var lElementId = mGlobal.GenerateUniqueID("ID")
var lOnClickSelect= ' onclick="mGlobal.ElementPropertyListLoad(\''+lElementId+'\');" '
lHTMLList+='\
<div class="item" id="'+lElementId+'" '+lOnClickSelect+'>\
@ -679,7 +785,7 @@
///Очистить дерево
mGlobal.ElementTree.fClear();
///Прогрузить новое дерево
mGlobal.ElementTree.fRender(lResponseJSON.Result,$(".openrpa-value-backend")[0].value);
mGlobal.ElementTree.fRender(lResponseJSON.Result,$(".openrpa-value-backend")[0].value,"-");
///Показать ошибку, если таковая возникла
if (lResponseJSON["ErrorFlag"]) {
mGlobal.ShowModal("GUI Error",lResponseJSON.ErrorMessage+" \nTraceback: "+lResponseJSON.ErrorTraceback);

@ -78,12 +78,15 @@ def SessionRDPStart(inRDPFilePath):
[
[{"title": "Подключение к удаленному рабочему столу", "class_name": "#32770", "backend": "win32"},
{"title": "Боль&ше не выводить запрос о подключениях к этому компьютеру", "friendly_class_name": "CheckBox"}],
[{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "D&on't ask me again for connections to this computer",
"friendly_class_name": "CheckBox"}],
[{"title_re": f"{lRDPFileName} — .*",
"class_name": "TscShellContainerClass", "backend": "win32"}]
],
60
)
#Click if 0 is appear
#Click if 0 is appear (RUS)
if 0 in lWaitResult:
#Check the box do not retry
UIDesktop.UIOSelector_Get_UIO([{"title": "Подключение к удаленному рабочему столу", "backend": "win32"},
@ -98,6 +101,22 @@ def SessionRDPStart(inRDPFilePath):
],
60
)
# Click if 1 is appear (ENG)
if 1 in lWaitResult:
# Check the box do not retry
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "D&on't ask me again for connections to this computer",
"friendly_class_name": "CheckBox"}]).check()
# Go to connection
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "Co&nnect", "class_name": "Button"}]).click()
lWaitResult = UIDesktop.UIOSelectorsSecs_WaitAppear_List(
[
[{"title_re": f"{lRDPFileName} — .*",
"class_name": "TscShellContainerClass", "backend": "win32"}]
],
60
)
#Prepare little window
SessionScreen100x550(lRDPFileName)
return None

@ -0,0 +1,22 @@
#Robot RDPActive settings
def Settings():
mDict = {
"RDPList":
[
{
"Host": "77.77.22.22", # Host address
"Port": "7777", # RDP Port
"Login": "test", # Login
"Password": "test", # Password
"Screen": {
"Width": 1680, #Width of the remote desktop in pixels
"Height": 1050, #Height of the remote desktop in pixels
# "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen
"FlagUseAllMonitors": False, # True or False
"DepthBit": "32" # "32" or "24" or "16" or "15"
},
"SessionHex":"" # Hex is created when robot runs
}
]
}
return mDict
Loading…
Cancel
Save