v1.2.0 is released - GUIDE is near

dev-linux
Ivan Maslov 4 years ago
parent 2899e4622e
commit 83e5fa8b12

@ -35,9 +35,10 @@ Now you can use the following docs:
- ENG Guide MarkDown [|OPEN GITLAB|](Wiki/ENG_Guide/markdown/index.md)
- ENG Guide PDF [|WAIT|]()
- RUS Article: Less cost - no paid RPA [|OPEN HABR|](https://habr.com/ru/post/509644/)
- RUS Article: Less cost - no paid RPA [|OPEN HABR|](https://habr.com/ru/post/506766/)
- RUS Tutorial Desktop UI [|OPEN HABR|](https://habr.com/ru/post/509644/); [|OPEN GITLAB|](Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md)
- RUS Tutorial Web UI [|OPEN HABR|](https://habr.com/ru/post/515310/); [|OPEN GITLAB|](Wiki/RUS_Tutorial/WebGUI_Habr/3.%20WebGUI_Habr.md)
- RUS Leaflet pyOpenRPA v4.pdf [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/pyOpenRPA/Wiki/RUS_Leaflet/RUS%20Leaflet%20pyOpenRPA%20v4.pdf)
## Copyrights & Contacts
pyOpenRPA is created by Ivan Maslov (Russia). Use it for free (MIT)!

@ -1,88 +0,0 @@
Metadata-Version: 2.1
Name: pyOpenRPA
Version: 1.1.20
Summary: First open source RPA platform for business
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
Author: Ivan Maslov
Author-email: Ivan.Maslov@unicodelabs.ru
License: MIT
Keywords: OpenRPA RPA Robot Automation Robotization OpenSource
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: License :: OSI Approved :: MIT License
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.7
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Home Automation
Description-Content-Type: text/markdown
Requires-Dist: pywinauto (>=0.6.8)
Requires-Dist: WMI (>=1.4.9)
Requires-Dist: pillow (>=6.0.0)
Requires-Dist: keyboard (>=0.13.3)
Requires-Dist: pyautogui (>=0.9.44)
Requires-Dist: pywin32 (>=224)
Requires-Dist: crypto (>=1.4.1)
# OpenRPA
First open source RPA platform for business is released!
# How to run
Studio
Double click to Studio\StudioRun_32.cmd or Studio\StudioRun_64.cmd
# Robot how to debug
Robot\PythonDebug_64.cmd
import Robot
Robot.ActivityRun(
{
ModuleName: <"GUI"|..., str>,
ActivityName: <Function or procedure name in module, str>,
ArgumentList: [<Argument 1, any type>, ...] - optional,
ArgumentDict: {<Argument 1 name, str>:<Argument 1 value, any type>, ...} - optional
}
)
# Robot example script:
Robot\Examples\GetFolderList\Python_32_Script_Run.cmd
# Python 32 bit
Resources\WPy32-3720\python-3.7.2\python.exe
# Python 64 bit
Resources\WPy64-3720\python-3.7.2.amd64\python.exe
# Module GUI activity List:
############################
Новая версия
############################
Получить список элементов, который удовлетворяет условиям через расширенный движок поиска
[
{
"index":<Позиция элемента в родительском объекте>,
"depth_start" - глубина, с которой начинается поиск (по умолчанию 1)
"depth_end" - глубина, до которой ведется поиск (по умолчанию 1)
"class_name" - наименование класса, который требуется искать
"title" - наименование заголовка
"rich_text" - наименование rich_text
}
]
# Open RPA Wiki
- [Home](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/home)
- [04. Desktop app access (win32 & ui automation)](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/04.-Desktop-app-access-(win32-&-ui-automation))
#Dependencies
* Python 3 x32 [psutil, pywinauto, wmi, PIL, keyboard, pyautogui, win32api (pywin32), selenium, openCV, tesseract, requests, lxml, PyMuPDF]
* Python 3 x64 [psutil, pywinauto, wmi, PIL, keyboard, pyautogui, win32api (pywin32), selenium, openCV, tesseract, requests, lxml, PyMuPDF]
* pywinauto (Windows GUI automation)
* Semantic UI CSS framework
* JsRender by https://www.jsviews.com (switch to Handlebars)
* Handlebars
Created by Unicode Labs (Ivan Maslov)

@ -1,319 +0,0 @@
pyOpenRPA-1.1.20.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.1.20.dist-info/METADATA,sha256=B3Ph33GyqyoXYSX_0wGNMu6KLwFG_lj6NIXaCKJP-TA,3352
pyOpenRPA-1.1.20.dist-info/RECORD,,
pyOpenRPA-1.1.20.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA-1.1.20.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.1.20.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/.idea/inspectionProfiles/profiles_settings.xml,sha256=YXLFmX7rPNGcnKK1uX1uKYPN0fpgskYNe7t0BV7cqkY,174
pyOpenRPA/.idea/misc.xml,sha256=ySjeaQ1DfqxaRTlFGT_3zW5r9mWuwxoAK_AX4QiuAZM,203
pyOpenRPA/.idea/modules.xml,sha256=Q__U1JIA2cjxbLRXAv-SfYY00fZA0TNlpkkbY4s3ncg,277
pyOpenRPA/.idea/pyOpenRPA.iml,sha256=EXh41F8lqRiSBMVg-n2tKaEaHC6_3gGSuKkPJA12Na0,408
pyOpenRPA/.idea/vcs.xml,sha256=2HygA1oRAwc3VBf-irxHrX5JJG9DXuQwrN0BlubhoKY,191
pyOpenRPA/.idea/workspace.xml,sha256=kcCP7x0iSOAWJdy7YtntGrgsQ04QIq0b6_9w04DKxfg,2555
pyOpenRPA/Info.md,sha256=u4Nv-PjniSF0Zlbtr6jEJX2vblK3_1zhSLNUgOdtDaA,85
pyOpenRPA/Orchestrator/BackwardCompatibility.py,sha256=y1Dyb8wmRcJmk1SxTVmgpR8r64Aa-Io9MG_5khvYgH0,3672
pyOpenRPA/Orchestrator/Orchestrator.py,sha256=32AVVDVpMgam9Zg5n79WJDiuhGQTehtBWTFQrm6Mzhg,12387
pyOpenRPA/Orchestrator/Processor.py,sha256=JI7nnkwXXnpkSJx6GlxoPjjiFOv3q3e-xZDLxKVYKrg,12634
pyOpenRPA/Orchestrator/RobotRDPActive/CMDStr.py,sha256=6otw1WnR2_evvQ5LGyOVh0BLk_nTdilViGub7p56fXQ,1531
pyOpenRPA/Orchestrator/RobotRDPActive/Clipboard.py,sha256=YB5HJL-Qf4IlVrFHyRv_ZMJ0Vo4vjyYqWKjvrTnf1k4,1564
pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py,sha256=fEwwCaYggb_KB72_9Bi-bn1zvglssNWNaWz9GTaiVk4,26543
pyOpenRPA/Orchestrator/RobotRDPActive/ConnectorExceptions.py,sha256=wwH9JOoMFFxDKQ7IyNyh1OkFkZ23o1cD8Jm3n31ycII,657
pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py,sha256=AQ_u9QVSLpce9hhSacm3UT98bErc636MXza4Q6mHsSc,12264
pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py,sha256=jCtHXExgRW0licn8K-xSO3tFd6P-4IFzp46TdS57vQ4,10726
pyOpenRPA/Orchestrator/RobotRDPActive/Scheduler.py,sha256=21N0ilFzWI1mj3X5S9tPMgwvG7BviuBxfTuqBY85Hy4,9144
pyOpenRPA/Orchestrator/RobotRDPActive/Template.rdp,sha256=JEMVYkEmNcfg_p8isdIyvj9E-2ZB5mj-R3MkcNMKxkA,2426
pyOpenRPA/Orchestrator/RobotRDPActive/Timer.py,sha256=y8--fUvg10qEFomecl_cmdWpdGjarZBlFpMbs_GvzoQ,1077
pyOpenRPA/Orchestrator/RobotRDPActive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Orchestrator/RobotRDPActive/__main__.py,sha256=z9PaUK4_nBiGd0YJdYVHV_rFx6VjZaxrrmKxSyoTFwY,2508
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/CMDStr.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Clipboard.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Connector.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/ConnectorExceptions.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Processor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/RobotRDPActive.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Scheduler.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Timer.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/ConsoleStart.bat,sha256=_HNadUKHOYI5y6foG3srh8wjSzhX33xaKNylFtDjOJk,114
pyOpenRPA/Orchestrator/RobotScreenActive/Monitor.py,sha256=TV-YisVqa_uGiyJLG9oK4u-5aDjGiFYZFh1dPjOgYc8,492
pyOpenRPA/Orchestrator/RobotScreenActive/Screen.py,sha256=VnYcvCVymrD35l2J4ln_tlVn7CilZhxE4Ggw9P-OhIw,606
pyOpenRPA/Orchestrator/RobotScreenActive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Orchestrator/RobotScreenActive/__main__.py,sha256=JASxDDVKWUU7DAbDkRrGTrPk-P7LZchTZFh8usp6b4U,593
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/Monitor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/Screen.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Server.py,sha256=dO82x5_tmPSn0oKgdYs7BzM3kZZkh5MWNegxUEwE01I,25694
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=dK8pQzg2mcLPjbizOPCP7yHMMVLiTh8RbYVnJXn-Mvg,15640
pyOpenRPA/Orchestrator/Timer.py,sha256=HvYtEeH2Q5WVVjgds9XaBpWRmvZgwgBXurJDdVVq_T0,2097
pyOpenRPA/Orchestrator/Web/Index.js,sha256=zdbj1ioNgxhprLpGIQ2YYraKUMUpkBiVoR-3GXGR5X0,28258
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=uRjdlkK8-yyrh4y3BkBYlFkRHzzPlHWz5dRh1FmG5QE,14260
pyOpenRPA/Orchestrator/Web/favicon.ico,sha256=6S8XwSQ_3FXPpaX6zYkf8uUewVXO9bHnrrDHEoWrEgw,112922
pyOpenRPA/Orchestrator/__init__.py,sha256=qVH8fEPgXk54rmy-ol0PnT8GF5OlGE0a8mExwJ4tFqY,124
pyOpenRPA/Orchestrator/__main__.py,sha256=cOd8WU77VGgzTZUB0WmWpPmdYyMZY1zVyuU9yx26MKs,144
pyOpenRPA/Orchestrator/__pycache__/BackwardCompatibility.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/Orchestrator.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/Processor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/Server.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/ServerSettings.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/Timer.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/README.md,sha256=e2hKh7Tx6DAsX6jY_hBDhguL1L2Wiv6iugDB5otMzIA,2293
pyOpenRPA/Resources/Web/Google/LatoItalic.css,sha256=pB6OZ6F2VsaqkL-g5hW-wE_T0m9H_NltzmzjX-XAKDk,3112
pyOpenRPA/Resources/Web/Handlebars/handlebars-v4.1.2.js,sha256=h6O4BrhyPtJspLDEQwogC53uHFRozuBpxvN2S4tJHE8,171994
pyOpenRPA/Resources/Web/JsRender/jsrender.min.js,sha256=00hs6PwCiAfN_gatFdLofj3yBf8ue5Z7jCXX_th2FFg,25927
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/.versions,sha256=gGkuqPk07gAhjnNJVjVR_BA4SSBzqazbY8eEpddH01U,72
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/LICENSE,sha256=ifWbZZ0piwisfkIil1gacnBMxNnAHa7yCn1etItX1Y4,1102
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/README.md,sha256=oITQ5k-7jxoYAAQpzAXFROqgcnGzPrTd7GqkZSGqKW8,448
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/accordion.css,sha256=UC6U37i_pXBVMlUmFMLi1S8FIhFycJjAePP-hRGKzQM,8971
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/accordion.js,sha256=6cCQ6FlT1bM_QA4OpA_vfMljasKU1foGszlAIyhWi3A,20790
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/accordion.min.css,sha256=u9_5Zru9uMTtrXZpdfLawT_kJ5LFcmrMFr1QWXfDqwA,6955
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/accordion.min.js,sha256=kt0Dfi-mrxAU-iYsfDrkROHrb55Hi0lVWC7MT46_xnU,7100
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/ad.css,sha256=CiW55EUiruW1Tp0jrz2yDvQ8jYxDVMDmVcROV5_eBzo,4176
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/ad.min.css,sha256=7D7QYK0TBRyE4dN3SYXD_owb0j8UXywfPKzab2e743I,2066
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/api.js,sha256=Vjx6JZpe0iVJ6t8gp3TO3UjIyZkNBPN-taCS8MWwvJI,40952
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/api.min.js,sha256=und4HgOg2CxzBcqdJOvcT9LfJx0Hf9xQmEO_u7r1Ync,14594
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/breadcrumb.css,sha256=SJD_Mmi9BUmGXVhCXlIM1ei93yJVreQx0FAT68_t01w,2166
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/breadcrumb.min.css,sha256=-40OBPSbvydFFq9P3XPydeyWOrsh8g600mK9HXNoLnI,1192
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/button.css,sha256=wdCjDbx3M-jkpA7whQetZvX3ZE7wyBwRlCbcTVXKobc,116361
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/button.min.css,sha256=37bmMDGVPsjpcyAe7GqWsqv3UpsPTvlE5AiCVtT5NxY,90207
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/card.css,sha256=0oHZ2Qh74uybsgxLhP2ag_kQGTyOx3Kbzsjs6LvARzI,25330
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/card.min.css,sha256=anR2MHuWyx-iEc6wsI5nBMWnboFRqvOT7r-KOrKK-BQ,17410
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/checkbox.css,sha256=5u4dyQfH-wpdFbakv5CV4uIhWbBb2Tge0ZC5-tA2dX8,17473
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/checkbox.js,sha256=s-cRpbhGBxHgpnZdU3yFZciSW4n1QuruHjkX6gCyqT0,26912
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/checkbox.min.css,sha256=cy6WFzeIQ_5hHE7LEFxAK8yfR_zdfjoEubGRy1wCLv4,12727
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/checkbox.min.js,sha256=mlvPY4Gm-w6mgnAZ2GVMiBo5UDU7x_vaxKA5VRxdjR4,11369
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/colorize.js,sha256=imQdcIH6qpozSWEYeIpilPOfKHOJbD6V9RuKOC7yyEE,8710
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/colorize.min.js,sha256=oUDFJRLSaINMaJIZmuzYttfcMgkb7I6CpuEJ6bMfAVI,3270
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/comment.css,sha256=WAotERTFZQyxKNDJiSLlreq5KVja4xNM_bXUeG7NyVQ,5120
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/comment.min.css,sha256=JYlEkH8IupEqfItr2N9WZaNYkyF6rX2bnP6Y8ktXdCU,2945
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/container.css,sha256=bzDnWjcw404DoiHuz6-3iMRmbzJePDPgUGHcx3nFAuU,3099
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/container.min.css,sha256=VizQkNfO7_OANkM37_7xKxHQPEcUTBRuj3R_xkaULO8,1925
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dimmer.css,sha256=xKjQ9JWKG6zlrjyB5zECQc5vLZ7uCg7S5X-aUNKh6b8,5559
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dimmer.js,sha256=TuB9IPn4wx2n47nRVYf9CKvLotDL9d7gQcNArXupiRU,22303
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dimmer.min.css,sha256=-MBET9URQztSrMHpKaB8oyTckkm-lXisQbuxqd2UyOk,3517
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dimmer.min.js,sha256=4jCyaIQIKQX4zzzvspDqEvUmsPnpkr5lFuDOvKR_Wbo,8071
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/divider.css,sha256=a_0UrPhzoGJZZd8PBDgc5C0utGbzM6hjZbkDyy4pzfw,8034
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/divider.min.css,sha256=2XcokR56EPJZJh0ofnGgp-QPx2VpHYzDcdZdtR08uBs,6097
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dropdown.css,sha256=rJfAK26TU_FrVEYQxX1iWS4Z91SORlfnM128BfpI1II,37420
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dropdown.js,sha256=KnpOJhLPr4nCvh6M4qxqs8Y8lPGNZgLK6jZcGWrYzHo,145962
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dropdown.min.css,sha256=7Lwg8bz5Df_7YZ6D-ywoa01hT3IkqC09ZKBKtGe6gow,25679
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dropdown.min.js,sha256=uEocYy6a0MpPLLHtYV7QAGdOeMRwE0Am2WtnOg_hBfM,50895
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/embed.css,sha256=19QhoCUbplkH_W5a7ejlpO6PoqSEFVA1xdHvaZp98yw,3169
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/embed.js,sha256=O3znHvAxO5xYlwzn4y3lQDde_iTdy29iUAmPqNfg4-0,20926
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/embed.min.css,sha256=SHH3TOGQhg1d5mrYCZeko1qvN3_NoETWQzBmfGUOpjc,1836
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/embed.min.js,sha256=QN4vIzPRpT4BFVPyA702nPG8nZKWfM-HygoF9jPBDJA,7728
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/feed.css,sha256=aFj6fLvIPQfeRxyKu_TlLKeUcwmI5GwOR7pY1Lb0JKM,5845
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/feed.min.css,sha256=-l8OBrtbhQi-fhQLHwA0cut_JWOuRWc44I0KpPxUx_M,3590
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/flag.css,sha256=rvyaZDdUGBPNuvOE8lzpW-Z4q3LYkJi8T99JlN1aF3E,22423
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/flag.min.css,sha256=WX74cISnDHD9kiyzCAiXiUWfnmv6cwdmBXgXtA5TUuw,18577
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/form.css,sha256=oNyqIev2BGrxigiMt72unbkne8-OWJ6UtaUGM4XZ9Y4,29092
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/form.js,sha256=FCxhpdJMgA6H88ka82b0jcqg-a8S53T0sVVbS_chLPA,57618
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/form.min.css,sha256=BmOkPn-zjy4WbHvcIvm18Vq0nhJjwADEBxvsLqX0sXg,21568
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/form.min.js,sha256=fK_KHBgbjblWL2-hRtohUzj6b12XWi6pVujkG1Ru9-w,20458
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/grid.css,sha256=I35Jh57rWCJoLMuJYXksccmBzc6V1XC1Mi_na_oAp84,73036
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/grid.min.css,sha256=5iW6X6_QT_7PgFBce4OTfLOOaSoovOoOb2U8w1yZDtc,57335
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/header.css,sha256=32EgHb7XmTT_AWH7Nr08PjXP2op-xhwlSqSIThcZKmY,13499
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/header.min.css,sha256=hHgAxfAsLFDPcyU6T6cRE_M6R-4rKEfPX5kOHVyJNes,8872
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/icon.css,sha256=CHLhcJDvnks69dz2lyZC0idfGnPFx4qdKA82Hm_bEDo,86945
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/icon.min.css,sha256=4opKQbtTAtsuIkfkEMuIA3eD3T4m1X3mfiCVTS6x2_A,67019
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/image.css,sha256=eZLe0mOsWAJETFvjXHlZXAnSY87SGQlRDJna2_EZ67U,5676
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/image.min.css,sha256=eXzqGHi6p4yiYGCiYPOcGXYbKeQtA0Df_w0gN88KCD0,3727
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/input.css,sha256=lYFTBK5TuWVaB2LSwjdl83iM9l4rn7jPwoFcEfvHQR8,12699
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/input.min.css,sha256=4ouF0Y10UKjiT6iJlHxD5aOe8WljYoAxPqpiy7iEdSw,8692
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/item.css,sha256=O1HR21E9wHtGxCmsqxcEc_65R6Ln3mOvImRwYMQso1g,9753
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/item.min.css,sha256=JRycvfshgviiiwTeAKUj0iPOov4-Uwaue3fTqaY_e5s,5985
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/label.css,sha256=9tLlAtf1Y3NSngCdO1DZ5YcRW_bu2dUKYUAXHPXm2hQ,28382
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/label.min.css,sha256=lzompqItwR2t_PJowmd07tg8QUPAb6yj58N9TwuNS6I,20005
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/list.css,sha256=CI9lvTBhVzN64aRNjJIwhG6bhKydfIbk_RdYQiaAYwE,22486
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/list.min.css,sha256=uXVJMLBcGUe7MZETm-CQO5LMhIbTFxajYZRBFTCTftY,16094
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/loader.css,sha256=Yz3gBB1JS-86XzSzztcNLE24ViO7UnP15A4M4hrFZUY,7128
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/loader.min.css,sha256=XtALKS7EZswkHXCCOthbxsuu36_tpZbqh-LMT1gaRAg,4702
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/menu.css,sha256=aOYMc10qx8D7fVQ7R83XXUkbrrFExpWkWc6ZnECfOJ4,45279
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/menu.min.css,sha256=cRSLOaiPiyfTQ4B4HT1OCF_2CWNzGcPO9Nns6Jrf4hg,31506
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/message.css,sha256=baLR2EbwIWTGTSvNc9qb2FmcWBeZHM3W0kBNvEdxZZU,12466
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/message.min.css,sha256=_plszMa027XkVjjehCTWxgIAftsTT1alP5I6EYfoVMI,8354
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/modal.css,sha256=86mR_k66q9mOP7jwLV6J4iRW1a06eSyQ6tcoZpUlHf8,12800
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/modal.js,sha256=ACX5Za25KIugyXD7eFndkqa18n7LHjZrBkWSpLs8uqQ,33442
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/modal.min.css,sha256=2GGe09HtCS6k__kprnoTwPMNu2CFCjEpaLQ2NBMLua8,8012
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/modal.min.js,sha256=8POmd6680Gev-MdgKbVOHP-9lm-9WB1AVyuLf2WRcxc,12701
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/nag.css,sha256=3Pz6rq1vWHNvB7UHhGFMPYvrP7VZP_pTM4PlwthnviI,2727
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/nag.js,sha256=KuXGvpOopM0i7syRO2cLSXrJ5I7AjwW3m7JMJLfGuN4,15553
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/nag.min.css,sha256=ohX1Du58QE8pgiBVEzmlhuT2rERTdxY4sasod_53NV4,1483
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/nag.min.js,sha256=UN_1Vcu3C_zxEatS7UZKw1x2blSyihZT2F1cmq7UZOk,5696
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/placeholder.css,sha256=ihZF0mK6texbUk_qWnqHqoZ0scXyDhHy-tr77Wougwg,5938
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/placeholder.min.css,sha256=UIFHVCJ1agMPhpUv-aqm6GeN3EmqUv5vClMm_5LEpuM,4452
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/popup.css,sha256=EitCUPKebavrCN6zwsWGZKfKCNjRJhaEGf6dJlCim7g,17407
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/popup.js,sha256=kzErFmfWsOMKZH-mbyLXQpJo_ajderu7pnq_faA7teM,52273
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/popup.min.css,sha256=YlUBHRAaq5FwMcI2g3DQtgcmxmRNG1rEZaGK2LCgVZ0,12032
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/popup.min.js,sha256=VvJYDjsOSD6VaYYZhuQYiPOpBbpRnmaddxVd6shZ9mU,18630
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/progress.css,sha256=p2R5CYj1cVgj0mT7XTBcKKky02140m4A-PumSFirAqc,10669
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/progress.js,sha256=uAQsAqW_DWnH0hK5dC0MVBBwuDyyu8UNolLxO0OSCfs,31204
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/progress.min.css,sha256=JtEqDPto1ZJiE-6k_WoZnzlhFUgwLJqH6VowDWGRez4,7422
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/progress.min.js,sha256=B676J_Jywi6IJ9e_E62nmk7Gn9KDkRQc7RfcIBKPQcI,12331
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/rail.css,sha256=XUZeNKRfoqs2bRnKz49lJU8ufQ625eFrtL7IxXLzBD0,2646
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/rail.min.css,sha256=4rrNcI5NVX845Bc9aBTWjwjg7tnakWuMHl8zWK-ucmE,1453
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/rating.css,sha256=E_jbykfZK88UZ6kKhL0T8mqn29mzefpwNzCDZEkIyKE,20696
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/rating.js,sha256=rxHeOv-TB5-ViM9hOfODUZMGqWUMNyPvIVIov306LuQ,14869
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/rating.min.css,sha256=4coaKkBwUtNfJL53qHC_TzTE7BmLMuVxDu_Z3gGOs7Q,18393
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/rating.min.js,sha256=jprk9qns6QqU1UWGtHMwug9A_ls7tVMV8p2mueJlj74,5354
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/reset.css,sha256=ygW8luaW-MLjYb6fFQYl0HBo4w-P9zwYkVZLpFOMFh0,9123
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/reset.min.css,sha256=Cm0OrnD_mnGgt3DPmGhhNLeNUAfYfQlCX2uCK7TG_o8,2822
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/reveal.css,sha256=33mQj7j0sprB4_0PrBqMJXxyXXFs4eP2rKoraaht8e8,8177
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/reveal.min.css,sha256=cHuyo1zDTWJH9C1f1GPtKHwuTzA_IUSFAfTH3q5yoME,5784
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/search.css,sha256=XN5UApUr9lkI_R-ThVSHhNM3UEMEvl8Z6LAYhFABPKw,10377
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/search.js,sha256=bm3TK1__R62sMnnTL_haoNAZiWbua0IGEgwfdQRpuRo,51211
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/search.min.css,sha256=HONcBrv7-3sDkmJ9Zwh8KYXWyy_fUw_MjDjhNMtU7hU,6891
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/search.min.js,sha256=gkqnhj5TvM_vwvHKAb4zBC7uL6mndcAlK6CEv5iEUwg,17622
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/segment.css,sha256=FERuSI78q9zgv_iWxHnXIbSnJDsgNKaLh8IgThCD9OM,20063
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/segment.min.css,sha256=zLmNnl__Po9TAZWlayMZpH_DpZXhaHXTcSa8KGeRxMs,13763
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/shape.css,sha256=5sbfPkJ2vSJEo7Ht21qKtfupKDnPdYtwpxkszIHwqsY,3865
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/shape.js,sha256=6D_QO1uZyRzcGRxxaCGP4zRTcnHH-rF11XSDj8fsVn0,29873
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/shape.min.css,sha256=7KDwgqAZXncDCzulBQT3C9UcI_kopiPdoSF2NxpJQWE,2521
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/shape.min.js,sha256=Njt3jnaL2VeRaG0rRHt2niY7YXHeD4Z_fj17tN2syLU,10803
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sidebar.css,sha256=pboKxonzco97CJSpXvUG9Bj65PyqdlTlmi8C_XNQcJI,15757
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sidebar.js,sha256=-nippst3RqSK6cFS0b1VQIhhZ7x455Oq5vpvjxdFOhc,34488
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sidebar.min.css,sha256=FxNmgO-xW6HZ8kqkaDpzZG2GGTYYvBIkhHFsPPUx8f8,10726
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sidebar.min.js,sha256=LxCRzL8rRPXulWQPWkMgncUHL0hBU4IHsuNOVzIMi3I,13466
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/site.css,sha256=tpW_cbiDbTbWVk1ECO4bnddYLlytmUgArSW1Jx3x9DU,3918
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/site.js,sha256=-yF4ejA2WwzIujQ1y9b-i6dxpRYCE8lCSU76CQ9hZhw,14604
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/site.min.css,sha256=AYTFsBcTjn7JH9tBf1s3S68Fxr83IHQf5t5FpD0vGcw,2452
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/site.min.js,sha256=f-45BTFplAj5X_I64VjaIAqTulT6dVhF-rHvOG8pZpM,6066
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/state.js,sha256=rdhOQ83U-t08-IE-ZL7qwiJ_2NPtm0E--BfFJVRylSY,21498
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/state.min.js,sha256=sgXcJIgGI3ymppa7VewFhV3g4rnB_D55Yvoo-QX4Whw,7804
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/statistic.css,sha256=zC6fj8Mg8giRj0rcaq1GVcAfmdLfb0QYgBx_B-7bXlE,13221
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/statistic.min.css,sha256=Nbx1qdI_NIb-YBfRIMcmKn-IdY5OmUdd8gNIGgA2TCs,9594
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/step.css,sha256=3dgzVkMcFYJKP_UPk7quva4L7GLD6sln1aroRZlrcw8,23555
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/step.min.css,sha256=hifahh65UcRx9Cux-rpwi5pTJImD83BlfH1qbkiaWCI,19188
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sticky.css,sha256=eOSA5O3_qugssoDgdTovRNvNMe0kEWqQz1yQGJFZCQM,1288
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sticky.js,sha256=kHIMXTF2Wj8DYTaDRRqQ9ZVNUTOjDbBF84Dwm4tFYaM,31814
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sticky.min.css,sha256=SYOFZjW67UWxBsrtAfD4g0Tvf6CnltYw_IN0VemK2hU,607
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sticky.min.js,sha256=fu91ThJa6qnZoQAGTpxUw5Q1UN7d2Y_KHS0kjoteWCw,11854
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/tab.css,sha256=aX-PA0rhwxK3q6l3A3przKBvFAQ9LkhlDV3mETbQR98,1865
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/tab.js,sha256=xvNcoJnirQ1TJgVMy_8_AARTIveekx3bgoXNLc-FhC0,33771
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/tab.min.css,sha256=vTnhMR4q6W1dLyB3QYdtwRWnl2XLdtFA0I3kSnZH_EY,1075
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/tab.min.js,sha256=MgUTbr8RHTNylv3wIeBmCec-mS1iL9IJW7Y0NahYmrs,11487
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/table.css,sha256=omOnJC5bkklgjC6vJgTYJae-wbp3MSIu-mUM0gc5Q-o,25536
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/table.min.css,sha256=ODiMJS5bcTBrVMu-BtZytuSNpu3wHtILDb8no5BLNhw,18015
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/transition.css,sha256=XMKp0LQFx2Ec2oOjFuAPJik8VrDUgysP4TNOJH3Rzuw,49176
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/transition.js,sha256=sccxnC8Z9hx9lzlJLPYQ9E5FHETVYEVaA1uIQaA7ubU,36076
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/transition.min.css,sha256=cty1gaoozlRlEnqcQir7t93a7sOy2uCLp0c4jyBLWwA,33525
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/transition.min.js,sha256=k30cmb6hiQ_LGKpX2AcllUduUJ0kA4DKKStgUxkGQzM,13010
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/video.css,sha256=R9cpZZmFTZ70NmFVp7XhHOXaoZ3iodK1WlxGrisY7Tw,2346
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/video.js,sha256=Si_eMYc42BiLyyl4ur4u7K17kyw9biw-eAtbidaQH0c,16252
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/video.min.css,sha256=0MWKfR7_d_meresYhKG49N4ikgDL9YKvdj4ffNqhti0,1328
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/video.min.js,sha256=f7uHgbRqRCqHKBJm7CB31wMMnTjYHPmYaLi1D2i9QfI,6090
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/visibility.js,sha256=p_2kDyoT-GlUY_iLWH8RCRtSl-zunZ1oNx3dJwvyKbA,44180
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/visibility.min.js,sha256=Th3QlAMxD5M2RJ9nNOvuxJZCgZIlavx5-51jABKTs2A,16294
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/visit.js,sha256=9DsUmsPzmp3XD1pplmIeV5tNIeqEHMml5hcr3omsBJw,16142
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/visit.min.js,sha256=bT8zWI7mcAwX-Fyt67gogo3u_IT7q8uimamY5Vhk3eU,5887
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/package.js,sha256=BHq6qGCSMdDXDGJxZ4zxnKaREbFM2un2VqCkydrBTf0,774
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/package.json,sha256=Sy3ZVA4SxFzecOO88h1IVAnBiuDpRtXiUg6ME_YArI0,524
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.css,sha256=aje_ma2N_7VT1k2QTOLeqr3SfQ3Cr-7vB05D2-uo-YQ,869203
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.js,sha256=t-thIOFbQol3-vcB3C7kRbS49jG2_LC5dEp7NLxBpuA,759089
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.min.css,sha256=f5Dpq5VRrbzn8POovxN9HR3S7LhHQIAiCKYz4PB4ZZA,628934
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.min.js,sha256=69cT25pJVUmAyniwWMglXlEOEeZYuhmD8Hbj58gCS7Y,275740
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/brand-icons.eot,sha256=0CPFX94iBJXxOoe3KZXg35jI0ok1dymdGZ2lu_W0_gI,98640
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/brand-icons.svg,sha256=IcTTApw6luFW48z0iPvWxbD_LpBQYBaIN5LGFInrfpU,508636
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/brand-icons.ttf,sha256=QuNp3Iw3KXO6d6gmti0seiBwUyMT34MqIyiN23aXQVg,98404
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/brand-icons.woff,sha256=n6_Ww-e_wUXbQqkG5fpo_mpvlyIfAT0-gz_DIxuZLEQ,63728
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/brand-icons.woff2,sha256=59TVNAu-V6Adj3mSFC4nY9Q41Xg4kMdnSDBu6_oFamk,54488
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.eot,sha256=i04bhH4iIz1PRn00-u_nvL_rzm-pu77lYMRc2JSGh1E,106004
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.otf,sha256=vcXQufOXvoPohsdLAUHRlUqkOEs1nc5JgpmUxKLh978,93888
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.svg,sha256=GzY2PC_CxigjA7ao5Pm45c8-mD38cSHKeoiagKC-kA4,392355
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.ttf,sha256=y3-B9UL1xBiju7mtP5--eEFR0TsEzsUOzt7GATMko9o,105784
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.woff,sha256=lbakhA-HEeyrQnvCNuuGCY235ceCuvsTnIwwgFql_-E,50524
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.woff2,sha256=Q0RmtZVFqKHKxt2zgZfNxrNZlamMPzgS-4jWGxwwDdM,40148
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outline-icons.eot,sha256=RTf6BjQO5iwmTp16TYqryrPee9osXMM0AQ9GtoMQb8s,31156
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outline-icons.svg,sha256=T4_RcS28l2Pa57YNTH3ryg_433tFrdN6pDBt0iGL1zE,107567
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outline-icons.ttf,sha256=Zxchcur85FY3JeZhBD1duFS4Z2ip6L05dY2-gcR5aTU,30928
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outline-icons.woff,sha256=S8NZwnBXs-0LrKZtbFNJpdSmBQlvvHh1Bhui2Ro9bQU,14712
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outline-icons.woff2,sha256=TSiDRDsk5CRSf2oKeqKJez33HyOdtANzxP92DkgUeAE,12240
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/images/flags.png,sha256=lNXH8WYTAcSm3Ekdct1VmgYgzZF6gm8N8bAju5bqnd0,28123
pyOpenRPA/Resources/Web/jQuery/jquery-3.1.1.min.js,sha256=HPMOWdIdSuVgr3FD9ZE-_MgiK8qk_MdQjrgCtfqp6U4,86713
pyOpenRPA/Resources/Web/pyOpenRPA_logo.png,sha256=7rulXo_C57xJQEaYWmAkChxXb6xbDW2zq-werzVbDbc,4899
pyOpenRPA/Robot/Clipboard.py,sha256=q76X8L21zJwcwdoJJNPeCEwAV30xS6ylHP1WwvtxoWI,722
pyOpenRPA/Robot/OrchestratorConnector.py,sha256=JUtdiUXCruqUqBD19gJBl9jk_b-tpWWx_v3MfBoKzoQ,20445
pyOpenRPA/Robot/README.md,sha256=e2hKh7Tx6DAsX6jY_hBDhguL1L2Wiv6iugDB5otMzIA,2293
pyOpenRPA/Robot/SettingsTemplate.py,sha256=Rp5XPeV2I4tCS2uf4Zkqm_ERJ6pZMg4-e5_lMqGJYLk,1453
pyOpenRPA/Robot/Test.py,sha256=qXr990nXiFZX5SNv6QN9GLb_U4HZRmJnbZR2qSnwilY,2878
pyOpenRPA/Robot/UIDesktop.py,sha256=3I2bllTDvR9d10O2ltkjoKmYw34wkkDAZfPlRpwbj30,77476
pyOpenRPA/Robot/Utils/JSONNormalize.py,sha256=aIuVzuZDazhxkCOzoOjfhHVz66mp2FWdfPv5E7KWF5Y,3890
pyOpenRPA/Robot/Utils/ProcessBitness.py,sha256=WlKL-DklGaoTnchtapOTM_ydxSB4yOeo9lcG3zr2VME,4524
pyOpenRPA/Robot/Utils/ProcessCommunicator.py,sha256=8GfmLnOvAdosmt7YNT86uEV9cjhKippssCX62wOMJwM,8039
pyOpenRPA/Robot/Utils/TimerRepeat.py,sha256=_kTct3X9SIEvS3DKM5bGNnjRBVJasmMFZntQaVbPX_E,961
pyOpenRPA/Robot/Utils/ValueVerify.py,sha256=ObskxU4fOMoCGw74_nzYt6-a5jjrAckb3sdBLYyhYxY,777
pyOpenRPA/Robot/Utils/__init__.py,sha256=pHlSQGRFKmn5RCTHIf-3a2ooA9T2xNOWridckynP7W4,28
pyOpenRPA/Robot/Utils/__pycache__/JSONNormalize.cpython-37.pyc,,
pyOpenRPA/Robot/Utils/__pycache__/ProcessBitness.cpython-37.pyc,,
pyOpenRPA/Robot/Utils/__pycache__/ProcessCommunicator.cpython-37.pyc,,
pyOpenRPA/Robot/Utils/__pycache__/TimerRepeat.cpython-37.pyc,,
pyOpenRPA/Robot/Utils/__pycache__/ValueVerify.cpython-37.pyc,,
pyOpenRPA/Robot/Utils/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Robot/Window.py,sha256=UJl-sg4RvvJ35aG9jZOzqGVwE15XK7qPHqoOBD13xFk,431
pyOpenRPA/Robot/__init__.py,sha256=L-5tPm6evytGWOzlqIq-2oiIhmQnruaxwIstyyaMkVI,253
pyOpenRPA/Robot/__main__.py,sha256=l6II8JuXCsnVOcfs6-2jvogKYTVhbfj3Jl2ld3OIP7s,1992
pyOpenRPA/Robot/__pycache__/Clipboard.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/OrchestratorConnector.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/SettingsTemplate.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/Test.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/UIDesktop.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/Window.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Studio/JSONNormalize.py,sha256=g0Z8G2wojCgTAdZtyRiCfe0_FHSeAi72Va7R7mk27gg,3347
pyOpenRPA/Studio/ProcessCommunicator.py,sha256=HD3XASJae31_HV3OznFe8E2MgZFXnwt7YveVN82M8nU,7912
pyOpenRPA/Studio/RobotConnector.py,sha256=CYO0dQoqfs44SYD_VZ_TJh3WFu_DXigHBLHj4GJ2Icc,5038
pyOpenRPA/Studio/Studio.py,sha256=_BXQjAMHew2fRWloXdqPOmYHX6i6C8ELPsW1TZNvjz4,8618
pyOpenRPA/Studio/ValueVerify.py,sha256=ObskxU4fOMoCGw74_nzYt6-a5jjrAckb3sdBLYyhYxY,777
pyOpenRPA/Studio/Web/Index.xhtml,sha256=wo3Y5CzWJQYMw9AgNHXynt1yGDLIoihRlt1weFLSuYQ,48240
pyOpenRPA/Studio/Web/favicon.ico,sha256=6S8XwSQ_3FXPpaX6zYkf8uUewVXO9bHnrrDHEoWrEgw,112922
pyOpenRPA/Studio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Studio/__main__.py,sha256=_57Rnq9DKbmmlpGFqIwVrWn_LRcU8jjmMTOny4_zlP8,308
pyOpenRPA/Studio/__pycache__/JSONNormalize.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/ProcessCommunicator.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/RobotConnector.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/Studio.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/ValueVerify.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/ExcelCom.py,sha256=hp0dvXOEC7Au00ueh7pqxkdixV-PC-km7tCt-wRunYs,343
pyOpenRPA/Tools/RobotDB/HowToUse,sha256=TUXPZAFcse-PSlKFM6jcaYuuZZEmXOSSvgeqrbmIDoc,1473
pyOpenRPA/Tools/RobotDB/RobotDB.py,sha256=qtGu8PS2atd0L8taCNpk-08Qpxp8Qz1lqwAcBkyLFLM,1655
pyOpenRPA/Tools/RobotDB/Server.py,sha256=rjW9Sg-j9P8pFQD66Uih-rke6-f6sCulinwi4_W-3mc,19933
pyOpenRPA/Tools/RobotDB/ServerSettings.py,sha256=5p9JwrpKHh68oVHIWazTajB6AOfzeapARbvGcJOFmNc,7406
pyOpenRPA/Tools/RobotDB/__init__.py,sha256=qVH8fEPgXk54rmy-ol0PnT8GF5OlGE0a8mExwJ4tFqY,124
pyOpenRPA/Tools/RobotDB/__main__.py,sha256=w9sXIF4r_PeWJjHJutTuH8DSYpXxpgcAN0KUOjiJ6PI,140
pyOpenRPA/Tools/RobotDB/__pycache__/ExcelCom.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/RobotDB.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/Server.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/ServerSettings.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotScreenActive/ConsoleStart.bat,sha256=_HNadUKHOYI5y6foG3srh8wjSzhX33xaKNylFtDjOJk,114
pyOpenRPA/Tools/RobotScreenActive/Monitor.py,sha256=TV-YisVqa_uGiyJLG9oK4u-5aDjGiFYZFh1dPjOgYc8,492
pyOpenRPA/Tools/RobotScreenActive/Screen.py,sha256=VnYcvCVymrD35l2J4ln_tlVn7CilZhxE4Ggw9P-OhIw,606
pyOpenRPA/Tools/RobotScreenActive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/RobotScreenActive/__main__.py,sha256=JASxDDVKWUU7DAbDkRrGTrPk-P7LZchTZFh8usp6b4U,593
pyOpenRPA/Tools/RobotScreenActive/__pycache__/Monitor.cpython-37.pyc,,
pyOpenRPA/Tools/RobotScreenActive/__pycache__/Screen.cpython-37.pyc,,
pyOpenRPA/Tools/RobotScreenActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotScreenActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/Crypter.py,sha256=VRrE5-oQxQtvMEPHM1lMXp2CKnceNBmIWJnsJoJkaVE,3616
pyOpenRPA/Tools/SafeSource/DistrCreate.py,sha256=-_8BTle57LBKVknnB_3af-LghxrRmRGfRNu08CLNIvY,3232
pyOpenRPA/Tools/SafeSource/DistrRun.py,sha256=zwUh6Jy-rDAZHV6fcTUMupkukojntFMroHJHMsNQgrE,9637
pyOpenRPA/Tools/SafeSource/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/SafeSource/__main__.py,sha256=g5aYWnuUZoM2jDX2mSIl9tRAJg05tu5VxD2rGJWcACg,649
pyOpenRPA/Tools/SafeSource/__pycache__/Crypter.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/DistrCreate.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/Terminator.py,sha256=VcjX3gFXiCGu3MMCidhrTNsmC9wsAqfjRJdTSU9fLnU,2178
pyOpenRPA/Tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/__pycache__/Terminator.cpython-37.pyc,,
pyOpenRPA/Tools/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/__init__.py,sha256=HIl4GtAt0lGzG2lJPyRwIevTFjIX1iwfYYFpPSUlxAc,175
pyOpenRPA/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/test.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.1)
Root-Is-Purelib: true
Tag: py3-none-any

@ -1,6 +1,288 @@
# Def to check inGSettings and update structure to the backward compatibility
# !!! ATTENTION: Backward compatibility has been started from v1.1.13 !!!
# So you can use config of the orchestrator 1.1.13 in new Orchestrator versions and all will be ok :) (hope it's true)
import win32security, json, datetime, time, copy
# # # # # # # # # # # # # # # # # # #
# Backward compatibility Web defs up to v1.2.0
# # # # # # # # # # # # # # # # # # #
# UserAccess get rights hierarchy dict in json
def v1_2_0_UserRoleHierarchyGet(inRequest,inGlobalDict):
inResponseDict = inRequest.OpenRPAResponseDict
# Create result JSON
lResultDict = inRequest.OpenRPA["DefUserRoleHierarchyGet"]() # Get the User Role Hierarchy list
# Send message back to client
message = json.dumps(lResultDict)
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
from inspect import signature # For detect count of def args
# /Orchestrator/RobotRDPActive/ControlPanelDictGet
def v1_2_0_RobotRDPActive_ControlPanelDictGet(inRequest,inGlobalDict):
inResponseDict = inRequest.OpenRPAResponseDict
lResultDict = {
"DataList":[
# {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False}
]
}
# Iterate throught the RDP List
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]:
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"]["FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lResultDict["DataList"].append(lDataItemDict)
# Send message back to client
message = json.dumps(lResultDict)
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
# def to check control panels for selected session
def v1_2_0_Monitor_ControlPanelDictGet_SessionCheckInit(inRequest,inGlobalDict):
lL = inGlobalDict["Logger"] # Alias for logger
lLifetimeSecFloat = inGlobalDict["Client"]["Session"]["LifetimeSecFloat"]
lLifetimeRequestSecFloat = inGlobalDict["Client"]["Session"]["LifetimeRequestSecFloat"]
lControlPanelRefreshIntervalSecFloat = inGlobalDict["Client"]["Session"]["ControlPanelRefreshIntervalSecFloat"]
lCookieSessionGUIDStr = None # generate the new GUID
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Technicaldef - interval check control panels + check actuality of the session by the datetime
def TechnicalCheck():
lItemValue = inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]
# Lifetime is ok - check control panel
lDatasetCurrentBytes = v1_2_0_Monitor_ControlPanelDictGet(inRequest,inGlobalDict) # Call the control panel
if lDatasetCurrentBytes != lItemValue["DatasetLast"]["ControlPanel"]["Data"]: # Check if dataset is changed
lItemValue["DatasetLast"]["ControlPanel"]["Data"] = lDatasetCurrentBytes # Set new datset
lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] = True # Set flag to return the data
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Technicaldef - Create new session struct
def TechnicalSessionNew(inSessionGUIDStr):
lCookieSessionGUIDStr = inSessionGUIDStr # Generate the new GUID
lSessionNew = { # Session with some GUID str. On client session guid stored in cookie "SessionGUIDStr"
"InitDatetime": datetime.datetime.now(), # Datetime when session GUID was created
"DatasetLast": {
"ControlPanel": {
"Data": None, # Struct to check with new iterations. None if starts
"ReturnBool": False # flag to return, close request and return data as json
}
},
"ClientRequestHandler": inRequest, # Last client request handler
"UserADStr": inRequest.OpenRPA["User"], # User, who connect. None if user is not exists
"DomainADStr": inRequest.OpenRPA["Domain"], # Domain of the user who connect. None if user is not exists
}
inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr] = lSessionNew # Set new session in dict
inRequest.OpenRPAResponseDict["SetCookies"]["SessionGUIDStr"] = lCookieSessionGUIDStr # Set SessionGUIDStr in cookies
if lL: lL.info(f"New session GUID is created. GUID {lCookieSessionGUIDStr}")
return lCookieSessionGUIDStr
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
lCreateNewSessionBool = False # Flag to create new session structure
# step 1 - get cookie SessionGUIDStr
lSessionGUIDStr = inRequest.headers.get("SessionGUIDStr", None)
if lSessionGUIDStr is not None: # Check if GUID session is ok
#inRequest.OpenRPAResponseDict["StatusCode"] = 301
#inRequest.OpenRPAResponseDict["Headers"]["Location"] = "/"
#if lL: lL.info(f"GUID is detected - send HTTP 301 to refresh page")
lCookieSessionGUIDStr = lSessionGUIDStr # Get the existing GUID
if lSessionGUIDStr not in inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lCookieSessionGUIDStr= TechnicalSessionNew(inSessionGUIDStr = lSessionGUIDStr) # Create new session
else: # Update the datetime of the request session
inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]["InitDatetime"]=datetime.datetime.now()
else:
lCookieSessionGUIDStr = TechnicalSessionNew(inSessionGUIDStr = lSessionGUIDStr) # Create new session
# Init the RobotRDPActive in another thread
#lThreadCheckCPInterval = threading.Thread(target=TechnicalIntervalCheck)
#lThreadCheckCPInterval.daemon = True # Run the thread in daemon mode.
#lThreadCheckCPInterval.start() # Start the thread execution.
# Step 2 - interval check if data is exist
lTimeStartSecFloat = time.time()
lDoWhileBool = True # Flag to iterate throught the lifetime of the request
while lDoWhileBool:
#print(lTechnicalSessionGUIDCache)
#print(lCookieSessionGUIDStr)
if lCookieSessionGUIDStr in inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lItemValue = inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]
if (time.time() - lTimeStartSecFloat) >= lLifetimeRequestSecFloat: # Check if lifetime client request is over or has no key
if lL: lL.debug(f"Client request lifetime is over")
lDoWhileBool = False # Stop the iterations
if lDoWhileBool:
TechnicalCheck() # Calculate the CP
if lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] == True: # Return data if data flag it True
lDatasetCurrentBytes = lItemValue["DatasetLast"]["ControlPanel"]["Data"] # Set new dataset
inResponseDict = inRequest.OpenRPAResponseDict
inResponseDict["Body"] = lDatasetCurrentBytes
lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] = False # Set flag that data was returned
lDoWhileBool = False # Stop the iterations
else:
lCookieSessionGUIDStr = TechnicalSessionNew(inSessionGUIDStr = lCookieSessionGUIDStr) # Create new session
if lDoWhileBool: # Sleep if we wait hte next iteration
time.sleep(lControlPanelRefreshIntervalSecFloat) # Sleep to the next iteration
def v1_2_0_Monitor_ControlPanelDictGet(inRequest,inGlobalDict):
inResponseDict = inRequest.OpenRPAResponseDict
lL = inGlobalDict["Logger"] # Alias for logger
# Create result JSON
lResultJSON = {"RenderRobotList": [], "RenderRDPList": []}
lRenderFunctionsRobotList = inGlobalDict["ControlPanelDict"]["RobotList"]
for lItem in lRenderFunctionsRobotList:
lUACBool = True # Check if render function is applicable User Access Rights (UAC)
if inGlobalDict["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True:
lUserRights = inGlobalDict["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
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"](inGlobalDict)
elif lDEFARGLen == 2: # def (inRequest, inGSettings)
lItemResultDict = lItem["RenderFunction"](inRequest, inGlobalDict)
elif lDEFARGLen == 0: # def ()
lItemResultDict = lItem["RenderFunction"]()
# RunFunction
lResultJSON["RenderRobotList"].append(lItemResultDict)
except Exception as e:
if lL: lL.exception(f"Error in control panel. CP item {lItem}. Exception is below")
# Iterate throught the RDP list
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]:
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][
lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr": "", "SessionHexStr": "", "IsFullScreenBool": False,
"IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"][
"FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lResultJSON["RenderRDPList"].append(lDataItemDict)
# Send message back to client
message = json.dumps(lResultJSON)
# Write content as utf-8 data
#inResponseDict["Body"] = bytes(message, "utf8")
return bytes(message, "utf8")
from . import __Orchestrator__ # For user defs
# v1.2.0 Def for old procesor to new processor
# Return new activity for the new processor
def v1_2_0_ProcessorOld2NewActivityDict(inActivityOld):
if inActivityOld["Type"] == "WindowsLogon":
lResult = {
"Def": __Orchestrator__.OSCredentialsVerify, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList":[], # Args list
"ArgDict":{"inUserStr": inActivityOld["User"],"inPasswordStr":inActivityOld["Password"],"inDomainStr":inActivityOld["Domain"]}, # Args dictionary
"ArgGSettings": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "GlobalDictKeyListValueGet":
lResult = {
"Def": __Orchestrator__.GSettingsKeyListValueGet, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList":[], # Args list
"ArgDict":{"inKeyList": inActivityOld["KeyList"]}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "CMDStart":
lResult = {
"Def": __Orchestrator__.OSCMD, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inCMDStr": inActivityOld["Command"]}, # Args dictionary
"ArgGSettings": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": "inLogger" # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "OrchestratorRestart":
lResult = {
"Def": __Orchestrator__.OrchestratorRestart, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "OrchestratorSessionSave":
lResult = {
"Def": __Orchestrator__.OrchestratorSessionSave,
# def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "GlobalDictKeyListValueSet":
lResult = {
"Def": __Orchestrator__.GSettingsKeyListValueSet, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inKeyList": inActivityOld["KeyList"], "inValue": inActivityOld["Value"]}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "GlobalDictKeyListValueAppend":
lResult = {
"Def": __Orchestrator__.GSettingsKeyListValueAppend, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inKeyList": inActivityOld["KeyList"], "inValue": inActivityOld["Value"]}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "GlobalDictKeyListValueOperator+":
lResult = {
"Def": __Orchestrator__.GSettingsKeyListValueOperatorPlus, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inKeyList": inActivityOld["KeyList"], "inValue": inActivityOld["Value"]}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "ProcessStart":
lResult = {
"Def": __Orchestrator__.ProcessStart, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inPathStr": inActivityOld["Path"], "inArgList": inActivityOld["ArgList"]}, # Args dictionary
"ArgGSettings": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "ProcessStartIfTurnedOff":
lResult = {
"Def": __Orchestrator__.ProcessStart, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inPathStr": inActivityOld["Path"], "inArgList": inActivityOld["ArgList"], "inStopProcessNameWOExeStr": inActivityOld["CheckTaskName"]}, # Args dictionary
"ArgGSettings": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "ProcessStop":
lResult = {
"Def": __Orchestrator__.ProcessStop, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inProcessNameWOExeStr": inActivityOld["Name"], "inCloseForceBool": inActivityOld["FlagForce"], "inUserNameStr": inActivityOld["User"]}, # Args dictionary
"ArgGSettings": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "PythonStart":
lResult = {
"Def": __Orchestrator__.PythonStart, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inModulePathStr": inActivityOld["ModuleName"], "inDefNameStr": inActivityOld["FunctionName"], "inArgList": inActivityOld["ArgList"],
"inArgDict": inActivityOld["ArgDict"] }, # Args dictionary
"ArgGSettings": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": "inLogger" # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
else:
raise Exception(f"BackwardCompatibility up to v1.2.0, old processor: No type {inActivityOld['Type']} has been found in old processor.")
return lResult # return the result
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # HERE IS THE MAIN DEF WHICH IS LAUNCHES WHEN START # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def Update(inGSettings):
lL = inGSettings["Logger"] # Alias for logger
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@ -8,7 +290,7 @@ def Update(inGSettings):
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if "Autocleaner" not in inGSettings: # Add "Autocleaner" structure
inGSettings["Autocleaner"] = { # Some gurbage is collecting in g settings. So you can configure autocleaner to periodically clear gSettings
"IntervalSecFloat": 600.0, # Sec float to periodically clear gsettings
"IntervalSecFloat": 7200.0, # Sec float to periodically clear gsettings
}
if lL: lL.warning(f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Autocleaner' structure") # Log about compatibility
if "Client" not in inGSettings: # Add "Client" structure
@ -34,10 +316,109 @@ def Update(inGSettings):
}
}
if lL: lL.warning(f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Client' structure") # Log about compatibility
if "RequestTimeoutSecFloat" not in inGSettings["Server"]: # Add Server > "RequestTimeoutSecFloat" property
if "Server" in inGSettings and "RequestTimeoutSecFloat" not in inGSettings["Server"]: # Add Server > "RequestTimeoutSecFloat" property
inGSettings["Server"]["RequestTimeoutSecFloat"] = 300 # Time to handle request in seconds
if lL: lL.warning(
f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Server' > 'RequestTimeoutSecFloat' property") # Log about compatibility
if "DefSettingsUpdatePathList" not in inGSettings["OrchestratorStart"]: # Add OrchestratorStart > "DefSettingsUpdatePathList" property
inGSettings["OrchestratorStart"]["DefSettingsUpdatePathList"] = [] # List of the .py files which should be loaded before init the algorythms
if lL: lL.warning(f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'OrchestratorStart' > 'DefSettingsUpdatePathList' property list") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'OrchestratorStart' > 'DefSettingsUpdatePathList' property list") # Log about compatibility
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# v1.1.20 to v1.2.0
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Update Structure gSettings["Processor"]
from . import SettingsTemplate
if "DumpLogListRefreshIntervalSecFloat" not in inGSettings["Client"]: # Create new ProcessorDict structure
inGSettings["Client"].update({
"DumpLogListRefreshIntervalSecFloat": 3.0, # Duration between updates for the Client
"DumpLogListCountInt": 100, # Set the max row for the dump
"DumpLogList": [], # Will be filled automatically
"DumpLogListHashStr": None, # Will be filled automatically
})
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'Client > DumpLog... with default parameters'") # Log about compatibility
if "Processor" in inGSettings: # Check if Processor exist
# Update Logger
if lL is not None:
SettingsTemplate.LoggerDumpLogHandlerAdd(inLogger=lL, inGSettingsClientDict=inGSettings["Client"])
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Add web dump log in logger as handler") # Log about compatibility
del inGSettings["Processor"] # Remove the key
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Remove old structure 'Processor'") # Log about compatibility
if "ProcessorDict" not in inGSettings: # Create new ProcessorDict structure
inGSettings["ProcessorDict"]={
"ActivityList": [ # List of the activities
# {
# "Def":"DefAliasTest", # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
# "ArgList":[1,2,3], # Args list
# "ArgDict":{"ttt":1,"222":2,"dsd":3} # Args dictionary
# "ArgGSettings": # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# },
],
"AliasDefDict": {} , # Storage for def with Str alias. To use it see pyOpenRPA.Orchestrator.ControlPanel
"CheckIntervalSecFloat": 1.0, # Interval for check gSettings in ProcessorDict > ActivityList
"ExecuteBool": True, # Flag to execute thread processor
"ThreadIdInt": None # Fill thread id when processor will be inited
}
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new structure 'ProcessorDict'") # Log about compatibility
if "VersionStr" not in inGSettings: # Create new ProcessorDict structure
inGSettings["VersionStr"] = None
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'VersionStr'") # Log about compatibility
if "AgentDict" not in inGSettings: # Create new AgentDict structure
inGSettings["AgentDict"]= {}
if lL: lL.warning(
f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'AgentDict'") # Log about compatibility
# Alg to convert UAC ControlPanelAllawedList to UACClient hierarchy
# 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
# # Convert to UACClient dict
if "Server" in inGSettings:
# Check if Server is active > convert to ServerDict
inGSettings["ServerDict"] = inGSettings["Server"]
if lL: lL.warning(
f"Backward compatibility (v1.1.20 to v1.2.0): Convert Server to ServerDict") # Log about compatibility
# Remove old structure Scheduler
del inGSettings["Server"]
lShowWarnBool = False
lRuleDomainUserDeepCopyDict = copy.deepcopy(inGSettings["ServerDict"]["AccessUsers"]["RuleDomainUserDict"])
for lItemKeyTurple in lRuleDomainUserDeepCopyDict:
lDomainUpperStr = lItemKeyTurple[0]
lUserUpperStr = lItemKeyTurple[1]
lItemDict = lRuleDomainUserDeepCopyDict[lItemKeyTurple]
if "ControlPanelKeyAllowedList" in lItemDict:
lShowWarnBool = True
if len(lItemDict["ControlPanelKeyAllowedList"])>0:
lUACClientDict = {"pyOpenRPADict": {"CPKeyDict": {}}}
else:
lUACClientDict = {}
for lAllowedKeyItemStr in lItemDict["ControlPanelKeyAllowedList"]:
lUACClientDict["pyOpenRPADict"]["CPKeyDict"][lAllowedKeyItemStr]=True # Convert
# Send update UACDict for user by the list
__Orchestrator__.UACUpdate(inGSettings=inGSettings,inADLoginStr=lUserUpperStr, inADStr=lDomainUpperStr, inRoleHierarchyAllowedDict=lUACClientDict)
# remove "ControlPanelKeyAllowedList" - will be removed in __Orchestrator__.UACUpdate
#del inGSettings["ServerDict"]["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"]
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Convert ControlPanelDict to CPDict") # Log about compatibility
# Check if Scheduler is active > convert to SchedulerDict
if "Scheduler" in inGSettings:
if "SchedulerDict" not in inGSettings: inGSettings["SchedulerDict"]={ "CheckIntervalSecFloat": 5.0, "ActivityTimeList":[]}
if "ActivityTimeCheckLoopSeconds" in inGSettings["Scheduler"]:
inGSettings["SchedulerDict"]["CheckIntervalSecFloat"] = inGSettings["Scheduler"]["ActivityTimeCheckLoopSeconds"]
for lItemDict in inGSettings["Scheduler"]["ActivityTimeList"]:
# Append to the new struct if this is not periodic ("TimeHH:MMStart"and "TimeHH:MMStop")
if "TimeHH:MMStart" not in lItemDict and "TimeHH:MMStop" not in lItemDict:
lItemDict["ActivityList"]=[v1_2_0_ProcessorOld2NewActivityDict(inActivityOld=lItemDict["Activity"])]
del lItemDict["Activity"]
inGSettings["SchedulerDict"]["ActivityTimeList"].append(lItemDict)
# Remove old structure Scheduler
del inGSettings["Scheduler"]
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Convert Scheduler to SchedulerDict with new features") # Log about compatibility

@ -1,205 +0,0 @@
import subprocess
import json
import datetime
import time
import codecs
import os
import signal
import sys #Get input argument
import pdb
from . import Server
from . import Timer
from . import Processor
from . import BackwardCompatibility # Backward compatibility from v1.1.13
#from .Settings import Settings
import importlib
from importlib import util
import threading # Multi-threading for RobotRDPActive
from .RobotRDPActive import RobotRDPActive #Start robot rdp active
from .RobotScreenActive import Monitor #Start robot screen active
import uuid # Generate uuid
import datetime # datetime
#Единый глобальный словарь (За основу взять из Settings.py)
global gSettingsDict
# Interval gsettings auto cleaner
def GSettingsAutocleaner(inGSettings):
while True:
time.sleep(inGSettings["Autocleaner"]["IntervalSecFloat"]) # Wait for the next iteration
lL = inGSettings["Logger"]
if lL: lL.info(f"Autocleaner is running") # Info
lNowDatetime = datetime.datetime.now() # Get now time
# Clean old items in Client > Session > TechnicalSessionGUIDCache
lTechnicalSessionGUIDCacheNew = {}
for lItemKeyStr in inGSettings["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lItemValue = inGSettings["Client"]["Session"]["TechnicalSessionGUIDCache"][lItemKeyStr]
if (lNowDatetime - lItemValue["InitDatetime"]).total_seconds() < inGSettings["Client"]["Session"]["LifetimeSecFloat"]: # Add if lifetime is ok
lTechnicalSessionGUIDCacheNew[lItemKeyStr]=lItemValue # Lifetime is ok - set
else:
if lL: lL.debug(f"Client > Session > TechnicalSessionGUIDCache > lItemKeyStr: Lifetime is expired. Remove from gSettings") # Info
inGSettings["Client"]["Session"]["TechnicalSessionGUIDCache"] = lTechnicalSessionGUIDCacheNew # Set updated Cache
# # # # # # # # # # # # # # # # # # # # # # # # # #
#Call Settings function from argv[1] file
################################################
lSubmoduleFunctionName = "Settings"
lFileFullPath = sys.argv[1]
lModuleName = (lFileFullPath.split("\\")[-1])[0:-3]
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification)
lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec)
gSettingsDict = None
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
gSettingsDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
#################################################
#mGlobalDict = Settings.Settings(sys.argv[1])
#Logger alias
lL = gSettingsDict["Logger"]
if lL: lL.info("Link the gSettings in submodules") #Logging
Processor.gSettingsDict = gSettingsDict
Timer.gSettingsDict = gSettingsDict
Timer.Processor.gSettingsDict = gSettingsDict
Server.gSettingsDict = gSettingsDict
Server.Processor.gSettingsDict = gSettingsDict
# Check _SessionLast_RDPList.json in working directory. if exist - load into gsettings
# GSettings
#"RobotRDPActive": {
# "RDPList": {
if os.path.exists("_SessionLast_RDPList.json"):
lFile = open("_SessionLast_RDPList.json", "r", encoding="utf-8")
lSessionLastRDPList = json.loads(lFile.read())
lFile.close() # Close the file
os.remove("_SessionLast_RDPList.json") # remove the temp file
gSettingsDict["RobotRDPActive"]["RDPList"]=lSessionLastRDPList # Set the last session dict
if lL: lL.warning(f"RDP Session List was restored from previous Orchestrator session")
#Инициализация настроечных параметров
lDaemonLoopSeconds=gSettingsDict["Scheduler"]["ActivityTimeCheckLoopSeconds"]
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
lDaemonLastDateTime=datetime.datetime.now()
gSettingsDict["Server"]["WorkingDirectoryPathStr"] = os.getcwd() # Set working directory in g settings
# Init SettingsUpdate defs from file list (after RDP restore)
lSettingsUpdateFilePathList = gSettingsDict.get("OrchestratorStart", {}).get("DefSettingsUpdatePathList",[])
lSubmoduleFunctionName = "SettingsUpdate"
lSettingsPath = "\\".join(os.path.join(os.getcwd(), __file__).split("\\")[:-1])
for lModuleFilePathItem in lSettingsUpdateFilePathList: # Import defs with try catch
try: # Try to init - go next if error and log in logger
lModuleName = lModuleFilePathItem[0:-3]
lFileFullPath = os.path.join(lSettingsPath, lModuleFilePathItem)
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification)
lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec)
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(gSettingsDict)
except Exception as e:
if lL: lL.exception(f"Error when init .py file in orchestrator '{lModuleFilePathItem}'. Exception is below:")
# Turn on backward compatibility
BackwardCompatibility.Update(inGSettings= gSettingsDict)
#Инициализация сервера
lThreadServer = Server.RobotDaemonServer("ServerThread", gSettingsDict)
lThreadServer.start()
if lL: lL.info("Web server has been started") #Logging
# Init the RobotScreenActive in another thread
lRobotScreenActiveThread = threading.Thread(target= Monitor.CheckScreen)
lRobotScreenActiveThread.daemon = True # Run the thread in daemon mode.
lRobotScreenActiveThread.start() # Start the thread execution.
if lL: lL.info("Robot Screen active has been started") #Logging
# Init the RobotRDPActive in another thread
lRobotRDPActiveThread = threading.Thread(target= RobotRDPActive.RobotRDPActive, kwargs={"inGSettings":gSettingsDict})
lRobotRDPActiveThread.daemon = True # Run the thread in daemon mode.
lRobotRDPActiveThread.start() # Start the thread execution.
if lL: lL.info("Robot RDP active has been started") #Logging
# Init autocleaner in another thread
lAutocleanerThread = threading.Thread(target= GSettingsAutocleaner, kwargs={"inGSettings":gSettingsDict})
lAutocleanerThread.daemon = True # Run the thread in daemon mode.
lAutocleanerThread.start() # Start the thread execution.
if lL: lL.info("Autocleaner thread has been started") #Logging
# Orchestrator start activity
if lL: lL.info("Orchestrator start activity run") #Logging
for lActivityItem in gSettingsDict["OrchestratorStart"]["ActivityList"]:
Processor.ActivityListOrDict(lActivityItem)
if lL: lL.info("Scheduler loop start") #Logging
gDaemonActivityLogDictRefreshSecInt = 10 # The second period for clear lDaemonActivityLogDict from old items
gDaemonActivityLogDictLastTime = time.time() # The second perioad for clean lDaemonActivityLogDict from old items
while True:
lCurrentDateTime = datetime.datetime.now()
#Циклический обход правил
lFlagSearchActivityType=True
# Periodically clear the lDaemonActivityLogDict
if time.time()-gDaemonActivityLogDictLastTime>=gDaemonActivityLogDictRefreshSecInt:
gDaemonActivityLogDictLastTime = time.time() # Update the time
for lIndex, lItem in enumerate(lDaemonActivityLogDict):
if lItem["ActivityEndDateTime"] and lCurrentDateTime<=lItem["ActivityEndDateTime"]:
pass
# Activity is actual - do not delete now
else:
# remove the activity - not actual
lDaemonActivityLogDict.pop(lIndex,None)
lIterationLastDateTime = lDaemonLastDateTime # Get current datetime before iterator (need for iterate all activities in loop)
# Iterate throught the activity list
for lIndex, lItem in enumerate(gSettingsDict["Scheduler"]["ActivityTimeList"]):
# Prepare GUID of the activity
lGUID = None
if "GUID" in lItem and lItem["GUID"]:
lGUID = lItem["GUID"]
else:
lGUID = str(uuid.uuid4())
lItem["GUID"]=lGUID
#Проверка дней недели, в рамках которых можно запускать активность
lItemWeekdayList=lItem.get("WeekdayList", [0, 1, 2, 3, 4, 5, 6])
if lCurrentDateTime.weekday() in lItemWeekdayList:
if lFlagSearchActivityType:
#######################################################################
#Branch 1 - if has TimeHH:MM
#######################################################################
if "TimeHH:MM" in lItem:
#Вид активности - запуск процесса
#Сформировать временной штамп, относительно которого надо будет проверять время
#часовой пояс пока не учитываем
lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MM"],"%H:%M")
lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
#Убедиться в том, что время наступило
if (
lActivityDateTime>=lDaemonLastDateTime and
lCurrentDateTime>=lActivityDateTime):
# Log info about activity
if lL: lL.info(f"Scheduler:: Activity is started. Scheduler item: {lItem}") #Logging
# Do the activity
Processor.ActivityListOrDict(lItem["Activity"])
lIterationLastDateTime = datetime.datetime.now() # Set the new datetime for the new processor activity
#######################################################################
#Branch 2 - if TimeHH:MMStart, TimeHH:MMStop, ActivityIntervalSeconds
#######################################################################
if "TimeHH:MMStart" in lItem and "TimeHH:MMStop" in lItem and "ActivityIntervalSeconds" in lItem:
#Сформировать временной штамп, относительно которого надо будет проверять время
#часовой пояс пока не учитываем
lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStart"],"%H:%M")
lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
lActivityTimeEndDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStop"],"%H:%M")
lActivityTimeEndDateTime=lActivityTimeEndDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
#Убедиться в том, что время наступило
if (
lCurrentDateTime<lActivityTimeEndDateTime and
lCurrentDateTime>=lActivityDateTime and
(lGUID,lActivityDateTime) not in lDaemonActivityLogDict):
#Запись в массив отработанных активностей
lDaemonActivityLogDict[(lGUID,lActivityDateTime)]={"ActivityStartDateTime":lCurrentDateTime, "ActivityEndDateTime":lActivityTimeEndDateTime}
#Запуск циклической процедуры
Timer.activityLoopStart(lItem["ActivityIntervalSeconds"], lActivityTimeEndDateTime, lItem["Activity"])
lDaemonLastDateTime = lIterationLastDateTime # Set the new datetime for the new processor activity
#Уснуть до следующего прогона
time.sleep(lDaemonLoopSeconds)

@ -1,301 +1,100 @@
import datetime
import http.client
import json
import pdb
import os
import sys
import subprocess
import importlib
import psutil
#Input arg
# [
# {
# "Type": <RemoteMachineProcessingRun>,
# host: <localhost>,
# port: <port>,
# bodyObject: <object dict, int, str, list>
# },
# {
# "Type": "CMDStart",
# "Command": ""
# },
# {
# "Type": "OrchestratorRestart"
# },
# {
# "Type": "OrchestratorSessionSave"
# },
# {
# "Type": "GlobalDictKeyListValueSet",
# "KeyList": ["key1","key2",...],
# "Value": <List, Dict, String, int>
# },
# {
# "Type": "GlobalDictKeyListValueAppend",
# "KeyList": ["key1","key2",...],
# "Value": <List, Dict, String, int>
# },
# {
# "Type": "GlobalDictKeyListValueOperator+",
# "KeyList": ["key1","key2",...],
# "Value": <List, Dict, String, int>
# },
# {
# "Type": "GlobalDictKeyListValueGet",
# "KeyList": ["key1","key2",...]
# },
# {
# "Type":"ProcessStart",
# "Path":"",
# "ArgList":[]
# },
# {
# "Type":"ProcessStartIfTurnedOff",
# "CheckTaskName":"", #Check if current task name is not active (then start process),
# "Path":"",
# "ArgList":[]
# },
# {
# "Type":"ProcessStop",
# "Name":"",
# "FlagForce":True,
# "User":"" #Empty - all users, user or %username%
# },
# {
# "Type":"PythonStart",
# "ModuleName":"",
# "FunctionName":"",
# "ArgList":[],
# "ArgDict":{}
# },
# {
# "Type":"WindowsLogon",
# "Domain":"",
# "User":"",
# "Password":""
# # Return "Result": True - user is logged on, False - user is not logged on
# }
# ]
##################################
#Output result
# <input arg> with attributes:
# "DateTimeUTCStringStart"
# "DateTimeUTCStringStop"
# "Result"
gSettingsDict = None
def Activity(inActivity):
#Глобальная переменная - глобальный словарь унаследованный от Settings.py
global gSettingsDict
lL = gSettingsDict["Logger"] # Alias for logger
#Alias (compatibility)
lItem = inActivity
lCurrentDateTime = datetime.datetime.now()
###########################################################
#Обработка запроса на отправку команды на удаленную машину
###########################################################
if lItem["Type"]=="RemoteMachineProcessingRun":
lHTTPConnection = http.client.HTTPConnection(lItem["host"], lItem["port"], timeout=5)
try:
lHTTPConnection.request("POST","/ProcessingRun",json.dumps(lItem["bodyObject"]))
except Exception as e:
#Объединение словарей
lItem["Result"] = {"State":"disconnected","ExceptionString":str(e)}
# 1.2.0 - general processor - contains old orchestrator processor + RDPActive processor
import time, copy, threading
# Run processor synchronious
# inThreadControlDict = {"ThreadExecuteBool":True}
def ProcessorRunSync(inGSettings, inRobotRDPThreadControlDict):
"""
"ProcessorDict": { # Has been changed. New general processor (one threaded) v.1.2.0
"ActivityList": [ # List of the activities
# {
# "Def":"DefAliasTest", # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
# "ArgList":[1,2,3], # Args list
# "ArgDict":{"ttt":1,"222":2,"dsd":3}, # Args dictionary
# "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# },
],
"AliasDefDict": {}, # Storage for def with Str alias. To use it see pyOpenRPA.Orchestrator.ControlPanel
"CheckIntervalSecFloat": 1.0 # Interval for check gSettings in ProcessorDict > ActivityList
"ExecuteBool": True # Flag to execute thread processor
"""
lL = inGSettings["Logger"] # Logger alias
inGSettings["ProcessorDict"]["ThreadIdInt"] = threading.get_ident() # fill Processor thread id
while inGSettings["ProcessorDict"]["ExecuteBool"]:
lActivityList = inGSettings["ProcessorDict"]["ActivityList"] # Alias
if len(lActivityList)>0:
if lL: lL.debug(f'Processor ActivityList len: {len(lActivityList)}')
lActivityItem = inGSettings["ProcessorDict"]["ActivityList"].pop(0) # Extract the first item from processor queue
inRobotRDPThreadControlDict["ThreadExecuteBool"]=False # Stop the RobotRDPActive monitoring
ActivityListExecute(inGSettings = inGSettings, inActivityList = [lActivityItem]) # execute the activity item
inRobotRDPThreadControlDict["ThreadExecuteBool"] = True # Continue the RobotRDPActive monitoring
else:
lHTTPResponse=lHTTPConnection.getresponse()
lHTTPResponseByteArray=lHTTPResponse.read()
lItem["Result"] = json.loads(lHTTPResponseByteArray.decode('utf8'))
###########################################################
#Обработка команды CMDStart
###########################################################
if lItem["Type"]=="CMDStart":
lCMDCode="cmd /c "+lItem["Command"]
subprocess.Popen(lCMDCode)
lResultCMDRun=1#os.system(lCMDCode)
lItem["Result"] = str(lResultCMDRun)
###########################################################
#Обработка команды OrchestratorRestart
###########################################################
if lItem["Type"]=="OrchestratorRestart":
# Dump RDP List in file json
lFile = open("_SessionLast_RDPList.json", "w", encoding="utf-8")
lFile.write(json.dumps(gSettingsDict["RobotRDPActive"]["RDPList"])) # dump json to file
lFile.close() # Close the file
if lL: lL.info(f"Orchestrator has dump the RDP list before the restart. The RDP List is {gSettingsDict['RobotRDPActive']['RDPList']}. Do restart")
# Restart session
os.execl(sys.executable, os.path.abspath(__file__), *sys.argv)
lItem["Result"] = True
sys.exit(0)
###########################################################
# Обработка команды OrchestratorSessionSave
###########################################################
if lItem["Type"] == "OrchestratorSessionSave":
# Dump RDP List in file json
lFile = open("_SessionLast_RDPList.json", "w", encoding="utf-8")
lFile.write(json.dumps(gSettingsDict["RobotRDPActive"]["RDPList"])) # dump json to file
lFile.close() # Close the file
if lL: lL.info(
f"Orchestrator has dump the RDP list before the restart. The RDP List is {gSettingsDict['RobotRDPActive']['RDPList']}")
lItem["Result"] = True
###########################################################
#Обработка команды GlobalDictKeyListValueSet
###########################################################
if lItem["Type"]=="GlobalDictKeyListValueSet":
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
#Check if key - value exists
if lItem2 in lDict:
pass
else:
lDict[lItem2]={}
lDict=lDict[lItem2]
#Set value
lDict[lItem["KeyList"][-1]]=lItem["Value"]
lItem["Result"] = True
###########################################################
# Обработка команды GlobalDictKeyListValueAppend
###########################################################
if lItem["Type"] == "GlobalDictKeyListValueAppend":
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
# Check if key - value exists
if lItem2 in lDict:
pass
else:
lDict[lItem2] = {}
lDict = lDict[lItem2]
# Set value
lDict[lItem["KeyList"][-1]].append(lItem["Value"])
lItem["Result"] = True
###########################################################
# Обработка команды GlobalDictKeyListValueOperator+
###########################################################
if lItem["Type"] == "GlobalDictKeyListValueOperator+":
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
# Check if key - value exists
if lItem2 in lDict:
pass
else:
lDict[lItem2] = {}
lDict = lDict[lItem2]
# Set value
lDict[lItem["KeyList"][-1]]+=lItem["Value"]
lItem["Result"] = True
###########################################################
#Обработка команды GlobalDictKeyListValueGet
###########################################################
if lItem["Type"]=="GlobalDictKeyListValueGet":
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
#Check if key - value exists
if lItem2 in lDict:
pass
else:
lDict[lItem2]={}
lDict=lDict[lItem2]
#Return value
lItem["Result"]=lDict.get(lItem["KeyList"][-1],None)
#####################################
#ProcessStart
#####################################
if lItem["Type"]=="ProcessStart":
#Вид активности - запуск процесса
#Запись в массив отработанных активностей
#Запустить процесс
lItemArgs=[lItem["Path"]]
lItemArgs.extend(lItem["ArgList"])
subprocess.Popen(lItemArgs,shell=True)
#####################################
#ProcessStartIfTurnedOff
#####################################
if lItem["Type"]=="ProcessStartIfTurnedOff":
#Check if process running
#remove .exe from Taskname if exists
lCheckTaskName = lItem["CheckTaskName"]
if len(lCheckTaskName)>4:
if lCheckTaskName[-4:].upper() != ".EXE":
lCheckTaskName = lCheckTaskName+".exe"
else:
lCheckTaskName = lCheckTaskName+".exe"
#Check if process exist
if not CheckIfProcessRunning(lCheckTaskName):
#Вид активности - запуск процесса
#Запись в массив отработанных активностей
#Запустить процесс
lItemArgs=[lItem["Path"]]
lItemArgs.extend(lItem["ArgList"])
subprocess.Popen(lItemArgs,shell=True)
#################################
#ProcessStop
#################################
if lItem["Type"]=="ProcessStop":
#Вид активности - остановка процесса
#часовой пояс пока не учитываем
#Сформировать команду на завершение
lActivityCloseCommand='taskkill /im '+lItem["Name"]
#TODO Сделать безопасную обработку,если параметра нет в конфигурации
if lItem.get('FlagForce',False):
lActivityCloseCommand+=" /F"
#Завершить процессы только текущего пользоваиеля
if lItem.get('User',"")!="":
lActivityCloseCommand+=f' /fi "username eq {lItem["User"]}"'
#Завершить процесс
os.system(lActivityCloseCommand)
#################################
#PythonStart
#################################
if lItem["Type"]=="PythonStart":
try:
#Подключить модуль для вызова
lModule=importlib.import_module(lItem["ModuleName"])
#Найти функцию
lFunction=getattr(lModule,lItem["FunctionName"])
lItem["Result"]=lFunction(*lItem.get("ArgList",[]),**lItem.get("ArgDict",{}))
except Exception as e:
if lL: lL.exception("Loop activity error: module/function not founded")
#################################
# Windows logon
#################################
if lItem["Type"] == "WindowsLogon":
import win32security
try:
hUser = win32security.LogonUser(
lItem["User"],
lItem["Domain"],
lItem["Password"],
win32security.LOGON32_LOGON_NETWORK,
win32security.LOGON32_PROVIDER_DEFAULT
)
except win32security.error:
lItem["Result"] = False
else:
lItem["Result"] = True
###################################
#Вернуть результат
return lItem
time.sleep(inGSettings["ProcessorDict"]["CheckIntervalSecFloat"]) # Sleep when list is empty
# Execute ActivityItem list
# return the def result
def ActivityListExecute(inGSettings, inActivityList):
lL = inGSettings["Logger"] # Logger alias
lResultList = [] # init the result list
try:
for lActivityItem in inActivityList: # Iterate throught the activity list
if lL: lL.info(f'pyOpenRPA Processor.ActivityListExecute:: Def:{str(lActivityItem["Def"])}. Parameters are not available to see.')
lDef = None # Def variable
if callable(lActivityItem["Def"]): # CHeck if def is callable
lDef = lActivityItem["Def"] # Get the def
else: # Is not callable - check alias
lDef = inGSettings["ProcessorDict"]["AliasDefDict"].get(lActivityItem["Def"], None) # get def if def key in Alias def storage
#gSettings
lGSettingsDictKey = lActivityItem.pop("ArgGSettings",None)
# # Prepare arg dict - gSettings
if type(lGSettingsDictKey) is str and lGSettingsDictKey is not "": # check if gSetting key is in ArgDict 13.02.2021 - Fix when ArgGSettings is ""
lActivityItem["ArgDict"][lGSettingsDictKey] = inGSettings # Set the gSettings in dict
# # Prepare arg list
elif type(lGSettingsDictKey) is int: # check if gSetting key is in ArgDict
lActivityItem["ArgList"].insert(lGSettingsDictKey,inGSettings)# Set the gSettings in list by the index
#Logger
lLoggerDictKey = lActivityItem.pop("ArgLogger",None)
# # Prepare arg dict - Logger
if type(lLoggerDictKey) is str and lLoggerDictKey is not "": # check if gSetting key is in ArgDict 13.02.2021 - Fix when ArgLogger is ""
lActivityItem["ArgDict"][lLoggerDictKey] = lL # Set the lLogger in dict
# # Prepare arg list
elif type(lLoggerDictKey) is int: # check if gSetting key is in ArgDict
lActivityItem["ArgList"].insert(lLoggerDictKey,lL)# Set the lLogger in list by the index
try: # try to run function from Processor.py
lActivityItemResult = lDef(*lActivityItem["ArgList"], **lActivityItem["ArgDict"])
lResultList.append(lActivityItemResult) # return the result
except Exception as e:
if lL: lL.exception(f"pyOpenRPA Processor.ActivityListExecute: Exception in def execution - activity will be ignored.") # Logging
lResultList.append(e) # return the generated exception
except Exception as e:
if lL: lL.exception(f"pyOpenRPA Processor.ActivityListExecute: Exception when initialisation - All activity list will be ignored.") # Logging
return lResultList # return the result list
def __ActivityListVerify__(inActivityList):
"""
Verify ActivityList variable - raise exception if input list is not list of dict with structure:
# "Def":"DefAliasTest", # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
# "ArgList":[1,2,3], # Args list
# "ArgDict":{"ttt":1,"222":2,"dsd":3}, # Args dictionary
# "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
def ActivityListOrDict(inActivityListOrDict):
#Check arg type (list or dict)
if type(inActivityListOrDict)==list:
#List activity
lResult=[]
for lItem in inActivityListOrDict:
lResult.append(Activity(lItem))
return lResult
if type(inActivityListOrDict)==dict:
#Dict activity
return Activity(inActivityListOrDict)
def CheckIfProcessRunning(processName):
'''
Check if there is any running process that contains the given name processName.
'''
#Iterate over the all the running process
for proc in psutil.process_iter():
try:
# Check if process name contains the given name string.
if processName.lower() in proc.name().lower():
return True
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
return False;
:param inActivityList:
:return:
"""
# CASE LIST
if type(inActivityList) is list:
for lItem in inActivityList:
# CASE LIST item is LIST
if type(lItem) is list:
raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Your ActivityList item is list too. List of the list :(")
# CASE Item is not dict
if type(lItem) is not dict:
raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Your ActivityList item is is not dict")
# CASE HAS NO "Def"
if "Def" not in lItem:
raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Activity item has no attribute 'Def'")
#CASE NOT LIST
else:
raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Your ActivityList is not a list.")

@ -245,6 +245,7 @@ def SessionCMDRun(inSessionHex,inCMDCommandStr = "echo 1", inModeStr="CROSSCHECK
# Exit fullscreen mode
SessionScreenSize_X_Y_W_H(inSessionHex=inSessionHex, inXInt=10, inYInt=10, inWInt=550,
inHInt=350) # Prepare little window
return lResult
# Check if session is in Full screen mode
# Return True - is in fullscreen
# example print(Connector.SessionIsFullScreen(""))
@ -305,11 +306,12 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
Clipboard.TextSet(lClipboardTextOld)
lCrosscheckKeyStr = str(random.randrange(999,9999999))
lRecoveryCMDResponsibleRetryIteratorInt = 0 # Init the retry iterator
lCommandIsTooBigBool = False
lCMDPostFixStr = "" # Case default "RUN"
while lRecoveryCMDResponsibleRetryIteratorInt<gRecoveryCMDResponsibleRetryCountInt: # loop for retry
# # # # # # # # # # # # # OPEN WINDOW RUN # # # # # # # # # # # # # # #
lRecoveryWindowRUNRetryIteratorInt = 0 # Init the retry iterator
while lRecoveryWindowRUNRetryIteratorInt<gRecoveryWindowRUNRetryCountInt: # loop for retry
lCMDPostFixStr = "" # Case default "RUN"
if inModeStr == "CROSSCHECK":
#lCMDPostFixStr = f"& (echo {lCrosscheckKeyStr} | clip)"
lCMDPostFixStr = f"| (echo {lCrosscheckKeyStr} | clip)" # Bugfix async set clipboard data
@ -324,7 +326,14 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
keyboard.send("backspace") # Delete selected all
time.sleep(gKeyboardHotkeyDelaySecFloat) # Wait for RUN window will appear ctrl+a+backspace is async - so we need some timeout...
lInputStr = f"cmd /c ({inCMDCommandStr}) {lCMDPostFixStr}" # Generate the output string for RUN window
keyboard.write(lInputStr) # Write new text
if len(lInputStr) <= 259:
keyboard.write(lInputStr) # Write new text
else:
if lL: lL.warning(
f"RDP.SystemCMDRun: ATTENTION! Your command is too big for the RUN window (len is {len(lInputStr)}). Orchestrator will send this command to the new cmd window. ")
lInputStr = "cmd"
lCommandIsTooBigBool = True
keyboard.write(lInputStr) # Write cmd
time.sleep(gKeyboardHotkeyDelaySecFloat)
# Check if autocomplete
# # # # # # #
@ -348,26 +357,38 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
if lClipboardStr == lInputStr: # Cross check the clipboard data and input string
lRecoveryWindowRUNRetryIteratorInt = gRecoveryWindowRUNRetryCountInt # Set final count to block the loop
else: # Failed - wait and retry
if lL: lL.warning(f"RDP::SystemCMDRun: Window run doesn't appear. Wait for {gRecoveryWindowRUNRetryIntervalSecInt}[s.] and retry. Current retry iterator is {lRecoveryWindowRUNRetryIteratorInt}. CMD Str: {lInputStr}") # Log the error
if lL: lL.warning(f"RDP::SystemCMDRun: RUN window (win+r) doesn't appear. Wait for {gRecoveryWindowRUNRetryIntervalSecInt}[s.] and retry. Current retry iterator is {lRecoveryWindowRUNRetryIteratorInt}. CMD Str: {lInputStr}") # Log the error
lRecoveryWindowRUNRetryIteratorInt = lRecoveryWindowRUNRetryIteratorInt + 1 # Increment the iterator
if lRecoveryWindowRUNRetryIteratorInt == gRecoveryWindowRUNRetryCountInt:
if lL: lL.warning(f"RDP::SystemCMDRun: Retry count is over. Raise the error. CMD Str: {lInputStr}") # Log the error
if lL: lL.warning(f"RDP::SystemCMDRun: RUN window (win+r) retry count is over. Raise the error. CMD Str: {lInputStr}") # Log the error
raise ConnectorExceptions.RUNExistError() # Raise the error
time.sleep(gRecoveryWindowRUNRetryIntervalSecInt) # wait for some seconds before new iteration
# # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # RUN CMD # # # # # # # # # # # # # # #
if inModeStr == "LISTEN": # if mode == LISTEN - set random number in clipboard
Clipboard.TextSet(lClipboardTextOld) #
time.sleep(0.5) # wait some time for the next operation
keyboard.press_and_release('enter') # Execute CMD
time.sleep(1)
if lCommandIsTooBigBool == True:
# Case when string is tool big - call cmd and then type text into
#keyboard.write("cmd") # Open cmd
#time.sleep(1)
#keyboard.press_and_release('enter') # Execute CMD
keyboard.write(f"(({inCMDCommandStr}) {lCMDPostFixStr}) && exit", delay=0.05) # send command
time.sleep(1)
keyboard.press_and_release('enter') # Execute command
if inModeStr == "CROSSCHECK" or inModeStr == "LISTEN": # Get OutStr (Case CROSSCHECK and LISTEN)
lClipboardWaitTimeStartSec = time.time()
lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard
while lResult["OutStr"] == lClipboardTextOld and (time.time() - lClipboardWaitTimeStartSec) <= inClipboardTimeoutSec:
while lResult["OutStr"].startswith(lClipboardTextOld) and (time.time() - lClipboardWaitTimeStartSec) <= inClipboardTimeoutSec:
lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard
time.sleep(0.5) # wait some time for the next operation
if lResult["OutStr"] == lClipboardTextOld: # If value hasn't been changed - retry send
lRecoveryCMDResponsibleRetryIteratorInt = lRecoveryCMDResponsibleRetryIteratorInt + 1 # increment the iterator
if lL: lL.warning(f"RDP::SystemCMDRun: CMD command doesn't been executed (no changes in clipboard data). Wait for {gRecoveryCMDResponsibleRetryIntervalSecInt}[s.] and retry from start window RUN. Current retry iterator is {lRecoveryCMDResponsibleRetryIteratorInt}. CMD Str: {lInputStr}, Clipboard data: {lResult['OutStr']}") # Log the error
if lRecoveryCMDResponsibleRetryIteratorInt >= gRecoveryCMDResponsibleRetryCountInt: # raise the error if retry count is exceeded
if lL: lL.warning(f"RDP::SystemCMDRun: Retry count is over. Raise the error.") # Log the error
if lL: lL.warning(f"RDP::SystemCMDRun: CMD command retry count is over. Raise the error.") # Log the error
raise ConnectorExceptions.CMDResponsibleError() # Raise the error
time.sleep(gRecoveryCMDResponsibleRetryIntervalSecInt) # wait for some seconds before new iteration
else: # Data was recieved - do crosscheck
@ -380,7 +401,7 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
lRecoveryCMDResponsibleRetryIteratorInt = lRecoveryCMDResponsibleRetryIteratorInt + 1 # increment the iterator
if lL: lL.warning(f"RDP::SystemCMDRun: CMD command doesn't been executed (wrong clipboard data). Wait for {gRecoveryCMDResponsibleRetryIntervalSecInt}[s.] and retry from start window RUN. Current retry iterator is {lRecoveryCMDResponsibleRetryIteratorInt}. CMD Str: {lInputStr}, Clipboard data: {lResult['OutStr']}") # Log the error
if lRecoveryCMDResponsibleRetryIteratorInt >= gRecoveryCMDResponsibleRetryCountInt: # raise the error if retry count is exceeded
if lL: lL.warning(f"RDP::SystemCMDRun: Retry count is over. Raise the error.") # Log the error
if lL: lL.warning(f"RDP::SystemCMDRun: CMD command retry count is over. Raise the error.") # Log the error
raise ConnectorExceptions.CMDResponsibleError() # Raise the error
time.sleep(gRecoveryCMDResponsibleRetryIntervalSecInt) # wait for some seconds before new iteration
else: # clipboard data has been changed but mode is not crosscheck - return success from function

@ -5,7 +5,8 @@ from . import ConnectorExceptions # Exceptions classes
from . import Connector
from . import Processor # Module for process some functions on thr RDP
# Main function
def RobotRDPActive(inGSettings):
# inThreadControlDict = {"ThreadExecuteBool":True}
def RobotRDPActive(inGSettings, inThreadControlDict):
# inGSettings = {
# ... "RobotRDPActive": {} ...
# }
@ -36,100 +37,91 @@ def RobotRDPActive(inGSettings):
lResponsibilityCheckLastSec = time.time() # Get current time for check interval
while lFlagWhile:
try:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check RDP window is OK - reconnect if connection was lost
lUIOSelectorList = []
lRDPConfigurationDictList = []
# Prepare selectors list for check
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
lRDPConfigurationDictList.append(lItem) # Add RDP Configuration in list
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
# Run wait command
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
for lItem in lRDPDissappearList: # Reconnect if connection was lost
lRDPConfigurationDict = lRDPConfigurationDictList[lItem] # Get RDP Configuration list
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
# Check if RDP window is not ignored
if not lRDPConfigurationDict["SessionIsIgnoredBool"]:
try:
Connector.Session(lRDPConfigurationDict, inScreenSize550x350Bool = True)
lRDPConfigurationDict["SessionIsWindowExistBool"] = True # Flag that session is started
if lL: lL.info(f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!") #Logging
# catch ConnectorExceptions.SessionWindowNotExistError
except ConnectorExceptions.SessionWindowNotExistError as e:
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
if lL: lL.warning(f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist!") #Logging
# general exceptions
except Exception as e:
if lL: lL.exception(f"!!! ATTENTION !!! Unrecognized error") #Logging
pass
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Safe turn off the - no need because of Orchestrator control
#if inGlobalDict.get("OrchestratorToRobotResetStorage", {}).get("SafeTurnOff", False):
# lFlagWhile = False
# # Set status disconnected for all RDP List
# for lItem in inGlobalDict["RDPList"]:
# lItem["SessionIsWindowExistBool"] = False
# lItem["SessionIsWindowResponsibleBool"] = False
# # Kill all RDP sessions
# os.system('taskkill /F /im mstsc.exe')
# # Return from function
# return
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Connector.SystemRDPWarningClickOk() # Click all warning messages
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check if RDP session is full screen (if is not ignored)
if inGlobalDict["FullScreenRDPSessionKeyStr"] is not None:
lRDPSessionKeyStr = inGlobalDict["FullScreenRDPSessionKeyStr"] # Get the RDPSessionKeyStr
if lRDPSessionKeyStr in inGlobalDict["RDPList"]: # Session Key is in dict
lRDPConfigurationDict = inGlobalDict["RDPList"][lRDPSessionKeyStr]
#if not lRDPConfigurationDict["SessionIsIgnoredBool"]: # Session is not ignored
# Check if full screen
lIsFullScreenBool = Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDict["SessionHex"])
if not lIsFullScreenBool: # If not the full screen
# Check all RDP window and minimize it
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]):
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"], inXInt=10, inYInt=10,
inWInt=550,
inHInt=350) # Prepare little window
# Set full screen for new window
Connector.SessionScreenFull(inSessionHex=lRDPConfigurationDict["SessionHex"], inLogger= inGSettings["Logger"], inRDPConfigurationItem=inGlobalDict["RDPList"][lRDPSessionKeyStrItem])
else:
# Check all RDP window and minimize it
if inThreadControlDict["ThreadExecuteBool"] == True:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check RDP window is OK - reconnect if connection was lost
lUIOSelectorList = []
lRDPConfigurationDictList = []
# Prepare selectors list for check
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]) or Connector.SessionIsMinimizedScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]): # If window is minimized - restore # if window in full screen - resize
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"],
inXInt=10, inYInt=10,
inWInt=550,
inHInt=350) # Prepare little window
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Iterate the activity list in robot RDP active
lActivityListNew = []
lActivityListOld = inGlobalDict["ActivityList"]
inGlobalDict["ActivityList"] = []
for lActivityItem in lActivityListOld:
lSubmoduleFunctionName = lActivityItem["DefNameStr"]
if lSubmoduleFunctionName in dir(Processor):
lActivityItemResult = None # init the variable
try: # try to run function from Processor.py
lActivityItemResult = getattr(Processor, lSubmoduleFunctionName)(
*lActivityItem["ArgList"], **lActivityItem["ArgDict"])
except Exception as e:
if lL: lL.exception(f"RDP::main: Exception when run def in processor.py - activity will be ignored. Activity item: {lActivityItem}") #Logging
lActivityItemResult = True # True - clear from repeat list
lActivityItemResultType = type(lActivityItemResult)
# Check if Result is bool
if lActivityItemResultType is bool:
if not lActivityItemResult:
# Activity is not done - add to list (retry in future)
lActivityListNew.append(lActivityItem)
inGlobalDict["ActivityList"] = lActivityListNew # Override the value
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
lItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
lRDPConfigurationDictList.append(lItem) # Add RDP Configuration in list
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
# Run wait command
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
for lItem in lRDPDissappearList: # Reconnect if connection was lost
lRDPConfigurationDict = lRDPConfigurationDictList[lItem] # Get RDP Configuration list
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
# Check if RDP window is not ignored
if not lRDPConfigurationDict["SessionIsIgnoredBool"]:
try:
Connector.Session(lRDPConfigurationDict, inScreenSize550x350Bool = True)
lRDPConfigurationDict["SessionIsWindowExistBool"] = True # Flag that session is started
if lL: lL.info(f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!") #Logging
# catch ConnectorExceptions.SessionWindowNotExistError
except ConnectorExceptions.SessionWindowNotExistError as e:
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
if lL: lL.warning(f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist!") #Logging
# general exceptions
except Exception as e:
if lL: lL.exception(f"!!! ATTENTION !!! Unrecognized error") #Logging
pass
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Connector.SystemRDPWarningClickOk() # Click all warning messages
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check if RDP session is full screen (if is not ignored)
if inGlobalDict["FullScreenRDPSessionKeyStr"] is not None:
lRDPSessionKeyStr = inGlobalDict["FullScreenRDPSessionKeyStr"] # Get the RDPSessionKeyStr
if lRDPSessionKeyStr in inGlobalDict["RDPList"]: # Session Key is in dict
lRDPConfigurationDict = inGlobalDict["RDPList"][lRDPSessionKeyStr]
#if not lRDPConfigurationDict["SessionIsIgnoredBool"]: # Session is not ignored
# Check if full screen
lIsFullScreenBool = Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDict["SessionHex"])
if not lIsFullScreenBool: # If not the full screen
# Check all RDP window and minimize it
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]):
if inThreadControlDict["ThreadExecuteBool"] == True: # TEST FEATURE BEFORE ONE THREAD INTEGRATION
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"], inXInt=10, inYInt=10,
inWInt=550,
inHInt=350) # Prepare little window
# Set full screen for new window
if inThreadControlDict["ThreadExecuteBool"] == True: # TEST FEATURE BEFORE ONE THREAD INTEGRATION
Connector.SessionScreenFull(inSessionHex=lRDPConfigurationDict["SessionHex"], inLogger= inGSettings["Logger"], inRDPConfigurationItem=inGlobalDict["RDPList"][lRDPSessionKeyStrItem])
else:
# Check all RDP window and minimize it
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]) or Connector.SessionIsMinimizedScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]): # If window is minimized - restore # if window in full screen - resize
if inThreadControlDict["ThreadExecuteBool"] == True: # TEST FEATURE BEFORE ONE THREAD INTEGRATION
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"],
inXInt=10, inYInt=10,
inWInt=550,
inHInt=350) # Prepare little window
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Iterate the activity list in robot RDP active
lActivityListNew = []
lActivityListOld = inGlobalDict["ActivityList"]
inGlobalDict["ActivityList"] = []
for lActivityItem in lActivityListOld:
lSubmoduleFunctionName = lActivityItem["DefNameStr"]
if lSubmoduleFunctionName in dir(Processor):
lActivityItemResult = None # init the variable
try: # try to run function from Processor.py
lActivityItemResult = getattr(Processor, lSubmoduleFunctionName)(
*lActivityItem["ArgList"], **lActivityItem["ArgDict"])
except Exception as e:
if lL: lL.exception(f"RDP::main: Exception when run def in processor.py - activity will be ignored. Activity item: {lActivityItem}") #Logging
lActivityItemResult = True # True - clear from repeat list
lActivityItemResultType = type(lActivityItemResult)
# Check if Result is bool
if lActivityItemResultType is bool:
if not lActivityItemResult:
# Activity is not done - add to list (retry in future)
lActivityListNew.append(lActivityItem)
inGlobalDict["ActivityList"] = lActivityListNew # Override the value
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
except RuntimeError as e:
# case noGUI error passed - do nothing
if lL: lL.warning(f"Host session has lost the GUI") #Logging

@ -11,7 +11,8 @@ from socketserver import ThreadingMixIn
import threading
import json
from threading import Thread
from . import Processor
from . import Processor # Add new processor
from . import ProcessorOld # Support old processor - deprecated defs only for backward compatibility
import urllib.parse # decode URL in string
import importlib
import pdb
@ -22,9 +23,26 @@ import os #for path operations
from http import cookies
global gSettingsDict
from . import ServerSettings
from . import __Orchestrator__
import copy
# Tool to merge complex dictionaries
def __ComplexDictMerge2to1__(in1Dict, in2Dict):
lPathList=None
if lPathList is None: lPathList = []
for lKeyStr in in2Dict:
if lKeyStr in in1Dict:
if isinstance(in1Dict[lKeyStr], dict) and isinstance(in2Dict[lKeyStr], dict):
__ComplexDictMerge2to1__(in1Dict[lKeyStr], in2Dict[lKeyStr])
elif in1Dict[lKeyStr] == in2Dict[lKeyStr]:
pass # same leaf value
else:
raise Exception('Conflict at %s' % '.'.join(lPathList + [str(lKeyStr)]))
else:
in1Dict[lKeyStr] = in2Dict[lKeyStr]
return in1Dict
#Authenticate function ()
# return dict
# {
@ -41,10 +59,10 @@ def AuthenticateVerify(inRequest):
lCookieAuthToken = lCookies.get("AuthToken", "").value
if lCookieAuthToken:
#Find AuthToken in GlobalDict
if lCookieAuthToken in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
if lCookieAuthToken in gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
#Auth Token Has Been Founded
lResult["Domain"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
lResult["Domain"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
#Set auth token
inRequest.OpenRPA["AuthToken"] = lCookieAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"]
@ -63,26 +81,18 @@ def AuthenticateVerify(inRequest):
if "\\" in lUser:
lDomain = lUser.split("\\")[0]
lUser = lUser.split("\\")[1]
#Try to logon - use processor
lLogonResult = Processor.Activity(
{
"Type": "WindowsLogon",
"Domain": lDomain,
"User": lUser,
"Password": lPassword
}
)
lLogonBool = __Orchestrator__.OSCredentialsVerify(inUserStr=lUser, inPasswordStr=lPassword, inDomainStr=lDomain)
#Check result
if lLogonResult["Result"]:
lResult["Domain"] = lLogonResult["Domain"]
lResult["User"] = lLogonResult["User"]
if lLogonBool:
lResult["Domain"] = lDomain
lResult["User"] = lUser
#Create token
lAuthToken=str(uuid.uuid1())
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
#Set-cookie
inRequest.OpenRPA["AuthToken"] = lAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"]
@ -123,13 +133,14 @@ def UserAccessCheckBefore(inMethod, inRequest):
#go next if user is identified
lUserDict = None
if lAuthToken:
lUserDict = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
lUserDict = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
#pdb.set_trace()
########################################
########################################
#Check general before rule (without User domain)
#Check rules
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []):
inRuleMatchURLList = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", [])
for lAccessRuleItem in inRuleMatchURLList:
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
@ -161,31 +172,35 @@ def UserAccessCheckBefore(inMethod, inRequest):
#Check access by User Domain
#Check rules to find first appicable
#Check rules
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []):
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
if lAccessRuleItem["Method"].upper() == inMethod:
#check Match type variant: BeginWith
if lAccessRuleItem["MatchType"].upper() == "BEGINWITH":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
lMethodMatchURLList = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", [])
if len(lMethodMatchURLList) > 0:
for lAccessRuleItem in lMethodMatchURLList:
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
if lAccessRuleItem["Method"].upper() == inMethod:
#check Match type variant: BeginWith
if lAccessRuleItem["MatchType"].upper() == "BEGINWITH":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
else:
return True
#####################################
#####################################
#Return lResult
@ -193,6 +208,8 @@ def UserAccessCheckBefore(inMethod, inRequest):
# HTTPRequestHandler class
class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Def to check User Role access grants
def UACClientCheck(self, inRoleKeyList): # Alias
return self.UserRoleAccessAsk(inRoleKeyList=inRoleKeyList)
def UserRoleAccessAsk(self, inRoleKeyList):
lResult = True # Init flag
lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy
@ -218,7 +235,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
def UserRoleHierarchyGet(self):
lDomainUpperStr = self.OpenRPA["Domain"].upper()
lUserUpperStr = self.OpenRPA["User"].upper()
return gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lDomainUpperStr, lUserUpperStr), {}).get("RoleHierarchyAllowedDict", {})
return gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lDomainUpperStr, lUserUpperStr), {}).get("RoleHierarchyAllowedDict", {})
#Tech def
#return {"headers":[],"body":"","statuscode":111}
@ -316,152 +333,168 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Write content as utf-8 data
self.wfile.write(inResponseDict["Body"])
def do_GET(self):
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
#####################################
#Do authentication
#Check if authentication is turned on
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
# Logging
# gSettingsDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
else:
#Check the user access (if flag)
####################################
lFlagUserAccess = True
#If need user authentication
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("GET", self)
######################################
if lFlagUserAccess:
lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1])
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in gSettingsDict["Server"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET")
if lFlagURLIsApplied:
self.ResponseDictSend()
return
#Monitor
if self.path == '/Monitor/JSONDaemonListGet':
try:
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
#####################################
#Do authentication
#Check if authentication is turned on
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
# Logging
# gSettingsDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
else:
#Check the user access (if flag)
####################################
lFlagUserAccess = True
#If need user authentication
if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("GET", self)
######################################
if lFlagUserAccess:
lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1])
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in gSettingsDict["ServerDict"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET")
if lFlagURLIsApplied:
self.ResponseDictSend()
return
#Monitor
if self.path == '/Monitor/JSONDaemonListGet':
# Send response status code
self.send_response(200)
# Send headers
self.send_header('Content-type','application/json')
self.end_headers()
# Send message back to client
message = json.dumps(gSettingsDict)
# Write content as utf-8 data
self.wfile.write(bytes(message, "utf8"))
#Filemanager function
if self.path.lower().startswith('/filemanager/'):
lFileURL=self.path[13:]
# check if file in FileURL - File Path Mapping Dict
if lFileURL.lower() in gSettingsDict["FileManager"]["FileURLFilePathDict"]:
self.SendResponseContentTypeFile('application/octet-stream', gSettingsDict["FileManager"]["FileURLFilePathDict"][lFileURL])
else:
#Set access denied code
# Send response status code
self.send_response(200)
self.send_response(403)
# Send headers
self.send_header('Content-type','application/json')
self.end_headers()
# Send message back to client
message = json.dumps(gSettingsDict)
# Write content as utf-8 data
self.wfile.write(bytes(message, "utf8"))
#Filemanager function
if self.path.lower().startswith('/filemanager/'):
lFileURL=self.path[13:]
# check if file in FileURL - File Path Mapping Dict
if lFileURL.lower() in gSettingsDict["FileManager"]["FileURLFilePathDict"]:
self.SendResponseContentTypeFile('application/octet-stream', gSettingsDict["FileManager"]["FileURLFilePathDict"][lFileURL])
else:
#Set access denied code
# Send response status code
self.send_response(403)
# Send headers
self.end_headers()
except Exception as e:
lL = gSettingsDict["Logger"]
if lL: lL.exception(f"Server.do_GET: Global error handler - look traceback below.")
# POST
def do_POST(self):
lL = gSettingsDict["Logger"]
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
#pdb.set_trace()
lResponseDict = {"Headers": {}, "SetCookies":{}, "Body": b"", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
#####################################
#Do authentication
#Check if authentication is turned on
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
lIsSuperToken = False # Is supertoken
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
# Get Flag is supertoken (True|False)
lIsSuperToken = gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(
self.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
else:
#Check the user access (if flag)
####################################
lFlagUserAccess = True
#If need user authentication
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("POST", self)
######################################
if lFlagUserAccess:
lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1])
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in gSettingsDict["Server"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST")
if lFlagURLIsApplied:
self.ResponseDictSend()
return
#Централизованная функция получения запросов/отправки
if self.path == '/Utils/Processor':
#ReadRequest
lInputObject={}
if self.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(self.headers.get('Content-Length'))
lInputByteArray=self.rfile.read(lInputByteArrayLength)
#Превращение массива байт в объект
lInputObject=json.loads(lInputByteArray.decode('utf8'))
try:
lL = gSettingsDict["Logger"]
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
#pdb.set_trace()
lResponseDict = {"Headers": {}, "SetCookies":{}, "Body": b"", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
#####################################
#Do authentication
#Check if authentication is turned on
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
lIsSuperToken = False # Is supertoken
if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
# Get Flag is supertoken (True|False)
lIsSuperToken = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(self.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
else:
#Check the user access (if flag)
####################################
lFlagUserAccess = True
#If need user authentication
if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("POST", self)
######################################
if lFlagUserAccess:
lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1])
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in gSettingsDict["ServerDict"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST")
if lFlagURLIsApplied:
self.ResponseDictSend()
return
#Централизованная функция получения запросов/отправки
if self.path == '/Utils/Processor':
#ReadRequest
lInputObject={}
if self.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(self.headers.get('Content-Length'))
lInputByteArray=self.rfile.read(lInputByteArrayLength)
#Превращение массива байт в объект
lInputObject=json.loads(lInputByteArray.decode('utf8'))
# Send response status code
self.send_response(200)
# Send headers
self.send_header('Content-type','application/json')
self.end_headers()
# Logging info about processor activity if not SuperToken ()
if not lIsSuperToken:
lActivityTypeListStr = ""
try:
if type(lInputObject) is list:
for lActivityItem in lInputObject:
lActivityTypeListStr+=f"{lActivityItem['Type']}; "
else:
lActivityTypeListStr += f"{lInputObject['Type']}"
except Exception as e:
lActivityTypeListStr = "Has some error with Activity Type read"
if lL: lL.info(f"Server:: !ATTENTION! /Utils/Processor will be deprecated in future. Use /pyOpenRPA/Processor or /pyOpenRPA/ActivityListExecute. User activity from web. Domain: {self.OpenRPA['Domain']}, Username: {self.OpenRPA['User']}, ActivityType: {lActivityTypeListStr}")
# Send message back to client
message = json.dumps(ProcessorOld.ActivityListOrDict(lInputObject))
# Write content as utf-8 data
self.wfile.write(bytes(message, "utf8"))
return
else:
#Set access denied code
# Send response status code
self.send_response(200)
self.send_response(403)
# Send headers
self.send_header('Content-type','application/json')
self.end_headers()
# Logging info about processor activity if not SuperToken ()
if not lIsSuperToken:
if lL: lL.info(f"Server:: User activity from web. Domain: {self.OpenRPA['Domain']}, Username: {self.OpenRPA['User']}, Activity: {lInputObject}")
# Send message back to client
message = json.dumps(Processor.ActivityListOrDict(lInputObject))
# Write content as utf-8 data
self.wfile.write(bytes(message, "utf8"))
return
else:
#Set access denied code
# Send response status code
self.send_response(403)
# Send headers
self.end_headers()
return
return
except Exception as e:
lL = gSettingsDict["Logger"]
if lL: lL.exception(f"Server.do_POST: Global error handler - look traceback below.")
#Logging
#!Turn it on to stop print in console
#def log_message(self, format, *args):
@ -470,7 +503,7 @@ class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
daemon_threads = True
"""Handle requests in a separate thread."""
def finish_request(self, request, client_address):
request.settimeout(gSettingsDict["Server"]["RequestTimeoutSecFloat"])
request.settimeout(gSettingsDict["ServerDict"]["RequestTimeoutSecFloat"])
# "super" can not be used because BaseServer is not created from object
HTTPServer.finish_request(self, request, client_address)
#inGlobalDict
@ -483,7 +516,7 @@ class RobotDaemonServer(Thread):
ServerSettings.SettingsUpdate(inGlobalDict)
def run(self):
inServerAddress="";
inPort = gSettingsDict["Server"]["ListenPort"];
inPort = gSettingsDict["ServerDict"]["ListenPort"];
# Server settings
# Choose port 8080, for port 80, which is normally used for a http server, you need root access
server_address = (inServerAddress, inPort)

@ -1,5 +1,7 @@
import json
import json, os
import copy
from inspect import signature # For detect count of def args
from . import __Orchestrator__
#ControlPanelDict
from desktopmagic.screengrab_win32 import (
getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage,
@ -9,163 +11,234 @@ import uuid # generate UUID4
import time # sleep functions
import datetime # datetime functions
import threading # Multi-threading
from .Web import Basic
from . import BackwardCompatibility # Support old up to 1.2.0 defs
from . import Processor
from . import SettingsTemplate
# # # # # # # # # # # #
# v 1.2.0 Functionallity
# # # # # # # # # # # #
# 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.
lUACCPTemplateKeyList=["pyOpenRPADict","CPKeyDict"]
lL = inGSettings["Logger"] # Alias for logger
# Create result JSON
lCPDict = {}
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
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":{"",""}}
def HiddenRDPDictGenerate(inRequest, inGSettings):
dUAC = inRequest.UACClientCheck # Alias.
lUACRDPTemplateKeyList=["pyOpenRPADict","RDPKeyDict"]
lRDPDict = {"HandlebarsList":[]}
# Iterate throught the RDP list
for lRDPSessionKeyStrItem in inGSettings["RobotRDPActive"]["RDPList"]:
# Check UAC
if dUAC(inRoleKeyList=lUACRDPTemplateKeyList+[lRDPSessionKeyStrItem]):
lRDPConfiguration = inGSettings["RobotRDPActive"]["RDPList"][
lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr": "", "SessionHexStr": "", "IsFullScreenBool": False,
"IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGSettings["RobotRDPActive"][
"FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lRDPDict[lDataItemDict["SessionKeyStr"]]=lDataItemDict
lHandlebarsDataItemDict = copy.deepcopy(lDataItemDict)
lHandlebarsDataItemDict["SessionKeyStr"]=lDataItemDict["SessionKeyStr"]
lRDPDict["HandlebarsList"].append(lHandlebarsDataItemDict)
return lRDPDict
# Return {"HostNameUpperStr;UserUpperStr":{"IsListenBool":True}, "HandlebarsList":[{"HostnameUpperStr":"","UserUpperStr":"","IsListenBool":True}]}
def HiddenAgentDictGenerate(inRequest, inGSettings):
dUAC = inRequest.UACClientCheck # Alias.
lUACAgentTemplateKeyList=["pyOpenRPADict","AgentKeyDict"]
lAgentDict = {"HandlebarsList":[]}
# Iterate throught the RDP list
for lAgentItemKeyStrItem in inGSettings["AgentDict"]:
# Check UAC
lKeyStr = f"{lAgentItemKeyStrItem[0]};{lAgentItemKeyStrItem[1]}" # turple ("HostNameUpperStr","UserUpperStr") > Str "HostNameUpperStr;UserUpperStr"
if dUAC(inRoleKeyList=lUACAgentTemplateKeyList+[lKeyStr]):
lDataItemDict = inGSettings["AgentDict"][lAgentItemKeyStrItem]
lAgentDict[lKeyStr]=lDataItemDict
lHandlebarsDataItemDict = copy.deepcopy(lDataItemDict)
lHandlebarsDataItemDict["HostnameUpperStr"]=lAgentItemKeyStrItem[0]
lHandlebarsDataItemDict["UserUpperStr"]=lAgentItemKeyStrItem[1]
lAgentDict["HandlebarsList"].append(lHandlebarsDataItemDict)
return lAgentDict
# /Orchestrator/RobotRDPActive/ControlPanelDictGet
def RobotRDPActive_ControlPanelDictGet(inRequest,inGlobalDict):
#v1.2.0 Send data container to the client from the server
# /pyOpenRPA/ServerData return {"HashStr" , "ServerDataDict": {"CPKeyStr":{"HTMLStr":"", DataDict:{}}}}
# Client: mGlobal.pyOpenRPA.ServerDataHashStr
# Client: mGlobal.pyOpenRPA.ServerDataDict
def pyOpenRPA_ServerData(inRequest,inGSettings):
# Extract the hash value from request
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lValueStr = (lInputByteArray.decode('utf8'))
# Generate ServerDataDict
lFlagDoGenerateBool = True
while lFlagDoGenerateBool:
lServerDataDict = {
"CPDict": HiddenCPDictGenerate(inRequest=inRequest, inGSettings=inGSettings),
"RDPDict": HiddenRDPDictGenerate(inRequest=inRequest, inGSettings=inGSettings),
"AgentDict": HiddenAgentDictGenerate(inRequest=inRequest, inGSettings=inGSettings),
"UserDict": {"UACClientDict": inRequest.OpenRPA["DefUserRoleHierarchyGet"](), "CWDPathStr": os.getcwd(), "VersionStr": inGSettings["VersionStr"]},
}
# Create JSON
lServerDataDictJSONStr = json.dumps(lServerDataDict)
# Generate hash
lServerDataHashStr = str(hash(lServerDataDictJSONStr))
if lValueStr!=lServerDataHashStr and lServerDataHashStr!= "" and lServerDataHashStr!= None: # Case if Hash is not equal
lFlagDoGenerateBool = False
else: # Case Hashes are equal
time.sleep(inGSettings["Client"]["Session"]["ControlPanelRefreshIntervalSecFloat"])
# Return the result if Hash is changed
lResult = {"HashStr": lServerDataHashStr, "ServerDataDict": lServerDataDict}
inResponseDict = inRequest.OpenRPAResponseDict
lResultDict = {
"DataList":[
# {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False}
]
}
# Iterate throught the RDP List
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]:
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"]["FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lResultDict["DataList"].append(lDataItemDict)
# Send message back to client
message = json.dumps(lResultDict)
message = json.dumps(lResult)
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
return lResult
# def to check control panels for selected session
def Monitor_ControlPanelDictGet_SessionCheckInit(inRequest,inGlobalDict):
lL = inGlobalDict["Logger"] # Alias for logger
lLifetimeSecFloat = inGlobalDict["Client"]["Session"]["LifetimeSecFloat"]
lLifetimeRequestSecFloat = inGlobalDict["Client"]["Session"]["LifetimeRequestSecFloat"]
lControlPanelRefreshIntervalSecFloat = inGlobalDict["Client"]["Session"]["ControlPanelRefreshIntervalSecFloat"]
lCookieSessionGUIDStr = None # generate the new GUID
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Technicaldef - interval check control panels + check actuality of the session by the datetime
def TechnicalCheck():
lItemValue = inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]
# Lifetime is ok - check control panel
lDatasetCurrentBytes = Monitor_ControlPanelDictGet(inRequest,inGlobalDict) # Call the control panel
if lDatasetCurrentBytes != lItemValue["DatasetLast"]["ControlPanel"]["Data"]: # Check if dataset is changed
lItemValue["DatasetLast"]["ControlPanel"]["Data"] = lDatasetCurrentBytes # Set new datset
lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] = True # Set flag to return the data
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Technicaldef - Create new session struct
def TechnicalSessionNew(inSessionGUIDStr):
lCookieSessionGUIDStr = inSessionGUIDStr # Generate the new GUID
lSessionNew = { # Session with some GUID str. On client session guid stored in cookie "SessionGUIDStr"
"InitDatetime": datetime.datetime.now(), # Datetime when session GUID was created
"DatasetLast": {
"ControlPanel": {
"Data": None, # Struct to check with new iterations. None if starts
"ReturnBool": False # flag to return, close request and return data as json
}
},
"ClientRequestHandler": inRequest, # Last client request handler
"UserADStr": inRequest.OpenRPA["User"], # User, who connect. None if user is not exists
"DomainADStr": inRequest.OpenRPA["Domain"], # Domain of the user who connect. None if user is not exists
}
inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr] = lSessionNew # Set new session in dict
inRequest.OpenRPAResponseDict["SetCookies"]["SessionGUIDStr"] = lCookieSessionGUIDStr # Set SessionGUIDStr in cookies
if lL: lL.info(f"New session GUID is created. GUID {lCookieSessionGUIDStr}")
return lCookieSessionGUIDStr
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
lCreateNewSessionBool = False # Flag to create new session structure
# step 1 - get cookie SessionGUIDStr
lSessionGUIDStr = inRequest.headers.get("SessionGUIDStr", None)
if lSessionGUIDStr is not None: # Check if GUID session is ok
lCookieSessionGUIDStr = lSessionGUIDStr # Get the existing GUID
if lSessionGUIDStr not in inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lCookieSessionGUIDStr= TechnicalSessionNew(inSessionGUIDStr = lSessionGUIDStr) # Create new session
else: # Update the datetime of the request session
inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]["InitDatetime"]=datetime.datetime.now()
else:
lCookieSessionGUIDStr = TechnicalSessionNew(inSessionGUIDStr = lSessionGUIDStr) # Create new session
# Init the RobotRDPActive in another thread
#lThreadCheckCPInterval = threading.Thread(target=TechnicalIntervalCheck)
#lThreadCheckCPInterval.daemon = True # Run the thread in daemon mode.
#lThreadCheckCPInterval.start() # Start the thread execution.
# Step 2 - interval check if data is exist
lTimeStartSecFloat = time.time()
lDoWhileBool = True # Flag to iterate throught the lifetime of the request
while lDoWhileBool:
#print(lTechnicalSessionGUIDCache)
#print(lCookieSessionGUIDStr)
if lCookieSessionGUIDStr in inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lItemValue = inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]
if (time.time() - lTimeStartSecFloat) >= lLifetimeRequestSecFloat: # Check if lifetime client request is over or has no key
if lL: lL.debug(f"Client request lifetime is over")
lDoWhileBool = False # Stop the iterations
if lDoWhileBool:
TechnicalCheck() # Calculate the CP
if lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] == True: # Return data if data flag it True
lDatasetCurrentBytes = lItemValue["DatasetLast"]["ControlPanel"]["Data"] # Set new dataset
inResponseDict = inRequest.OpenRPAResponseDict
inResponseDict["Body"] = lDatasetCurrentBytes
lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] = False # Set flag that data was returned
lDoWhileBool = False # Stop the iterations
else:
lCookieSessionGUIDStr = TechnicalSessionNew(inSessionGUIDStr = lCookieSessionGUIDStr) # Create new session
if lDoWhileBool: # Sleep if we wait hte next iteration
time.sleep(lControlPanelRefreshIntervalSecFloat) # Sleep to the next iteration
def Monitor_ControlPanelDictGet(inRequest,inGlobalDict):
# GET
# /pyOpenRPA/ServerJSInit return JavaScript to init on page
def pyOpenRPA_ServerJSInit(inRequest,inGSettings):
lResultStr = HiddenJSInitGenerate(inRequest=inRequest, inGSettings=inGSettings)
inResponseDict = inRequest.OpenRPAResponseDict
lL = inGlobalDict["Logger"] # Alias for logger
# Create result JSON
lResultJSON = {"RenderRobotList": [], "RenderRDPList": []}
lRenderFunctionsRobotList = inGlobalDict["ControlPanelDict"]["RobotList"]
for lItem in lRenderFunctionsRobotList:
lUACBool = True # Check if render function is applicable User Access Rights (UAC)
if inGlobalDict["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True:
lUserRights = inGlobalDict["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
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"](inGlobalDict)
elif lDEFARGLen == 2: # def (inRequest, inGSettings)
lItemResultDict = lItem["RenderFunction"](inRequest, inGlobalDict)
elif lDEFARGLen == 0: # def ()
lItemResultDict = lItem["RenderFunction"]()
# RunFunction
lResultJSON["RenderRobotList"].append(lItemResultDict)
except Exception as e:
if lL: lL.exception(f"Error in control panel. CP item {lItem}. Exception is below")
# Iterate throught the RDP list
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]:
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][
lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr": "", "SessionHexStr": "", "IsFullScreenBool": False,
"IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"][
"FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lResultJSON["RenderRDPList"].append(lDataItemDict)
# Send message back to client
message = json.dumps(lResultJSON)
# Write content as utf-8 data
#inResponseDict["Body"] = bytes(message, "utf8")
return bytes(message, "utf8")
# UserAccess get rights hierarchy dict in json
def UserRoleHierarchyGet(inRequest,inGlobalDict):
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
# Client: mGlobal.pyOpenRPA.ServerLogList
def pyOpenRPA_ServerLog(inRequest,inGSDict):
# Extract the hash value from request
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lValueStr = (lInputByteArray.decode('utf8'))
# Generate ServerDataDict
lFlagDoGenerateBool = True
while lFlagDoGenerateBool:
lServerLogList = inGSDict["Client"]["DumpLogList"]
# Get hash
lServerLogListHashStr = inGSDict["Client"]["DumpLogListHashStr"]
if lValueStr!=lServerLogListHashStr and lServerLogListHashStr!= "" and lServerLogListHashStr!= None: # Case if Hash is not equal Fix because None can be obtained without JSON decode
lFlagDoGenerateBool = False
else: # Case Hashes are equal
time.sleep(inGSDict["Client"]["DumpLogListRefreshIntervalSecFloat"])
# Return the result if Hash is changed
lResult = {"HashStr": lServerLogListHashStr, "ServerLogList": lServerLogList}
inResponseDict = inRequest.OpenRPAResponseDict
# Create result JSON
lResultDict = inRequest.OpenRPA["DefUserRoleHierarchyGet"]() # Get the User Role Hierarchy list
# Send message back to client
message = json.dumps(lResultDict)
message = json.dumps(lResult)
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
return lResult
def GetScreenshot(inRequest,inGlobalDict):
def pyOpenRPA_Screenshot(inRequest,inGlobalDict):
# Get Screenshot
def SaveScreenshot(inFilePath):
# grab fullscreen
@ -182,6 +255,139 @@ def GetScreenshot(inRequest,inGlobalDict):
inRequest.OpenRPAResponseDict["Body"] = lFileObject.read()
# Закрыть файловый объект
lFileObject.close()
# Add activity item or activity list to the processor queue
# Body is Activity item or Activity List
def pyOpenRPA_Processor(inRequest, inGSettings):
lL = inGSettings["Logger"]
# Recieve the data
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lInput = json.loads(lInputByteArray.decode('utf8'))
# If list - operator plus
if type(lInput) is list:
# Logging info about processor activity if not SuperToken ()
if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings):
lActivityTypeListStr = ""
try:
for lActivityItem in lInput:
lActivityTypeListStr += f"{lActivityItem['Def']}; "
except Exception as e:
lActivityTypeListStr = "Has some error with Activity Type read"
if lL: lL.info(f"ServerSettings.pyOpenRPA_Processor. User activity from web. Domain: {inRequest.OpenRPA['Domain']}, Username: {inRequest.OpenRPA['User']}, ActivityType: {lActivityTypeListStr}")
# Append in list
inGSettings["ProcessorDict"]["ActivityList"]+=lInput
else:
# Logging info about processor activity if not SuperToken ()
if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings):
lActivityTypeListStr = ""
try:
lActivityTypeListStr = lInput['Def']
except Exception as e:
lActivityTypeListStr = "Has some error with Activity Type read"
if lL: lL.info(f"ServerSettings.pyOpenRPA_Processor. User activity from web. Domain: {inRequest.OpenRPA['Domain']}, Username: {inRequest.OpenRPA['User']}, ActivityType: {lActivityTypeListStr}")
# Append in list
inGSettings["ProcessorDict"]["ActivityList"].append(lInput)
# Execute activity list
def pyOpenRPA_ActivityListExecute(inRequest, inGSettings):
# Recieve the data
lL = inGSettings["Logger"]
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lInput = json.loads(lInputByteArray.decode('utf8'))
# If list - operator plus
if type(lInput) is list:
# Logging info about processor activity if not SuperToken ()
if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings):
lActivityTypeListStr = ""
try:
for lActivityItem in lInput:
lActivityTypeListStr += f"{lActivityItem['Def']}; "
except Exception as e:
lActivityTypeListStr = "Has some error with Activity Type read"
if lL: lL.info(f"ServerSettings.pyOpenRPA_ActivityListExecute. User activity from web. Domain: {inRequest.OpenRPA['Domain']}, Username: {inRequest.OpenRPA['User']}, ActivityType: {lActivityTypeListStr}")
# Execution
lResultList = Processor.ActivityListExecute(inGSettings = inGSettings, inActivityList = lInput)
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lResultList), "utf8")
else:
# Logging info about processor activity if not SuperToken ()
if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings):
lActivityTypeListStr = ""
try:
lActivityTypeListStr = lInput['Def']
except Exception as e:
lActivityTypeListStr = "Has some error with Activity Type read"
if lL: lL.info(f"ServerSettings.pyOpenRPA_ActivityListExecute. User activity from web. Domain: {inRequest.OpenRPA['Domain']}, Username: {inRequest.OpenRPA['User']}, ActivityType: {lActivityTypeListStr}")
# Execution
lResultList = Processor.ActivityListExecute(inGSettings = inGSettings, inActivityList = [lInput])
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lResultList[0]), "utf8")
# See docs in Agent (pyOpenRPA.Agent.O2A)
def pyOpenRPA_Agent_O2A(inRequest, inGSettings):
lL = inGSettings["Logger"] # Alias
lConnectionLifetimeSecFloat = 3600.0 # 60 min * 60 sec 3600.0
lTimeStartFloat = time.time()
# Recieve the data
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lInput = json.loads(lInputByteArray.decode('utf8'))
# Check if item is created
lAgentDictItemKeyTurple = (lInput["HostNameUpperStr"],lInput["UserUpperStr"])
if lAgentDictItemKeyTurple not in inGSettings["AgentDict"]:
inGSettings["AgentDict"][lAgentDictItemKeyTurple] = SettingsTemplate.__AgentDictItemCreate__()
lThisAgentDict = inGSettings["AgentDict"][lAgentDictItemKeyTurple]
lThisAgentDict["IsListenBool"]=True # Set is online
lThisAgentDict["ConnectionCountInt"] += 1 # increment connection count
# Test solution
lDoLoopBool = True
while lDoLoopBool:
# Check if lifetime is over
if time.time() - lTimeStartFloat > lConnectionLifetimeSecFloat: # Lifetime is over
lThisAgentDict["IsListenBool"] = False # Set is offline
lDoLoopBool = False
else: # Lifetime is good - do alg
lThisAgentDict["IsListenBool"] = True # Set is online
lQueueList = lThisAgentDict["ActivityList"]
if len(lQueueList)>0:# Do some operations if has queue items
if lL: lL.debug(f'O2A BEFORE: ConnectionCountInt: {lThisAgentDict["ConnectionCountInt"]};ConnectionFirstQueueItemCountInt {lThisAgentDict["ConnectionFirstQueueItemCountInt"]}')
if lThisAgentDict["ConnectionCountInt"] == lThisAgentDict["ConnectionFirstQueueItemCountInt"] + 1:
# POP QUEUE ITEM CONDITION ConnectionCountInt == ConnectionFirstQueueItemCountInt + 1
lActivityItem = lThisAgentDict["ActivityList"].pop(0)
lThisAgentDict["ConnectionFirstQueueItemCountInt"] = 0
if lL: lL.debug(f"Activity was deleted from the list: {lThisAgentDict['ActivityList']}")
else:
lActivityItem = lThisAgentDict["ActivityList"][0]
lThisAgentDict["ConnectionFirstQueueItemCountInt"] += 1
if lL: lL.debug(f"Activity was !not! deleted from the list: {lThisAgentDict['ActivityList']}")
if lL: lL.debug(f'O2A AFTER: ConnectionCountInt: {lThisAgentDict["ConnectionCountInt"]};ConnectionFirstQueueItemCountInt {lThisAgentDict["ConnectionFirstQueueItemCountInt"]}')
# Send QUEUE ITEM
if lL: lL.info(f"Activity item to agent Hostname {lInput['HostNameUpperStr']}, User {lInput['UserUpperStr']}. Activity item: {lActivityItem}")
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lActivityItem), "utf8")
lDoLoopBool = False # CLose the connection
else: # no queue item - sleep for the next iteration
time.sleep(1)
lThisAgentDict["ConnectionCountInt"] -= 1 # Connection go to be closed - decrement the connection count
# See docs in Agent (pyOpenRPA.Agent.A2O)
def pyOpenRPA_Agent_A2O(inRequest, inGSettings):
# Recieve the data
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lInput = json.loads(lInputByteArray.decode('utf8'))
if "LogList" in lInput:
for lLogItemStr in lInput["LogList"]:
inGSettings["Logger"].info(lLogItemStr)
def SettingsUpdate(inGlobalConfiguration):
import os
import pyOpenRPA.Orchestrator
@ -207,10 +413,19 @@ def SettingsUpdate(inGlobalConfiguration):
{"Method":"GET", "URL": "/3rdParty/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.woff2", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\themes\\default\\assets\\fonts\\icons.woff2"), "ResponseContentType": "font/woff2"},
{"Method":"GET", "URL": "/favicon.ico", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "Web\\favicon.ico"), "ResponseContentType": "image/x-icon"},
{"Method":"GET", "URL": "/3rdParty/Handlebars/handlebars-v4.1.2.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Handlebars\\handlebars-v4.1.2.js"), "ResponseContentType": "application/javascript"},
{"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": Monitor_ControlPanelDictGet_SessionCheckInit, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": GetScreenshot, "ResponseContentType": "image/png"},
{"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_Monitor_ControlPanelDictGet_SessionCheckInit, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": pyOpenRPA_Screenshot, "ResponseContentType": "image/png"},
{"Method": "GET", "URL": "/pyOpenRPA_logo.png", "MatchType": "Equal", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\pyOpenRPA_logo.png"), "ResponseContentType": "image/png"},
{"Method": "POST", "URL": "/Orchestrator/UserRoleHierarchyGet", "MatchType": "Equal","ResponseDefRequestGlobal": UserRoleHierarchyGet, "ResponseContentType": "application/json"}
{"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/ProcessorQueueAdd", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Processor, "ResponseContentType": "application/json"},
{"Method": "POST", "URL": "/pyOpenRPA/ActivityListExecute", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ActivityListExecute, "ResponseContentType": "application/json"},
{"Method": "POST", "URL": "/pyOpenRPA/Agent/O2A", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Agent_O2A, "ResponseContentType": "application/json"},
{"Method": "POST", "URL": "/pyOpenRPA/Agent/A2O", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Agent_A2O, "ResponseContentType": "application/json"},
]
inGlobalConfiguration["Server"]["URLList"]=inGlobalConfiguration["Server"]["URLList"]+lURLList
inGlobalConfiguration["ServerDict"]["URLList"]=inGlobalConfiguration["ServerDict"]["URLList"]+lURLList
return inGlobalConfiguration

@ -1,4 +1,5 @@
var mGlobal={}
mGlobal.pyOpenRPA = {}
window.onload=function() {
//document.cookie = "SessionGUIDStr=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
//Render existing data
@ -121,11 +122,17 @@ $(document).ready(function() {
lCMDCode=$(".openrpa-controller-cmd-run-input")[0].value
///Подготовить конфигурацию
lData = [
{"Type":"CMDStart", "Command": lCMDCode }
{
"Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList":[], // Args list
"ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary
"ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
]
$.ajax({
type: "POST",
url: 'Utils/Processor',
url: '/pyOpenRPA/ActivityListExecute',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
@ -221,7 +228,7 @@ $(document).ready(function() {
}
//inHostURI: http://localhost:8081
mGlobal.Monitor.ScreenshotModal.Show=function(inHostURI=" ") {
$('.ui.modal.daemon-screenshot').modal('show');
$('.ui.modal.daemon-screenshot').modal({'onHide':function (inElement) {mGlobal.Monitor.ScreenshotModal.Close();} }).modal('show');
//Функция обновления картинки
lScreenshotUpdate=function() {
@ -276,125 +283,342 @@ $(document).ready(function() {
mGlobal.Monitor.fControlPanelRefresh_TechnicalRender = function()
{
lResponseJSON = mGlobal.Monitor.mDatasetLast
if (lResponseJSON!= null) {
///Escape onclick
/// RenderRobotList
lResponseJSON["RenderRobotList"].forEach(
function(lItem){
if ('FooterButtonX2List' in lItem) {
/// FooterButtonX2List
lItem["FooterButtonX2List"].forEach(
function(lItem2){
if ('OnClick' in lItem) {
lOnClickEscaped = lItem["OnClick"];
lOnClickEscaped = lOnClickEscaped.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
lItem["OnClick"] = lOnClickEscaped;
/// New version of control panels
for (var lKeyStr in lResponseJSON){
if (lKeyStr != "RenderRobotList") { /// Check if not "RenderRobotList"
lCPDict = lResponseJSON[lKeyStr]
/// Render HTML
if ("HTMLStr" in lCPDict) {
}
}
}
/// v1.2.0 Backward compatibility - support old control panels
if ("RenderRobotList" in lResponseJSON) {
///Escape onclick
/// RenderRobotList
lResponseJSON["RenderRobotList"].forEach(
function(lItem){
if ('FooterButtonX2List' in lItem) {
/// FooterButtonX2List
lItem["FooterButtonX2List"].forEach(
function(lItem2){
if ('OnClick' in lItem) {
lOnClickEscaped = lItem["OnClick"];
lOnClickEscaped = lOnClickEscaped.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
lItem["OnClick"] = lOnClickEscaped;
}
}
}
);
/// FooterButtonX1List
lItem["FooterButtonX1List"].forEach(
function(lItem2){
if ('OnClick' in lItem) {
lOnClickEscaped = lItem["OnClick"];
lOnClickEscaped = lOnClickEscaped.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
lItem["OnClick"] = lOnClickEscaped;
);
/// FooterButtonX1List
lItem["FooterButtonX1List"].forEach(
function(lItem2){
if ('OnClick' in lItem) {
lOnClickEscaped = lItem["OnClick"];
lOnClickEscaped = lOnClickEscaped.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
lItem["OnClick"] = lOnClickEscaped;
}
}
}
);
);
}
}
}
);
//////////////////////////////////////////////////////////
///Сформировать HTML код новой таблицы - контрольная панель
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-control-panel",lResponseJSON)
//Присвоить ответ в mGlobal.Monitor.mResponseList
mGlobal.Monitor.mResponseList = lResponseJSON
///Set result in mGlobal.DataStorage
lResponseJSON["RenderRobotList"].forEach(
function(lItem){
if ('DataStorageKey' in lItem) {
mGlobal["DataStorage"][lItem['DataStorageKey']]=lItem
);
//////////////////////////////////////////////////////////
///Сформировать HTML код новой таблицы - контрольная панель
lHTMLCode+=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-control-panel",lResponseJSON)
//Присвоить ответ в mGlobal.Monitor.mResponseList
mGlobal.Monitor.mResponseList = lResponseJSON
///Set result in mGlobal.DataStorage
lResponseJSON["RenderRobotList"].forEach(
function(lItem){
if ('DataStorageKey' in lItem) {
mGlobal["DataStorage"][lItem['DataStorageKey']]=lItem
}
}
)
///Прогрузить новую таблицу
$(".openrpa-control-panel").html(lHTMLCode)
////////////////////////////////////////////////////
/// !RDP List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON)
//Присвоить ответ в mGlobal.RobotRDPActive.mResponseList
mGlobal.RobotRDPActive.mResponseList = lResponseJSON
///Прогрузить новую таблицу
$(".openrpa-robotrdpactive-control-panel").html(lHTMLCode)
///Очистить дерево
//mGlobal.ElementTree.fClear();
////////////////////////////////////////////////////
/// !UserAgent List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".pyOpenRPA-Agent-ListTemplate",lResponseJSON)
//Присвоить ответ в mGlobal.RobotRDPActive.mResponseList
mGlobal.RobotRDPActive.mResponseList = lResponseJSON
///Прогрузить новую таблицу
$(".pyOpenRPA-Agent-List").html(lHTMLCode)
///Очистить дерево
//mGlobal.ElementTree.fClear();
}
}
}
///v 1.2.0 pyOpenRPA
/// Execute ActivityItem
mGlobal.pyOpenRPA.ActivityItemExecute=function(inActivityItem) {
///EXAMPLE
// {
// "Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"])
// "ArgList":[], // Args list
// "ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary
// "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
// "ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
// }
///Подготовить конфигурацию
lData = [inActivityItem]
$.ajax({
type: "POST",
url: '/pyOpenRPA/ActivityListExecute',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
console.log(lResponseJSON)
},
dataType: "text"
});
}
/// Execute ActivityList
mGlobal.pyOpenRPA.ActivityListExecute=function(inActivityList) {
///EXAMPLE
// [{
// "Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"])
// "ArgList":[], // Args list
// "ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary
// "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
// "ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
// }]
///Подготовить конфигурацию
lData = inActivityList
$.ajax({
type: "POST",
url: '/pyOpenRPA/ActivityListExecute',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
console.log(lResponseJSON)
},
dataType: "text"
});
}
/// Add ActivityList in processor queue
mGlobal.pyOpenRPA.ProcessorQueueAdd=function(inActivityList) {
///EXAMPLE
// [{
// "Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"])
// "ArgList":[], // Args list
// "ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary
// "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
// "ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
// }]
///Подготовить конфигурацию
lData = inActivityList
$.ajax({
type: "POST",
url: '/pyOpenRPA/ProcessorQueueAdd',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
console.log(lResponseJSON)
},
dataType: "text"
});
}
/// 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
mGlobal.pyOpenRPA.ServerDataHashStr = ""
mGlobal.pyOpenRPA.ServerDataRefreshDef_TechnicalRender = function()
{
lResponseJSON = mGlobal.pyOpenRPA.ServerDataDict
if (lResponseJSON!= null) {
/// New version of control panels
lHTMLCode = '<div class="ui cards">'
for (var lKeyStr in lResponseJSON["CPDict"]){
lCPDict = lResponseJSON["CPDict"][lKeyStr]
/// Render HTML
if ("HTMLStr" in lCPDict) {
lHTMLCode+=lCPDict["HTMLStr"]
}
}
lHTMLCode += '</div>'
///Прогрузить новую таблицу
$(".openrpa-control-panel").html(lHTMLCode)
////////////////////////////////////////////////////
///Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON)
/// !RDP List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON["RDPDict"])
//Присвоить ответ в mGlobal.RobotRDPActive.mResponseList
mGlobal.RobotRDPActive.mResponseList = lResponseJSON
mGlobal.RobotRDPActive.mResponseList = lResponseJSON["RDPDict"]
///Прогрузить новую таблицу
$(".openrpa-robotrdpactive-control-panel").html(lHTMLCode)
///Очистить дерево
//mGlobal.ElementTree.fClear();
////////////////////////////////////////////////////
/// !UserAgent List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".pyOpenRPA-Agent-ListTemplate",lResponseJSON["AgentDict"])
///Прогрузить новую таблицу
$(".pyOpenRPA-Agent-List").html(lHTMLCode)
///Очистить дерево
//mGlobal.ElementTree.fClear();
}
}
mGlobal.Monitor.mDatasetLast = null
mGlobal.Monitor.fControlPanelRefresh=function() {
mGlobal.pyOpenRPA.ServerDataRefreshDef=function() {
try {
//var XHR = new XMLHttpRequest();
//XHR.setRequestHeader("Cookies",document.cookie)
///Загрузка данных
//console.log("Request is sent")
//console.log(document.cookie)
$.ajax({
type: "GET",
headers: {"SessionGUIDStr":mGlobal.SessionGUIDStr},
url: 'Monitor/ControlPanelDictGet',
data: '',
//cache: false,
//xhr: XHR,
type: "POST",
headers: {},
url: 'pyOpenRPA/ServerData',
data: mGlobal.pyOpenRPA.ServerDataHashStr,
success: function(lData,l2,l3) {
try {
var lResponseJSON=JSON.parse(lData)
mGlobal.Monitor.mDatasetLast = lResponseJSON
mGlobal.Monitor.fControlPanelRefresh_TechnicalRender()
mGlobal.VersionStr = lResponseJSON["ServerDataDict"]["UserDict"]["VersionStr"]
mGlobal.pyOpenRPA.ServerDataDict = lResponseJSON["ServerDataDict"]
mGlobal.pyOpenRPA.ServerDataHashStr = lResponseJSON["HashStr"]
mGlobal.pyOpenRPA.ServerDataRefreshDef_TechnicalRender()
mGlobal.UserRoleUpdate();
setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,600) // If LOGS are update every ms - set some limit in ms on the client side
//mGlobal.pyOpenRPA.ServerDataRefreshDef() // Go to the next call
}
catch(error) {
console.log(error)
setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000)
}
mGlobal.Monitor.fControlPanelRefresh() // recursive
//mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive
},
dataType: "text",
error: function(jqXHR, textStatus, errorThrown ) {
sleep(3000)
mGlobal.Monitor.fControlPanelRefresh() // recursive
setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000)
//sleep(3000)
//mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive
}
});
}
catch(error) {
sleep(3000)
mGlobal.Monitor.fControlPanelRefresh() // recursive
setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000)
//sleep(3000)
//mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive
}
//mGlobal.Monitor.fControlPanelRefresh() // recursive
}
mGlobal.Monitor.fControlPanelRefresh()
mGlobal.Test=function() {
///Обнулить таблицу
lData = [
{
"Type":"GlobalDictKeyListValueSet",
"key_list":["Storage","Robot_R01"],
"value":{
"RunDateTimeString":"Test1",
"StepCurrentName":"Test2",
"StepCurrentDuration":"Test3"
/////////////////////////////////////////////////////////////
/// v1.2.0 pyOpenRPA ServerLogs
mGlobal.pyOpenRPA.ServerLogList = null
mGlobal.pyOpenRPA.ServerLogListHashStr = ""
mGlobal.pyOpenRPA.ServerLogListDoRenderBool = true
///Turn OFF rendering
mGlobal.pyOpenRPA.ServerLogListDoRenderFalse = function() {
///Set unfreeze button
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").html("Unfreeze textarea")
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").attr("onclick","mGlobal.pyOpenRPA.ServerLogListDoRenderTrue()")
$("textarea.mGlobal-pyOpenRPA-ServerLogList").css("background-color","#b9e2e8")
mGlobal.pyOpenRPA.ServerLogListDoRenderBool = false
}
///Turn ON rendering
mGlobal.pyOpenRPA.ServerLogListDoRenderTrue = function() {
mGlobal.pyOpenRPA.ServerLogListDoRenderBool = true
///Render last data
mGlobal.pyOpenRPA.ServerLogListRefreshDef_TechnicalRender()
///Set unfreeze button
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").html("Freeze textarea")
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").attr("onclick","mGlobal.pyOpenRPA.ServerLogListDoRenderFalse()")
$("textarea.mGlobal-pyOpenRPA-ServerLogList").css("background-color","")
}
mGlobal.pyOpenRPA.ServerLogListScrollBottomDef = function() {
var lTA = $("textarea.mGlobal-pyOpenRPA-ServerLogList")[0];
lTA.scrollTop = lTA.scrollHeight;
}
mGlobal.pyOpenRPA.ServerLogListRefreshDef_TechnicalRender = function()
{
lResponseJSON = mGlobal.pyOpenRPA.ServerLogList
if (lResponseJSON!= null && mGlobal.pyOpenRPA.ServerLogListDoRenderBool==true) {
lText = lResponseJSON.join("\n") /// Code for the processing the text
$("textarea.mGlobal-pyOpenRPA-ServerLogList")[0].value= lText ///Прогрузить новую таблицу
mGlobal.pyOpenRPA.ServerLogListScrollBottomDef() //Scroll to the bottom
}
}
mGlobal.pyOpenRPA.ServerLogListRefreshDef=function() {
try {
$.ajax({
type: "POST",
headers: {},
url: 'pyOpenRPA/ServerLog',
data: mGlobal.pyOpenRPA.ServerLogListHashStr,
success: function(lData,l2,l3) {
try {
var lResponseJSON=JSON.parse(lData)
mGlobal.pyOpenRPA.ServerLogList = lResponseJSON["ServerLogList"]
mGlobal.pyOpenRPA.ServerLogListHashStr = lResponseJSON["HashStr"]
mGlobal.pyOpenRPA.ServerLogListRefreshDef_TechnicalRender()
}
catch(error) {
}
setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,600) // If LOGS are update every ms - set some limit in ms on the client side
//mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive
},
dataType: "text",
error: function(jqXHR, textStatus, errorThrown ) {
setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,3000)
//sleep(3000)
//mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive
}
}
]
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
//console.log(lData)
},
dataType: "text"
});
});
}
catch(error) {
setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,3000)
//sleep(3000)
//mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive
}
}
/////////////////////////////////////////////////////////////
mGlobal.Monitor.mDatasetLast = null
///////////////////////////////
///Processor functions
///////////////////////////////
@ -615,7 +839,7 @@ $(document).ready(function() {
// UAC Ask
mGlobal.UserRoleAsk=function(inList) {
var lResult = true; // Init flag
var lRoleHierarchyDict = mGlobal.UserRoleHierarchyDict; // get the Hierarchy
var lRoleHierarchyDict = mGlobal.pyOpenRPA.ServerDataDict.UserDict.UACClientDict; // get the Hierarchy
// Try to get value from key list
var lKeyValue = lRoleHierarchyDict; // Init the base
var lListLength = inList.length;
@ -641,64 +865,31 @@ $(document).ready(function() {
}
// Check user roles and update the Orchestrator UI
mGlobal.UserRoleUpdate=function() {
$.ajax({
type: "POST",
url: 'Orchestrator/UserRoleHierarchyGet',
data: "",
success:
function(lData,l2,l3)
{
var lUACAsk = mGlobal.UserRoleAsk // Alias
var lResponseDict=JSON.parse(lData)
mGlobal.UserRoleHierarchyDict = lResponseDict // set the user role hierarchy
//Turn on the Lookmachine screenshot button
if (lUACAsk(["Orchestrator","Controls","LookMachineScreenshots"])) {
$(".openrpa-control-lookmachinescreenshot").show() //Show button
}
//Turn on the restart orchestrator button
if (lUACAsk(["Orchestrator","Controls","RestartOrchestrator"])) {
$(".openrpa-control-restartorchestrator").show() //Show button
}
//Turn on the rdp session list
if (lUACAsk(["Orchestrator","RDPActive","ListRead"])) {
$(".openrpa-rdpactive-title").show() //Show section
$(".openrpa-robotrdpactive-control-panel-general").show() //Show section
}
//Turn on the restart PC button
if (lUACAsk(["Orchestrator","Controls","RestartPC"])) {
$(".openrpa-control-restartpc").show() //Show button
}
//Turn on the git update + restart orchestrator
if (lUACAsk(["Orchestrator","Controls","GITRestartOrchestrator"])) {
$(".openrpa-control-gitrestartorchestrator").show() //Show button
}
},
dataType: "text"
});
}
mGlobal.UserRoleUpdate() // Cal the update User Roles function
// Orchestrator model
mGlobal.WorkingDirectoryPathStr = null
mGlobal.OrchestratorModelUpdate=function() {
lData = [
{
"Type": "GlobalDictKeyListValueGet",
"KeyList": ["Server","WorkingDirectoryPathStr"]
}
]
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lUACAsk = mGlobal.UserRoleAsk // Alias
var lResponseList=JSON.parse(lData)
mGlobal.WorkingDirectoryPathStr = lResponseList[0]["Result"]
},
dataType: "text"
});
var lUACAsk = mGlobal.UserRoleAsk // Alias
//CPKeyDict
if (lUACAsk(["pyOpenRPADict","CPKeyDict"])) { $(".UACClient-pyOpenRPADict-CPKeyDict").show(); }
//RDPKeyDict
if (lUACAsk(["pyOpenRPADict","RDPKeyDict"])) { $(".UACClient-pyOpenRPADict-RDPKeyDict").show(); }
//AgentKeyDict
if (lUACAsk(["pyOpenRPADict","AgentKeyDict"])) { $(".UACClient-pyOpenRPADict-AgentKeyDict").show(); }
// AdminDict
if (lUACAsk(["pyOpenRPADict","AdminDict","LogViewerBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-LogViewerBool").show(); }
if (lUACAsk(["pyOpenRPADict","AdminDict","CMDInputBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-CMDInputBool").show(); }
if (lUACAsk(["pyOpenRPADict","AdminDict","ScreenshotViewerBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-ScreenshotViewerBool").show(); }
if (lUACAsk(["pyOpenRPADict","AdminDict","RestartOrchestratorBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorBool").show(); }
if (lUACAsk(["pyOpenRPADict","AdminDict","RestartOrchestratorGITPullBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorGITPullBool").show(); }
if (lUACAsk(["pyOpenRPADict","AdminDict","RestartPCBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-RestartPCBool").show(); }
}
mGlobal.OrchestratorModelUpdate() // Cal the update orchestrator model
/// 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
mGlobal.pyOpenRPA.ServerLogListDoRenderTrue(); // Init button to freeze/unfreeze textare with logs
$('.ui.dropdown').dropdown();
});

@ -59,11 +59,12 @@
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
<h1 class="ui header inverted">Orchestrator Web GUI</h1>
&nbsp;&nbsp;&nbsp;
<h1 class="ui header inverted">ORCHESTRATOR WEB GUI</h1>
</div>
</div>
<div class="row">
<div class="sixteen wide column openrpa-control-panel-general" >
<div class="sixteen wide column openrpa-control-panel-general UACClient-pyOpenRPADict-CPKeyDict" style="display:none;" >
<h4 class="ui horizontal divider header">
<i class="clipboard list icon"></i>
Dashboard (Robot control panel)
@ -116,125 +117,92 @@
</div>
<div class="row">
<div class="five wide column">
<h2 class="ui header">
<i class="settings icon"></i>
<div class="content">
Administration
</div>
</h2>
<div class="ui animated button openrpa-control-lookmachinescreenshot huge green" onclick="mGlobal.Monitor.ScreenshotModal.Show();" style="display: none; margin-top: 5px;">
<div class="visible content">Show live screenshots</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-restartorchestrator yellow" onclick="mGlobal.Controller.OrchestratorRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Restart Orchestrator</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-gitrestartorchestrator" onclick="mGlobal.Controller.OrchestratorGITPullRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Git pull + restart Orchestrator</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
<script class="openrpa-hidden-monitor-table-general" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table">
<thead>
<tr>
<th>Machine name</th>
<th>Machihe host</th>
<th>Status</th>
<th>Actions,length: {{childs.length}}</th>
</tr>
</thead>
<tbody>
{{#ListenURLList}}
<tr><td>{{Description}}</td><td>{{URL}}</td><td class="negative">None</td></tr>
{{/ListenURLList}}
</tbody>
</table>
</script>
<script class="openrpa-handlebar-template-table-filter" style="display:none" type="text/x-handlebars-template">
{{#if Title}}
<h1>{{{Title}}}</h1>
{{/if}}
{{#if FilterOnKeyUp}}
<div class="ui icon input search" style="width:500px;">
<input type="text" onkeyup="{{#if FilterOnKeyUp}}{{{FilterOnKeyUp}}}{{/if}}" placeholder="Search...">
<i class="inverted circular search link icon"></i>
</div>
<div class="ui animated button openrpa-control-restartpc red" onclick="mGlobal.Controller.PCRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Restart PC</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
{{/if}}
<table class="ui celled table selectable inverted">
<thead>
<tr>
{{#Columns}}
<th>{{{this}}}</th>
{{/Columns}}
</tr>
</thead>
<tbody>
{{#Rows}}
<tr>
{{#this}}
<td>
{{{this}}}
</td>
{{/this}}
</tr>
{{/Rows}}
</tbody>
</table>
</script>
<script class="openrpa-handlebar-template-list-filter" style="display:none" type="text/x-handlebars-template">
{{#if Title}}
<h1>{{{Title}}}</h1>
{{/if}}
{{#if FilterOnKeyUp}}
<div class="ui icon input search" style="width:500px;">
<input type="text" onkeyup="{{#if FilterOnKeyUp}}{{{FilterOnKeyUp}}}{{/if}}" placeholder="Search...">
<i class="inverted circular search link icon"></i>
</div>
<script class="openrpa-hidden-monitor-table-general" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table">
<thead>
<tr>
<th>Machine name</th>
<th>Machihe host</th>
<th>Status</th>
<th>Actions,length: {{childs.length}}</th>
</tr>
</thead>
<tbody>
{{#ListenURLList}}
<tr><td>{{Description}}</td><td>{{URL}}</td><td class="negative">None</td></tr>
{{/ListenURLList}}
</tbody>
</table>
</script>
<script class="openrpa-handlebar-template-table-filter" style="display:none" type="text/x-handlebars-template">
{{#if Title}}
<h1>{{{Title}}}</h1>
{{/if}}
{{#if FilterOnKeyUp}}
<div class="ui icon input search" style="width:500px;">
<input type="text" onkeyup="{{#if FilterOnKeyUp}}{{{FilterOnKeyUp}}}{{/if}}" placeholder="Search...">
<i class="inverted circular search link icon"></i>
</div>
{{/if}}
<table class="ui celled table selectable inverted">
<thead>
<tr>
{{#Columns}}
<th>{{{this}}}</th>
{{/Columns}}
</tr>
</thead>
<tbody>
{{#Rows}}
<tr>
{{#this}}
<td>
{{{this}}}
</td>
{{/this}}
</tr>
{{/Rows}}
</tbody>
</table>
</script>
<script class="openrpa-handlebar-template-list-filter" style="display:none" type="text/x-handlebars-template">
{{#if Title}}
<h1>{{{Title}}}</h1>
{{/if}}
{{#if FilterOnKeyUp}}
<div class="ui icon input search" style="width:500px;">
<input type="text" onkeyup="{{#if FilterOnKeyUp}}{{{FilterOnKeyUp}}}{{/if}}" placeholder="Search...">
<i class="inverted circular search link icon"></i>
</div>
{{/if}}
<div class="ui inverted segment">
<div class="ui inverted relaxed divided list">
{{#List}}
<div class="item">
<i class="map marker icon"></i>
<div class="content">
<a class="header">{{{Header}}}</a>
<div class="description">{{{Description}}}</div>
</div>
{{/if}}
<div class="ui inverted segment">
<div class="ui inverted relaxed divided list">
{{#List}}
<div class="item">
<i class="map marker icon"></i>
<div class="content">
<a class="header">{{{Header}}}</a>
<div class="description">{{{Description}}}</div>
</div>
{{/List}}
</div>
{{/List}}
</div>
</script>
</div>
<div class="two wide column">
</div>
<div class="nine wide column openrpa-robotrdpactive-control-panel-general" style="display:none;">
<h2 class="ui header openrpa-rdpactive-title" style="display:none;">
<i class="server icon"></i>
</div>
</script>
<div class="eight wide column openrpa-robotrdpactive-control-panel-general UACClient-pyOpenRPADict-RDPKeyDict" style="display:none;">
<h2 class="ui header openrpa-rdpactive-title">
<i class="desktop icon"></i>
<div class="content">
RDP active list
</div>
</h2>
<div class="openrpa-robotrdpactive-control-panel"></div>
<script class="openrpa-hidden-robotrdpactive-control-panel" style="display:none" type="text/x-handlebars-template">
<div class="ui inverted segment">
<div class="ui inverted segment" style="background: #368279">
<div class="ui inverted relaxed divided list">
{{#RenderRDPList}}
{{#HandlebarsList}}
<div class="item">
<div class="right floated content">
<div class="ui button" onclick="mGlobal.Processor.ServerValueAppend(['RobotRDPActive','ActivityList'],{'DefNameStr': 'RDPSessionReconnect', 'ArgList': [], 'ArgDict': {'inRDPSessionKeyStr': '{{{SessionKeyStr}}}'} })" >Reconnect</div>
@ -258,7 +226,38 @@
{{{SessionHexStr}}}
</div>
</div>
{{/RenderRDPList}}
{{/HandlebarsList}}
</div>
</div>
</script>
</div>
<div class="eight wide column UACClient-pyOpenRPADict-AgentKeyDict" style="display:none">
<h2 class="ui header " style="">
<i class="bug icon"></i>
<div class="content">
Agent active list
</div>
</h2>
<div class="pyOpenRPA-Agent-List"></div>
<script class="pyOpenRPA-Agent-ListTemplate" style="display:none" type="text/x-handlebars-template">
<div class="ui inverted segment" style="background: #368279">
<div class="ui inverted relaxed divided list">
{{#HandlebarsList}}
<div class="item">
<div class="right floated content">
{{#if IsListenBool}}
<i class="circle icon green"></i>
Online
{{else}}
<i class="circle icon red"></i>
Offline
{{/if}}
</div>
<div class="content">
<div class="header">Hostname: {{{HostnameUpperStr}}}, User: {{{UserUpperStr}}}</div>
</div>
</div>
{{/HandlebarsList}}
</div>
</div>
</script>
@ -269,6 +268,68 @@
<div class="row openrpa-monitor">
</div>
<div class="row">
<div class="sixteen wide column" style="">
<h2 class="ui header">
<i class="settings icon"></i>
<div class="content">
Administration
</div>
</h2>
</div>
</div>
<div class="row">
<div class="sixteen wide column" style="">
<h4 class="ui horizontal divider header" >
<i class="clipboard list icon"></i>
Logs
</h4>
<textarea class="mGlobal-pyOpenRPA-ServerLogList UACClient-pyOpenRPADict-AdminDict-LogViewerBool" readonly="readonly" style="width:100%; display:none; resize: none; font-family:monospace; font-weight: bold;" id="textarea_id" rows="20">
</textarea>
<a class="mGlobal-pyOpenRPA-ServerLogListDoRender" onclick="" style="cursor: pointer;">Freeze textarea</a>
<div class="ui fluid action input UACClient-pyOpenRPADict-AdminDict-CMDInputBool" style="display:none;">
<input class="openrpa-controller-cmd-run-input" type="text" placeholder="CMD Code...">
<div class="ui button" onclick="mGlobal.Controller.CMDRun();">Run!</div>
<div class="ui button" onclick="mGlobal.Controller.CMDRunGUILogout();">GUI Logout</div>
</div>
</div>
</div>
<h4 class="ui horizontal divider header">
<i class="clipboard list icon"></i>
Controls
</h4>
<div class="four ui buttons">
<div class="ui animated button openrpa-control-lookmachinescreenshot green UACClient-pyOpenRPADict-AdminDict-ScreenshotViewerBool" onclick="mGlobal.Monitor.ScreenshotModal.Show();" style="display: none; margin-top: 5px;">
<div class="visible content">Show live screenshots</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-restartorchestrator orange UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorBool" onclick="mGlobal.Controller.OrchestratorRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Restart orchestrator</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-gitrestartorchestrator teal UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorGITPullBool" onclick="mGlobal.Controller.OrchestratorGITPullRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Git pull, restart orchestrator</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-restartpc red UACClient-pyOpenRPADict-AdminDict-RestartPCBool" onclick="mGlobal.Controller.PCRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Restart PC</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
</div>
<div class="row black">
@ -341,11 +402,6 @@
</div>
<div class="content">
<img src="GetScreenshot" class="ui fluid image">
<div class="ui fluid action input">
<input class="openrpa-controller-cmd-run-input" type="text" placeholder="CMD Code...">
<div class="ui button" onclick="mGlobal.Controller.CMDRun();">Run!</div>
<div class="ui button" onclick="mGlobal.Controller.CMDRunGUILogout();">GUI Logout</div>
</div>
</div>
<div class="actions">
<div class="ui green ok inverted button" onclick="mGlobal.Monitor.ScreenshotModal.Close()">

@ -1,7 +1,9 @@
r"""
The OpenRPA package (from UnicodeLabs)
The pyOpenRPA package (from UnicodeLabs)
"""
from .Web import Basic
from .__Orchestrator__ import *
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'

@ -1,4 +1,5 @@
import sys
lFolderPath = "\\".join(__file__.split("\\")[:-3])
sys.path.insert(0, lFolderPath)
from pyOpenRPA.Orchestrator import Orchestrator
from pyOpenRPA.Orchestrator import __Orchestrator__
__Orchestrator__.__deprecated_orchestrator_start__() # Backward compatibility below the v1.2.0. Will be deprecated in 1.3.0

@ -103,6 +103,14 @@ mDefaultPywinautoBackend="win32"
#inFlagRaiseException - Флаг True - выкинуть ошибку в случае обнаружении пустого списка
#old name - PywinautoExtElementsGet
def UIOSelector_Get_UIOList (inSpecificationList,inElement=None,inFlagRaiseException=True):
'''
Get the UIO list by the selector
:param inSpecificationList: UIO Selector
:param inElement: Входной элемент - показатель, что не требуется выполнять коннект к процессу
:param inFlagRaiseException: Флаг True - выкинуть ошибку в случае обнаружении пустого списка
:return:
'''
#Создать копию входного листа, чтобы не менять массив в других верхнеуровневых функциях
inSpecificationList=copy.deepcopy(inSpecificationList)
lResultList=[]
@ -232,6 +240,14 @@ def UIOSelector_Get_UIOList (inSpecificationList,inElement=None,inFlagRaiseExcep
#inFlagRaiseException - Флаг True - выкинуть ошибку в случае обнаружении пустого списка
#old name - PywinautoExtElementGet
def UIOSelector_Get_UIO (inSpecificationList,inElement=None,inFlagRaiseException=True):
'''
Get the pywinauto object by the UIO selector.
:param inSpecificationList:
:param inElement:
:param inFlagRaiseException:
:return:
'''
lResult=None
#Получить родительский объект если на вход ничего не поступило
lResultList=UIOSelector_Get_UIOList(inSpecificationList,inElement,False)
@ -247,6 +263,12 @@ def UIOSelector_Get_UIO (inSpecificationList,inElement=None,inFlagRaiseException
#UIOSelector
#old name - -
def UIOSelector_Exist_Bool (inUIOSelector):
'''
Check if object is exist by the UIO selector.
:param inUIOSelector:
:return: True - Object is exist. False - else case
'''
lResult=False
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
@ -280,6 +302,18 @@ def UIOSelector_Exist_Bool (inUIOSelector):
#####Внимание#####
##Функция ожидания появления элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться)
def UIOSelectorsSecs_WaitAppear_List (inSpecificationListList,inWaitSecs,inFlagWaitAllInMoment=False):
'''
Wait for many UI object will appear in GUI for inWaitSecs seconds.
:param inSpecificationListList: UIOSelector list.
Example: [
[{"title":"notepad"},{"title":"OK"}],
[{"title":"notepad"},{"title":"Cancel"}]
]
:param inWaitSecs: Float value (seconds) for wait UI element appear in GUI
:param inFlagWaitAllInMoment: True - Wait all UI objects from the UIOSelector list to be appeared
:return: List of index, which UI object UIO will be appeared. Example: [1] # Appear only UI object with UIO selector: [{"title":"notepad"},{"title":"Cancel"}]
'''
lResultFlag=False
lSecsSleep = 1 #Настроечный параметр
lSecsDone = 0
@ -319,6 +353,19 @@ def UIOSelectorsSecs_WaitAppear_List (inSpecificationListList,inWaitSecs,inFlagW
#####Внимание#####
##Функция ожидания пропажи элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться)
def UIOSelectorsSecs_WaitDisappear_List (inSpecificationListList,inWaitSecs,inFlagWaitAllInMoment=False):
'''
Wait for many UI object will disappear in GUI for inWaitSecs seconds.
:param inSpecificationListList: UIOSelector list.
Example: [
[{"title":"notepad"},{"title":"OK"}],
[{"title":"notepad"},{"title":"Cancel"}]
]
:param inWaitSecs: Float value (seconds) for wait UI element disappear in GUI
:param inFlagWaitAllInMoment: True - Wait all UI objects from the UIOSelector list to be disappeared.
:return: List of index, which UI object UIO will be disappeared. Example: [1] # Disappear only UI object with UIO selector: [{"title":"notepad"},{"title":"Cancel"}]
:return:
'''
lResultFlag=False
lSecsSleep = 1 #Настроечный параметр
lSecsDone = 0
@ -355,6 +402,13 @@ def UIOSelectorsSecs_WaitDisappear_List (inSpecificationListList,inWaitSecs,inFl
#return: Bool - True - UIO is appear
#old name - -
def UIOSelectorSecs_WaitAppear_Bool (inSpecificationList,inWaitSecs):
'''
Wait for UI object will appear in GUI for inWaitSecs seconds.
:param inSpecificationList: UIOSelector. Example: [{"title":"notepad"},{"title":"OK"}]
:param inWaitSecs: Float value (seconds) for wait UI element appear in GUI
:return: True - UI object will appear. False - else case
'''
lWaitAppearList=UIOSelectorsSecs_WaitAppear_List([inSpecificationList],inWaitSecs)
lResult=False
if len(lWaitAppearList)>0:
@ -367,6 +421,14 @@ def UIOSelectorSecs_WaitAppear_Bool (inSpecificationList,inWaitSecs):
#return: Bool - True - UIO is Disappear
#old name - -
def UIOSelectorSecs_WaitDisappear_Bool (inSpecificationList,inWaitSecs):
'''
Wait for UI object will disappear in GUI for inWaitSecs seconds.
:param inSpecificationList: UIOSelector.
Example: [{"title":"notepad"},{"title":"OK"}]
:param inWaitSecs: Float value (seconds) for wait UI element disappear in GUI
:return: True - UI object will disappear. False - else case
'''
lWaitDisappearList=UIOSelectorsSecs_WaitDisappear_List([inSpecificationList],inWaitSecs)
lResult=False
if len(lWaitDisappearList)>0:
@ -378,6 +440,12 @@ def UIOSelectorSecs_WaitDisappear_Bool (inSpecificationList,inWaitSecs):
#old name - None
#return None (if Process not found), int 32, or int 64
def UIOSelector_Get_BitnessInt (inSpecificationList):
'''
Detect process bitness by the UI Object UIO Selector.
:param inSpecificationList: UIOSelector. Example: [{"title":"notepad"},{"title":"OK"}]
:return: int 32 or int 64
'''
lResult=None
#Получить объект Application (Для проверки разрядности)
lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList)
@ -393,6 +461,12 @@ def UIOSelector_Get_BitnessInt (inSpecificationList):
#old name - None
#return None (if Process not found), int 32, or int 64
def UIOSelector_Get_BitnessStr (inSpecificationList):
'''
Detect process bitness by the UI Object UIO Selector.
:param inSpecificationList: UIOSelector. Example: [{"title":"notepad"},{"title":"OK"}]
:return: str "32" or str "64"
'''
lResult=None
#Получить объект Application (Для проверки разрядности)
lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList)
@ -407,15 +481,23 @@ def UIOSelector_Get_BitnessStr (inSpecificationList):
#old name - None
#return int 32, or int 64
def Get_OSBitnessInt ():
lResult=32;
'''
Detect OS bitness.
:return: int 32 or int 64
'''
lResult=32
if pywinauto.sysinfo.is_x64_OS():
lResult=64;
return lResult;
lResult=64
return lResult
#################################################################################################
#Safe get other process or None if destination app is the other/same bitness
#inUIOSelector - selector of the destination
#return None or process (of the other bitness)
def UIOSelector_SafeOtherGet_Process(inUIOSelector):
'''
Safe get other process or None if destination app is the other/same bitness
:param inUIOSelector: UIO Selector of the UI object
:return: None or process (of the other bitness)
'''
#Default value
lResult = None
#Go check bitness if selector exists
@ -426,11 +508,14 @@ def UIOSelector_SafeOtherGet_Process(inUIOSelector):
lResult = Utils.ProcessBitness.OtherProcessGet()
return lResult
##################################################################################################
#inControlSpecificationArray - List of dict, dict in pywinauto.find_windows notation
#Backend selection - attribute "backend" ("win32" || "uia") in 1-st list element
#return list of UIO object
#old name - GetControl
def PWASpecification_Get_UIO(inControlSpecificationArray):
'''
#Backend def selection - attribute "backend" ("win32" || "uia") in 1-st list element
#old name - GetControl
:param inControlSpecificationArray: List of dict, dict in pywinauto.find_windows notation
:return: list of UIO object
'''
#Определение backend
lBackend=mDefaultPywinautoBackend
if "backend" in inControlSpecificationArray[0]:
@ -440,7 +525,7 @@ def PWASpecification_Get_UIO(inControlSpecificationArray):
inControlSpecificationOriginArray=copy.deepcopy(inControlSpecificationArray)
inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
lResultList=[]
lTempObject=None
if len(inControlSpecificationArray) > 0:
#Сформировать выборку элементов, которые подходят под первый уровень спецификации
@ -477,11 +562,13 @@ def PWASpecification_Get_UIO(inControlSpecificationArray):
lResultList.append(lTempObject)
return lResultList
##################################################################################################
#inControlSpecificationArray - List of dict, dict in pywinauto.find_windows notation
#Backend selection - attribute "backend" ("win32" || "uia") in 1-st list element
#return process application object
#old name - None
def PWASpecification_Get_PWAApplication(inControlSpecificationArray):
'''
#Backend selection - attribute "backend" ("win32" || "uia") in 1-st list element
:param inControlSpecificationArray: List of dict, dict in pywinauto.find_windows notation
:return: process application object
'''
inControlSpecificationArray=copy.deepcopy(inControlSpecificationArray)
#Определение backend
lBackend=mDefaultPywinautoBackend
@ -492,7 +579,7 @@ def PWASpecification_Get_PWAApplication(inControlSpecificationArray):
inControlSpecificationOriginArray=inControlSpecificationArray
inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
lResultList=[]
lTempObject=None
if len(inControlSpecificationArray) > 0:
#Выполнить подключение к объекту
@ -513,10 +600,14 @@ def PWASpecification_Get_PWAApplication(inControlSpecificationArray):
return lTempObject
###########################################################################################################
#inElementSpecificationList = UIOSelector (see description on the top of the document)
#result = pywinauto element wrapper instance or None
#old name - AutomationSearchMouseElement
def UIOSelector_SearchChildByMouse_UIO(inElementSpecification):
'''
UIOSelector (see description on the top of the document)
#old name - AutomationSearchMouseElement
:param inElementSpecification: UIOSelector of the UI Object
:return: pywinauto element wrapper instance or None
'''
lGUISearchElementSelected=None
#Настройка - частота обновления подсвечивания
lTimeSleepSeconds=0.4
@ -548,17 +639,21 @@ def UIOSelector_SearchChildByMouse_UIO(inElementSpecification):
UIO_Highlight(lElementFounded)
else:
#Была нажата клавиша Ctrl - выйти из цикла
lFlagLoop=False;
lFlagLoop=False
#Заснуть до следующего цикла
time.sleep(lTimeSleepSeconds)
#Вернуть результат поиска
return lElementFoundedList
####################################################################################################
#inElementSpecification - UIOSelector
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - AutomationSearchMouseElementHierarchy
def UIOSelector_SearchChildByMouse_UIOTree(inUIOSelector):
'''
!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
:param inUIOSelector: UIOSelector of the UI Object
:return: ?
'''
lItemInfo = []
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
@ -687,6 +782,12 @@ def UIOSelector_Get_UIOInfoList (inUIOSelector, inElement=None):
#inSpecificationList - UIOSelector
#old name - PywinautoExtTryToRestore
def UIOSelector_TryRestore_Dict(inSpecificationList):
"""
Try to restore (maximize) window, if it's minimized. (!IMPORTANT! When use UIA framework minimized windows doesn't appear by the UIOSelector. You need to try restore windows and after that try to get UIO)
:param inSpecificationList: UIOSelector - List of items, which contains condition attributes
:return:
"""
lResult={}
try:
#Подготовка взодного массива
@ -705,6 +806,12 @@ def UIOSelector_TryRestore_Dict(inSpecificationList):
#inControlSpecificationArray - UIOSelector
#old name - ElementActionGetList
def UIOSelector_Get_UIOActivityList (inUIOSelector):
"""
Get the list of the UI object activities
:param inUIOSelector: UIOSelector - List of items, which contains condition attributes
:return:
"""
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
@ -742,7 +849,18 @@ def UIOSelector_Get_UIOActivityList (inUIOSelector):
#inUIOSelector
#inActionName - UIOActivity (name) from Pywinauto
#old name - ElementRunAction
def UIOSelectorUIOActivity_Run_Dict(inUIOSelector, inActionName, inArgumentList=[], inkwArgumentObject={}):
def UIOSelectorUIOActivity_Run_Dict(inUIOSelector, inActionName, inArgumentList=None, inkwArgumentObject=None):
"""
Run the activity in UIO (UI Object)
:param inUIOSelector: UIOSelector - List of items, which contains condition attributes
:param inActionName: UIOActivity (name) activity name string from Pywinauto
:param inArgumentList:
:param inkwArgumentObject:
:return:
"""
if inArgumentList is None: inArgumentList=[] # 2021 02 22 Minor fix by Ivan Maslov
if inkwArgumentObject is None: inkwArgumentObject={} # 2021 02 22 Minor fix by Ivan Maslov
lResult={}
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
@ -790,13 +908,19 @@ def UIOSelectorUIOActivity_Run_Dict(inUIOSelector, inActionName, inArgumentList=
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementGetInfo
def UIOSelector_Get_UIOInfo(inUIOSelector):
"""
Get the UIO dict of the attributes
:param inUIOSelector: UIOSelector - List of items, which contains condition attributes
:return:
"""
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
#Подготовка входного массива
inUIOSelector=UIOSelector_SearchUIONormalize_UIOSelector(inUIOSelector)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
lResultList=[]
if len(inUIOSelector) > 0:
#Получить объект
lTempObject=UIOSelector_Get_UIO(inUIOSelector)
@ -824,7 +948,8 @@ def UIOSelector_Get_UIOInfo(inUIOSelector):
#inHierarchyList: [{"index":<>,"element":<>}] - technical argument for internal purpose
#result -List of dict [{"index":<>,"element":<>}] -- list of element hierarchy specifications
#old name - GUISearchElementByRootXY
def UIOXY_SearchChild_ListDict(inRootElement,inX,inY,inHierarchyList=[]):
def UIOXY_SearchChild_ListDict(inRootElement,inX,inY,inHierarchyList=None):
if inHierarchyList is None: inHierarchyList = []
#Инициализация результирующего значения
lResultElement = None
lResultElementX1 = None
@ -913,7 +1038,17 @@ def UIOXY_SearchChild_ListDict(inRootElement,inX,inY,inHierarchyList=[]):
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#inControlSpecificationArray- UIOSelector
#old name - ElementGetChildElementList
def UIOSelector_GetChildList_UIOList(inUIOSelector=[], inBackend=mDefaultPywinautoBackend):
def UIOSelector_GetChildList_UIOList(inUIOSelector=None, inBackend=mDefaultPywinautoBackend):
"""
Get list of child UIO's by the parent UIOSelector
:param inUIOSelector: UIOSelector - List of items, which contains condition attributes
:param inBackend: "win32" or "uia"
:return:
"""
if inUIOSelector is None: inUIOSelector = []
#mRobotLogger.info(f"File!!!!")
#mRobotLogger.info(f"inSelector:{str(inUIOSelector)}, inBackend:{str(inBackend)}")
#pdb.set_trace()
@ -1194,7 +1329,7 @@ def BackendStr_GetTopLevelList_UIOInfo(inBackend=mDefaultPywinautoBackend):
lResultList2=[]
for lI in lResultList:
lTempObjectInfo=lI
lResultList2.append(UIOEI_Convert_UIOInfo(lI));
lResultList2.append(UIOEI_Convert_UIOInfo(lI))
return lResultList2
###################################################################################################
@ -1202,6 +1337,12 @@ def BackendStr_GetTopLevelList_UIOInfo(inBackend=mDefaultPywinautoBackend):
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementDrawOutlineNew
def UIOSelector_Highlight(inUIOSelector):
"""
Highlight (draw outline) the element (in app) by the UIO selector.
:param inUIOSelector: UIOSelector - List of items, which contains condition attributes
:return:
"""
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
@ -1227,6 +1368,13 @@ def UIOSelector_Highlight(inUIOSelector):
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementDrawOutlineNewFocus
def UIOSelector_FocusHighlight(inUIOSelector):
"""
Set focus and highlight (draw outline) the element (in app) by the UIO selector.
:param inUIOSelector: UIOSelector - List of items, which contains condition attributes
:return:
"""
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:

@ -3,7 +3,7 @@ r"""
The OpenRPA package (from UnicodeLabs)
"""
__version__ = 'v1.1.20'
__version__ = 'v1.2.0'
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'
#from .Core import Robot

@ -1,88 +0,0 @@
Metadata-Version: 2.1
Name: pyOpenRPA
Version: 1.1.20
Summary: First open source RPA platform for business
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
Author: Ivan Maslov
Author-email: Ivan.Maslov@unicodelabs.ru
License: MIT
Keywords: OpenRPA RPA Robot Automation Robotization OpenSource
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: License :: OSI Approved :: MIT License
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.7
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Home Automation
Description-Content-Type: text/markdown
Requires-Dist: pywinauto (>=0.6.8)
Requires-Dist: WMI (>=1.4.9)
Requires-Dist: pillow (>=6.0.0)
Requires-Dist: keyboard (>=0.13.3)
Requires-Dist: pyautogui (>=0.9.44)
Requires-Dist: pywin32 (>=224)
Requires-Dist: crypto (>=1.4.1)
# OpenRPA
First open source RPA platform for business is released!
# How to run
Studio
Double click to Studio\StudioRun_32.cmd or Studio\StudioRun_64.cmd
# Robot how to debug
Robot\PythonDebug_64.cmd
import Robot
Robot.ActivityRun(
{
ModuleName: <"GUI"|..., str>,
ActivityName: <Function or procedure name in module, str>,
ArgumentList: [<Argument 1, any type>, ...] - optional,
ArgumentDict: {<Argument 1 name, str>:<Argument 1 value, any type>, ...} - optional
}
)
# Robot example script:
Robot\Examples\GetFolderList\Python_32_Script_Run.cmd
# Python 32 bit
Resources\WPy32-3720\python-3.7.2\python.exe
# Python 64 bit
Resources\WPy64-3720\python-3.7.2.amd64\python.exe
# Module GUI activity List:
############################
Новая версия
############################
Получить список элементов, который удовлетворяет условиям через расширенный движок поиска
[
{
"index":<Позиция элемента в родительском объекте>,
"depth_start" - глубина, с которой начинается поиск (по умолчанию 1)
"depth_end" - глубина, до которой ведется поиск (по умолчанию 1)
"class_name" - наименование класса, который требуется искать
"title" - наименование заголовка
"rich_text" - наименование rich_text
}
]
# Open RPA Wiki
- [Home](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/home)
- [04. Desktop app access (win32 & ui automation)](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/04.-Desktop-app-access-(win32-&-ui-automation))
#Dependencies
* Python 3 x32 [psutil, pywinauto, wmi, PIL, keyboard, pyautogui, win32api (pywin32), selenium, openCV, tesseract, requests, lxml, PyMuPDF]
* Python 3 x64 [psutil, pywinauto, wmi, PIL, keyboard, pyautogui, win32api (pywin32), selenium, openCV, tesseract, requests, lxml, PyMuPDF]
* pywinauto (Windows GUI automation)
* Semantic UI CSS framework
* JsRender by https://www.jsviews.com (switch to Handlebars)
* Handlebars
Created by Unicode Labs (Ivan Maslov)

@ -1,319 +0,0 @@
pyOpenRPA-1.1.20.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.1.20.dist-info/METADATA,sha256=B3Ph33GyqyoXYSX_0wGNMu6KLwFG_lj6NIXaCKJP-TA,3352
pyOpenRPA-1.1.20.dist-info/RECORD,,
pyOpenRPA-1.1.20.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA-1.1.20.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.1.20.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/.idea/inspectionProfiles/profiles_settings.xml,sha256=YXLFmX7rPNGcnKK1uX1uKYPN0fpgskYNe7t0BV7cqkY,174
pyOpenRPA/.idea/misc.xml,sha256=ySjeaQ1DfqxaRTlFGT_3zW5r9mWuwxoAK_AX4QiuAZM,203
pyOpenRPA/.idea/modules.xml,sha256=Q__U1JIA2cjxbLRXAv-SfYY00fZA0TNlpkkbY4s3ncg,277
pyOpenRPA/.idea/pyOpenRPA.iml,sha256=EXh41F8lqRiSBMVg-n2tKaEaHC6_3gGSuKkPJA12Na0,408
pyOpenRPA/.idea/vcs.xml,sha256=2HygA1oRAwc3VBf-irxHrX5JJG9DXuQwrN0BlubhoKY,191
pyOpenRPA/.idea/workspace.xml,sha256=kcCP7x0iSOAWJdy7YtntGrgsQ04QIq0b6_9w04DKxfg,2555
pyOpenRPA/Info.md,sha256=u4Nv-PjniSF0Zlbtr6jEJX2vblK3_1zhSLNUgOdtDaA,85
pyOpenRPA/Orchestrator/BackwardCompatibility.py,sha256=y1Dyb8wmRcJmk1SxTVmgpR8r64Aa-Io9MG_5khvYgH0,3672
pyOpenRPA/Orchestrator/Orchestrator.py,sha256=32AVVDVpMgam9Zg5n79WJDiuhGQTehtBWTFQrm6Mzhg,12387
pyOpenRPA/Orchestrator/Processor.py,sha256=JI7nnkwXXnpkSJx6GlxoPjjiFOv3q3e-xZDLxKVYKrg,12634
pyOpenRPA/Orchestrator/RobotRDPActive/CMDStr.py,sha256=6otw1WnR2_evvQ5LGyOVh0BLk_nTdilViGub7p56fXQ,1531
pyOpenRPA/Orchestrator/RobotRDPActive/Clipboard.py,sha256=YB5HJL-Qf4IlVrFHyRv_ZMJ0Vo4vjyYqWKjvrTnf1k4,1564
pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py,sha256=fEwwCaYggb_KB72_9Bi-bn1zvglssNWNaWz9GTaiVk4,26543
pyOpenRPA/Orchestrator/RobotRDPActive/ConnectorExceptions.py,sha256=wwH9JOoMFFxDKQ7IyNyh1OkFkZ23o1cD8Jm3n31ycII,657
pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py,sha256=AQ_u9QVSLpce9hhSacm3UT98bErc636MXza4Q6mHsSc,12264
pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py,sha256=jCtHXExgRW0licn8K-xSO3tFd6P-4IFzp46TdS57vQ4,10726
pyOpenRPA/Orchestrator/RobotRDPActive/Scheduler.py,sha256=21N0ilFzWI1mj3X5S9tPMgwvG7BviuBxfTuqBY85Hy4,9144
pyOpenRPA/Orchestrator/RobotRDPActive/Template.rdp,sha256=JEMVYkEmNcfg_p8isdIyvj9E-2ZB5mj-R3MkcNMKxkA,2426
pyOpenRPA/Orchestrator/RobotRDPActive/Timer.py,sha256=y8--fUvg10qEFomecl_cmdWpdGjarZBlFpMbs_GvzoQ,1077
pyOpenRPA/Orchestrator/RobotRDPActive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Orchestrator/RobotRDPActive/__main__.py,sha256=z9PaUK4_nBiGd0YJdYVHV_rFx6VjZaxrrmKxSyoTFwY,2508
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/CMDStr.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Clipboard.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Connector.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/ConnectorExceptions.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Processor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/RobotRDPActive.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Scheduler.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Timer.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/ConsoleStart.bat,sha256=_HNadUKHOYI5y6foG3srh8wjSzhX33xaKNylFtDjOJk,114
pyOpenRPA/Orchestrator/RobotScreenActive/Monitor.py,sha256=TV-YisVqa_uGiyJLG9oK4u-5aDjGiFYZFh1dPjOgYc8,492
pyOpenRPA/Orchestrator/RobotScreenActive/Screen.py,sha256=VnYcvCVymrD35l2J4ln_tlVn7CilZhxE4Ggw9P-OhIw,606
pyOpenRPA/Orchestrator/RobotScreenActive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Orchestrator/RobotScreenActive/__main__.py,sha256=JASxDDVKWUU7DAbDkRrGTrPk-P7LZchTZFh8usp6b4U,593
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/Monitor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/Screen.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotScreenActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Server.py,sha256=dO82x5_tmPSn0oKgdYs7BzM3kZZkh5MWNegxUEwE01I,25694
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=dK8pQzg2mcLPjbizOPCP7yHMMVLiTh8RbYVnJXn-Mvg,15640
pyOpenRPA/Orchestrator/Timer.py,sha256=HvYtEeH2Q5WVVjgds9XaBpWRmvZgwgBXurJDdVVq_T0,2097
pyOpenRPA/Orchestrator/Web/Index.js,sha256=zdbj1ioNgxhprLpGIQ2YYraKUMUpkBiVoR-3GXGR5X0,28258
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=uRjdlkK8-yyrh4y3BkBYlFkRHzzPlHWz5dRh1FmG5QE,14260
pyOpenRPA/Orchestrator/Web/favicon.ico,sha256=6S8XwSQ_3FXPpaX6zYkf8uUewVXO9bHnrrDHEoWrEgw,112922
pyOpenRPA/Orchestrator/__init__.py,sha256=qVH8fEPgXk54rmy-ol0PnT8GF5OlGE0a8mExwJ4tFqY,124
pyOpenRPA/Orchestrator/__main__.py,sha256=cOd8WU77VGgzTZUB0WmWpPmdYyMZY1zVyuU9yx26MKs,144
pyOpenRPA/Orchestrator/__pycache__/BackwardCompatibility.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/Orchestrator.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/Processor.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/Server.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/ServerSettings.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/Timer.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/README.md,sha256=e2hKh7Tx6DAsX6jY_hBDhguL1L2Wiv6iugDB5otMzIA,2293
pyOpenRPA/Resources/Web/Google/LatoItalic.css,sha256=pB6OZ6F2VsaqkL-g5hW-wE_T0m9H_NltzmzjX-XAKDk,3112
pyOpenRPA/Resources/Web/Handlebars/handlebars-v4.1.2.js,sha256=h6O4BrhyPtJspLDEQwogC53uHFRozuBpxvN2S4tJHE8,171994
pyOpenRPA/Resources/Web/JsRender/jsrender.min.js,sha256=00hs6PwCiAfN_gatFdLofj3yBf8ue5Z7jCXX_th2FFg,25927
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/.versions,sha256=gGkuqPk07gAhjnNJVjVR_BA4SSBzqazbY8eEpddH01U,72
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/LICENSE,sha256=ifWbZZ0piwisfkIil1gacnBMxNnAHa7yCn1etItX1Y4,1102
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/README.md,sha256=oITQ5k-7jxoYAAQpzAXFROqgcnGzPrTd7GqkZSGqKW8,448
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/accordion.css,sha256=UC6U37i_pXBVMlUmFMLi1S8FIhFycJjAePP-hRGKzQM,8971
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/accordion.js,sha256=6cCQ6FlT1bM_QA4OpA_vfMljasKU1foGszlAIyhWi3A,20790
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/accordion.min.css,sha256=u9_5Zru9uMTtrXZpdfLawT_kJ5LFcmrMFr1QWXfDqwA,6955
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/accordion.min.js,sha256=kt0Dfi-mrxAU-iYsfDrkROHrb55Hi0lVWC7MT46_xnU,7100
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/ad.css,sha256=CiW55EUiruW1Tp0jrz2yDvQ8jYxDVMDmVcROV5_eBzo,4176
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/ad.min.css,sha256=7D7QYK0TBRyE4dN3SYXD_owb0j8UXywfPKzab2e743I,2066
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/api.js,sha256=Vjx6JZpe0iVJ6t8gp3TO3UjIyZkNBPN-taCS8MWwvJI,40952
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/api.min.js,sha256=und4HgOg2CxzBcqdJOvcT9LfJx0Hf9xQmEO_u7r1Ync,14594
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/breadcrumb.css,sha256=SJD_Mmi9BUmGXVhCXlIM1ei93yJVreQx0FAT68_t01w,2166
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/breadcrumb.min.css,sha256=-40OBPSbvydFFq9P3XPydeyWOrsh8g600mK9HXNoLnI,1192
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/button.css,sha256=wdCjDbx3M-jkpA7whQetZvX3ZE7wyBwRlCbcTVXKobc,116361
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/button.min.css,sha256=37bmMDGVPsjpcyAe7GqWsqv3UpsPTvlE5AiCVtT5NxY,90207
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/card.css,sha256=0oHZ2Qh74uybsgxLhP2ag_kQGTyOx3Kbzsjs6LvARzI,25330
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/card.min.css,sha256=anR2MHuWyx-iEc6wsI5nBMWnboFRqvOT7r-KOrKK-BQ,17410
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/checkbox.css,sha256=5u4dyQfH-wpdFbakv5CV4uIhWbBb2Tge0ZC5-tA2dX8,17473
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/checkbox.js,sha256=s-cRpbhGBxHgpnZdU3yFZciSW4n1QuruHjkX6gCyqT0,26912
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/checkbox.min.css,sha256=cy6WFzeIQ_5hHE7LEFxAK8yfR_zdfjoEubGRy1wCLv4,12727
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/checkbox.min.js,sha256=mlvPY4Gm-w6mgnAZ2GVMiBo5UDU7x_vaxKA5VRxdjR4,11369
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/colorize.js,sha256=imQdcIH6qpozSWEYeIpilPOfKHOJbD6V9RuKOC7yyEE,8710
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/colorize.min.js,sha256=oUDFJRLSaINMaJIZmuzYttfcMgkb7I6CpuEJ6bMfAVI,3270
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/comment.css,sha256=WAotERTFZQyxKNDJiSLlreq5KVja4xNM_bXUeG7NyVQ,5120
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/comment.min.css,sha256=JYlEkH8IupEqfItr2N9WZaNYkyF6rX2bnP6Y8ktXdCU,2945
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/container.css,sha256=bzDnWjcw404DoiHuz6-3iMRmbzJePDPgUGHcx3nFAuU,3099
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/container.min.css,sha256=VizQkNfO7_OANkM37_7xKxHQPEcUTBRuj3R_xkaULO8,1925
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dimmer.css,sha256=xKjQ9JWKG6zlrjyB5zECQc5vLZ7uCg7S5X-aUNKh6b8,5559
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dimmer.js,sha256=TuB9IPn4wx2n47nRVYf9CKvLotDL9d7gQcNArXupiRU,22303
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dimmer.min.css,sha256=-MBET9URQztSrMHpKaB8oyTckkm-lXisQbuxqd2UyOk,3517
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dimmer.min.js,sha256=4jCyaIQIKQX4zzzvspDqEvUmsPnpkr5lFuDOvKR_Wbo,8071
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/divider.css,sha256=a_0UrPhzoGJZZd8PBDgc5C0utGbzM6hjZbkDyy4pzfw,8034
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/divider.min.css,sha256=2XcokR56EPJZJh0ofnGgp-QPx2VpHYzDcdZdtR08uBs,6097
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dropdown.css,sha256=rJfAK26TU_FrVEYQxX1iWS4Z91SORlfnM128BfpI1II,37420
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dropdown.js,sha256=KnpOJhLPr4nCvh6M4qxqs8Y8lPGNZgLK6jZcGWrYzHo,145962
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dropdown.min.css,sha256=7Lwg8bz5Df_7YZ6D-ywoa01hT3IkqC09ZKBKtGe6gow,25679
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/dropdown.min.js,sha256=uEocYy6a0MpPLLHtYV7QAGdOeMRwE0Am2WtnOg_hBfM,50895
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/embed.css,sha256=19QhoCUbplkH_W5a7ejlpO6PoqSEFVA1xdHvaZp98yw,3169
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/embed.js,sha256=O3znHvAxO5xYlwzn4y3lQDde_iTdy29iUAmPqNfg4-0,20926
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/embed.min.css,sha256=SHH3TOGQhg1d5mrYCZeko1qvN3_NoETWQzBmfGUOpjc,1836
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/embed.min.js,sha256=QN4vIzPRpT4BFVPyA702nPG8nZKWfM-HygoF9jPBDJA,7728
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/feed.css,sha256=aFj6fLvIPQfeRxyKu_TlLKeUcwmI5GwOR7pY1Lb0JKM,5845
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/feed.min.css,sha256=-l8OBrtbhQi-fhQLHwA0cut_JWOuRWc44I0KpPxUx_M,3590
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/flag.css,sha256=rvyaZDdUGBPNuvOE8lzpW-Z4q3LYkJi8T99JlN1aF3E,22423
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/flag.min.css,sha256=WX74cISnDHD9kiyzCAiXiUWfnmv6cwdmBXgXtA5TUuw,18577
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/form.css,sha256=oNyqIev2BGrxigiMt72unbkne8-OWJ6UtaUGM4XZ9Y4,29092
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/form.js,sha256=FCxhpdJMgA6H88ka82b0jcqg-a8S53T0sVVbS_chLPA,57618
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/form.min.css,sha256=BmOkPn-zjy4WbHvcIvm18Vq0nhJjwADEBxvsLqX0sXg,21568
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/form.min.js,sha256=fK_KHBgbjblWL2-hRtohUzj6b12XWi6pVujkG1Ru9-w,20458
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/grid.css,sha256=I35Jh57rWCJoLMuJYXksccmBzc6V1XC1Mi_na_oAp84,73036
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/grid.min.css,sha256=5iW6X6_QT_7PgFBce4OTfLOOaSoovOoOb2U8w1yZDtc,57335
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/header.css,sha256=32EgHb7XmTT_AWH7Nr08PjXP2op-xhwlSqSIThcZKmY,13499
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/header.min.css,sha256=hHgAxfAsLFDPcyU6T6cRE_M6R-4rKEfPX5kOHVyJNes,8872
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/icon.css,sha256=CHLhcJDvnks69dz2lyZC0idfGnPFx4qdKA82Hm_bEDo,86945
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/icon.min.css,sha256=4opKQbtTAtsuIkfkEMuIA3eD3T4m1X3mfiCVTS6x2_A,67019
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/image.css,sha256=eZLe0mOsWAJETFvjXHlZXAnSY87SGQlRDJna2_EZ67U,5676
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/image.min.css,sha256=eXzqGHi6p4yiYGCiYPOcGXYbKeQtA0Df_w0gN88KCD0,3727
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/input.css,sha256=lYFTBK5TuWVaB2LSwjdl83iM9l4rn7jPwoFcEfvHQR8,12699
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/input.min.css,sha256=4ouF0Y10UKjiT6iJlHxD5aOe8WljYoAxPqpiy7iEdSw,8692
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/item.css,sha256=O1HR21E9wHtGxCmsqxcEc_65R6Ln3mOvImRwYMQso1g,9753
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/item.min.css,sha256=JRycvfshgviiiwTeAKUj0iPOov4-Uwaue3fTqaY_e5s,5985
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/label.css,sha256=9tLlAtf1Y3NSngCdO1DZ5YcRW_bu2dUKYUAXHPXm2hQ,28382
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/label.min.css,sha256=lzompqItwR2t_PJowmd07tg8QUPAb6yj58N9TwuNS6I,20005
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/list.css,sha256=CI9lvTBhVzN64aRNjJIwhG6bhKydfIbk_RdYQiaAYwE,22486
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/list.min.css,sha256=uXVJMLBcGUe7MZETm-CQO5LMhIbTFxajYZRBFTCTftY,16094
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/loader.css,sha256=Yz3gBB1JS-86XzSzztcNLE24ViO7UnP15A4M4hrFZUY,7128
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/loader.min.css,sha256=XtALKS7EZswkHXCCOthbxsuu36_tpZbqh-LMT1gaRAg,4702
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/menu.css,sha256=aOYMc10qx8D7fVQ7R83XXUkbrrFExpWkWc6ZnECfOJ4,45279
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/menu.min.css,sha256=cRSLOaiPiyfTQ4B4HT1OCF_2CWNzGcPO9Nns6Jrf4hg,31506
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/message.css,sha256=baLR2EbwIWTGTSvNc9qb2FmcWBeZHM3W0kBNvEdxZZU,12466
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/message.min.css,sha256=_plszMa027XkVjjehCTWxgIAftsTT1alP5I6EYfoVMI,8354
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/modal.css,sha256=86mR_k66q9mOP7jwLV6J4iRW1a06eSyQ6tcoZpUlHf8,12800
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/modal.js,sha256=ACX5Za25KIugyXD7eFndkqa18n7LHjZrBkWSpLs8uqQ,33442
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/modal.min.css,sha256=2GGe09HtCS6k__kprnoTwPMNu2CFCjEpaLQ2NBMLua8,8012
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/modal.min.js,sha256=8POmd6680Gev-MdgKbVOHP-9lm-9WB1AVyuLf2WRcxc,12701
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/nag.css,sha256=3Pz6rq1vWHNvB7UHhGFMPYvrP7VZP_pTM4PlwthnviI,2727
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/nag.js,sha256=KuXGvpOopM0i7syRO2cLSXrJ5I7AjwW3m7JMJLfGuN4,15553
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/nag.min.css,sha256=ohX1Du58QE8pgiBVEzmlhuT2rERTdxY4sasod_53NV4,1483
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/nag.min.js,sha256=UN_1Vcu3C_zxEatS7UZKw1x2blSyihZT2F1cmq7UZOk,5696
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/placeholder.css,sha256=ihZF0mK6texbUk_qWnqHqoZ0scXyDhHy-tr77Wougwg,5938
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/placeholder.min.css,sha256=UIFHVCJ1agMPhpUv-aqm6GeN3EmqUv5vClMm_5LEpuM,4452
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/popup.css,sha256=EitCUPKebavrCN6zwsWGZKfKCNjRJhaEGf6dJlCim7g,17407
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/popup.js,sha256=kzErFmfWsOMKZH-mbyLXQpJo_ajderu7pnq_faA7teM,52273
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/popup.min.css,sha256=YlUBHRAaq5FwMcI2g3DQtgcmxmRNG1rEZaGK2LCgVZ0,12032
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/popup.min.js,sha256=VvJYDjsOSD6VaYYZhuQYiPOpBbpRnmaddxVd6shZ9mU,18630
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/progress.css,sha256=p2R5CYj1cVgj0mT7XTBcKKky02140m4A-PumSFirAqc,10669
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/progress.js,sha256=uAQsAqW_DWnH0hK5dC0MVBBwuDyyu8UNolLxO0OSCfs,31204
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/progress.min.css,sha256=JtEqDPto1ZJiE-6k_WoZnzlhFUgwLJqH6VowDWGRez4,7422
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/progress.min.js,sha256=B676J_Jywi6IJ9e_E62nmk7Gn9KDkRQc7RfcIBKPQcI,12331
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/rail.css,sha256=XUZeNKRfoqs2bRnKz49lJU8ufQ625eFrtL7IxXLzBD0,2646
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/rail.min.css,sha256=4rrNcI5NVX845Bc9aBTWjwjg7tnakWuMHl8zWK-ucmE,1453
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/rating.css,sha256=E_jbykfZK88UZ6kKhL0T8mqn29mzefpwNzCDZEkIyKE,20696
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/rating.js,sha256=rxHeOv-TB5-ViM9hOfODUZMGqWUMNyPvIVIov306LuQ,14869
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/rating.min.css,sha256=4coaKkBwUtNfJL53qHC_TzTE7BmLMuVxDu_Z3gGOs7Q,18393
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/rating.min.js,sha256=jprk9qns6QqU1UWGtHMwug9A_ls7tVMV8p2mueJlj74,5354
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/reset.css,sha256=ygW8luaW-MLjYb6fFQYl0HBo4w-P9zwYkVZLpFOMFh0,9123
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/reset.min.css,sha256=Cm0OrnD_mnGgt3DPmGhhNLeNUAfYfQlCX2uCK7TG_o8,2822
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/reveal.css,sha256=33mQj7j0sprB4_0PrBqMJXxyXXFs4eP2rKoraaht8e8,8177
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/reveal.min.css,sha256=cHuyo1zDTWJH9C1f1GPtKHwuTzA_IUSFAfTH3q5yoME,5784
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/search.css,sha256=XN5UApUr9lkI_R-ThVSHhNM3UEMEvl8Z6LAYhFABPKw,10377
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/search.js,sha256=bm3TK1__R62sMnnTL_haoNAZiWbua0IGEgwfdQRpuRo,51211
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/search.min.css,sha256=HONcBrv7-3sDkmJ9Zwh8KYXWyy_fUw_MjDjhNMtU7hU,6891
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/search.min.js,sha256=gkqnhj5TvM_vwvHKAb4zBC7uL6mndcAlK6CEv5iEUwg,17622
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/segment.css,sha256=FERuSI78q9zgv_iWxHnXIbSnJDsgNKaLh8IgThCD9OM,20063
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/segment.min.css,sha256=zLmNnl__Po9TAZWlayMZpH_DpZXhaHXTcSa8KGeRxMs,13763
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/shape.css,sha256=5sbfPkJ2vSJEo7Ht21qKtfupKDnPdYtwpxkszIHwqsY,3865
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/shape.js,sha256=6D_QO1uZyRzcGRxxaCGP4zRTcnHH-rF11XSDj8fsVn0,29873
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/shape.min.css,sha256=7KDwgqAZXncDCzulBQT3C9UcI_kopiPdoSF2NxpJQWE,2521
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/shape.min.js,sha256=Njt3jnaL2VeRaG0rRHt2niY7YXHeD4Z_fj17tN2syLU,10803
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sidebar.css,sha256=pboKxonzco97CJSpXvUG9Bj65PyqdlTlmi8C_XNQcJI,15757
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sidebar.js,sha256=-nippst3RqSK6cFS0b1VQIhhZ7x455Oq5vpvjxdFOhc,34488
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sidebar.min.css,sha256=FxNmgO-xW6HZ8kqkaDpzZG2GGTYYvBIkhHFsPPUx8f8,10726
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sidebar.min.js,sha256=LxCRzL8rRPXulWQPWkMgncUHL0hBU4IHsuNOVzIMi3I,13466
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/site.css,sha256=tpW_cbiDbTbWVk1ECO4bnddYLlytmUgArSW1Jx3x9DU,3918
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/site.js,sha256=-yF4ejA2WwzIujQ1y9b-i6dxpRYCE8lCSU76CQ9hZhw,14604
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/site.min.css,sha256=AYTFsBcTjn7JH9tBf1s3S68Fxr83IHQf5t5FpD0vGcw,2452
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/site.min.js,sha256=f-45BTFplAj5X_I64VjaIAqTulT6dVhF-rHvOG8pZpM,6066
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/state.js,sha256=rdhOQ83U-t08-IE-ZL7qwiJ_2NPtm0E--BfFJVRylSY,21498
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/state.min.js,sha256=sgXcJIgGI3ymppa7VewFhV3g4rnB_D55Yvoo-QX4Whw,7804
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/statistic.css,sha256=zC6fj8Mg8giRj0rcaq1GVcAfmdLfb0QYgBx_B-7bXlE,13221
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/statistic.min.css,sha256=Nbx1qdI_NIb-YBfRIMcmKn-IdY5OmUdd8gNIGgA2TCs,9594
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/step.css,sha256=3dgzVkMcFYJKP_UPk7quva4L7GLD6sln1aroRZlrcw8,23555
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/step.min.css,sha256=hifahh65UcRx9Cux-rpwi5pTJImD83BlfH1qbkiaWCI,19188
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sticky.css,sha256=eOSA5O3_qugssoDgdTovRNvNMe0kEWqQz1yQGJFZCQM,1288
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sticky.js,sha256=kHIMXTF2Wj8DYTaDRRqQ9ZVNUTOjDbBF84Dwm4tFYaM,31814
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sticky.min.css,sha256=SYOFZjW67UWxBsrtAfD4g0Tvf6CnltYw_IN0VemK2hU,607
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/sticky.min.js,sha256=fu91ThJa6qnZoQAGTpxUw5Q1UN7d2Y_KHS0kjoteWCw,11854
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/tab.css,sha256=aX-PA0rhwxK3q6l3A3przKBvFAQ9LkhlDV3mETbQR98,1865
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/tab.js,sha256=xvNcoJnirQ1TJgVMy_8_AARTIveekx3bgoXNLc-FhC0,33771
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/tab.min.css,sha256=vTnhMR4q6W1dLyB3QYdtwRWnl2XLdtFA0I3kSnZH_EY,1075
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/tab.min.js,sha256=MgUTbr8RHTNylv3wIeBmCec-mS1iL9IJW7Y0NahYmrs,11487
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/table.css,sha256=omOnJC5bkklgjC6vJgTYJae-wbp3MSIu-mUM0gc5Q-o,25536
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/table.min.css,sha256=ODiMJS5bcTBrVMu-BtZytuSNpu3wHtILDb8no5BLNhw,18015
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/transition.css,sha256=XMKp0LQFx2Ec2oOjFuAPJik8VrDUgysP4TNOJH3Rzuw,49176
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/transition.js,sha256=sccxnC8Z9hx9lzlJLPYQ9E5FHETVYEVaA1uIQaA7ubU,36076
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/transition.min.css,sha256=cty1gaoozlRlEnqcQir7t93a7sOy2uCLp0c4jyBLWwA,33525
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/transition.min.js,sha256=k30cmb6hiQ_LGKpX2AcllUduUJ0kA4DKKStgUxkGQzM,13010
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/video.css,sha256=R9cpZZmFTZ70NmFVp7XhHOXaoZ3iodK1WlxGrisY7Tw,2346
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/video.js,sha256=Si_eMYc42BiLyyl4ur4u7K17kyw9biw-eAtbidaQH0c,16252
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/video.min.css,sha256=0MWKfR7_d_meresYhKG49N4ikgDL9YKvdj4ffNqhti0,1328
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/video.min.js,sha256=f7uHgbRqRCqHKBJm7CB31wMMnTjYHPmYaLi1D2i9QfI,6090
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/visibility.js,sha256=p_2kDyoT-GlUY_iLWH8RCRtSl-zunZ1oNx3dJwvyKbA,44180
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/visibility.min.js,sha256=Th3QlAMxD5M2RJ9nNOvuxJZCgZIlavx5-51jABKTs2A,16294
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/visit.js,sha256=9DsUmsPzmp3XD1pplmIeV5tNIeqEHMml5hcr3omsBJw,16142
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/components/visit.min.js,sha256=bT8zWI7mcAwX-Fyt67gogo3u_IT7q8uimamY5Vhk3eU,5887
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/package.js,sha256=BHq6qGCSMdDXDGJxZ4zxnKaREbFM2un2VqCkydrBTf0,774
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/package.json,sha256=Sy3ZVA4SxFzecOO88h1IVAnBiuDpRtXiUg6ME_YArI0,524
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.css,sha256=aje_ma2N_7VT1k2QTOLeqr3SfQ3Cr-7vB05D2-uo-YQ,869203
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.js,sha256=t-thIOFbQol3-vcB3C7kRbS49jG2_LC5dEp7NLxBpuA,759089
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.min.css,sha256=f5Dpq5VRrbzn8POovxN9HR3S7LhHQIAiCKYz4PB4ZZA,628934
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.min.js,sha256=69cT25pJVUmAyniwWMglXlEOEeZYuhmD8Hbj58gCS7Y,275740
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/brand-icons.eot,sha256=0CPFX94iBJXxOoe3KZXg35jI0ok1dymdGZ2lu_W0_gI,98640
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/brand-icons.svg,sha256=IcTTApw6luFW48z0iPvWxbD_LpBQYBaIN5LGFInrfpU,508636
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/brand-icons.ttf,sha256=QuNp3Iw3KXO6d6gmti0seiBwUyMT34MqIyiN23aXQVg,98404
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/brand-icons.woff,sha256=n6_Ww-e_wUXbQqkG5fpo_mpvlyIfAT0-gz_DIxuZLEQ,63728
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/brand-icons.woff2,sha256=59TVNAu-V6Adj3mSFC4nY9Q41Xg4kMdnSDBu6_oFamk,54488
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.eot,sha256=i04bhH4iIz1PRn00-u_nvL_rzm-pu77lYMRc2JSGh1E,106004
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.otf,sha256=vcXQufOXvoPohsdLAUHRlUqkOEs1nc5JgpmUxKLh978,93888
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.svg,sha256=GzY2PC_CxigjA7ao5Pm45c8-mD38cSHKeoiagKC-kA4,392355
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.ttf,sha256=y3-B9UL1xBiju7mtP5--eEFR0TsEzsUOzt7GATMko9o,105784
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.woff,sha256=lbakhA-HEeyrQnvCNuuGCY235ceCuvsTnIwwgFql_-E,50524
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.woff2,sha256=Q0RmtZVFqKHKxt2zgZfNxrNZlamMPzgS-4jWGxwwDdM,40148
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outline-icons.eot,sha256=RTf6BjQO5iwmTp16TYqryrPee9osXMM0AQ9GtoMQb8s,31156
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outline-icons.svg,sha256=T4_RcS28l2Pa57YNTH3ryg_433tFrdN6pDBt0iGL1zE,107567
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outline-icons.ttf,sha256=Zxchcur85FY3JeZhBD1duFS4Z2ip6L05dY2-gcR5aTU,30928
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outline-icons.woff,sha256=S8NZwnBXs-0LrKZtbFNJpdSmBQlvvHh1Bhui2Ro9bQU,14712
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outline-icons.woff2,sha256=TSiDRDsk5CRSf2oKeqKJez33HyOdtANzxP92DkgUeAE,12240
pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/images/flags.png,sha256=lNXH8WYTAcSm3Ekdct1VmgYgzZF6gm8N8bAju5bqnd0,28123
pyOpenRPA/Resources/Web/jQuery/jquery-3.1.1.min.js,sha256=HPMOWdIdSuVgr3FD9ZE-_MgiK8qk_MdQjrgCtfqp6U4,86713
pyOpenRPA/Resources/Web/pyOpenRPA_logo.png,sha256=7rulXo_C57xJQEaYWmAkChxXb6xbDW2zq-werzVbDbc,4899
pyOpenRPA/Robot/Clipboard.py,sha256=q76X8L21zJwcwdoJJNPeCEwAV30xS6ylHP1WwvtxoWI,722
pyOpenRPA/Robot/OrchestratorConnector.py,sha256=JUtdiUXCruqUqBD19gJBl9jk_b-tpWWx_v3MfBoKzoQ,20445
pyOpenRPA/Robot/README.md,sha256=e2hKh7Tx6DAsX6jY_hBDhguL1L2Wiv6iugDB5otMzIA,2293
pyOpenRPA/Robot/SettingsTemplate.py,sha256=Rp5XPeV2I4tCS2uf4Zkqm_ERJ6pZMg4-e5_lMqGJYLk,1453
pyOpenRPA/Robot/Test.py,sha256=qXr990nXiFZX5SNv6QN9GLb_U4HZRmJnbZR2qSnwilY,2878
pyOpenRPA/Robot/UIDesktop.py,sha256=3I2bllTDvR9d10O2ltkjoKmYw34wkkDAZfPlRpwbj30,77476
pyOpenRPA/Robot/Utils/JSONNormalize.py,sha256=aIuVzuZDazhxkCOzoOjfhHVz66mp2FWdfPv5E7KWF5Y,3890
pyOpenRPA/Robot/Utils/ProcessBitness.py,sha256=WlKL-DklGaoTnchtapOTM_ydxSB4yOeo9lcG3zr2VME,4524
pyOpenRPA/Robot/Utils/ProcessCommunicator.py,sha256=8GfmLnOvAdosmt7YNT86uEV9cjhKippssCX62wOMJwM,8039
pyOpenRPA/Robot/Utils/TimerRepeat.py,sha256=_kTct3X9SIEvS3DKM5bGNnjRBVJasmMFZntQaVbPX_E,961
pyOpenRPA/Robot/Utils/ValueVerify.py,sha256=ObskxU4fOMoCGw74_nzYt6-a5jjrAckb3sdBLYyhYxY,777
pyOpenRPA/Robot/Utils/__init__.py,sha256=pHlSQGRFKmn5RCTHIf-3a2ooA9T2xNOWridckynP7W4,28
pyOpenRPA/Robot/Utils/__pycache__/JSONNormalize.cpython-37.pyc,,
pyOpenRPA/Robot/Utils/__pycache__/ProcessBitness.cpython-37.pyc,,
pyOpenRPA/Robot/Utils/__pycache__/ProcessCommunicator.cpython-37.pyc,,
pyOpenRPA/Robot/Utils/__pycache__/TimerRepeat.cpython-37.pyc,,
pyOpenRPA/Robot/Utils/__pycache__/ValueVerify.cpython-37.pyc,,
pyOpenRPA/Robot/Utils/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Robot/Window.py,sha256=UJl-sg4RvvJ35aG9jZOzqGVwE15XK7qPHqoOBD13xFk,431
pyOpenRPA/Robot/__init__.py,sha256=L-5tPm6evytGWOzlqIq-2oiIhmQnruaxwIstyyaMkVI,253
pyOpenRPA/Robot/__main__.py,sha256=l6II8JuXCsnVOcfs6-2jvogKYTVhbfj3Jl2ld3OIP7s,1992
pyOpenRPA/Robot/__pycache__/Clipboard.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/OrchestratorConnector.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/SettingsTemplate.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/Test.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/UIDesktop.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/Window.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Robot/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Studio/JSONNormalize.py,sha256=g0Z8G2wojCgTAdZtyRiCfe0_FHSeAi72Va7R7mk27gg,3347
pyOpenRPA/Studio/ProcessCommunicator.py,sha256=HD3XASJae31_HV3OznFe8E2MgZFXnwt7YveVN82M8nU,7912
pyOpenRPA/Studio/RobotConnector.py,sha256=CYO0dQoqfs44SYD_VZ_TJh3WFu_DXigHBLHj4GJ2Icc,5038
pyOpenRPA/Studio/Studio.py,sha256=_BXQjAMHew2fRWloXdqPOmYHX6i6C8ELPsW1TZNvjz4,8618
pyOpenRPA/Studio/ValueVerify.py,sha256=ObskxU4fOMoCGw74_nzYt6-a5jjrAckb3sdBLYyhYxY,777
pyOpenRPA/Studio/Web/Index.xhtml,sha256=wo3Y5CzWJQYMw9AgNHXynt1yGDLIoihRlt1weFLSuYQ,48240
pyOpenRPA/Studio/Web/favicon.ico,sha256=6S8XwSQ_3FXPpaX6zYkf8uUewVXO9bHnrrDHEoWrEgw,112922
pyOpenRPA/Studio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Studio/__main__.py,sha256=_57Rnq9DKbmmlpGFqIwVrWn_LRcU8jjmMTOny4_zlP8,308
pyOpenRPA/Studio/__pycache__/JSONNormalize.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/ProcessCommunicator.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/RobotConnector.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/Studio.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/ValueVerify.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Studio/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/ExcelCom.py,sha256=hp0dvXOEC7Au00ueh7pqxkdixV-PC-km7tCt-wRunYs,343
pyOpenRPA/Tools/RobotDB/HowToUse,sha256=TUXPZAFcse-PSlKFM6jcaYuuZZEmXOSSvgeqrbmIDoc,1473
pyOpenRPA/Tools/RobotDB/RobotDB.py,sha256=qtGu8PS2atd0L8taCNpk-08Qpxp8Qz1lqwAcBkyLFLM,1655
pyOpenRPA/Tools/RobotDB/Server.py,sha256=rjW9Sg-j9P8pFQD66Uih-rke6-f6sCulinwi4_W-3mc,19933
pyOpenRPA/Tools/RobotDB/ServerSettings.py,sha256=5p9JwrpKHh68oVHIWazTajB6AOfzeapARbvGcJOFmNc,7406
pyOpenRPA/Tools/RobotDB/__init__.py,sha256=qVH8fEPgXk54rmy-ol0PnT8GF5OlGE0a8mExwJ4tFqY,124
pyOpenRPA/Tools/RobotDB/__main__.py,sha256=w9sXIF4r_PeWJjHJutTuH8DSYpXxpgcAN0KUOjiJ6PI,140
pyOpenRPA/Tools/RobotDB/__pycache__/ExcelCom.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/RobotDB.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/Server.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/ServerSettings.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotDB/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotScreenActive/ConsoleStart.bat,sha256=_HNadUKHOYI5y6foG3srh8wjSzhX33xaKNylFtDjOJk,114
pyOpenRPA/Tools/RobotScreenActive/Monitor.py,sha256=TV-YisVqa_uGiyJLG9oK4u-5aDjGiFYZFh1dPjOgYc8,492
pyOpenRPA/Tools/RobotScreenActive/Screen.py,sha256=VnYcvCVymrD35l2J4ln_tlVn7CilZhxE4Ggw9P-OhIw,606
pyOpenRPA/Tools/RobotScreenActive/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/RobotScreenActive/__main__.py,sha256=JASxDDVKWUU7DAbDkRrGTrPk-P7LZchTZFh8usp6b4U,593
pyOpenRPA/Tools/RobotScreenActive/__pycache__/Monitor.cpython-37.pyc,,
pyOpenRPA/Tools/RobotScreenActive/__pycache__/Screen.cpython-37.pyc,,
pyOpenRPA/Tools/RobotScreenActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/RobotScreenActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/Crypter.py,sha256=VRrE5-oQxQtvMEPHM1lMXp2CKnceNBmIWJnsJoJkaVE,3616
pyOpenRPA/Tools/SafeSource/DistrCreate.py,sha256=-_8BTle57LBKVknnB_3af-LghxrRmRGfRNu08CLNIvY,3232
pyOpenRPA/Tools/SafeSource/DistrRun.py,sha256=zwUh6Jy-rDAZHV6fcTUMupkukojntFMroHJHMsNQgrE,9637
pyOpenRPA/Tools/SafeSource/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/SafeSource/__main__.py,sha256=g5aYWnuUZoM2jDX2mSIl9tRAJg05tu5VxD2rGJWcACg,649
pyOpenRPA/Tools/SafeSource/__pycache__/Crypter.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/DistrCreate.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Tools/SafeSource/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Tools/Terminator.py,sha256=VcjX3gFXiCGu3MMCidhrTNsmC9wsAqfjRJdTSU9fLnU,2178
pyOpenRPA/Tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/__pycache__/Terminator.cpython-37.pyc,,
pyOpenRPA/Tools/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/__init__.py,sha256=HIl4GtAt0lGzG2lJPyRwIevTFjIX1iwfYYFpPSUlxAc,175
pyOpenRPA/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/test.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.1)
Root-Is-Purelib: true
Tag: py3-none-any

@ -1,6 +1,288 @@
# Def to check inGSettings and update structure to the backward compatibility
# !!! ATTENTION: Backward compatibility has been started from v1.1.13 !!!
# So you can use config of the orchestrator 1.1.13 in new Orchestrator versions and all will be ok :) (hope it's true)
import win32security, json, datetime, time, copy
# # # # # # # # # # # # # # # # # # #
# Backward compatibility Web defs up to v1.2.0
# # # # # # # # # # # # # # # # # # #
# UserAccess get rights hierarchy dict in json
def v1_2_0_UserRoleHierarchyGet(inRequest,inGlobalDict):
inResponseDict = inRequest.OpenRPAResponseDict
# Create result JSON
lResultDict = inRequest.OpenRPA["DefUserRoleHierarchyGet"]() # Get the User Role Hierarchy list
# Send message back to client
message = json.dumps(lResultDict)
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
from inspect import signature # For detect count of def args
# /Orchestrator/RobotRDPActive/ControlPanelDictGet
def v1_2_0_RobotRDPActive_ControlPanelDictGet(inRequest,inGlobalDict):
inResponseDict = inRequest.OpenRPAResponseDict
lResultDict = {
"DataList":[
# {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False}
]
}
# Iterate throught the RDP List
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]:
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"]["FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lResultDict["DataList"].append(lDataItemDict)
# Send message back to client
message = json.dumps(lResultDict)
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
# def to check control panels for selected session
def v1_2_0_Monitor_ControlPanelDictGet_SessionCheckInit(inRequest,inGlobalDict):
lL = inGlobalDict["Logger"] # Alias for logger
lLifetimeSecFloat = inGlobalDict["Client"]["Session"]["LifetimeSecFloat"]
lLifetimeRequestSecFloat = inGlobalDict["Client"]["Session"]["LifetimeRequestSecFloat"]
lControlPanelRefreshIntervalSecFloat = inGlobalDict["Client"]["Session"]["ControlPanelRefreshIntervalSecFloat"]
lCookieSessionGUIDStr = None # generate the new GUID
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Technicaldef - interval check control panels + check actuality of the session by the datetime
def TechnicalCheck():
lItemValue = inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]
# Lifetime is ok - check control panel
lDatasetCurrentBytes = v1_2_0_Monitor_ControlPanelDictGet(inRequest,inGlobalDict) # Call the control panel
if lDatasetCurrentBytes != lItemValue["DatasetLast"]["ControlPanel"]["Data"]: # Check if dataset is changed
lItemValue["DatasetLast"]["ControlPanel"]["Data"] = lDatasetCurrentBytes # Set new datset
lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] = True # Set flag to return the data
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Technicaldef - Create new session struct
def TechnicalSessionNew(inSessionGUIDStr):
lCookieSessionGUIDStr = inSessionGUIDStr # Generate the new GUID
lSessionNew = { # Session with some GUID str. On client session guid stored in cookie "SessionGUIDStr"
"InitDatetime": datetime.datetime.now(), # Datetime when session GUID was created
"DatasetLast": {
"ControlPanel": {
"Data": None, # Struct to check with new iterations. None if starts
"ReturnBool": False # flag to return, close request and return data as json
}
},
"ClientRequestHandler": inRequest, # Last client request handler
"UserADStr": inRequest.OpenRPA["User"], # User, who connect. None if user is not exists
"DomainADStr": inRequest.OpenRPA["Domain"], # Domain of the user who connect. None if user is not exists
}
inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr] = lSessionNew # Set new session in dict
inRequest.OpenRPAResponseDict["SetCookies"]["SessionGUIDStr"] = lCookieSessionGUIDStr # Set SessionGUIDStr in cookies
if lL: lL.info(f"New session GUID is created. GUID {lCookieSessionGUIDStr}")
return lCookieSessionGUIDStr
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
lCreateNewSessionBool = False # Flag to create new session structure
# step 1 - get cookie SessionGUIDStr
lSessionGUIDStr = inRequest.headers.get("SessionGUIDStr", None)
if lSessionGUIDStr is not None: # Check if GUID session is ok
#inRequest.OpenRPAResponseDict["StatusCode"] = 301
#inRequest.OpenRPAResponseDict["Headers"]["Location"] = "/"
#if lL: lL.info(f"GUID is detected - send HTTP 301 to refresh page")
lCookieSessionGUIDStr = lSessionGUIDStr # Get the existing GUID
if lSessionGUIDStr not in inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lCookieSessionGUIDStr= TechnicalSessionNew(inSessionGUIDStr = lSessionGUIDStr) # Create new session
else: # Update the datetime of the request session
inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]["InitDatetime"]=datetime.datetime.now()
else:
lCookieSessionGUIDStr = TechnicalSessionNew(inSessionGUIDStr = lSessionGUIDStr) # Create new session
# Init the RobotRDPActive in another thread
#lThreadCheckCPInterval = threading.Thread(target=TechnicalIntervalCheck)
#lThreadCheckCPInterval.daemon = True # Run the thread in daemon mode.
#lThreadCheckCPInterval.start() # Start the thread execution.
# Step 2 - interval check if data is exist
lTimeStartSecFloat = time.time()
lDoWhileBool = True # Flag to iterate throught the lifetime of the request
while lDoWhileBool:
#print(lTechnicalSessionGUIDCache)
#print(lCookieSessionGUIDStr)
if lCookieSessionGUIDStr in inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lItemValue = inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]
if (time.time() - lTimeStartSecFloat) >= lLifetimeRequestSecFloat: # Check if lifetime client request is over or has no key
if lL: lL.debug(f"Client request lifetime is over")
lDoWhileBool = False # Stop the iterations
if lDoWhileBool:
TechnicalCheck() # Calculate the CP
if lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] == True: # Return data if data flag it True
lDatasetCurrentBytes = lItemValue["DatasetLast"]["ControlPanel"]["Data"] # Set new dataset
inResponseDict = inRequest.OpenRPAResponseDict
inResponseDict["Body"] = lDatasetCurrentBytes
lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] = False # Set flag that data was returned
lDoWhileBool = False # Stop the iterations
else:
lCookieSessionGUIDStr = TechnicalSessionNew(inSessionGUIDStr = lCookieSessionGUIDStr) # Create new session
if lDoWhileBool: # Sleep if we wait hte next iteration
time.sleep(lControlPanelRefreshIntervalSecFloat) # Sleep to the next iteration
def v1_2_0_Monitor_ControlPanelDictGet(inRequest,inGlobalDict):
inResponseDict = inRequest.OpenRPAResponseDict
lL = inGlobalDict["Logger"] # Alias for logger
# Create result JSON
lResultJSON = {"RenderRobotList": [], "RenderRDPList": []}
lRenderFunctionsRobotList = inGlobalDict["ControlPanelDict"]["RobotList"]
for lItem in lRenderFunctionsRobotList:
lUACBool = True # Check if render function is applicable User Access Rights (UAC)
if inGlobalDict["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True:
lUserRights = inGlobalDict["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
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"](inGlobalDict)
elif lDEFARGLen == 2: # def (inRequest, inGSettings)
lItemResultDict = lItem["RenderFunction"](inRequest, inGlobalDict)
elif lDEFARGLen == 0: # def ()
lItemResultDict = lItem["RenderFunction"]()
# RunFunction
lResultJSON["RenderRobotList"].append(lItemResultDict)
except Exception as e:
if lL: lL.exception(f"Error in control panel. CP item {lItem}. Exception is below")
# Iterate throught the RDP list
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]:
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][
lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr": "", "SessionHexStr": "", "IsFullScreenBool": False,
"IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"][
"FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lResultJSON["RenderRDPList"].append(lDataItemDict)
# Send message back to client
message = json.dumps(lResultJSON)
# Write content as utf-8 data
#inResponseDict["Body"] = bytes(message, "utf8")
return bytes(message, "utf8")
from . import __Orchestrator__ # For user defs
# v1.2.0 Def for old procesor to new processor
# Return new activity for the new processor
def v1_2_0_ProcessorOld2NewActivityDict(inActivityOld):
if inActivityOld["Type"] == "WindowsLogon":
lResult = {
"Def": __Orchestrator__.OSCredentialsVerify, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList":[], # Args list
"ArgDict":{"inUserStr": inActivityOld["User"],"inPasswordStr":inActivityOld["Password"],"inDomainStr":inActivityOld["Domain"]}, # Args dictionary
"ArgGSettings": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "GlobalDictKeyListValueGet":
lResult = {
"Def": __Orchestrator__.GSettingsKeyListValueGet, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList":[], # Args list
"ArgDict":{"inKeyList": inActivityOld["KeyList"]}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "CMDStart":
lResult = {
"Def": __Orchestrator__.OSCMD, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inCMDStr": inActivityOld["Command"]}, # Args dictionary
"ArgGSettings": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": "inLogger" # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "OrchestratorRestart":
lResult = {
"Def": __Orchestrator__.OrchestratorRestart, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "OrchestratorSessionSave":
lResult = {
"Def": __Orchestrator__.OrchestratorSessionSave,
# def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "GlobalDictKeyListValueSet":
lResult = {
"Def": __Orchestrator__.GSettingsKeyListValueSet, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inKeyList": inActivityOld["KeyList"], "inValue": inActivityOld["Value"]}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "GlobalDictKeyListValueAppend":
lResult = {
"Def": __Orchestrator__.GSettingsKeyListValueAppend, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inKeyList": inActivityOld["KeyList"], "inValue": inActivityOld["Value"]}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "GlobalDictKeyListValueOperator+":
lResult = {
"Def": __Orchestrator__.GSettingsKeyListValueOperatorPlus, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inKeyList": inActivityOld["KeyList"], "inValue": inActivityOld["Value"]}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "ProcessStart":
lResult = {
"Def": __Orchestrator__.ProcessStart, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inPathStr": inActivityOld["Path"], "inArgList": inActivityOld["ArgList"]}, # Args dictionary
"ArgGSettings": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "ProcessStartIfTurnedOff":
lResult = {
"Def": __Orchestrator__.ProcessStart, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inPathStr": inActivityOld["Path"], "inArgList": inActivityOld["ArgList"], "inStopProcessNameWOExeStr": inActivityOld["CheckTaskName"]}, # Args dictionary
"ArgGSettings": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "ProcessStop":
lResult = {
"Def": __Orchestrator__.ProcessStop, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inProcessNameWOExeStr": inActivityOld["Name"], "inCloseForceBool": inActivityOld["FlagForce"], "inUserNameStr": inActivityOld["User"]}, # Args dictionary
"ArgGSettings": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
elif inActivityOld["Type"] == "PythonStart":
lResult = {
"Def": __Orchestrator__.PythonStart, # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList": [], # Args list
"ArgDict": {"inModulePathStr": inActivityOld["ModuleName"], "inDefNameStr": inActivityOld["FunctionName"], "inArgList": inActivityOld["ArgList"],
"inArgDict": inActivityOld["ArgDict"] }, # Args dictionary
"ArgGSettings": None, # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": "inLogger" # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
else:
raise Exception(f"BackwardCompatibility up to v1.2.0, old processor: No type {inActivityOld['Type']} has been found in old processor.")
return lResult # return the result
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # HERE IS THE MAIN DEF WHICH IS LAUNCHES WHEN START # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def Update(inGSettings):
lL = inGSettings["Logger"] # Alias for logger
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@ -8,7 +290,7 @@ def Update(inGSettings):
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if "Autocleaner" not in inGSettings: # Add "Autocleaner" structure
inGSettings["Autocleaner"] = { # Some gurbage is collecting in g settings. So you can configure autocleaner to periodically clear gSettings
"IntervalSecFloat": 600.0, # Sec float to periodically clear gsettings
"IntervalSecFloat": 7200.0, # Sec float to periodically clear gsettings
}
if lL: lL.warning(f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Autocleaner' structure") # Log about compatibility
if "Client" not in inGSettings: # Add "Client" structure
@ -34,10 +316,109 @@ def Update(inGSettings):
}
}
if lL: lL.warning(f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Client' structure") # Log about compatibility
if "RequestTimeoutSecFloat" not in inGSettings["Server"]: # Add Server > "RequestTimeoutSecFloat" property
if "Server" in inGSettings and "RequestTimeoutSecFloat" not in inGSettings["Server"]: # Add Server > "RequestTimeoutSecFloat" property
inGSettings["Server"]["RequestTimeoutSecFloat"] = 300 # Time to handle request in seconds
if lL: lL.warning(
f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Server' > 'RequestTimeoutSecFloat' property") # Log about compatibility
if "DefSettingsUpdatePathList" not in inGSettings["OrchestratorStart"]: # Add OrchestratorStart > "DefSettingsUpdatePathList" property
inGSettings["OrchestratorStart"]["DefSettingsUpdatePathList"] = [] # List of the .py files which should be loaded before init the algorythms
if lL: lL.warning(f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'OrchestratorStart' > 'DefSettingsUpdatePathList' property list") # Log about compatibility
if lL: lL.warning(f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'OrchestratorStart' > 'DefSettingsUpdatePathList' property list") # Log about compatibility
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# v1.1.20 to v1.2.0
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Update Structure gSettings["Processor"]
from . import SettingsTemplate
if "DumpLogListRefreshIntervalSecFloat" not in inGSettings["Client"]: # Create new ProcessorDict structure
inGSettings["Client"].update({
"DumpLogListRefreshIntervalSecFloat": 3.0, # Duration between updates for the Client
"DumpLogListCountInt": 100, # Set the max row for the dump
"DumpLogList": [], # Will be filled automatically
"DumpLogListHashStr": None, # Will be filled automatically
})
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'Client > DumpLog... with default parameters'") # Log about compatibility
if "Processor" in inGSettings: # Check if Processor exist
# Update Logger
if lL is not None:
SettingsTemplate.LoggerDumpLogHandlerAdd(inLogger=lL, inGSettingsClientDict=inGSettings["Client"])
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Add web dump log in logger as handler") # Log about compatibility
del inGSettings["Processor"] # Remove the key
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Remove old structure 'Processor'") # Log about compatibility
if "ProcessorDict" not in inGSettings: # Create new ProcessorDict structure
inGSettings["ProcessorDict"]={
"ActivityList": [ # List of the activities
# {
# "Def":"DefAliasTest", # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
# "ArgList":[1,2,3], # Args list
# "ArgDict":{"ttt":1,"222":2,"dsd":3} # Args dictionary
# "ArgGSettings": # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# },
],
"AliasDefDict": {} , # Storage for def with Str alias. To use it see pyOpenRPA.Orchestrator.ControlPanel
"CheckIntervalSecFloat": 1.0, # Interval for check gSettings in ProcessorDict > ActivityList
"ExecuteBool": True, # Flag to execute thread processor
"ThreadIdInt": None # Fill thread id when processor will be inited
}
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new structure 'ProcessorDict'") # Log about compatibility
if "VersionStr" not in inGSettings: # Create new ProcessorDict structure
inGSettings["VersionStr"] = None
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'VersionStr'") # Log about compatibility
if "AgentDict" not in inGSettings: # Create new AgentDict structure
inGSettings["AgentDict"]= {}
if lL: lL.warning(
f"Backward compatibility (v1.1.20 to v1.2.0): Create new attribute 'AgentDict'") # Log about compatibility
# Alg to convert UAC ControlPanelAllawedList to UACClient hierarchy
# 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
# # Convert to UACClient dict
if "Server" in inGSettings:
# Check if Server is active > convert to ServerDict
inGSettings["ServerDict"] = inGSettings["Server"]
if lL: lL.warning(
f"Backward compatibility (v1.1.20 to v1.2.0): Convert Server to ServerDict") # Log about compatibility
# Remove old structure Scheduler
del inGSettings["Server"]
lShowWarnBool = False
lRuleDomainUserDeepCopyDict = copy.deepcopy(inGSettings["ServerDict"]["AccessUsers"]["RuleDomainUserDict"])
for lItemKeyTurple in lRuleDomainUserDeepCopyDict:
lDomainUpperStr = lItemKeyTurple[0]
lUserUpperStr = lItemKeyTurple[1]
lItemDict = lRuleDomainUserDeepCopyDict[lItemKeyTurple]
if "ControlPanelKeyAllowedList" in lItemDict:
lShowWarnBool = True
if len(lItemDict["ControlPanelKeyAllowedList"])>0:
lUACClientDict = {"pyOpenRPADict": {"CPKeyDict": {}}}
else:
lUACClientDict = {}
for lAllowedKeyItemStr in lItemDict["ControlPanelKeyAllowedList"]:
lUACClientDict["pyOpenRPADict"]["CPKeyDict"][lAllowedKeyItemStr]=True # Convert
# Send update UACDict for user by the list
__Orchestrator__.UACUpdate(inGSettings=inGSettings,inADLoginStr=lUserUpperStr, inADStr=lDomainUpperStr, inRoleHierarchyAllowedDict=lUACClientDict)
# remove "ControlPanelKeyAllowedList" - will be removed in __Orchestrator__.UACUpdate
#del inGSettings["ServerDict"]["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"]
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Convert ControlPanelDict to CPDict") # Log about compatibility
# Check if Scheduler is active > convert to SchedulerDict
if "Scheduler" in inGSettings:
if "SchedulerDict" not in inGSettings: inGSettings["SchedulerDict"]={ "CheckIntervalSecFloat": 5.0, "ActivityTimeList":[]}
if "ActivityTimeCheckLoopSeconds" in inGSettings["Scheduler"]:
inGSettings["SchedulerDict"]["CheckIntervalSecFloat"] = inGSettings["Scheduler"]["ActivityTimeCheckLoopSeconds"]
for lItemDict in inGSettings["Scheduler"]["ActivityTimeList"]:
# Append to the new struct if this is not periodic ("TimeHH:MMStart"and "TimeHH:MMStop")
if "TimeHH:MMStart" not in lItemDict and "TimeHH:MMStop" not in lItemDict:
lItemDict["ActivityList"]=[v1_2_0_ProcessorOld2NewActivityDict(inActivityOld=lItemDict["Activity"])]
del lItemDict["Activity"]
inGSettings["SchedulerDict"]["ActivityTimeList"].append(lItemDict)
# Remove old structure Scheduler
del inGSettings["Scheduler"]
if lL: lL.warning(f"Backward compatibility (v1.1.20 to v1.2.0): Convert Scheduler to SchedulerDict with new features") # Log about compatibility

@ -1,205 +0,0 @@
import subprocess
import json
import datetime
import time
import codecs
import os
import signal
import sys #Get input argument
import pdb
from . import Server
from . import Timer
from . import Processor
from . import BackwardCompatibility # Backward compatibility from v1.1.13
#from .Settings import Settings
import importlib
from importlib import util
import threading # Multi-threading for RobotRDPActive
from .RobotRDPActive import RobotRDPActive #Start robot rdp active
from .RobotScreenActive import Monitor #Start robot screen active
import uuid # Generate uuid
import datetime # datetime
#Единый глобальный словарь (За основу взять из Settings.py)
global gSettingsDict
# Interval gsettings auto cleaner
def GSettingsAutocleaner(inGSettings):
while True:
time.sleep(inGSettings["Autocleaner"]["IntervalSecFloat"]) # Wait for the next iteration
lL = inGSettings["Logger"]
if lL: lL.info(f"Autocleaner is running") # Info
lNowDatetime = datetime.datetime.now() # Get now time
# Clean old items in Client > Session > TechnicalSessionGUIDCache
lTechnicalSessionGUIDCacheNew = {}
for lItemKeyStr in inGSettings["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lItemValue = inGSettings["Client"]["Session"]["TechnicalSessionGUIDCache"][lItemKeyStr]
if (lNowDatetime - lItemValue["InitDatetime"]).total_seconds() < inGSettings["Client"]["Session"]["LifetimeSecFloat"]: # Add if lifetime is ok
lTechnicalSessionGUIDCacheNew[lItemKeyStr]=lItemValue # Lifetime is ok - set
else:
if lL: lL.debug(f"Client > Session > TechnicalSessionGUIDCache > lItemKeyStr: Lifetime is expired. Remove from gSettings") # Info
inGSettings["Client"]["Session"]["TechnicalSessionGUIDCache"] = lTechnicalSessionGUIDCacheNew # Set updated Cache
# # # # # # # # # # # # # # # # # # # # # # # # # #
#Call Settings function from argv[1] file
################################################
lSubmoduleFunctionName = "Settings"
lFileFullPath = sys.argv[1]
lModuleName = (lFileFullPath.split("\\")[-1])[0:-3]
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification)
lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec)
gSettingsDict = None
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
gSettingsDict = getattr(lTechModuleFromSpec, lSubmoduleFunctionName)()
#################################################
#mGlobalDict = Settings.Settings(sys.argv[1])
#Logger alias
lL = gSettingsDict["Logger"]
if lL: lL.info("Link the gSettings in submodules") #Logging
Processor.gSettingsDict = gSettingsDict
Timer.gSettingsDict = gSettingsDict
Timer.Processor.gSettingsDict = gSettingsDict
Server.gSettingsDict = gSettingsDict
Server.Processor.gSettingsDict = gSettingsDict
# Check _SessionLast_RDPList.json in working directory. if exist - load into gsettings
# GSettings
#"RobotRDPActive": {
# "RDPList": {
if os.path.exists("_SessionLast_RDPList.json"):
lFile = open("_SessionLast_RDPList.json", "r", encoding="utf-8")
lSessionLastRDPList = json.loads(lFile.read())
lFile.close() # Close the file
os.remove("_SessionLast_RDPList.json") # remove the temp file
gSettingsDict["RobotRDPActive"]["RDPList"]=lSessionLastRDPList # Set the last session dict
if lL: lL.warning(f"RDP Session List was restored from previous Orchestrator session")
#Инициализация настроечных параметров
lDaemonLoopSeconds=gSettingsDict["Scheduler"]["ActivityTimeCheckLoopSeconds"]
lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
lDaemonLastDateTime=datetime.datetime.now()
gSettingsDict["Server"]["WorkingDirectoryPathStr"] = os.getcwd() # Set working directory in g settings
# Init SettingsUpdate defs from file list (after RDP restore)
lSettingsUpdateFilePathList = gSettingsDict.get("OrchestratorStart", {}).get("DefSettingsUpdatePathList",[])
lSubmoduleFunctionName = "SettingsUpdate"
lSettingsPath = "\\".join(os.path.join(os.getcwd(), __file__).split("\\")[:-1])
for lModuleFilePathItem in lSettingsUpdateFilePathList: # Import defs with try catch
try: # Try to init - go next if error and log in logger
lModuleName = lModuleFilePathItem[0:-3]
lFileFullPath = os.path.join(lSettingsPath, lModuleFilePathItem)
lTechSpecification = importlib.util.spec_from_file_location(lModuleName, lFileFullPath)
lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification)
lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec)
if lSubmoduleFunctionName in dir(lTechModuleFromSpec):
# Run SettingUpdate function in submodule
getattr(lTechModuleFromSpec, lSubmoduleFunctionName)(gSettingsDict)
except Exception as e:
if lL: lL.exception(f"Error when init .py file in orchestrator '{lModuleFilePathItem}'. Exception is below:")
# Turn on backward compatibility
BackwardCompatibility.Update(inGSettings= gSettingsDict)
#Инициализация сервера
lThreadServer = Server.RobotDaemonServer("ServerThread", gSettingsDict)
lThreadServer.start()
if lL: lL.info("Web server has been started") #Logging
# Init the RobotScreenActive in another thread
lRobotScreenActiveThread = threading.Thread(target= Monitor.CheckScreen)
lRobotScreenActiveThread.daemon = True # Run the thread in daemon mode.
lRobotScreenActiveThread.start() # Start the thread execution.
if lL: lL.info("Robot Screen active has been started") #Logging
# Init the RobotRDPActive in another thread
lRobotRDPActiveThread = threading.Thread(target= RobotRDPActive.RobotRDPActive, kwargs={"inGSettings":gSettingsDict})
lRobotRDPActiveThread.daemon = True # Run the thread in daemon mode.
lRobotRDPActiveThread.start() # Start the thread execution.
if lL: lL.info("Robot RDP active has been started") #Logging
# Init autocleaner in another thread
lAutocleanerThread = threading.Thread(target= GSettingsAutocleaner, kwargs={"inGSettings":gSettingsDict})
lAutocleanerThread.daemon = True # Run the thread in daemon mode.
lAutocleanerThread.start() # Start the thread execution.
if lL: lL.info("Autocleaner thread has been started") #Logging
# Orchestrator start activity
if lL: lL.info("Orchestrator start activity run") #Logging
for lActivityItem in gSettingsDict["OrchestratorStart"]["ActivityList"]:
Processor.ActivityListOrDict(lActivityItem)
if lL: lL.info("Scheduler loop start") #Logging
gDaemonActivityLogDictRefreshSecInt = 10 # The second period for clear lDaemonActivityLogDict from old items
gDaemonActivityLogDictLastTime = time.time() # The second perioad for clean lDaemonActivityLogDict from old items
while True:
lCurrentDateTime = datetime.datetime.now()
#Циклический обход правил
lFlagSearchActivityType=True
# Periodically clear the lDaemonActivityLogDict
if time.time()-gDaemonActivityLogDictLastTime>=gDaemonActivityLogDictRefreshSecInt:
gDaemonActivityLogDictLastTime = time.time() # Update the time
for lIndex, lItem in enumerate(lDaemonActivityLogDict):
if lItem["ActivityEndDateTime"] and lCurrentDateTime<=lItem["ActivityEndDateTime"]:
pass
# Activity is actual - do not delete now
else:
# remove the activity - not actual
lDaemonActivityLogDict.pop(lIndex,None)
lIterationLastDateTime = lDaemonLastDateTime # Get current datetime before iterator (need for iterate all activities in loop)
# Iterate throught the activity list
for lIndex, lItem in enumerate(gSettingsDict["Scheduler"]["ActivityTimeList"]):
# Prepare GUID of the activity
lGUID = None
if "GUID" in lItem and lItem["GUID"]:
lGUID = lItem["GUID"]
else:
lGUID = str(uuid.uuid4())
lItem["GUID"]=lGUID
#Проверка дней недели, в рамках которых можно запускать активность
lItemWeekdayList=lItem.get("WeekdayList", [0, 1, 2, 3, 4, 5, 6])
if lCurrentDateTime.weekday() in lItemWeekdayList:
if lFlagSearchActivityType:
#######################################################################
#Branch 1 - if has TimeHH:MM
#######################################################################
if "TimeHH:MM" in lItem:
#Вид активности - запуск процесса
#Сформировать временной штамп, относительно которого надо будет проверять время
#часовой пояс пока не учитываем
lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MM"],"%H:%M")
lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
#Убедиться в том, что время наступило
if (
lActivityDateTime>=lDaemonLastDateTime and
lCurrentDateTime>=lActivityDateTime):
# Log info about activity
if lL: lL.info(f"Scheduler:: Activity is started. Scheduler item: {lItem}") #Logging
# Do the activity
Processor.ActivityListOrDict(lItem["Activity"])
lIterationLastDateTime = datetime.datetime.now() # Set the new datetime for the new processor activity
#######################################################################
#Branch 2 - if TimeHH:MMStart, TimeHH:MMStop, ActivityIntervalSeconds
#######################################################################
if "TimeHH:MMStart" in lItem and "TimeHH:MMStop" in lItem and "ActivityIntervalSeconds" in lItem:
#Сформировать временной штамп, относительно которого надо будет проверять время
#часовой пояс пока не учитываем
lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStart"],"%H:%M")
lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
lActivityTimeEndDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStop"],"%H:%M")
lActivityTimeEndDateTime=lActivityTimeEndDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day)
#Убедиться в том, что время наступило
if (
lCurrentDateTime<lActivityTimeEndDateTime and
lCurrentDateTime>=lActivityDateTime and
(lGUID,lActivityDateTime) not in lDaemonActivityLogDict):
#Запись в массив отработанных активностей
lDaemonActivityLogDict[(lGUID,lActivityDateTime)]={"ActivityStartDateTime":lCurrentDateTime, "ActivityEndDateTime":lActivityTimeEndDateTime}
#Запуск циклической процедуры
Timer.activityLoopStart(lItem["ActivityIntervalSeconds"], lActivityTimeEndDateTime, lItem["Activity"])
lDaemonLastDateTime = lIterationLastDateTime # Set the new datetime for the new processor activity
#Уснуть до следующего прогона
time.sleep(lDaemonLoopSeconds)

@ -1,301 +1,100 @@
import datetime
import http.client
import json
import pdb
import os
import sys
import subprocess
import importlib
import psutil
#Input arg
# [
# {
# "Type": <RemoteMachineProcessingRun>,
# host: <localhost>,
# port: <port>,
# bodyObject: <object dict, int, str, list>
# },
# {
# "Type": "CMDStart",
# "Command": ""
# },
# {
# "Type": "OrchestratorRestart"
# },
# {
# "Type": "OrchestratorSessionSave"
# },
# {
# "Type": "GlobalDictKeyListValueSet",
# "KeyList": ["key1","key2",...],
# "Value": <List, Dict, String, int>
# },
# {
# "Type": "GlobalDictKeyListValueAppend",
# "KeyList": ["key1","key2",...],
# "Value": <List, Dict, String, int>
# },
# {
# "Type": "GlobalDictKeyListValueOperator+",
# "KeyList": ["key1","key2",...],
# "Value": <List, Dict, String, int>
# },
# {
# "Type": "GlobalDictKeyListValueGet",
# "KeyList": ["key1","key2",...]
# },
# {
# "Type":"ProcessStart",
# "Path":"",
# "ArgList":[]
# },
# {
# "Type":"ProcessStartIfTurnedOff",
# "CheckTaskName":"", #Check if current task name is not active (then start process),
# "Path":"",
# "ArgList":[]
# },
# {
# "Type":"ProcessStop",
# "Name":"",
# "FlagForce":True,
# "User":"" #Empty - all users, user or %username%
# },
# {
# "Type":"PythonStart",
# "ModuleName":"",
# "FunctionName":"",
# "ArgList":[],
# "ArgDict":{}
# },
# {
# "Type":"WindowsLogon",
# "Domain":"",
# "User":"",
# "Password":""
# # Return "Result": True - user is logged on, False - user is not logged on
# }
# ]
##################################
#Output result
# <input arg> with attributes:
# "DateTimeUTCStringStart"
# "DateTimeUTCStringStop"
# "Result"
gSettingsDict = None
def Activity(inActivity):
#Глобальная переменная - глобальный словарь унаследованный от Settings.py
global gSettingsDict
lL = gSettingsDict["Logger"] # Alias for logger
#Alias (compatibility)
lItem = inActivity
lCurrentDateTime = datetime.datetime.now()
###########################################################
#Обработка запроса на отправку команды на удаленную машину
###########################################################
if lItem["Type"]=="RemoteMachineProcessingRun":
lHTTPConnection = http.client.HTTPConnection(lItem["host"], lItem["port"], timeout=5)
try:
lHTTPConnection.request("POST","/ProcessingRun",json.dumps(lItem["bodyObject"]))
except Exception as e:
#Объединение словарей
lItem["Result"] = {"State":"disconnected","ExceptionString":str(e)}
# 1.2.0 - general processor - contains old orchestrator processor + RDPActive processor
import time, copy, threading
# Run processor synchronious
# inThreadControlDict = {"ThreadExecuteBool":True}
def ProcessorRunSync(inGSettings, inRobotRDPThreadControlDict):
"""
"ProcessorDict": { # Has been changed. New general processor (one threaded) v.1.2.0
"ActivityList": [ # List of the activities
# {
# "Def":"DefAliasTest", # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
# "ArgList":[1,2,3], # Args list
# "ArgDict":{"ttt":1,"222":2,"dsd":3}, # Args dictionary
# "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# },
],
"AliasDefDict": {}, # Storage for def with Str alias. To use it see pyOpenRPA.Orchestrator.ControlPanel
"CheckIntervalSecFloat": 1.0 # Interval for check gSettings in ProcessorDict > ActivityList
"ExecuteBool": True # Flag to execute thread processor
"""
lL = inGSettings["Logger"] # Logger alias
inGSettings["ProcessorDict"]["ThreadIdInt"] = threading.get_ident() # fill Processor thread id
while inGSettings["ProcessorDict"]["ExecuteBool"]:
lActivityList = inGSettings["ProcessorDict"]["ActivityList"] # Alias
if len(lActivityList)>0:
if lL: lL.debug(f'Processor ActivityList len: {len(lActivityList)}')
lActivityItem = inGSettings["ProcessorDict"]["ActivityList"].pop(0) # Extract the first item from processor queue
inRobotRDPThreadControlDict["ThreadExecuteBool"]=False # Stop the RobotRDPActive monitoring
ActivityListExecute(inGSettings = inGSettings, inActivityList = [lActivityItem]) # execute the activity item
inRobotRDPThreadControlDict["ThreadExecuteBool"] = True # Continue the RobotRDPActive monitoring
else:
lHTTPResponse=lHTTPConnection.getresponse()
lHTTPResponseByteArray=lHTTPResponse.read()
lItem["Result"] = json.loads(lHTTPResponseByteArray.decode('utf8'))
###########################################################
#Обработка команды CMDStart
###########################################################
if lItem["Type"]=="CMDStart":
lCMDCode="cmd /c "+lItem["Command"]
subprocess.Popen(lCMDCode)
lResultCMDRun=1#os.system(lCMDCode)
lItem["Result"] = str(lResultCMDRun)
###########################################################
#Обработка команды OrchestratorRestart
###########################################################
if lItem["Type"]=="OrchestratorRestart":
# Dump RDP List in file json
lFile = open("_SessionLast_RDPList.json", "w", encoding="utf-8")
lFile.write(json.dumps(gSettingsDict["RobotRDPActive"]["RDPList"])) # dump json to file
lFile.close() # Close the file
if lL: lL.info(f"Orchestrator has dump the RDP list before the restart. The RDP List is {gSettingsDict['RobotRDPActive']['RDPList']}. Do restart")
# Restart session
os.execl(sys.executable, os.path.abspath(__file__), *sys.argv)
lItem["Result"] = True
sys.exit(0)
###########################################################
# Обработка команды OrchestratorSessionSave
###########################################################
if lItem["Type"] == "OrchestratorSessionSave":
# Dump RDP List in file json
lFile = open("_SessionLast_RDPList.json", "w", encoding="utf-8")
lFile.write(json.dumps(gSettingsDict["RobotRDPActive"]["RDPList"])) # dump json to file
lFile.close() # Close the file
if lL: lL.info(
f"Orchestrator has dump the RDP list before the restart. The RDP List is {gSettingsDict['RobotRDPActive']['RDPList']}")
lItem["Result"] = True
###########################################################
#Обработка команды GlobalDictKeyListValueSet
###########################################################
if lItem["Type"]=="GlobalDictKeyListValueSet":
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
#Check if key - value exists
if lItem2 in lDict:
pass
else:
lDict[lItem2]={}
lDict=lDict[lItem2]
#Set value
lDict[lItem["KeyList"][-1]]=lItem["Value"]
lItem["Result"] = True
###########################################################
# Обработка команды GlobalDictKeyListValueAppend
###########################################################
if lItem["Type"] == "GlobalDictKeyListValueAppend":
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
# Check if key - value exists
if lItem2 in lDict:
pass
else:
lDict[lItem2] = {}
lDict = lDict[lItem2]
# Set value
lDict[lItem["KeyList"][-1]].append(lItem["Value"])
lItem["Result"] = True
###########################################################
# Обработка команды GlobalDictKeyListValueOperator+
###########################################################
if lItem["Type"] == "GlobalDictKeyListValueOperator+":
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
# Check if key - value exists
if lItem2 in lDict:
pass
else:
lDict[lItem2] = {}
lDict = lDict[lItem2]
# Set value
lDict[lItem["KeyList"][-1]]+=lItem["Value"]
lItem["Result"] = True
###########################################################
#Обработка команды GlobalDictKeyListValueGet
###########################################################
if lItem["Type"]=="GlobalDictKeyListValueGet":
lDict = gSettingsDict
for lItem2 in lItem["KeyList"][:-1]:
#Check if key - value exists
if lItem2 in lDict:
pass
else:
lDict[lItem2]={}
lDict=lDict[lItem2]
#Return value
lItem["Result"]=lDict.get(lItem["KeyList"][-1],None)
#####################################
#ProcessStart
#####################################
if lItem["Type"]=="ProcessStart":
#Вид активности - запуск процесса
#Запись в массив отработанных активностей
#Запустить процесс
lItemArgs=[lItem["Path"]]
lItemArgs.extend(lItem["ArgList"])
subprocess.Popen(lItemArgs,shell=True)
#####################################
#ProcessStartIfTurnedOff
#####################################
if lItem["Type"]=="ProcessStartIfTurnedOff":
#Check if process running
#remove .exe from Taskname if exists
lCheckTaskName = lItem["CheckTaskName"]
if len(lCheckTaskName)>4:
if lCheckTaskName[-4:].upper() != ".EXE":
lCheckTaskName = lCheckTaskName+".exe"
else:
lCheckTaskName = lCheckTaskName+".exe"
#Check if process exist
if not CheckIfProcessRunning(lCheckTaskName):
#Вид активности - запуск процесса
#Запись в массив отработанных активностей
#Запустить процесс
lItemArgs=[lItem["Path"]]
lItemArgs.extend(lItem["ArgList"])
subprocess.Popen(lItemArgs,shell=True)
#################################
#ProcessStop
#################################
if lItem["Type"]=="ProcessStop":
#Вид активности - остановка процесса
#часовой пояс пока не учитываем
#Сформировать команду на завершение
lActivityCloseCommand='taskkill /im '+lItem["Name"]
#TODO Сделать безопасную обработку,если параметра нет в конфигурации
if lItem.get('FlagForce',False):
lActivityCloseCommand+=" /F"
#Завершить процессы только текущего пользоваиеля
if lItem.get('User',"")!="":
lActivityCloseCommand+=f' /fi "username eq {lItem["User"]}"'
#Завершить процесс
os.system(lActivityCloseCommand)
#################################
#PythonStart
#################################
if lItem["Type"]=="PythonStart":
try:
#Подключить модуль для вызова
lModule=importlib.import_module(lItem["ModuleName"])
#Найти функцию
lFunction=getattr(lModule,lItem["FunctionName"])
lItem["Result"]=lFunction(*lItem.get("ArgList",[]),**lItem.get("ArgDict",{}))
except Exception as e:
if lL: lL.exception("Loop activity error: module/function not founded")
#################################
# Windows logon
#################################
if lItem["Type"] == "WindowsLogon":
import win32security
try:
hUser = win32security.LogonUser(
lItem["User"],
lItem["Domain"],
lItem["Password"],
win32security.LOGON32_LOGON_NETWORK,
win32security.LOGON32_PROVIDER_DEFAULT
)
except win32security.error:
lItem["Result"] = False
else:
lItem["Result"] = True
###################################
#Вернуть результат
return lItem
time.sleep(inGSettings["ProcessorDict"]["CheckIntervalSecFloat"]) # Sleep when list is empty
# Execute ActivityItem list
# return the def result
def ActivityListExecute(inGSettings, inActivityList):
lL = inGSettings["Logger"] # Logger alias
lResultList = [] # init the result list
try:
for lActivityItem in inActivityList: # Iterate throught the activity list
if lL: lL.info(f'pyOpenRPA Processor.ActivityListExecute:: Def:{str(lActivityItem["Def"])}. Parameters are not available to see.')
lDef = None # Def variable
if callable(lActivityItem["Def"]): # CHeck if def is callable
lDef = lActivityItem["Def"] # Get the def
else: # Is not callable - check alias
lDef = inGSettings["ProcessorDict"]["AliasDefDict"].get(lActivityItem["Def"], None) # get def if def key in Alias def storage
#gSettings
lGSettingsDictKey = lActivityItem.pop("ArgGSettings",None)
# # Prepare arg dict - gSettings
if type(lGSettingsDictKey) is str and lGSettingsDictKey is not "": # check if gSetting key is in ArgDict 13.02.2021 - Fix when ArgGSettings is ""
lActivityItem["ArgDict"][lGSettingsDictKey] = inGSettings # Set the gSettings in dict
# # Prepare arg list
elif type(lGSettingsDictKey) is int: # check if gSetting key is in ArgDict
lActivityItem["ArgList"].insert(lGSettingsDictKey,inGSettings)# Set the gSettings in list by the index
#Logger
lLoggerDictKey = lActivityItem.pop("ArgLogger",None)
# # Prepare arg dict - Logger
if type(lLoggerDictKey) is str and lLoggerDictKey is not "": # check if gSetting key is in ArgDict 13.02.2021 - Fix when ArgLogger is ""
lActivityItem["ArgDict"][lLoggerDictKey] = lL # Set the lLogger in dict
# # Prepare arg list
elif type(lLoggerDictKey) is int: # check if gSetting key is in ArgDict
lActivityItem["ArgList"].insert(lLoggerDictKey,lL)# Set the lLogger in list by the index
try: # try to run function from Processor.py
lActivityItemResult = lDef(*lActivityItem["ArgList"], **lActivityItem["ArgDict"])
lResultList.append(lActivityItemResult) # return the result
except Exception as e:
if lL: lL.exception(f"pyOpenRPA Processor.ActivityListExecute: Exception in def execution - activity will be ignored.") # Logging
lResultList.append(e) # return the generated exception
except Exception as e:
if lL: lL.exception(f"pyOpenRPA Processor.ActivityListExecute: Exception when initialisation - All activity list will be ignored.") # Logging
return lResultList # return the result list
def __ActivityListVerify__(inActivityList):
"""
Verify ActivityList variable - raise exception if input list is not list of dict with structure:
# "Def":"DefAliasTest", # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
# "ArgList":[1,2,3], # Args list
# "ArgDict":{"ttt":1,"222":2,"dsd":3}, # Args dictionary
# "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
def ActivityListOrDict(inActivityListOrDict):
#Check arg type (list or dict)
if type(inActivityListOrDict)==list:
#List activity
lResult=[]
for lItem in inActivityListOrDict:
lResult.append(Activity(lItem))
return lResult
if type(inActivityListOrDict)==dict:
#Dict activity
return Activity(inActivityListOrDict)
def CheckIfProcessRunning(processName):
'''
Check if there is any running process that contains the given name processName.
'''
#Iterate over the all the running process
for proc in psutil.process_iter():
try:
# Check if process name contains the given name string.
if processName.lower() in proc.name().lower():
return True
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
return False;
:param inActivityList:
:return:
"""
# CASE LIST
if type(inActivityList) is list:
for lItem in inActivityList:
# CASE LIST item is LIST
if type(lItem) is list:
raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Your ActivityList item is list too. List of the list :(")
# CASE Item is not dict
if type(lItem) is not dict:
raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Your ActivityList item is is not dict")
# CASE HAS NO "Def"
if "Def" not in lItem:
raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Activity item has no attribute 'Def'")
#CASE NOT LIST
else:
raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Your ActivityList is not a list.")

@ -245,6 +245,7 @@ def SessionCMDRun(inSessionHex,inCMDCommandStr = "echo 1", inModeStr="CROSSCHECK
# Exit fullscreen mode
SessionScreenSize_X_Y_W_H(inSessionHex=inSessionHex, inXInt=10, inYInt=10, inWInt=550,
inHInt=350) # Prepare little window
return lResult
# Check if session is in Full screen mode
# Return True - is in fullscreen
# example print(Connector.SessionIsFullScreen(""))
@ -305,11 +306,12 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
Clipboard.TextSet(lClipboardTextOld)
lCrosscheckKeyStr = str(random.randrange(999,9999999))
lRecoveryCMDResponsibleRetryIteratorInt = 0 # Init the retry iterator
lCommandIsTooBigBool = False
lCMDPostFixStr = "" # Case default "RUN"
while lRecoveryCMDResponsibleRetryIteratorInt<gRecoveryCMDResponsibleRetryCountInt: # loop for retry
# # # # # # # # # # # # # OPEN WINDOW RUN # # # # # # # # # # # # # # #
lRecoveryWindowRUNRetryIteratorInt = 0 # Init the retry iterator
while lRecoveryWindowRUNRetryIteratorInt<gRecoveryWindowRUNRetryCountInt: # loop for retry
lCMDPostFixStr = "" # Case default "RUN"
if inModeStr == "CROSSCHECK":
#lCMDPostFixStr = f"& (echo {lCrosscheckKeyStr} | clip)"
lCMDPostFixStr = f"| (echo {lCrosscheckKeyStr} | clip)" # Bugfix async set clipboard data
@ -324,7 +326,14 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
keyboard.send("backspace") # Delete selected all
time.sleep(gKeyboardHotkeyDelaySecFloat) # Wait for RUN window will appear ctrl+a+backspace is async - so we need some timeout...
lInputStr = f"cmd /c ({inCMDCommandStr}) {lCMDPostFixStr}" # Generate the output string for RUN window
keyboard.write(lInputStr) # Write new text
if len(lInputStr) <= 259:
keyboard.write(lInputStr) # Write new text
else:
if lL: lL.warning(
f"RDP.SystemCMDRun: ATTENTION! Your command is too big for the RUN window (len is {len(lInputStr)}). Orchestrator will send this command to the new cmd window. ")
lInputStr = "cmd"
lCommandIsTooBigBool = True
keyboard.write(lInputStr) # Write cmd
time.sleep(gKeyboardHotkeyDelaySecFloat)
# Check if autocomplete
# # # # # # #
@ -348,26 +357,38 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
if lClipboardStr == lInputStr: # Cross check the clipboard data and input string
lRecoveryWindowRUNRetryIteratorInt = gRecoveryWindowRUNRetryCountInt # Set final count to block the loop
else: # Failed - wait and retry
if lL: lL.warning(f"RDP::SystemCMDRun: Window run doesn't appear. Wait for {gRecoveryWindowRUNRetryIntervalSecInt}[s.] and retry. Current retry iterator is {lRecoveryWindowRUNRetryIteratorInt}. CMD Str: {lInputStr}") # Log the error
if lL: lL.warning(f"RDP::SystemCMDRun: RUN window (win+r) doesn't appear. Wait for {gRecoveryWindowRUNRetryIntervalSecInt}[s.] and retry. Current retry iterator is {lRecoveryWindowRUNRetryIteratorInt}. CMD Str: {lInputStr}") # Log the error
lRecoveryWindowRUNRetryIteratorInt = lRecoveryWindowRUNRetryIteratorInt + 1 # Increment the iterator
if lRecoveryWindowRUNRetryIteratorInt == gRecoveryWindowRUNRetryCountInt:
if lL: lL.warning(f"RDP::SystemCMDRun: Retry count is over. Raise the error. CMD Str: {lInputStr}") # Log the error
if lL: lL.warning(f"RDP::SystemCMDRun: RUN window (win+r) retry count is over. Raise the error. CMD Str: {lInputStr}") # Log the error
raise ConnectorExceptions.RUNExistError() # Raise the error
time.sleep(gRecoveryWindowRUNRetryIntervalSecInt) # wait for some seconds before new iteration
# # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # RUN CMD # # # # # # # # # # # # # # #
if inModeStr == "LISTEN": # if mode == LISTEN - set random number in clipboard
Clipboard.TextSet(lClipboardTextOld) #
time.sleep(0.5) # wait some time for the next operation
keyboard.press_and_release('enter') # Execute CMD
time.sleep(1)
if lCommandIsTooBigBool == True:
# Case when string is tool big - call cmd and then type text into
#keyboard.write("cmd") # Open cmd
#time.sleep(1)
#keyboard.press_and_release('enter') # Execute CMD
keyboard.write(f"(({inCMDCommandStr}) {lCMDPostFixStr}) && exit", delay=0.05) # send command
time.sleep(1)
keyboard.press_and_release('enter') # Execute command
if inModeStr == "CROSSCHECK" or inModeStr == "LISTEN": # Get OutStr (Case CROSSCHECK and LISTEN)
lClipboardWaitTimeStartSec = time.time()
lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard
while lResult["OutStr"] == lClipboardTextOld and (time.time() - lClipboardWaitTimeStartSec) <= inClipboardTimeoutSec:
while lResult["OutStr"].startswith(lClipboardTextOld) and (time.time() - lClipboardWaitTimeStartSec) <= inClipboardTimeoutSec:
lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard
time.sleep(0.5) # wait some time for the next operation
if lResult["OutStr"] == lClipboardTextOld: # If value hasn't been changed - retry send
lRecoveryCMDResponsibleRetryIteratorInt = lRecoveryCMDResponsibleRetryIteratorInt + 1 # increment the iterator
if lL: lL.warning(f"RDP::SystemCMDRun: CMD command doesn't been executed (no changes in clipboard data). Wait for {gRecoveryCMDResponsibleRetryIntervalSecInt}[s.] and retry from start window RUN. Current retry iterator is {lRecoveryCMDResponsibleRetryIteratorInt}. CMD Str: {lInputStr}, Clipboard data: {lResult['OutStr']}") # Log the error
if lRecoveryCMDResponsibleRetryIteratorInt >= gRecoveryCMDResponsibleRetryCountInt: # raise the error if retry count is exceeded
if lL: lL.warning(f"RDP::SystemCMDRun: Retry count is over. Raise the error.") # Log the error
if lL: lL.warning(f"RDP::SystemCMDRun: CMD command retry count is over. Raise the error.") # Log the error
raise ConnectorExceptions.CMDResponsibleError() # Raise the error
time.sleep(gRecoveryCMDResponsibleRetryIntervalSecInt) # wait for some seconds before new iteration
else: # Data was recieved - do crosscheck
@ -380,7 +401,7 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
lRecoveryCMDResponsibleRetryIteratorInt = lRecoveryCMDResponsibleRetryIteratorInt + 1 # increment the iterator
if lL: lL.warning(f"RDP::SystemCMDRun: CMD command doesn't been executed (wrong clipboard data). Wait for {gRecoveryCMDResponsibleRetryIntervalSecInt}[s.] and retry from start window RUN. Current retry iterator is {lRecoveryCMDResponsibleRetryIteratorInt}. CMD Str: {lInputStr}, Clipboard data: {lResult['OutStr']}") # Log the error
if lRecoveryCMDResponsibleRetryIteratorInt >= gRecoveryCMDResponsibleRetryCountInt: # raise the error if retry count is exceeded
if lL: lL.warning(f"RDP::SystemCMDRun: Retry count is over. Raise the error.") # Log the error
if lL: lL.warning(f"RDP::SystemCMDRun: CMD command retry count is over. Raise the error.") # Log the error
raise ConnectorExceptions.CMDResponsibleError() # Raise the error
time.sleep(gRecoveryCMDResponsibleRetryIntervalSecInt) # wait for some seconds before new iteration
else: # clipboard data has been changed but mode is not crosscheck - return success from function

@ -5,7 +5,8 @@ from . import ConnectorExceptions # Exceptions classes
from . import Connector
from . import Processor # Module for process some functions on thr RDP
# Main function
def RobotRDPActive(inGSettings):
# inThreadControlDict = {"ThreadExecuteBool":True}
def RobotRDPActive(inGSettings, inThreadControlDict):
# inGSettings = {
# ... "RobotRDPActive": {} ...
# }
@ -36,100 +37,91 @@ def RobotRDPActive(inGSettings):
lResponsibilityCheckLastSec = time.time() # Get current time for check interval
while lFlagWhile:
try:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check RDP window is OK - reconnect if connection was lost
lUIOSelectorList = []
lRDPConfigurationDictList = []
# Prepare selectors list for check
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
lRDPConfigurationDictList.append(lItem) # Add RDP Configuration in list
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
# Run wait command
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
for lItem in lRDPDissappearList: # Reconnect if connection was lost
lRDPConfigurationDict = lRDPConfigurationDictList[lItem] # Get RDP Configuration list
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
# Check if RDP window is not ignored
if not lRDPConfigurationDict["SessionIsIgnoredBool"]:
try:
Connector.Session(lRDPConfigurationDict, inScreenSize550x350Bool = True)
lRDPConfigurationDict["SessionIsWindowExistBool"] = True # Flag that session is started
if lL: lL.info(f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!") #Logging
# catch ConnectorExceptions.SessionWindowNotExistError
except ConnectorExceptions.SessionWindowNotExistError as e:
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
if lL: lL.warning(f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist!") #Logging
# general exceptions
except Exception as e:
if lL: lL.exception(f"!!! ATTENTION !!! Unrecognized error") #Logging
pass
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Safe turn off the - no need because of Orchestrator control
#if inGlobalDict.get("OrchestratorToRobotResetStorage", {}).get("SafeTurnOff", False):
# lFlagWhile = False
# # Set status disconnected for all RDP List
# for lItem in inGlobalDict["RDPList"]:
# lItem["SessionIsWindowExistBool"] = False
# lItem["SessionIsWindowResponsibleBool"] = False
# # Kill all RDP sessions
# os.system('taskkill /F /im mstsc.exe')
# # Return from function
# return
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Connector.SystemRDPWarningClickOk() # Click all warning messages
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check if RDP session is full screen (if is not ignored)
if inGlobalDict["FullScreenRDPSessionKeyStr"] is not None:
lRDPSessionKeyStr = inGlobalDict["FullScreenRDPSessionKeyStr"] # Get the RDPSessionKeyStr
if lRDPSessionKeyStr in inGlobalDict["RDPList"]: # Session Key is in dict
lRDPConfigurationDict = inGlobalDict["RDPList"][lRDPSessionKeyStr]
#if not lRDPConfigurationDict["SessionIsIgnoredBool"]: # Session is not ignored
# Check if full screen
lIsFullScreenBool = Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDict["SessionHex"])
if not lIsFullScreenBool: # If not the full screen
# Check all RDP window and minimize it
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]):
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"], inXInt=10, inYInt=10,
inWInt=550,
inHInt=350) # Prepare little window
# Set full screen for new window
Connector.SessionScreenFull(inSessionHex=lRDPConfigurationDict["SessionHex"], inLogger= inGSettings["Logger"], inRDPConfigurationItem=inGlobalDict["RDPList"][lRDPSessionKeyStrItem])
else:
# Check all RDP window and minimize it
if inThreadControlDict["ThreadExecuteBool"] == True:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check RDP window is OK - reconnect if connection was lost
lUIOSelectorList = []
lRDPConfigurationDictList = []
# Prepare selectors list for check
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]) or Connector.SessionIsMinimizedScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]): # If window is minimized - restore # if window in full screen - resize
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"],
inXInt=10, inYInt=10,
inWInt=550,
inHInt=350) # Prepare little window
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Iterate the activity list in robot RDP active
lActivityListNew = []
lActivityListOld = inGlobalDict["ActivityList"]
inGlobalDict["ActivityList"] = []
for lActivityItem in lActivityListOld:
lSubmoduleFunctionName = lActivityItem["DefNameStr"]
if lSubmoduleFunctionName in dir(Processor):
lActivityItemResult = None # init the variable
try: # try to run function from Processor.py
lActivityItemResult = getattr(Processor, lSubmoduleFunctionName)(
*lActivityItem["ArgList"], **lActivityItem["ArgDict"])
except Exception as e:
if lL: lL.exception(f"RDP::main: Exception when run def in processor.py - activity will be ignored. Activity item: {lActivityItem}") #Logging
lActivityItemResult = True # True - clear from repeat list
lActivityItemResultType = type(lActivityItemResult)
# Check if Result is bool
if lActivityItemResultType is bool:
if not lActivityItemResult:
# Activity is not done - add to list (retry in future)
lActivityListNew.append(lActivityItem)
inGlobalDict["ActivityList"] = lActivityListNew # Override the value
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
lItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
lRDPConfigurationDictList.append(lItem) # Add RDP Configuration in list
lUIOSelectorList.append([{"title_re": f"{lItem['SessionHex']}.*", "backend": "win32"}])
# Run wait command
lRDPDissappearList = UIDesktop.UIOSelectorsSecs_WaitDisappear_List(lUIOSelectorList, inListUpdateTimeout)
for lItem in lRDPDissappearList: # Reconnect if connection was lost
lRDPConfigurationDict = lRDPConfigurationDictList[lItem] # Get RDP Configuration list
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
# Check if RDP window is not ignored
if not lRDPConfigurationDict["SessionIsIgnoredBool"]:
try:
Connector.Session(lRDPConfigurationDict, inScreenSize550x350Bool = True)
lRDPConfigurationDict["SessionIsWindowExistBool"] = True # Flag that session is started
if lL: lL.info(f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session has been initialized!") #Logging
# catch ConnectorExceptions.SessionWindowNotExistError
except ConnectorExceptions.SessionWindowNotExistError as e:
lRDPConfigurationDict["SessionIsWindowExistBool"] = False # Set flag that session is disconnected
if lL: lL.warning(f"SessionHex: {str(lRDPConfigurationDict['SessionHex'])}:: Session is not exist!") #Logging
# general exceptions
except Exception as e:
if lL: lL.exception(f"!!! ATTENTION !!! Unrecognized error") #Logging
pass
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Connector.SystemRDPWarningClickOk() # Click all warning messages
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check if RDP session is full screen (if is not ignored)
if inGlobalDict["FullScreenRDPSessionKeyStr"] is not None:
lRDPSessionKeyStr = inGlobalDict["FullScreenRDPSessionKeyStr"] # Get the RDPSessionKeyStr
if lRDPSessionKeyStr in inGlobalDict["RDPList"]: # Session Key is in dict
lRDPConfigurationDict = inGlobalDict["RDPList"][lRDPSessionKeyStr]
#if not lRDPConfigurationDict["SessionIsIgnoredBool"]: # Session is not ignored
# Check if full screen
lIsFullScreenBool = Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDict["SessionHex"])
if not lIsFullScreenBool: # If not the full screen
# Check all RDP window and minimize it
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]):
if inThreadControlDict["ThreadExecuteBool"] == True: # TEST FEATURE BEFORE ONE THREAD INTEGRATION
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"], inXInt=10, inYInt=10,
inWInt=550,
inHInt=350) # Prepare little window
# Set full screen for new window
if inThreadControlDict["ThreadExecuteBool"] == True: # TEST FEATURE BEFORE ONE THREAD INTEGRATION
Connector.SessionScreenFull(inSessionHex=lRDPConfigurationDict["SessionHex"], inLogger= inGSettings["Logger"], inRDPConfigurationItem=inGlobalDict["RDPList"][lRDPSessionKeyStrItem])
else:
# Check all RDP window and minimize it
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]) or Connector.SessionIsMinimizedScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]): # If window is minimized - restore # if window in full screen - resize
if inThreadControlDict["ThreadExecuteBool"] == True: # TEST FEATURE BEFORE ONE THREAD INTEGRATION
Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"],
inXInt=10, inYInt=10,
inWInt=550,
inHInt=350) # Prepare little window
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Iterate the activity list in robot RDP active
lActivityListNew = []
lActivityListOld = inGlobalDict["ActivityList"]
inGlobalDict["ActivityList"] = []
for lActivityItem in lActivityListOld:
lSubmoduleFunctionName = lActivityItem["DefNameStr"]
if lSubmoduleFunctionName in dir(Processor):
lActivityItemResult = None # init the variable
try: # try to run function from Processor.py
lActivityItemResult = getattr(Processor, lSubmoduleFunctionName)(
*lActivityItem["ArgList"], **lActivityItem["ArgDict"])
except Exception as e:
if lL: lL.exception(f"RDP::main: Exception when run def in processor.py - activity will be ignored. Activity item: {lActivityItem}") #Logging
lActivityItemResult = True # True - clear from repeat list
lActivityItemResultType = type(lActivityItemResult)
# Check if Result is bool
if lActivityItemResultType is bool:
if not lActivityItemResult:
# Activity is not done - add to list (retry in future)
lActivityListNew.append(lActivityItem)
inGlobalDict["ActivityList"] = lActivityListNew # Override the value
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
except RuntimeError as e:
# case noGUI error passed - do nothing
if lL: lL.warning(f"Host session has lost the GUI") #Logging

@ -11,7 +11,8 @@ from socketserver import ThreadingMixIn
import threading
import json
from threading import Thread
from . import Processor
from . import Processor # Add new processor
from . import ProcessorOld # Support old processor - deprecated defs only for backward compatibility
import urllib.parse # decode URL in string
import importlib
import pdb
@ -22,9 +23,26 @@ import os #for path operations
from http import cookies
global gSettingsDict
from . import ServerSettings
from . import __Orchestrator__
import copy
# Tool to merge complex dictionaries
def __ComplexDictMerge2to1__(in1Dict, in2Dict):
lPathList=None
if lPathList is None: lPathList = []
for lKeyStr in in2Dict:
if lKeyStr in in1Dict:
if isinstance(in1Dict[lKeyStr], dict) and isinstance(in2Dict[lKeyStr], dict):
__ComplexDictMerge2to1__(in1Dict[lKeyStr], in2Dict[lKeyStr])
elif in1Dict[lKeyStr] == in2Dict[lKeyStr]:
pass # same leaf value
else:
raise Exception('Conflict at %s' % '.'.join(lPathList + [str(lKeyStr)]))
else:
in1Dict[lKeyStr] = in2Dict[lKeyStr]
return in1Dict
#Authenticate function ()
# return dict
# {
@ -41,10 +59,10 @@ def AuthenticateVerify(inRequest):
lCookieAuthToken = lCookies.get("AuthToken", "").value
if lCookieAuthToken:
#Find AuthToken in GlobalDict
if lCookieAuthToken in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
if lCookieAuthToken in gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}):
#Auth Token Has Been Founded
lResult["Domain"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
lResult["Domain"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
#Set auth token
inRequest.OpenRPA["AuthToken"] = lCookieAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"]
@ -63,26 +81,18 @@ def AuthenticateVerify(inRequest):
if "\\" in lUser:
lDomain = lUser.split("\\")[0]
lUser = lUser.split("\\")[1]
#Try to logon - use processor
lLogonResult = Processor.Activity(
{
"Type": "WindowsLogon",
"Domain": lDomain,
"User": lUser,
"Password": lPassword
}
)
lLogonBool = __Orchestrator__.OSCredentialsVerify(inUserStr=lUser, inPasswordStr=lPassword, inDomainStr=lDomain)
#Check result
if lLogonResult["Result"]:
lResult["Domain"] = lLogonResult["Domain"]
lResult["User"] = lLogonResult["User"]
if lLogonBool:
lResult["Domain"] = lDomain
lResult["User"] = lUser
#Create token
lAuthToken=str(uuid.uuid1())
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
#Set-cookie
inRequest.OpenRPA["AuthToken"] = lAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"]
@ -123,13 +133,14 @@ def UserAccessCheckBefore(inMethod, inRequest):
#go next if user is identified
lUserDict = None
if lAuthToken:
lUserDict = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
lUserDict = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
#pdb.set_trace()
########################################
########################################
#Check general before rule (without User domain)
#Check rules
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []):
inRuleMatchURLList = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", [])
for lAccessRuleItem in inRuleMatchURLList:
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
@ -161,31 +172,35 @@ def UserAccessCheckBefore(inMethod, inRequest):
#Check access by User Domain
#Check rules to find first appicable
#Check rules
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []):
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
if lAccessRuleItem["Method"].upper() == inMethod:
#check Match type variant: BeginWith
if lAccessRuleItem["MatchType"].upper() == "BEGINWITH":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
lMethodMatchURLList = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", [])
if len(lMethodMatchURLList) > 0:
for lAccessRuleItem in lMethodMatchURLList:
#Go next execution if flag is false
if not lResult:
#Check if Method is identical
if lAccessRuleItem["Method"].upper() == inMethod:
#check Match type variant: BeginWith
if lAccessRuleItem["MatchType"].upper() == "BEGINWITH":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.startswith(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
#check Match type variant: Contains
elif lAccessRuleItem["MatchType"].upper() == "CONTAINS":
lURLPath = inRequest.path
lURLPath = lURLPath.upper()
if lURLPath.contains(lAccessRuleItem["URL"].upper()):
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: Equal
elif lAccessRuleItem["MatchType"].upper() == "EQUAL":
if lAccessRuleItem["URL"].upper() == inRequest.path.upper():
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
# check Match type variant: EqualCase
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
else:
return True
#####################################
#####################################
#Return lResult
@ -193,6 +208,8 @@ def UserAccessCheckBefore(inMethod, inRequest):
# HTTPRequestHandler class
class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Def to check User Role access grants
def UACClientCheck(self, inRoleKeyList): # Alias
return self.UserRoleAccessAsk(inRoleKeyList=inRoleKeyList)
def UserRoleAccessAsk(self, inRoleKeyList):
lResult = True # Init flag
lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy
@ -218,7 +235,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
def UserRoleHierarchyGet(self):
lDomainUpperStr = self.OpenRPA["Domain"].upper()
lUserUpperStr = self.OpenRPA["User"].upper()
return gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lDomainUpperStr, lUserUpperStr), {}).get("RoleHierarchyAllowedDict", {})
return gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lDomainUpperStr, lUserUpperStr), {}).get("RoleHierarchyAllowedDict", {})
#Tech def
#return {"headers":[],"body":"","statuscode":111}
@ -316,152 +333,168 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Write content as utf-8 data
self.wfile.write(inResponseDict["Body"])
def do_GET(self):
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
#####################################
#Do authentication
#Check if authentication is turned on
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
# Logging
# gSettingsDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
else:
#Check the user access (if flag)
####################################
lFlagUserAccess = True
#If need user authentication
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("GET", self)
######################################
if lFlagUserAccess:
lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1])
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in gSettingsDict["Server"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET")
if lFlagURLIsApplied:
self.ResponseDictSend()
return
#Monitor
if self.path == '/Monitor/JSONDaemonListGet':
try:
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
#####################################
#Do authentication
#Check if authentication is turned on
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
# Logging
# gSettingsDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}")
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
else:
#Check the user access (if flag)
####################################
lFlagUserAccess = True
#If need user authentication
if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("GET", self)
######################################
if lFlagUserAccess:
lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1])
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in gSettingsDict["ServerDict"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET")
if lFlagURLIsApplied:
self.ResponseDictSend()
return
#Monitor
if self.path == '/Monitor/JSONDaemonListGet':
# Send response status code
self.send_response(200)
# Send headers
self.send_header('Content-type','application/json')
self.end_headers()
# Send message back to client
message = json.dumps(gSettingsDict)
# Write content as utf-8 data
self.wfile.write(bytes(message, "utf8"))
#Filemanager function
if self.path.lower().startswith('/filemanager/'):
lFileURL=self.path[13:]
# check if file in FileURL - File Path Mapping Dict
if lFileURL.lower() in gSettingsDict["FileManager"]["FileURLFilePathDict"]:
self.SendResponseContentTypeFile('application/octet-stream', gSettingsDict["FileManager"]["FileURLFilePathDict"][lFileURL])
else:
#Set access denied code
# Send response status code
self.send_response(200)
self.send_response(403)
# Send headers
self.send_header('Content-type','application/json')
self.end_headers()
# Send message back to client
message = json.dumps(gSettingsDict)
# Write content as utf-8 data
self.wfile.write(bytes(message, "utf8"))
#Filemanager function
if self.path.lower().startswith('/filemanager/'):
lFileURL=self.path[13:]
# check if file in FileURL - File Path Mapping Dict
if lFileURL.lower() in gSettingsDict["FileManager"]["FileURLFilePathDict"]:
self.SendResponseContentTypeFile('application/octet-stream', gSettingsDict["FileManager"]["FileURLFilePathDict"][lFileURL])
else:
#Set access denied code
# Send response status code
self.send_response(403)
# Send headers
self.end_headers()
except Exception as e:
lL = gSettingsDict["Logger"]
if lL: lL.exception(f"Server.do_GET: Global error handler - look traceback below.")
# POST
def do_POST(self):
lL = gSettingsDict["Logger"]
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
#pdb.set_trace()
lResponseDict = {"Headers": {}, "SetCookies":{}, "Body": b"", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
#####################################
#Do authentication
#Check if authentication is turned on
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
lIsSuperToken = False # Is supertoken
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
# Get Flag is supertoken (True|False)
lIsSuperToken = gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(
self.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
else:
#Check the user access (if flag)
####################################
lFlagUserAccess = True
#If need user authentication
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("POST", self)
######################################
if lFlagUserAccess:
lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1])
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in gSettingsDict["Server"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST")
if lFlagURLIsApplied:
self.ResponseDictSend()
return
#Централизованная функция получения запросов/отправки
if self.path == '/Utils/Processor':
#ReadRequest
lInputObject={}
if self.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(self.headers.get('Content-Length'))
lInputByteArray=self.rfile.read(lInputByteArrayLength)
#Превращение массива байт в объект
lInputObject=json.loads(lInputByteArray.decode('utf8'))
try:
lL = gSettingsDict["Logger"]
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
#pdb.set_trace()
lResponseDict = {"Headers": {}, "SetCookies":{}, "Body": b"", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
#####################################
#Do authentication
#Check if authentication is turned on
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
lIsSuperToken = False # Is supertoken
if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
# Get Flag is supertoken (True|False)
lIsSuperToken = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(self.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
if lFlagAccessUserBlock:
AuthenticateBlock(self)
#####################################
else:
#Check the user access (if flag)
####################################
lFlagUserAccess = True
#If need user authentication
if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("POST", self)
######################################
if lFlagUserAccess:
lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1])
############################
#New server engine (url from global dict (URLList))
############################
for lURLItem in gSettingsDict["ServerDict"]["URLList"]:
#Check if all condition are applied
lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST")
if lFlagURLIsApplied:
self.ResponseDictSend()
return
#Централизованная функция получения запросов/отправки
if self.path == '/Utils/Processor':
#ReadRequest
lInputObject={}
if self.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(self.headers.get('Content-Length'))
lInputByteArray=self.rfile.read(lInputByteArrayLength)
#Превращение массива байт в объект
lInputObject=json.loads(lInputByteArray.decode('utf8'))
# Send response status code
self.send_response(200)
# Send headers
self.send_header('Content-type','application/json')
self.end_headers()
# Logging info about processor activity if not SuperToken ()
if not lIsSuperToken:
lActivityTypeListStr = ""
try:
if type(lInputObject) is list:
for lActivityItem in lInputObject:
lActivityTypeListStr+=f"{lActivityItem['Type']}; "
else:
lActivityTypeListStr += f"{lInputObject['Type']}"
except Exception as e:
lActivityTypeListStr = "Has some error with Activity Type read"
if lL: lL.info(f"Server:: !ATTENTION! /Utils/Processor will be deprecated in future. Use /pyOpenRPA/Processor or /pyOpenRPA/ActivityListExecute. User activity from web. Domain: {self.OpenRPA['Domain']}, Username: {self.OpenRPA['User']}, ActivityType: {lActivityTypeListStr}")
# Send message back to client
message = json.dumps(ProcessorOld.ActivityListOrDict(lInputObject))
# Write content as utf-8 data
self.wfile.write(bytes(message, "utf8"))
return
else:
#Set access denied code
# Send response status code
self.send_response(200)
self.send_response(403)
# Send headers
self.send_header('Content-type','application/json')
self.end_headers()
# Logging info about processor activity if not SuperToken ()
if not lIsSuperToken:
if lL: lL.info(f"Server:: User activity from web. Domain: {self.OpenRPA['Domain']}, Username: {self.OpenRPA['User']}, Activity: {lInputObject}")
# Send message back to client
message = json.dumps(Processor.ActivityListOrDict(lInputObject))
# Write content as utf-8 data
self.wfile.write(bytes(message, "utf8"))
return
else:
#Set access denied code
# Send response status code
self.send_response(403)
# Send headers
self.end_headers()
return
return
except Exception as e:
lL = gSettingsDict["Logger"]
if lL: lL.exception(f"Server.do_POST: Global error handler - look traceback below.")
#Logging
#!Turn it on to stop print in console
#def log_message(self, format, *args):
@ -470,7 +503,7 @@ class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
daemon_threads = True
"""Handle requests in a separate thread."""
def finish_request(self, request, client_address):
request.settimeout(gSettingsDict["Server"]["RequestTimeoutSecFloat"])
request.settimeout(gSettingsDict["ServerDict"]["RequestTimeoutSecFloat"])
# "super" can not be used because BaseServer is not created from object
HTTPServer.finish_request(self, request, client_address)
#inGlobalDict
@ -483,7 +516,7 @@ class RobotDaemonServer(Thread):
ServerSettings.SettingsUpdate(inGlobalDict)
def run(self):
inServerAddress="";
inPort = gSettingsDict["Server"]["ListenPort"];
inPort = gSettingsDict["ServerDict"]["ListenPort"];
# Server settings
# Choose port 8080, for port 80, which is normally used for a http server, you need root access
server_address = (inServerAddress, inPort)

@ -1,5 +1,7 @@
import json
import json, os
import copy
from inspect import signature # For detect count of def args
from . import __Orchestrator__
#ControlPanelDict
from desktopmagic.screengrab_win32 import (
getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage,
@ -9,163 +11,234 @@ import uuid # generate UUID4
import time # sleep functions
import datetime # datetime functions
import threading # Multi-threading
from .Web import Basic
from . import BackwardCompatibility # Support old up to 1.2.0 defs
from . import Processor
from . import SettingsTemplate
# # # # # # # # # # # #
# v 1.2.0 Functionallity
# # # # # # # # # # # #
# 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.
lUACCPTemplateKeyList=["pyOpenRPADict","CPKeyDict"]
lL = inGSettings["Logger"] # Alias for logger
# Create result JSON
lCPDict = {}
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
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":{"",""}}
def HiddenRDPDictGenerate(inRequest, inGSettings):
dUAC = inRequest.UACClientCheck # Alias.
lUACRDPTemplateKeyList=["pyOpenRPADict","RDPKeyDict"]
lRDPDict = {"HandlebarsList":[]}
# Iterate throught the RDP list
for lRDPSessionKeyStrItem in inGSettings["RobotRDPActive"]["RDPList"]:
# Check UAC
if dUAC(inRoleKeyList=lUACRDPTemplateKeyList+[lRDPSessionKeyStrItem]):
lRDPConfiguration = inGSettings["RobotRDPActive"]["RDPList"][
lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr": "", "SessionHexStr": "", "IsFullScreenBool": False,
"IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGSettings["RobotRDPActive"][
"FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lRDPDict[lDataItemDict["SessionKeyStr"]]=lDataItemDict
lHandlebarsDataItemDict = copy.deepcopy(lDataItemDict)
lHandlebarsDataItemDict["SessionKeyStr"]=lDataItemDict["SessionKeyStr"]
lRDPDict["HandlebarsList"].append(lHandlebarsDataItemDict)
return lRDPDict
# Return {"HostNameUpperStr;UserUpperStr":{"IsListenBool":True}, "HandlebarsList":[{"HostnameUpperStr":"","UserUpperStr":"","IsListenBool":True}]}
def HiddenAgentDictGenerate(inRequest, inGSettings):
dUAC = inRequest.UACClientCheck # Alias.
lUACAgentTemplateKeyList=["pyOpenRPADict","AgentKeyDict"]
lAgentDict = {"HandlebarsList":[]}
# Iterate throught the RDP list
for lAgentItemKeyStrItem in inGSettings["AgentDict"]:
# Check UAC
lKeyStr = f"{lAgentItemKeyStrItem[0]};{lAgentItemKeyStrItem[1]}" # turple ("HostNameUpperStr","UserUpperStr") > Str "HostNameUpperStr;UserUpperStr"
if dUAC(inRoleKeyList=lUACAgentTemplateKeyList+[lKeyStr]):
lDataItemDict = inGSettings["AgentDict"][lAgentItemKeyStrItem]
lAgentDict[lKeyStr]=lDataItemDict
lHandlebarsDataItemDict = copy.deepcopy(lDataItemDict)
lHandlebarsDataItemDict["HostnameUpperStr"]=lAgentItemKeyStrItem[0]
lHandlebarsDataItemDict["UserUpperStr"]=lAgentItemKeyStrItem[1]
lAgentDict["HandlebarsList"].append(lHandlebarsDataItemDict)
return lAgentDict
# /Orchestrator/RobotRDPActive/ControlPanelDictGet
def RobotRDPActive_ControlPanelDictGet(inRequest,inGlobalDict):
#v1.2.0 Send data container to the client from the server
# /pyOpenRPA/ServerData return {"HashStr" , "ServerDataDict": {"CPKeyStr":{"HTMLStr":"", DataDict:{}}}}
# Client: mGlobal.pyOpenRPA.ServerDataHashStr
# Client: mGlobal.pyOpenRPA.ServerDataDict
def pyOpenRPA_ServerData(inRequest,inGSettings):
# Extract the hash value from request
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lValueStr = (lInputByteArray.decode('utf8'))
# Generate ServerDataDict
lFlagDoGenerateBool = True
while lFlagDoGenerateBool:
lServerDataDict = {
"CPDict": HiddenCPDictGenerate(inRequest=inRequest, inGSettings=inGSettings),
"RDPDict": HiddenRDPDictGenerate(inRequest=inRequest, inGSettings=inGSettings),
"AgentDict": HiddenAgentDictGenerate(inRequest=inRequest, inGSettings=inGSettings),
"UserDict": {"UACClientDict": inRequest.OpenRPA["DefUserRoleHierarchyGet"](), "CWDPathStr": os.getcwd(), "VersionStr": inGSettings["VersionStr"]},
}
# Create JSON
lServerDataDictJSONStr = json.dumps(lServerDataDict)
# Generate hash
lServerDataHashStr = str(hash(lServerDataDictJSONStr))
if lValueStr!=lServerDataHashStr and lServerDataHashStr!= "" and lServerDataHashStr!= None: # Case if Hash is not equal
lFlagDoGenerateBool = False
else: # Case Hashes are equal
time.sleep(inGSettings["Client"]["Session"]["ControlPanelRefreshIntervalSecFloat"])
# Return the result if Hash is changed
lResult = {"HashStr": lServerDataHashStr, "ServerDataDict": lServerDataDict}
inResponseDict = inRequest.OpenRPAResponseDict
lResultDict = {
"DataList":[
# {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False}
]
}
# Iterate throught the RDP List
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]:
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"]["FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lResultDict["DataList"].append(lDataItemDict)
# Send message back to client
message = json.dumps(lResultDict)
message = json.dumps(lResult)
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
return lResult
# def to check control panels for selected session
def Monitor_ControlPanelDictGet_SessionCheckInit(inRequest,inGlobalDict):
lL = inGlobalDict["Logger"] # Alias for logger
lLifetimeSecFloat = inGlobalDict["Client"]["Session"]["LifetimeSecFloat"]
lLifetimeRequestSecFloat = inGlobalDict["Client"]["Session"]["LifetimeRequestSecFloat"]
lControlPanelRefreshIntervalSecFloat = inGlobalDict["Client"]["Session"]["ControlPanelRefreshIntervalSecFloat"]
lCookieSessionGUIDStr = None # generate the new GUID
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Technicaldef - interval check control panels + check actuality of the session by the datetime
def TechnicalCheck():
lItemValue = inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]
# Lifetime is ok - check control panel
lDatasetCurrentBytes = Monitor_ControlPanelDictGet(inRequest,inGlobalDict) # Call the control panel
if lDatasetCurrentBytes != lItemValue["DatasetLast"]["ControlPanel"]["Data"]: # Check if dataset is changed
lItemValue["DatasetLast"]["ControlPanel"]["Data"] = lDatasetCurrentBytes # Set new datset
lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] = True # Set flag to return the data
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Technicaldef - Create new session struct
def TechnicalSessionNew(inSessionGUIDStr):
lCookieSessionGUIDStr = inSessionGUIDStr # Generate the new GUID
lSessionNew = { # Session with some GUID str. On client session guid stored in cookie "SessionGUIDStr"
"InitDatetime": datetime.datetime.now(), # Datetime when session GUID was created
"DatasetLast": {
"ControlPanel": {
"Data": None, # Struct to check with new iterations. None if starts
"ReturnBool": False # flag to return, close request and return data as json
}
},
"ClientRequestHandler": inRequest, # Last client request handler
"UserADStr": inRequest.OpenRPA["User"], # User, who connect. None if user is not exists
"DomainADStr": inRequest.OpenRPA["Domain"], # Domain of the user who connect. None if user is not exists
}
inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr] = lSessionNew # Set new session in dict
inRequest.OpenRPAResponseDict["SetCookies"]["SessionGUIDStr"] = lCookieSessionGUIDStr # Set SessionGUIDStr in cookies
if lL: lL.info(f"New session GUID is created. GUID {lCookieSessionGUIDStr}")
return lCookieSessionGUIDStr
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
lCreateNewSessionBool = False # Flag to create new session structure
# step 1 - get cookie SessionGUIDStr
lSessionGUIDStr = inRequest.headers.get("SessionGUIDStr", None)
if lSessionGUIDStr is not None: # Check if GUID session is ok
lCookieSessionGUIDStr = lSessionGUIDStr # Get the existing GUID
if lSessionGUIDStr not in inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lCookieSessionGUIDStr= TechnicalSessionNew(inSessionGUIDStr = lSessionGUIDStr) # Create new session
else: # Update the datetime of the request session
inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]["InitDatetime"]=datetime.datetime.now()
else:
lCookieSessionGUIDStr = TechnicalSessionNew(inSessionGUIDStr = lSessionGUIDStr) # Create new session
# Init the RobotRDPActive in another thread
#lThreadCheckCPInterval = threading.Thread(target=TechnicalIntervalCheck)
#lThreadCheckCPInterval.daemon = True # Run the thread in daemon mode.
#lThreadCheckCPInterval.start() # Start the thread execution.
# Step 2 - interval check if data is exist
lTimeStartSecFloat = time.time()
lDoWhileBool = True # Flag to iterate throught the lifetime of the request
while lDoWhileBool:
#print(lTechnicalSessionGUIDCache)
#print(lCookieSessionGUIDStr)
if lCookieSessionGUIDStr in inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"]:
lItemValue = inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr]
if (time.time() - lTimeStartSecFloat) >= lLifetimeRequestSecFloat: # Check if lifetime client request is over or has no key
if lL: lL.debug(f"Client request lifetime is over")
lDoWhileBool = False # Stop the iterations
if lDoWhileBool:
TechnicalCheck() # Calculate the CP
if lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] == True: # Return data if data flag it True
lDatasetCurrentBytes = lItemValue["DatasetLast"]["ControlPanel"]["Data"] # Set new dataset
inResponseDict = inRequest.OpenRPAResponseDict
inResponseDict["Body"] = lDatasetCurrentBytes
lItemValue["DatasetLast"]["ControlPanel"]["ReturnBool"] = False # Set flag that data was returned
lDoWhileBool = False # Stop the iterations
else:
lCookieSessionGUIDStr = TechnicalSessionNew(inSessionGUIDStr = lCookieSessionGUIDStr) # Create new session
if lDoWhileBool: # Sleep if we wait hte next iteration
time.sleep(lControlPanelRefreshIntervalSecFloat) # Sleep to the next iteration
def Monitor_ControlPanelDictGet(inRequest,inGlobalDict):
# GET
# /pyOpenRPA/ServerJSInit return JavaScript to init on page
def pyOpenRPA_ServerJSInit(inRequest,inGSettings):
lResultStr = HiddenJSInitGenerate(inRequest=inRequest, inGSettings=inGSettings)
inResponseDict = inRequest.OpenRPAResponseDict
lL = inGlobalDict["Logger"] # Alias for logger
# Create result JSON
lResultJSON = {"RenderRobotList": [], "RenderRDPList": []}
lRenderFunctionsRobotList = inGlobalDict["ControlPanelDict"]["RobotList"]
for lItem in lRenderFunctionsRobotList:
lUACBool = True # Check if render function is applicable User Access Rights (UAC)
if inGlobalDict["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True:
lUserRights = inGlobalDict["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
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"](inGlobalDict)
elif lDEFARGLen == 2: # def (inRequest, inGSettings)
lItemResultDict = lItem["RenderFunction"](inRequest, inGlobalDict)
elif lDEFARGLen == 0: # def ()
lItemResultDict = lItem["RenderFunction"]()
# RunFunction
lResultJSON["RenderRobotList"].append(lItemResultDict)
except Exception as e:
if lL: lL.exception(f"Error in control panel. CP item {lItem}. Exception is below")
# Iterate throught the RDP list
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]:
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][
lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr": "", "SessionHexStr": "", "IsFullScreenBool": False,
"IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"][
"FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lResultJSON["RenderRDPList"].append(lDataItemDict)
# Send message back to client
message = json.dumps(lResultJSON)
# Write content as utf-8 data
#inResponseDict["Body"] = bytes(message, "utf8")
return bytes(message, "utf8")
# UserAccess get rights hierarchy dict in json
def UserRoleHierarchyGet(inRequest,inGlobalDict):
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
# Client: mGlobal.pyOpenRPA.ServerLogList
def pyOpenRPA_ServerLog(inRequest,inGSDict):
# Extract the hash value from request
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lValueStr = (lInputByteArray.decode('utf8'))
# Generate ServerDataDict
lFlagDoGenerateBool = True
while lFlagDoGenerateBool:
lServerLogList = inGSDict["Client"]["DumpLogList"]
# Get hash
lServerLogListHashStr = inGSDict["Client"]["DumpLogListHashStr"]
if lValueStr!=lServerLogListHashStr and lServerLogListHashStr!= "" and lServerLogListHashStr!= None: # Case if Hash is not equal Fix because None can be obtained without JSON decode
lFlagDoGenerateBool = False
else: # Case Hashes are equal
time.sleep(inGSDict["Client"]["DumpLogListRefreshIntervalSecFloat"])
# Return the result if Hash is changed
lResult = {"HashStr": lServerLogListHashStr, "ServerLogList": lServerLogList}
inResponseDict = inRequest.OpenRPAResponseDict
# Create result JSON
lResultDict = inRequest.OpenRPA["DefUserRoleHierarchyGet"]() # Get the User Role Hierarchy list
# Send message back to client
message = json.dumps(lResultDict)
message = json.dumps(lResult)
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
return lResult
def GetScreenshot(inRequest,inGlobalDict):
def pyOpenRPA_Screenshot(inRequest,inGlobalDict):
# Get Screenshot
def SaveScreenshot(inFilePath):
# grab fullscreen
@ -182,6 +255,139 @@ def GetScreenshot(inRequest,inGlobalDict):
inRequest.OpenRPAResponseDict["Body"] = lFileObject.read()
# Закрыть файловый объект
lFileObject.close()
# Add activity item or activity list to the processor queue
# Body is Activity item or Activity List
def pyOpenRPA_Processor(inRequest, inGSettings):
lL = inGSettings["Logger"]
# Recieve the data
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lInput = json.loads(lInputByteArray.decode('utf8'))
# If list - operator plus
if type(lInput) is list:
# Logging info about processor activity if not SuperToken ()
if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings):
lActivityTypeListStr = ""
try:
for lActivityItem in lInput:
lActivityTypeListStr += f"{lActivityItem['Def']}; "
except Exception as e:
lActivityTypeListStr = "Has some error with Activity Type read"
if lL: lL.info(f"ServerSettings.pyOpenRPA_Processor. User activity from web. Domain: {inRequest.OpenRPA['Domain']}, Username: {inRequest.OpenRPA['User']}, ActivityType: {lActivityTypeListStr}")
# Append in list
inGSettings["ProcessorDict"]["ActivityList"]+=lInput
else:
# Logging info about processor activity if not SuperToken ()
if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings):
lActivityTypeListStr = ""
try:
lActivityTypeListStr = lInput['Def']
except Exception as e:
lActivityTypeListStr = "Has some error with Activity Type read"
if lL: lL.info(f"ServerSettings.pyOpenRPA_Processor. User activity from web. Domain: {inRequest.OpenRPA['Domain']}, Username: {inRequest.OpenRPA['User']}, ActivityType: {lActivityTypeListStr}")
# Append in list
inGSettings["ProcessorDict"]["ActivityList"].append(lInput)
# Execute activity list
def pyOpenRPA_ActivityListExecute(inRequest, inGSettings):
# Recieve the data
lL = inGSettings["Logger"]
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lInput = json.loads(lInputByteArray.decode('utf8'))
# If list - operator plus
if type(lInput) is list:
# Logging info about processor activity if not SuperToken ()
if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings):
lActivityTypeListStr = ""
try:
for lActivityItem in lInput:
lActivityTypeListStr += f"{lActivityItem['Def']}; "
except Exception as e:
lActivityTypeListStr = "Has some error with Activity Type read"
if lL: lL.info(f"ServerSettings.pyOpenRPA_ActivityListExecute. User activity from web. Domain: {inRequest.OpenRPA['Domain']}, Username: {inRequest.OpenRPA['User']}, ActivityType: {lActivityTypeListStr}")
# Execution
lResultList = Processor.ActivityListExecute(inGSettings = inGSettings, inActivityList = lInput)
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lResultList), "utf8")
else:
# Logging info about processor activity if not SuperToken ()
if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings):
lActivityTypeListStr = ""
try:
lActivityTypeListStr = lInput['Def']
except Exception as e:
lActivityTypeListStr = "Has some error with Activity Type read"
if lL: lL.info(f"ServerSettings.pyOpenRPA_ActivityListExecute. User activity from web. Domain: {inRequest.OpenRPA['Domain']}, Username: {inRequest.OpenRPA['User']}, ActivityType: {lActivityTypeListStr}")
# Execution
lResultList = Processor.ActivityListExecute(inGSettings = inGSettings, inActivityList = [lInput])
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lResultList[0]), "utf8")
# See docs in Agent (pyOpenRPA.Agent.O2A)
def pyOpenRPA_Agent_O2A(inRequest, inGSettings):
lL = inGSettings["Logger"] # Alias
lConnectionLifetimeSecFloat = 3600.0 # 60 min * 60 sec 3600.0
lTimeStartFloat = time.time()
# Recieve the data
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lInput = json.loads(lInputByteArray.decode('utf8'))
# Check if item is created
lAgentDictItemKeyTurple = (lInput["HostNameUpperStr"],lInput["UserUpperStr"])
if lAgentDictItemKeyTurple not in inGSettings["AgentDict"]:
inGSettings["AgentDict"][lAgentDictItemKeyTurple] = SettingsTemplate.__AgentDictItemCreate__()
lThisAgentDict = inGSettings["AgentDict"][lAgentDictItemKeyTurple]
lThisAgentDict["IsListenBool"]=True # Set is online
lThisAgentDict["ConnectionCountInt"] += 1 # increment connection count
# Test solution
lDoLoopBool = True
while lDoLoopBool:
# Check if lifetime is over
if time.time() - lTimeStartFloat > lConnectionLifetimeSecFloat: # Lifetime is over
lThisAgentDict["IsListenBool"] = False # Set is offline
lDoLoopBool = False
else: # Lifetime is good - do alg
lThisAgentDict["IsListenBool"] = True # Set is online
lQueueList = lThisAgentDict["ActivityList"]
if len(lQueueList)>0:# Do some operations if has queue items
if lL: lL.debug(f'O2A BEFORE: ConnectionCountInt: {lThisAgentDict["ConnectionCountInt"]};ConnectionFirstQueueItemCountInt {lThisAgentDict["ConnectionFirstQueueItemCountInt"]}')
if lThisAgentDict["ConnectionCountInt"] == lThisAgentDict["ConnectionFirstQueueItemCountInt"] + 1:
# POP QUEUE ITEM CONDITION ConnectionCountInt == ConnectionFirstQueueItemCountInt + 1
lActivityItem = lThisAgentDict["ActivityList"].pop(0)
lThisAgentDict["ConnectionFirstQueueItemCountInt"] = 0
if lL: lL.debug(f"Activity was deleted from the list: {lThisAgentDict['ActivityList']}")
else:
lActivityItem = lThisAgentDict["ActivityList"][0]
lThisAgentDict["ConnectionFirstQueueItemCountInt"] += 1
if lL: lL.debug(f"Activity was !not! deleted from the list: {lThisAgentDict['ActivityList']}")
if lL: lL.debug(f'O2A AFTER: ConnectionCountInt: {lThisAgentDict["ConnectionCountInt"]};ConnectionFirstQueueItemCountInt {lThisAgentDict["ConnectionFirstQueueItemCountInt"]}')
# Send QUEUE ITEM
if lL: lL.info(f"Activity item to agent Hostname {lInput['HostNameUpperStr']}, User {lInput['UserUpperStr']}. Activity item: {lActivityItem}")
inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lActivityItem), "utf8")
lDoLoopBool = False # CLose the connection
else: # no queue item - sleep for the next iteration
time.sleep(1)
lThisAgentDict["ConnectionCountInt"] -= 1 # Connection go to be closed - decrement the connection count
# See docs in Agent (pyOpenRPA.Agent.A2O)
def pyOpenRPA_Agent_A2O(inRequest, inGSettings):
# Recieve the data
lValueStr = None
if inRequest.headers.get('Content-Length') is not None:
lInputByteArrayLength = int(inRequest.headers.get('Content-Length'))
lInputByteArray = inRequest.rfile.read(lInputByteArrayLength)
# Превращение массива байт в объект
lInput = json.loads(lInputByteArray.decode('utf8'))
if "LogList" in lInput:
for lLogItemStr in lInput["LogList"]:
inGSettings["Logger"].info(lLogItemStr)
def SettingsUpdate(inGlobalConfiguration):
import os
import pyOpenRPA.Orchestrator
@ -207,10 +413,19 @@ def SettingsUpdate(inGlobalConfiguration):
{"Method":"GET", "URL": "/3rdParty/Semantic-UI-CSS-master/themes/default/assets/fonts/icons.woff2", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\themes\\default\\assets\\fonts\\icons.woff2"), "ResponseContentType": "font/woff2"},
{"Method":"GET", "URL": "/favicon.ico", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "Web\\favicon.ico"), "ResponseContentType": "image/x-icon"},
{"Method":"GET", "URL": "/3rdParty/Handlebars/handlebars-v4.1.2.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Handlebars\\handlebars-v4.1.2.js"), "ResponseContentType": "application/javascript"},
{"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": Monitor_ControlPanelDictGet_SessionCheckInit, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": GetScreenshot, "ResponseContentType": "image/png"},
{"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_Monitor_ControlPanelDictGet_SessionCheckInit, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": pyOpenRPA_Screenshot, "ResponseContentType": "image/png"},
{"Method": "GET", "URL": "/pyOpenRPA_logo.png", "MatchType": "Equal", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\pyOpenRPA_logo.png"), "ResponseContentType": "image/png"},
{"Method": "POST", "URL": "/Orchestrator/UserRoleHierarchyGet", "MatchType": "Equal","ResponseDefRequestGlobal": UserRoleHierarchyGet, "ResponseContentType": "application/json"}
{"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/ProcessorQueueAdd", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Processor, "ResponseContentType": "application/json"},
{"Method": "POST", "URL": "/pyOpenRPA/ActivityListExecute", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ActivityListExecute, "ResponseContentType": "application/json"},
{"Method": "POST", "URL": "/pyOpenRPA/Agent/O2A", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Agent_O2A, "ResponseContentType": "application/json"},
{"Method": "POST", "URL": "/pyOpenRPA/Agent/A2O", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Agent_A2O, "ResponseContentType": "application/json"},
]
inGlobalConfiguration["Server"]["URLList"]=inGlobalConfiguration["Server"]["URLList"]+lURLList
inGlobalConfiguration["ServerDict"]["URLList"]=inGlobalConfiguration["ServerDict"]["URLList"]+lURLList
return inGlobalConfiguration

@ -1,4 +1,5 @@
var mGlobal={}
mGlobal.pyOpenRPA = {}
window.onload=function() {
//document.cookie = "SessionGUIDStr=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
//Render existing data
@ -121,11 +122,17 @@ $(document).ready(function() {
lCMDCode=$(".openrpa-controller-cmd-run-input")[0].value
///Подготовить конфигурацию
lData = [
{"Type":"CMDStart", "Command": lCMDCode }
{
"Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"])
"ArgList":[], // Args list
"ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary
"ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
]
$.ajax({
type: "POST",
url: 'Utils/Processor',
url: '/pyOpenRPA/ActivityListExecute',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
@ -221,7 +228,7 @@ $(document).ready(function() {
}
//inHostURI: http://localhost:8081
mGlobal.Monitor.ScreenshotModal.Show=function(inHostURI=" ") {
$('.ui.modal.daemon-screenshot').modal('show');
$('.ui.modal.daemon-screenshot').modal({'onHide':function (inElement) {mGlobal.Monitor.ScreenshotModal.Close();} }).modal('show');
//Функция обновления картинки
lScreenshotUpdate=function() {
@ -276,125 +283,342 @@ $(document).ready(function() {
mGlobal.Monitor.fControlPanelRefresh_TechnicalRender = function()
{
lResponseJSON = mGlobal.Monitor.mDatasetLast
if (lResponseJSON!= null) {
///Escape onclick
/// RenderRobotList
lResponseJSON["RenderRobotList"].forEach(
function(lItem){
if ('FooterButtonX2List' in lItem) {
/// FooterButtonX2List
lItem["FooterButtonX2List"].forEach(
function(lItem2){
if ('OnClick' in lItem) {
lOnClickEscaped = lItem["OnClick"];
lOnClickEscaped = lOnClickEscaped.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
lItem["OnClick"] = lOnClickEscaped;
/// New version of control panels
for (var lKeyStr in lResponseJSON){
if (lKeyStr != "RenderRobotList") { /// Check if not "RenderRobotList"
lCPDict = lResponseJSON[lKeyStr]
/// Render HTML
if ("HTMLStr" in lCPDict) {
}
}
}
/// v1.2.0 Backward compatibility - support old control panels
if ("RenderRobotList" in lResponseJSON) {
///Escape onclick
/// RenderRobotList
lResponseJSON["RenderRobotList"].forEach(
function(lItem){
if ('FooterButtonX2List' in lItem) {
/// FooterButtonX2List
lItem["FooterButtonX2List"].forEach(
function(lItem2){
if ('OnClick' in lItem) {
lOnClickEscaped = lItem["OnClick"];
lOnClickEscaped = lOnClickEscaped.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
lItem["OnClick"] = lOnClickEscaped;
}
}
}
);
/// FooterButtonX1List
lItem["FooterButtonX1List"].forEach(
function(lItem2){
if ('OnClick' in lItem) {
lOnClickEscaped = lItem["OnClick"];
lOnClickEscaped = lOnClickEscaped.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
lItem["OnClick"] = lOnClickEscaped;
);
/// FooterButtonX1List
lItem["FooterButtonX1List"].forEach(
function(lItem2){
if ('OnClick' in lItem) {
lOnClickEscaped = lItem["OnClick"];
lOnClickEscaped = lOnClickEscaped.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
lItem["OnClick"] = lOnClickEscaped;
}
}
}
);
);
}
}
}
);
//////////////////////////////////////////////////////////
///Сформировать HTML код новой таблицы - контрольная панель
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-control-panel",lResponseJSON)
//Присвоить ответ в mGlobal.Monitor.mResponseList
mGlobal.Monitor.mResponseList = lResponseJSON
///Set result in mGlobal.DataStorage
lResponseJSON["RenderRobotList"].forEach(
function(lItem){
if ('DataStorageKey' in lItem) {
mGlobal["DataStorage"][lItem['DataStorageKey']]=lItem
);
//////////////////////////////////////////////////////////
///Сформировать HTML код новой таблицы - контрольная панель
lHTMLCode+=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-control-panel",lResponseJSON)
//Присвоить ответ в mGlobal.Monitor.mResponseList
mGlobal.Monitor.mResponseList = lResponseJSON
///Set result in mGlobal.DataStorage
lResponseJSON["RenderRobotList"].forEach(
function(lItem){
if ('DataStorageKey' in lItem) {
mGlobal["DataStorage"][lItem['DataStorageKey']]=lItem
}
}
)
///Прогрузить новую таблицу
$(".openrpa-control-panel").html(lHTMLCode)
////////////////////////////////////////////////////
/// !RDP List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON)
//Присвоить ответ в mGlobal.RobotRDPActive.mResponseList
mGlobal.RobotRDPActive.mResponseList = lResponseJSON
///Прогрузить новую таблицу
$(".openrpa-robotrdpactive-control-panel").html(lHTMLCode)
///Очистить дерево
//mGlobal.ElementTree.fClear();
////////////////////////////////////////////////////
/// !UserAgent List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".pyOpenRPA-Agent-ListTemplate",lResponseJSON)
//Присвоить ответ в mGlobal.RobotRDPActive.mResponseList
mGlobal.RobotRDPActive.mResponseList = lResponseJSON
///Прогрузить новую таблицу
$(".pyOpenRPA-Agent-List").html(lHTMLCode)
///Очистить дерево
//mGlobal.ElementTree.fClear();
}
}
}
///v 1.2.0 pyOpenRPA
/// Execute ActivityItem
mGlobal.pyOpenRPA.ActivityItemExecute=function(inActivityItem) {
///EXAMPLE
// {
// "Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"])
// "ArgList":[], // Args list
// "ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary
// "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
// "ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
// }
///Подготовить конфигурацию
lData = [inActivityItem]
$.ajax({
type: "POST",
url: '/pyOpenRPA/ActivityListExecute',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
console.log(lResponseJSON)
},
dataType: "text"
});
}
/// Execute ActivityList
mGlobal.pyOpenRPA.ActivityListExecute=function(inActivityList) {
///EXAMPLE
// [{
// "Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"])
// "ArgList":[], // Args list
// "ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary
// "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
// "ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
// }]
///Подготовить конфигурацию
lData = inActivityList
$.ajax({
type: "POST",
url: '/pyOpenRPA/ActivityListExecute',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
console.log(lResponseJSON)
},
dataType: "text"
});
}
/// Add ActivityList in processor queue
mGlobal.pyOpenRPA.ProcessorQueueAdd=function(inActivityList) {
///EXAMPLE
// [{
// "Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"])
// "ArgList":[], // Args list
// "ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary
// "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
// "ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList)
// }]
///Подготовить конфигурацию
lData = inActivityList
$.ajax({
type: "POST",
url: '/pyOpenRPA/ProcessorQueueAdd',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
console.log(lResponseJSON)
},
dataType: "text"
});
}
/// 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
mGlobal.pyOpenRPA.ServerDataHashStr = ""
mGlobal.pyOpenRPA.ServerDataRefreshDef_TechnicalRender = function()
{
lResponseJSON = mGlobal.pyOpenRPA.ServerDataDict
if (lResponseJSON!= null) {
/// New version of control panels
lHTMLCode = '<div class="ui cards">'
for (var lKeyStr in lResponseJSON["CPDict"]){
lCPDict = lResponseJSON["CPDict"][lKeyStr]
/// Render HTML
if ("HTMLStr" in lCPDict) {
lHTMLCode+=lCPDict["HTMLStr"]
}
}
lHTMLCode += '</div>'
///Прогрузить новую таблицу
$(".openrpa-control-panel").html(lHTMLCode)
////////////////////////////////////////////////////
///Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON)
/// !RDP List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON["RDPDict"])
//Присвоить ответ в mGlobal.RobotRDPActive.mResponseList
mGlobal.RobotRDPActive.mResponseList = lResponseJSON
mGlobal.RobotRDPActive.mResponseList = lResponseJSON["RDPDict"]
///Прогрузить новую таблицу
$(".openrpa-robotrdpactive-control-panel").html(lHTMLCode)
///Очистить дерево
//mGlobal.ElementTree.fClear();
////////////////////////////////////////////////////
/// !UserAgent List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".pyOpenRPA-Agent-ListTemplate",lResponseJSON["AgentDict"])
///Прогрузить новую таблицу
$(".pyOpenRPA-Agent-List").html(lHTMLCode)
///Очистить дерево
//mGlobal.ElementTree.fClear();
}
}
mGlobal.Monitor.mDatasetLast = null
mGlobal.Monitor.fControlPanelRefresh=function() {
mGlobal.pyOpenRPA.ServerDataRefreshDef=function() {
try {
//var XHR = new XMLHttpRequest();
//XHR.setRequestHeader("Cookies",document.cookie)
///Загрузка данных
//console.log("Request is sent")
//console.log(document.cookie)
$.ajax({
type: "GET",
headers: {"SessionGUIDStr":mGlobal.SessionGUIDStr},
url: 'Monitor/ControlPanelDictGet',
data: '',
//cache: false,
//xhr: XHR,
type: "POST",
headers: {},
url: 'pyOpenRPA/ServerData',
data: mGlobal.pyOpenRPA.ServerDataHashStr,
success: function(lData,l2,l3) {
try {
var lResponseJSON=JSON.parse(lData)
mGlobal.Monitor.mDatasetLast = lResponseJSON
mGlobal.Monitor.fControlPanelRefresh_TechnicalRender()
mGlobal.VersionStr = lResponseJSON["ServerDataDict"]["UserDict"]["VersionStr"]
mGlobal.pyOpenRPA.ServerDataDict = lResponseJSON["ServerDataDict"]
mGlobal.pyOpenRPA.ServerDataHashStr = lResponseJSON["HashStr"]
mGlobal.pyOpenRPA.ServerDataRefreshDef_TechnicalRender()
mGlobal.UserRoleUpdate();
setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,600) // If LOGS are update every ms - set some limit in ms on the client side
//mGlobal.pyOpenRPA.ServerDataRefreshDef() // Go to the next call
}
catch(error) {
console.log(error)
setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000)
}
mGlobal.Monitor.fControlPanelRefresh() // recursive
//mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive
},
dataType: "text",
error: function(jqXHR, textStatus, errorThrown ) {
sleep(3000)
mGlobal.Monitor.fControlPanelRefresh() // recursive
setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000)
//sleep(3000)
//mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive
}
});
}
catch(error) {
sleep(3000)
mGlobal.Monitor.fControlPanelRefresh() // recursive
setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000)
//sleep(3000)
//mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive
}
//mGlobal.Monitor.fControlPanelRefresh() // recursive
}
mGlobal.Monitor.fControlPanelRefresh()
mGlobal.Test=function() {
///Обнулить таблицу
lData = [
{
"Type":"GlobalDictKeyListValueSet",
"key_list":["Storage","Robot_R01"],
"value":{
"RunDateTimeString":"Test1",
"StepCurrentName":"Test2",
"StepCurrentDuration":"Test3"
/////////////////////////////////////////////////////////////
/// v1.2.0 pyOpenRPA ServerLogs
mGlobal.pyOpenRPA.ServerLogList = null
mGlobal.pyOpenRPA.ServerLogListHashStr = ""
mGlobal.pyOpenRPA.ServerLogListDoRenderBool = true
///Turn OFF rendering
mGlobal.pyOpenRPA.ServerLogListDoRenderFalse = function() {
///Set unfreeze button
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").html("Unfreeze textarea")
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").attr("onclick","mGlobal.pyOpenRPA.ServerLogListDoRenderTrue()")
$("textarea.mGlobal-pyOpenRPA-ServerLogList").css("background-color","#b9e2e8")
mGlobal.pyOpenRPA.ServerLogListDoRenderBool = false
}
///Turn ON rendering
mGlobal.pyOpenRPA.ServerLogListDoRenderTrue = function() {
mGlobal.pyOpenRPA.ServerLogListDoRenderBool = true
///Render last data
mGlobal.pyOpenRPA.ServerLogListRefreshDef_TechnicalRender()
///Set unfreeze button
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").html("Freeze textarea")
$("a.mGlobal-pyOpenRPA-ServerLogListDoRender").attr("onclick","mGlobal.pyOpenRPA.ServerLogListDoRenderFalse()")
$("textarea.mGlobal-pyOpenRPA-ServerLogList").css("background-color","")
}
mGlobal.pyOpenRPA.ServerLogListScrollBottomDef = function() {
var lTA = $("textarea.mGlobal-pyOpenRPA-ServerLogList")[0];
lTA.scrollTop = lTA.scrollHeight;
}
mGlobal.pyOpenRPA.ServerLogListRefreshDef_TechnicalRender = function()
{
lResponseJSON = mGlobal.pyOpenRPA.ServerLogList
if (lResponseJSON!= null && mGlobal.pyOpenRPA.ServerLogListDoRenderBool==true) {
lText = lResponseJSON.join("\n") /// Code for the processing the text
$("textarea.mGlobal-pyOpenRPA-ServerLogList")[0].value= lText ///Прогрузить новую таблицу
mGlobal.pyOpenRPA.ServerLogListScrollBottomDef() //Scroll to the bottom
}
}
mGlobal.pyOpenRPA.ServerLogListRefreshDef=function() {
try {
$.ajax({
type: "POST",
headers: {},
url: 'pyOpenRPA/ServerLog',
data: mGlobal.pyOpenRPA.ServerLogListHashStr,
success: function(lData,l2,l3) {
try {
var lResponseJSON=JSON.parse(lData)
mGlobal.pyOpenRPA.ServerLogList = lResponseJSON["ServerLogList"]
mGlobal.pyOpenRPA.ServerLogListHashStr = lResponseJSON["HashStr"]
mGlobal.pyOpenRPA.ServerLogListRefreshDef_TechnicalRender()
}
catch(error) {
}
setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,600) // If LOGS are update every ms - set some limit in ms on the client side
//mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive
},
dataType: "text",
error: function(jqXHR, textStatus, errorThrown ) {
setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,3000)
//sleep(3000)
//mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive
}
}
]
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
//console.log(lData)
},
dataType: "text"
});
});
}
catch(error) {
setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,3000)
//sleep(3000)
//mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive
}
}
/////////////////////////////////////////////////////////////
mGlobal.Monitor.mDatasetLast = null
///////////////////////////////
///Processor functions
///////////////////////////////
@ -615,7 +839,7 @@ $(document).ready(function() {
// UAC Ask
mGlobal.UserRoleAsk=function(inList) {
var lResult = true; // Init flag
var lRoleHierarchyDict = mGlobal.UserRoleHierarchyDict; // get the Hierarchy
var lRoleHierarchyDict = mGlobal.pyOpenRPA.ServerDataDict.UserDict.UACClientDict; // get the Hierarchy
// Try to get value from key list
var lKeyValue = lRoleHierarchyDict; // Init the base
var lListLength = inList.length;
@ -641,64 +865,31 @@ $(document).ready(function() {
}
// Check user roles and update the Orchestrator UI
mGlobal.UserRoleUpdate=function() {
$.ajax({
type: "POST",
url: 'Orchestrator/UserRoleHierarchyGet',
data: "",
success:
function(lData,l2,l3)
{
var lUACAsk = mGlobal.UserRoleAsk // Alias
var lResponseDict=JSON.parse(lData)
mGlobal.UserRoleHierarchyDict = lResponseDict // set the user role hierarchy
//Turn on the Lookmachine screenshot button
if (lUACAsk(["Orchestrator","Controls","LookMachineScreenshots"])) {
$(".openrpa-control-lookmachinescreenshot").show() //Show button
}
//Turn on the restart orchestrator button
if (lUACAsk(["Orchestrator","Controls","RestartOrchestrator"])) {
$(".openrpa-control-restartorchestrator").show() //Show button
}
//Turn on the rdp session list
if (lUACAsk(["Orchestrator","RDPActive","ListRead"])) {
$(".openrpa-rdpactive-title").show() //Show section
$(".openrpa-robotrdpactive-control-panel-general").show() //Show section
}
//Turn on the restart PC button
if (lUACAsk(["Orchestrator","Controls","RestartPC"])) {
$(".openrpa-control-restartpc").show() //Show button
}
//Turn on the git update + restart orchestrator
if (lUACAsk(["Orchestrator","Controls","GITRestartOrchestrator"])) {
$(".openrpa-control-gitrestartorchestrator").show() //Show button
}
},
dataType: "text"
});
}
mGlobal.UserRoleUpdate() // Cal the update User Roles function
// Orchestrator model
mGlobal.WorkingDirectoryPathStr = null
mGlobal.OrchestratorModelUpdate=function() {
lData = [
{
"Type": "GlobalDictKeyListValueGet",
"KeyList": ["Server","WorkingDirectoryPathStr"]
}
]
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lUACAsk = mGlobal.UserRoleAsk // Alias
var lResponseList=JSON.parse(lData)
mGlobal.WorkingDirectoryPathStr = lResponseList[0]["Result"]
},
dataType: "text"
});
var lUACAsk = mGlobal.UserRoleAsk // Alias
//CPKeyDict
if (lUACAsk(["pyOpenRPADict","CPKeyDict"])) { $(".UACClient-pyOpenRPADict-CPKeyDict").show(); }
//RDPKeyDict
if (lUACAsk(["pyOpenRPADict","RDPKeyDict"])) { $(".UACClient-pyOpenRPADict-RDPKeyDict").show(); }
//AgentKeyDict
if (lUACAsk(["pyOpenRPADict","AgentKeyDict"])) { $(".UACClient-pyOpenRPADict-AgentKeyDict").show(); }
// AdminDict
if (lUACAsk(["pyOpenRPADict","AdminDict","LogViewerBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-LogViewerBool").show(); }
if (lUACAsk(["pyOpenRPADict","AdminDict","CMDInputBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-CMDInputBool").show(); }
if (lUACAsk(["pyOpenRPADict","AdminDict","ScreenshotViewerBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-ScreenshotViewerBool").show(); }
if (lUACAsk(["pyOpenRPADict","AdminDict","RestartOrchestratorBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorBool").show(); }
if (lUACAsk(["pyOpenRPADict","AdminDict","RestartOrchestratorGITPullBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorGITPullBool").show(); }
if (lUACAsk(["pyOpenRPADict","AdminDict","RestartPCBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-RestartPCBool").show(); }
}
mGlobal.OrchestratorModelUpdate() // Cal the update orchestrator model
/// 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
mGlobal.pyOpenRPA.ServerLogListDoRenderTrue(); // Init button to freeze/unfreeze textare with logs
$('.ui.dropdown').dropdown();
});

@ -59,11 +59,12 @@
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
<h1 class="ui header inverted">Orchestrator Web GUI</h1>
&nbsp;&nbsp;&nbsp;
<h1 class="ui header inverted">ORCHESTRATOR WEB GUI</h1>
</div>
</div>
<div class="row">
<div class="sixteen wide column openrpa-control-panel-general" >
<div class="sixteen wide column openrpa-control-panel-general UACClient-pyOpenRPADict-CPKeyDict" style="display:none;" >
<h4 class="ui horizontal divider header">
<i class="clipboard list icon"></i>
Dashboard (Robot control panel)
@ -116,125 +117,92 @@
</div>
<div class="row">
<div class="five wide column">
<h2 class="ui header">
<i class="settings icon"></i>
<div class="content">
Administration
</div>
</h2>
<div class="ui animated button openrpa-control-lookmachinescreenshot huge green" onclick="mGlobal.Monitor.ScreenshotModal.Show();" style="display: none; margin-top: 5px;">
<div class="visible content">Show live screenshots</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-restartorchestrator yellow" onclick="mGlobal.Controller.OrchestratorRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Restart Orchestrator</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-gitrestartorchestrator" onclick="mGlobal.Controller.OrchestratorGITPullRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Git pull + restart Orchestrator</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
<script class="openrpa-hidden-monitor-table-general" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table">
<thead>
<tr>
<th>Machine name</th>
<th>Machihe host</th>
<th>Status</th>
<th>Actions,length: {{childs.length}}</th>
</tr>
</thead>
<tbody>
{{#ListenURLList}}
<tr><td>{{Description}}</td><td>{{URL}}</td><td class="negative">None</td></tr>
{{/ListenURLList}}
</tbody>
</table>
</script>
<script class="openrpa-handlebar-template-table-filter" style="display:none" type="text/x-handlebars-template">
{{#if Title}}
<h1>{{{Title}}}</h1>
{{/if}}
{{#if FilterOnKeyUp}}
<div class="ui icon input search" style="width:500px;">
<input type="text" onkeyup="{{#if FilterOnKeyUp}}{{{FilterOnKeyUp}}}{{/if}}" placeholder="Search...">
<i class="inverted circular search link icon"></i>
</div>
<div class="ui animated button openrpa-control-restartpc red" onclick="mGlobal.Controller.PCRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Restart PC</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
{{/if}}
<table class="ui celled table selectable inverted">
<thead>
<tr>
{{#Columns}}
<th>{{{this}}}</th>
{{/Columns}}
</tr>
</thead>
<tbody>
{{#Rows}}
<tr>
{{#this}}
<td>
{{{this}}}
</td>
{{/this}}
</tr>
{{/Rows}}
</tbody>
</table>
</script>
<script class="openrpa-handlebar-template-list-filter" style="display:none" type="text/x-handlebars-template">
{{#if Title}}
<h1>{{{Title}}}</h1>
{{/if}}
{{#if FilterOnKeyUp}}
<div class="ui icon input search" style="width:500px;">
<input type="text" onkeyup="{{#if FilterOnKeyUp}}{{{FilterOnKeyUp}}}{{/if}}" placeholder="Search...">
<i class="inverted circular search link icon"></i>
</div>
<script class="openrpa-hidden-monitor-table-general" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table">
<thead>
<tr>
<th>Machine name</th>
<th>Machihe host</th>
<th>Status</th>
<th>Actions,length: {{childs.length}}</th>
</tr>
</thead>
<tbody>
{{#ListenURLList}}
<tr><td>{{Description}}</td><td>{{URL}}</td><td class="negative">None</td></tr>
{{/ListenURLList}}
</tbody>
</table>
</script>
<script class="openrpa-handlebar-template-table-filter" style="display:none" type="text/x-handlebars-template">
{{#if Title}}
<h1>{{{Title}}}</h1>
{{/if}}
{{#if FilterOnKeyUp}}
<div class="ui icon input search" style="width:500px;">
<input type="text" onkeyup="{{#if FilterOnKeyUp}}{{{FilterOnKeyUp}}}{{/if}}" placeholder="Search...">
<i class="inverted circular search link icon"></i>
</div>
{{/if}}
<table class="ui celled table selectable inverted">
<thead>
<tr>
{{#Columns}}
<th>{{{this}}}</th>
{{/Columns}}
</tr>
</thead>
<tbody>
{{#Rows}}
<tr>
{{#this}}
<td>
{{{this}}}
</td>
{{/this}}
</tr>
{{/Rows}}
</tbody>
</table>
</script>
<script class="openrpa-handlebar-template-list-filter" style="display:none" type="text/x-handlebars-template">
{{#if Title}}
<h1>{{{Title}}}</h1>
{{/if}}
{{#if FilterOnKeyUp}}
<div class="ui icon input search" style="width:500px;">
<input type="text" onkeyup="{{#if FilterOnKeyUp}}{{{FilterOnKeyUp}}}{{/if}}" placeholder="Search...">
<i class="inverted circular search link icon"></i>
</div>
{{/if}}
<div class="ui inverted segment">
<div class="ui inverted relaxed divided list">
{{#List}}
<div class="item">
<i class="map marker icon"></i>
<div class="content">
<a class="header">{{{Header}}}</a>
<div class="description">{{{Description}}}</div>
</div>
{{/if}}
<div class="ui inverted segment">
<div class="ui inverted relaxed divided list">
{{#List}}
<div class="item">
<i class="map marker icon"></i>
<div class="content">
<a class="header">{{{Header}}}</a>
<div class="description">{{{Description}}}</div>
</div>
{{/List}}
</div>
{{/List}}
</div>
</script>
</div>
<div class="two wide column">
</div>
<div class="nine wide column openrpa-robotrdpactive-control-panel-general" style="display:none;">
<h2 class="ui header openrpa-rdpactive-title" style="display:none;">
<i class="server icon"></i>
</div>
</script>
<div class="eight wide column openrpa-robotrdpactive-control-panel-general UACClient-pyOpenRPADict-RDPKeyDict" style="display:none;">
<h2 class="ui header openrpa-rdpactive-title">
<i class="desktop icon"></i>
<div class="content">
RDP active list
</div>
</h2>
<div class="openrpa-robotrdpactive-control-panel"></div>
<script class="openrpa-hidden-robotrdpactive-control-panel" style="display:none" type="text/x-handlebars-template">
<div class="ui inverted segment">
<div class="ui inverted segment" style="background: #368279">
<div class="ui inverted relaxed divided list">
{{#RenderRDPList}}
{{#HandlebarsList}}
<div class="item">
<div class="right floated content">
<div class="ui button" onclick="mGlobal.Processor.ServerValueAppend(['RobotRDPActive','ActivityList'],{'DefNameStr': 'RDPSessionReconnect', 'ArgList': [], 'ArgDict': {'inRDPSessionKeyStr': '{{{SessionKeyStr}}}'} })" >Reconnect</div>
@ -258,7 +226,38 @@
{{{SessionHexStr}}}
</div>
</div>
{{/RenderRDPList}}
{{/HandlebarsList}}
</div>
</div>
</script>
</div>
<div class="eight wide column UACClient-pyOpenRPADict-AgentKeyDict" style="display:none">
<h2 class="ui header " style="">
<i class="bug icon"></i>
<div class="content">
Agent active list
</div>
</h2>
<div class="pyOpenRPA-Agent-List"></div>
<script class="pyOpenRPA-Agent-ListTemplate" style="display:none" type="text/x-handlebars-template">
<div class="ui inverted segment" style="background: #368279">
<div class="ui inverted relaxed divided list">
{{#HandlebarsList}}
<div class="item">
<div class="right floated content">
{{#if IsListenBool}}
<i class="circle icon green"></i>
Online
{{else}}
<i class="circle icon red"></i>
Offline
{{/if}}
</div>
<div class="content">
<div class="header">Hostname: {{{HostnameUpperStr}}}, User: {{{UserUpperStr}}}</div>
</div>
</div>
{{/HandlebarsList}}
</div>
</div>
</script>
@ -269,6 +268,68 @@
<div class="row openrpa-monitor">
</div>
<div class="row">
<div class="sixteen wide column" style="">
<h2 class="ui header">
<i class="settings icon"></i>
<div class="content">
Administration
</div>
</h2>
</div>
</div>
<div class="row">
<div class="sixteen wide column" style="">
<h4 class="ui horizontal divider header" >
<i class="clipboard list icon"></i>
Logs
</h4>
<textarea class="mGlobal-pyOpenRPA-ServerLogList UACClient-pyOpenRPADict-AdminDict-LogViewerBool" readonly="readonly" style="width:100%; display:none; resize: none; font-family:monospace; font-weight: bold;" id="textarea_id" rows="20">
</textarea>
<a class="mGlobal-pyOpenRPA-ServerLogListDoRender" onclick="" style="cursor: pointer;">Freeze textarea</a>
<div class="ui fluid action input UACClient-pyOpenRPADict-AdminDict-CMDInputBool" style="display:none;">
<input class="openrpa-controller-cmd-run-input" type="text" placeholder="CMD Code...">
<div class="ui button" onclick="mGlobal.Controller.CMDRun();">Run!</div>
<div class="ui button" onclick="mGlobal.Controller.CMDRunGUILogout();">GUI Logout</div>
</div>
</div>
</div>
<h4 class="ui horizontal divider header">
<i class="clipboard list icon"></i>
Controls
</h4>
<div class="four ui buttons">
<div class="ui animated button openrpa-control-lookmachinescreenshot green UACClient-pyOpenRPADict-AdminDict-ScreenshotViewerBool" onclick="mGlobal.Monitor.ScreenshotModal.Show();" style="display: none; margin-top: 5px;">
<div class="visible content">Show live screenshots</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-restartorchestrator orange UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorBool" onclick="mGlobal.Controller.OrchestratorRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Restart orchestrator</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-gitrestartorchestrator teal UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorGITPullBool" onclick="mGlobal.Controller.OrchestratorGITPullRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Git pull, restart orchestrator</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
<div class="ui animated button openrpa-control-restartpc red UACClient-pyOpenRPADict-AdminDict-RestartPCBool" onclick="mGlobal.Controller.PCRestart();" style="display: none; margin-top: 5px;">
<div class="visible content">Restart PC</div>
<div class="hidden content">
<i class="right arrow icon"></i>
</div>
</div>
</div>
<div class="row black">
@ -341,11 +402,6 @@
</div>
<div class="content">
<img src="GetScreenshot" class="ui fluid image">
<div class="ui fluid action input">
<input class="openrpa-controller-cmd-run-input" type="text" placeholder="CMD Code...">
<div class="ui button" onclick="mGlobal.Controller.CMDRun();">Run!</div>
<div class="ui button" onclick="mGlobal.Controller.CMDRunGUILogout();">GUI Logout</div>
</div>
</div>
<div class="actions">
<div class="ui green ok inverted button" onclick="mGlobal.Monitor.ScreenshotModal.Close()">

@ -1,7 +1,9 @@
r"""
The OpenRPA package (from UnicodeLabs)
The pyOpenRPA package (from UnicodeLabs)
"""
from .Web import Basic
from .__Orchestrator__ import *
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'

@ -1,4 +1,5 @@
import sys
lFolderPath = "\\".join(__file__.split("\\")[:-3])
sys.path.insert(0, lFolderPath)
from pyOpenRPA.Orchestrator import Orchestrator
from pyOpenRPA.Orchestrator import __Orchestrator__
__Orchestrator__.__deprecated_orchestrator_start__() # Backward compatibility below the v1.2.0. Will be deprecated in 1.3.0

@ -103,6 +103,14 @@ mDefaultPywinautoBackend="win32"
#inFlagRaiseException - Флаг True - выкинуть ошибку в случае обнаружении пустого списка
#old name - PywinautoExtElementsGet
def UIOSelector_Get_UIOList (inSpecificationList,inElement=None,inFlagRaiseException=True):
'''
Get the UIO list by the selector
:param inSpecificationList: UIO Selector
:param inElement: Входной элемент - показатель, что не требуется выполнять коннект к процессу
:param inFlagRaiseException: Флаг True - выкинуть ошибку в случае обнаружении пустого списка
:return:
'''
#Создать копию входного листа, чтобы не менять массив в других верхнеуровневых функциях
inSpecificationList=copy.deepcopy(inSpecificationList)
lResultList=[]
@ -232,6 +240,14 @@ def UIOSelector_Get_UIOList (inSpecificationList,inElement=None,inFlagRaiseExcep
#inFlagRaiseException - Флаг True - выкинуть ошибку в случае обнаружении пустого списка
#old name - PywinautoExtElementGet
def UIOSelector_Get_UIO (inSpecificationList,inElement=None,inFlagRaiseException=True):
'''
Get the pywinauto object by the UIO selector.
:param inSpecificationList:
:param inElement:
:param inFlagRaiseException:
:return:
'''
lResult=None
#Получить родительский объект если на вход ничего не поступило
lResultList=UIOSelector_Get_UIOList(inSpecificationList,inElement,False)
@ -247,6 +263,12 @@ def UIOSelector_Get_UIO (inSpecificationList,inElement=None,inFlagRaiseException
#UIOSelector
#old name - -
def UIOSelector_Exist_Bool (inUIOSelector):
'''
Check if object is exist by the UIO selector.
:param inUIOSelector:
:return: True - Object is exist. False - else case
'''
lResult=False
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
@ -280,6 +302,18 @@ def UIOSelector_Exist_Bool (inUIOSelector):
#####Внимание#####
##Функция ожидания появления элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться)
def UIOSelectorsSecs_WaitAppear_List (inSpecificationListList,inWaitSecs,inFlagWaitAllInMoment=False):
'''
Wait for many UI object will appear in GUI for inWaitSecs seconds.
:param inSpecificationListList: UIOSelector list.
Example: [
[{"title":"notepad"},{"title":"OK"}],
[{"title":"notepad"},{"title":"Cancel"}]
]
:param inWaitSecs: Float value (seconds) for wait UI element appear in GUI
:param inFlagWaitAllInMoment: True - Wait all UI objects from the UIOSelector list to be appeared
:return: List of index, which UI object UIO will be appeared. Example: [1] # Appear only UI object with UIO selector: [{"title":"notepad"},{"title":"Cancel"}]
'''
lResultFlag=False
lSecsSleep = 1 #Настроечный параметр
lSecsDone = 0
@ -319,6 +353,19 @@ def UIOSelectorsSecs_WaitAppear_List (inSpecificationListList,inWaitSecs,inFlagW
#####Внимание#####
##Функция ожидания пропажи элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться)
def UIOSelectorsSecs_WaitDisappear_List (inSpecificationListList,inWaitSecs,inFlagWaitAllInMoment=False):
'''
Wait for many UI object will disappear in GUI for inWaitSecs seconds.
:param inSpecificationListList: UIOSelector list.
Example: [
[{"title":"notepad"},{"title":"OK"}],
[{"title":"notepad"},{"title":"Cancel"}]
]
:param inWaitSecs: Float value (seconds) for wait UI element disappear in GUI
:param inFlagWaitAllInMoment: True - Wait all UI objects from the UIOSelector list to be disappeared.
:return: List of index, which UI object UIO will be disappeared. Example: [1] # Disappear only UI object with UIO selector: [{"title":"notepad"},{"title":"Cancel"}]
:return:
'''
lResultFlag=False
lSecsSleep = 1 #Настроечный параметр
lSecsDone = 0
@ -355,6 +402,13 @@ def UIOSelectorsSecs_WaitDisappear_List (inSpecificationListList,inWaitSecs,inFl
#return: Bool - True - UIO is appear
#old name - -
def UIOSelectorSecs_WaitAppear_Bool (inSpecificationList,inWaitSecs):
'''
Wait for UI object will appear in GUI for inWaitSecs seconds.
:param inSpecificationList: UIOSelector. Example: [{"title":"notepad"},{"title":"OK"}]
:param inWaitSecs: Float value (seconds) for wait UI element appear in GUI
:return: True - UI object will appear. False - else case
'''
lWaitAppearList=UIOSelectorsSecs_WaitAppear_List([inSpecificationList],inWaitSecs)
lResult=False
if len(lWaitAppearList)>0:
@ -367,6 +421,14 @@ def UIOSelectorSecs_WaitAppear_Bool (inSpecificationList,inWaitSecs):
#return: Bool - True - UIO is Disappear
#old name - -
def UIOSelectorSecs_WaitDisappear_Bool (inSpecificationList,inWaitSecs):
'''
Wait for UI object will disappear in GUI for inWaitSecs seconds.
:param inSpecificationList: UIOSelector.
Example: [{"title":"notepad"},{"title":"OK"}]
:param inWaitSecs: Float value (seconds) for wait UI element disappear in GUI
:return: True - UI object will disappear. False - else case
'''
lWaitDisappearList=UIOSelectorsSecs_WaitDisappear_List([inSpecificationList],inWaitSecs)
lResult=False
if len(lWaitDisappearList)>0:
@ -378,6 +440,12 @@ def UIOSelectorSecs_WaitDisappear_Bool (inSpecificationList,inWaitSecs):
#old name - None
#return None (if Process not found), int 32, or int 64
def UIOSelector_Get_BitnessInt (inSpecificationList):
'''
Detect process bitness by the UI Object UIO Selector.
:param inSpecificationList: UIOSelector. Example: [{"title":"notepad"},{"title":"OK"}]
:return: int 32 or int 64
'''
lResult=None
#Получить объект Application (Для проверки разрядности)
lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList)
@ -393,6 +461,12 @@ def UIOSelector_Get_BitnessInt (inSpecificationList):
#old name - None
#return None (if Process not found), int 32, or int 64
def UIOSelector_Get_BitnessStr (inSpecificationList):
'''
Detect process bitness by the UI Object UIO Selector.
:param inSpecificationList: UIOSelector. Example: [{"title":"notepad"},{"title":"OK"}]
:return: str "32" or str "64"
'''
lResult=None
#Получить объект Application (Для проверки разрядности)
lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList)
@ -407,15 +481,23 @@ def UIOSelector_Get_BitnessStr (inSpecificationList):
#old name - None
#return int 32, or int 64
def Get_OSBitnessInt ():
lResult=32;
'''
Detect OS bitness.
:return: int 32 or int 64
'''
lResult=32
if pywinauto.sysinfo.is_x64_OS():
lResult=64;
return lResult;
lResult=64
return lResult
#################################################################################################
#Safe get other process or None if destination app is the other/same bitness
#inUIOSelector - selector of the destination
#return None or process (of the other bitness)
def UIOSelector_SafeOtherGet_Process(inUIOSelector):
'''
Safe get other process or None if destination app is the other/same bitness
:param inUIOSelector: UIO Selector of the UI object
:return: None or process (of the other bitness)
'''
#Default value
lResult = None
#Go check bitness if selector exists
@ -426,11 +508,14 @@ def UIOSelector_SafeOtherGet_Process(inUIOSelector):
lResult = Utils.ProcessBitness.OtherProcessGet()
return lResult
##################################################################################################
#inControlSpecificationArray - List of dict, dict in pywinauto.find_windows notation
#Backend selection - attribute "backend" ("win32" || "uia") in 1-st list element
#return list of UIO object
#old name - GetControl
def PWASpecification_Get_UIO(inControlSpecificationArray):
'''
#Backend def selection - attribute "backend" ("win32" || "uia") in 1-st list element
#old name - GetControl
:param inControlSpecificationArray: List of dict, dict in pywinauto.find_windows notation
:return: list of UIO object
'''
#Определение backend
lBackend=mDefaultPywinautoBackend
if "backend" in inControlSpecificationArray[0]:
@ -440,7 +525,7 @@ def PWASpecification_Get_UIO(inControlSpecificationArray):
inControlSpecificationOriginArray=copy.deepcopy(inControlSpecificationArray)
inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
lResultList=[]
lTempObject=None
if len(inControlSpecificationArray) > 0:
#Сформировать выборку элементов, которые подходят под первый уровень спецификации
@ -477,11 +562,13 @@ def PWASpecification_Get_UIO(inControlSpecificationArray):
lResultList.append(lTempObject)
return lResultList
##################################################################################################
#inControlSpecificationArray - List of dict, dict in pywinauto.find_windows notation
#Backend selection - attribute "backend" ("win32" || "uia") in 1-st list element
#return process application object
#old name - None
def PWASpecification_Get_PWAApplication(inControlSpecificationArray):
'''
#Backend selection - attribute "backend" ("win32" || "uia") in 1-st list element
:param inControlSpecificationArray: List of dict, dict in pywinauto.find_windows notation
:return: process application object
'''
inControlSpecificationArray=copy.deepcopy(inControlSpecificationArray)
#Определение backend
lBackend=mDefaultPywinautoBackend
@ -492,7 +579,7 @@ def PWASpecification_Get_PWAApplication(inControlSpecificationArray):
inControlSpecificationOriginArray=inControlSpecificationArray
inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
lResultList=[]
lTempObject=None
if len(inControlSpecificationArray) > 0:
#Выполнить подключение к объекту
@ -513,10 +600,14 @@ def PWASpecification_Get_PWAApplication(inControlSpecificationArray):
return lTempObject
###########################################################################################################
#inElementSpecificationList = UIOSelector (see description on the top of the document)
#result = pywinauto element wrapper instance or None
#old name - AutomationSearchMouseElement
def UIOSelector_SearchChildByMouse_UIO(inElementSpecification):
'''
UIOSelector (see description on the top of the document)
#old name - AutomationSearchMouseElement
:param inElementSpecification: UIOSelector of the UI Object
:return: pywinauto element wrapper instance or None
'''
lGUISearchElementSelected=None
#Настройка - частота обновления подсвечивания
lTimeSleepSeconds=0.4
@ -548,17 +639,21 @@ def UIOSelector_SearchChildByMouse_UIO(inElementSpecification):
UIO_Highlight(lElementFounded)
else:
#Была нажата клавиша Ctrl - выйти из цикла
lFlagLoop=False;
lFlagLoop=False
#Заснуть до следующего цикла
time.sleep(lTimeSleepSeconds)
#Вернуть результат поиска
return lElementFoundedList
####################################################################################################
#inElementSpecification - UIOSelector
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - AutomationSearchMouseElementHierarchy
def UIOSelector_SearchChildByMouse_UIOTree(inUIOSelector):
'''
!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
:param inUIOSelector: UIOSelector of the UI Object
:return: ?
'''
lItemInfo = []
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
@ -687,6 +782,12 @@ def UIOSelector_Get_UIOInfoList (inUIOSelector, inElement=None):
#inSpecificationList - UIOSelector
#old name - PywinautoExtTryToRestore
def UIOSelector_TryRestore_Dict(inSpecificationList):
"""
Try to restore (maximize) window, if it's minimized. (!IMPORTANT! When use UIA framework minimized windows doesn't appear by the UIOSelector. You need to try restore windows and after that try to get UIO)
:param inSpecificationList: UIOSelector - List of items, which contains condition attributes
:return:
"""
lResult={}
try:
#Подготовка взодного массива
@ -705,6 +806,12 @@ def UIOSelector_TryRestore_Dict(inSpecificationList):
#inControlSpecificationArray - UIOSelector
#old name - ElementActionGetList
def UIOSelector_Get_UIOActivityList (inUIOSelector):
"""
Get the list of the UI object activities
:param inUIOSelector: UIOSelector - List of items, which contains condition attributes
:return:
"""
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
@ -742,7 +849,18 @@ def UIOSelector_Get_UIOActivityList (inUIOSelector):
#inUIOSelector
#inActionName - UIOActivity (name) from Pywinauto
#old name - ElementRunAction
def UIOSelectorUIOActivity_Run_Dict(inUIOSelector, inActionName, inArgumentList=[], inkwArgumentObject={}):
def UIOSelectorUIOActivity_Run_Dict(inUIOSelector, inActionName, inArgumentList=None, inkwArgumentObject=None):
"""
Run the activity in UIO (UI Object)
:param inUIOSelector: UIOSelector - List of items, which contains condition attributes
:param inActionName: UIOActivity (name) activity name string from Pywinauto
:param inArgumentList:
:param inkwArgumentObject:
:return:
"""
if inArgumentList is None: inArgumentList=[] # 2021 02 22 Minor fix by Ivan Maslov
if inkwArgumentObject is None: inkwArgumentObject={} # 2021 02 22 Minor fix by Ivan Maslov
lResult={}
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
@ -790,13 +908,19 @@ def UIOSelectorUIOActivity_Run_Dict(inUIOSelector, inActionName, inArgumentList=
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementGetInfo
def UIOSelector_Get_UIOInfo(inUIOSelector):
"""
Get the UIO dict of the attributes
:param inUIOSelector: UIOSelector - List of items, which contains condition attributes
:return:
"""
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
#Подготовка входного массива
inUIOSelector=UIOSelector_SearchUIONormalize_UIOSelector(inUIOSelector)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
lResultList=[]
if len(inUIOSelector) > 0:
#Получить объект
lTempObject=UIOSelector_Get_UIO(inUIOSelector)
@ -824,7 +948,8 @@ def UIOSelector_Get_UIOInfo(inUIOSelector):
#inHierarchyList: [{"index":<>,"element":<>}] - technical argument for internal purpose
#result -List of dict [{"index":<>,"element":<>}] -- list of element hierarchy specifications
#old name - GUISearchElementByRootXY
def UIOXY_SearchChild_ListDict(inRootElement,inX,inY,inHierarchyList=[]):
def UIOXY_SearchChild_ListDict(inRootElement,inX,inY,inHierarchyList=None):
if inHierarchyList is None: inHierarchyList = []
#Инициализация результирующего значения
lResultElement = None
lResultElementX1 = None
@ -913,7 +1038,17 @@ def UIOXY_SearchChild_ListDict(inRootElement,inX,inY,inHierarchyList=[]):
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#inControlSpecificationArray- UIOSelector
#old name - ElementGetChildElementList
def UIOSelector_GetChildList_UIOList(inUIOSelector=[], inBackend=mDefaultPywinautoBackend):
def UIOSelector_GetChildList_UIOList(inUIOSelector=None, inBackend=mDefaultPywinautoBackend):
"""
Get list of child UIO's by the parent UIOSelector
:param inUIOSelector: UIOSelector - List of items, which contains condition attributes
:param inBackend: "win32" or "uia"
:return:
"""
if inUIOSelector is None: inUIOSelector = []
#mRobotLogger.info(f"File!!!!")
#mRobotLogger.info(f"inSelector:{str(inUIOSelector)}, inBackend:{str(inBackend)}")
#pdb.set_trace()
@ -1194,7 +1329,7 @@ def BackendStr_GetTopLevelList_UIOInfo(inBackend=mDefaultPywinautoBackend):
lResultList2=[]
for lI in lResultList:
lTempObjectInfo=lI
lResultList2.append(UIOEI_Convert_UIOInfo(lI));
lResultList2.append(UIOEI_Convert_UIOInfo(lI))
return lResultList2
###################################################################################################
@ -1202,6 +1337,12 @@ def BackendStr_GetTopLevelList_UIOInfo(inBackend=mDefaultPywinautoBackend):
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementDrawOutlineNew
def UIOSelector_Highlight(inUIOSelector):
"""
Highlight (draw outline) the element (in app) by the UIO selector.
:param inUIOSelector: UIOSelector - List of items, which contains condition attributes
:return:
"""
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
@ -1227,6 +1368,13 @@ def UIOSelector_Highlight(inUIOSelector):
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementDrawOutlineNewFocus
def UIOSelector_FocusHighlight(inUIOSelector):
"""
Set focus and highlight (draw outline) the element (in app) by the UIO selector.
:param inUIOSelector: UIOSelector - List of items, which contains condition attributes
:return:
"""
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:

@ -3,7 +3,7 @@ r"""
The OpenRPA package (from UnicodeLabs)
"""
__version__ = 'v1.1.20'
__version__ = 'v1.2.0'
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'
#from .Core import Robot

@ -3,11 +3,20 @@
####################################
- Guide
- - ENG - in progress (see content below), plan date 31.08.2020 (failed), new plan date march 2021
- - RUS - queue
- ENG - done 2021.03.11
- HTML `|OPEN GITLAB| <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html>`_
- MarkDown `|OPEN GITLAB| <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md>`_
- PDF `|WAIT| <>`_
- RUS - queue
- Tutorial
- - ENG - queue
- - RUS - queue
- Dev actions
- ENG - queue
- RUS - in progress
- Article: Less cost - no paid RPA `|OPEN HABR| <https://habr.com/ru/post/506766/>`_
- Tutorial Desktop UI `|OPEN HABR| <https://habr.com/ru/post/509644/>`_; `|OPEN GITLAB| <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md>`_
- Tutorial Web UI `|OPEN HABR| <https://habr.com/ru/post/515310/>`_; `|OPEN GITLAB| <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md>`_
Refactoring the arguments in UIDesktop.py (only in new branch pyOpenRPA version. For backward compatibility purpose), plan date -
- Leaflet
- ENG queue
- RUS done 2021.02.23
- RUS Leaflet pyOpenRPA v4.pdf `|OPEN GITLAB| <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/pyOpenRPA/Wiki/RUS_Leaflet/RUS%20Leaflet%20pyOpenRPA%20v4.pdf>`_

@ -7,16 +7,13 @@
pyOpenRPA is created by Ivan Maslov (Russia).
Use it absolutely for free!
My purpose is to create #IT4Business models all over the world.
My purpose is to create #IT4Business models in the companies.
I can help you to create the new #IT4Business in your company.
#IT4Business homepage - https://www.facebook.com/RU.IT4Business
#IT4Busines is the methodology which is created for build compact fast and reliable IT function in company.
If you has many IT specialists, very long deadlines for the IT tasks, many bugs in IT software - #IT4Business is for you :)
If you need some IT help - feel free to contact me (prefer e-mail or skype).
If you will find some issue in pyOpenRPA - write about it to me via e-mail/skype/gitlab issue.
Thank you!

@ -2,10 +2,21 @@
1. Description
************************
pyOpenRPA Robot is the python package.
pyOpenRPA Robot is the python package which allow you to create best RPA program.
The description of the functions you can find page 'Defs' (see menu)
pyOpenRPA Robot
##################################
.. automodule:: pyOpenRPA.Robot.UIDesktop
:members:
Here is the example of the pyOpenRPA usage.
.. code-block:: python
# EXAMPLE 1
from pyOpenRPA.Robot import UIDesktop
lNotepadOKButton = UIDesktop.UIOSelector_Get_UIO(
inSpecificationList=[
{"title":"notepad.exe"},{"title":"OK"}],
inElement=None,
inFlagRaiseException=True)
lNotepadOKButton.click()

@ -2,82 +2,7 @@
2. Defs
####################################
****************************************************************************************************
Desktop app UI access (win32 and UI automation dlls)
****************************************************************************************************
Definitions
############################################
- **UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]
- **UIOSelector** - List of dict (key attributes)
- **PWA** - PyWinAuto
- **PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)
- **UIOTree** - Recursive Dict of Dict ... (UI Parent -> Child hierarchy)
- **UIOInfo** - Dict of UIO attributes
- **UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module
- **UIOEI** - UI Object info object
What is UIO?
############################################
UIO is a User Interface Object (pyOpenRPA terminology). For maximum compatibility, this instance is inherited from the object model developed in the [pywinauto library (click to get a list of available class functions)](https://pywinauto.readthedocs.io/en/latest/code/pywinauto.base_wrapper.html).
This approach allows us to implement useful functionality that has already been successfully developed in other libraries, and Supplement it with the missing functionality. In our case, the missing functionality is the ability to dynamically access UIO objects using UIO selectors.
UIOSelector structure & example
############################################
<a name="UIOSelector_Structure_Examples"></a>
UIOSelector is the list of condition items for the UIO in GUI. Each item has condition attributes for detect applicable UIO. Here is the description of the available condition attributes in item.
**Desciption**<br>
```
[
{
"depth_start" :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
"depth_end" :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
"ctrl_index" || "index" :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
"title" :: [str] :: the condition for the UIO attribute *title*,
"title_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *title*,
"rich_text" :: [str] :: the condition for the UIO attribute *rich_text*,
"rich_text_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *rich_text*,
"class_name" :: [str] :: the condition for the UIO attribute *class_name*,
"class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *class_name*,
"friendly_class_name" :: [str] :: the condition for the UIO attribute *friendly_class_name*,
"friendly_class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *friendly_class_name*,
"control_type" :: [str] :: the condition for the UIO attribute *control_type*,
"control_type_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *control_type*,
"is_enabled" :: [bool] :: the condition for the UIO attribute *is_enabled*. If UI object is enabled on GUI,
"is_visible" :: [bool] :: the condition for the UIO attribute *is_visible*. If UI object is visible on GUI,
"backend" :: [str, "win32" || "uia"] :: the method of UIO extraction (default "win32"). ATTENTION! Current option can be only for the first item of the UIO selector. For the next items this option will be implemented from the first item.
},
{ ... specification next level UIO }
]
```
**The UIO selector example**
```
[
{"class_name":"CalcFrame", "backend":"win32"}, # 1-st level UIO specification
{"title":"Hex", "depth_start":3, "depth_end": 3} # 3-rd level specification (because of attribute depth_start|depth_stop)
]
```
The UIDesktop module (OpenRPA/Robot/UIDesktop.py)
########################################################################################
The UIDesktop is extension of the pywinauto module which provide access to the desktop apps by the **win32** and **ui automation** dll frameworks (big thx to the Microsoft :) ).
.. code-block:: python
# EXAMPLE 1
from pyOpenRPA.Robot import UIDesktop
UIDesktop.UIOSelector_Get_UIO(
inSpecificationList=[
{"title":"notepad.exe"},{"title":"OK"}],
inElement=None,
inFlagRaiseException=True)
Here you can find the functions description for interaction with desktop GUI applications
.. automodule:: pyOpenRPA.Robot.UIDesktop
:members:

@ -95,20 +95,20 @@ Use in studio script (n/a)
Here you can find the docs and examples of the OpenRPA desktop (GUI) app access.
****************************************************************************************************
Theory & practice. Desktop app UI access (win32 and UI automation dlls)
Desktop app UI access (win32 and UI automation dlls)
****************************************************************************************************
Definitions
############################################
**UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]<br>
**UIOSelector** - List of dict (key attributes)<br>
**PWA** - PyWinAuto<br>
**PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)<br>
**UIOTree** - Recursive Dict of Dict ... (UI Parent -> Child hierarchy)<br>
**UIOInfo** - Dict of UIO attributes<br>
**UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module<br>
**UIOEI** - UI Object info object
- **UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]
- **UIOSelector** - List of dict (key attributes)
- **PWA** - PyWinAuto
- **PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)
- **UIOTree** - Recursive Dict of Dict ... (UI Parent -> Child hierarchy)
- **UIOInfo** - Dict of UIO attributes
- **UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module
- **UIOEI** - UI Object info object
What is UIO?
@ -120,40 +120,58 @@ This approach allows us to implement useful functionality that has already been
UIOSelector structure & example
############################################
<a name="UIOSelector_Structure_Examples"></a>
UIOSelector is the list of condition items for the UIO in GUI. Each item has condition attributes for detect applicable UIO. Here is the description of the available condition attributes in item.
**Desciption**
```
[
{
"depth_start" :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
"depth_end" :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
"ctrl_index" || "index" :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
"title" :: [str] :: the condition for the UIO attribute *title*,
"title_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *title*,
"rich_text" :: [str] :: the condition for the UIO attribute *rich_text*,
"rich_text_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *rich_text*,
"class_name" :: [str] :: the condition for the UIO attribute *class_name*,
"class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *class_name*,
"friendly_class_name" :: [str] :: the condition for the UIO attribute *friendly_class_name*,
"friendly_class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *friendly_class_name*,
"control_type" :: [str] :: the condition for the UIO attribute *control_type*,
"control_type_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *control_type*,
"is_enabled" :: [bool] :: the condition for the UIO attribute *is_enabled*. If UI object is enabled on GUI,
"is_visible" :: [bool] :: the condition for the UIO attribute *is_visible*. If UI object is visible on GUI,
"backend" :: [str, "win32" || "uia"] :: the method of UIO extraction (default "win32"). ATTENTION! Current option can be only for the first item of the UIO selector. For the next items this option will be implemented from the first item.
},
{ ... specification next level UIO }
]
```
.. code-block:: python
[
{
"depth_start" :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
"depth_end" :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
"ctrl_index" || "index" :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
"title" :: [str] :: the condition for the UIO attribute *title*,
"title_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *title*,
"rich_text" :: [str] :: the condition for the UIO attribute *rich_text*,
"rich_text_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *rich_text*,
"class_name" :: [str] :: the condition for the UIO attribute *class_name*,
"class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *class_name*,
"friendly_class_name" :: [str] :: the condition for the UIO attribute *friendly_class_name*,
"friendly_class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *friendly_class_name*,
"control_type" :: [str] :: the condition for the UIO attribute *control_type*,
"control_type_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *control_type*,
"is_enabled" :: [bool] :: the condition for the UIO attribute *is_enabled*. If UI object is enabled on GUI,
"is_visible" :: [bool] :: the condition for the UIO attribute *is_visible*. If UI object is visible on GUI,
"backend" :: [str, "win32" || "uia"] :: the method of UIO extraction (default "win32"). ATTENTION! Current option can be only for the first item of the UIO selector. For the next items this option will be implemented from the first item.
},
{ ... specification next level UIO }
]
**The UIO selector example**
```
[
{"class_name":"CalcFrame", "backend":"win32"}, # 1-st level UIO specification
{"title":"Hex", "depth_start":3, "depth_end": 3} # 3-rd level specification (because of attribute depth_start|depth_stop)
]
```
.. code-block:: python
[
{"class_name":"CalcFrame", "backend":"win32"}, # 1-st level UIO specification
{"title":"Hex", "depth_start":3, "depth_end": 3} # 3-rd level specification (because of attribute depth_start|depth_stop)
]
The UIDesktop module (OpenRPA/Robot/UIDesktop.py)
########################################################################################
The UIDesktop is extension of the pywinauto module which provide access to the desktop apps by the **win32** and **ui automation** dll frameworks (big thx to the Microsoft :) ).
.. code-block:: python
# EXAMPLE 1
from pyOpenRPA.Robot import UIDesktop
UIDesktop.UIOSelector_Get_UIO(
inSpecificationList=[
{"title":"notepad.exe"},{"title":"OK"}],
inElement=None,
inFlagRaiseException=True)
The UIDesktop module (OpenRPA/Robot/UIDesktop.py)
########################################################################################
The UIDesktop is extension of the pywinauto module which provide access to the desktop apps by the **win32** and **ui automation** dll frameworks (big thx to the Microsoft :) ).

@ -2,15 +2,6 @@
2. How to use
####################################
.. only:: html
HTML CODE
.. only:: markdown
MARKDOWN CODE
Content
=======

@ -115,13 +115,14 @@ Wiki structure
**************************************************
In wiki you can use the following docs:
- ENG Guide HTML [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html)
- ENG Guide MarkDown [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md)
- ENG Guide PDF [|WAIT|]()
- RUS Article: Less cost - no paid RPA [|OPEN HABR|](https://habr.com/ru/post/509644/)
- RUS Tutorial Desktop UI [|OPEN HABR|](https://habr.com/ru/post/509644/); [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md)
- RUS Tutorial Web UI [|OPEN HABR|](https://habr.com/ru/post/515310/); [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md)
- ENG Guide HTML `[|OPEN GITLAB|] <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html>`_
- ENG Guide MarkDown `[|OPEN GITLAB|] <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md>`_
- ENG Guide PDF `[|WAIT|] <>`_
- RUS Article: Less cost - no paid RPA `[|OPEN HABR|] <https://habr.com/ru/post/506766/>`_
- RUS Tutorial Desktop UI `[|OPEN HABR|] <https://habr.com/ru/post/509644/>`_; `[|OPEN GITLAB|] <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md>`_
- RUS Tutorial Web UI `[|OPEN HABR|] <https://habr.com/ru/post/515310/>`_; `[|OPEN GITLAB|] <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md>`_
- RUS Leaflet pyOpenRPA v4.pdf `[|OPEN GITLAB|] <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/pyOpenRPA/Wiki/RUS_Leaflet/RUS Leaflet pyOpenRPA v4.pdf>`_
**************************************************
Guide content

@ -3,7 +3,7 @@ r"""
The OpenRPA package (from UnicodeLabs)
"""
__version__ = 'v1.1.20'
__version__ = 'v1.2.0'
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'
#from .Core import Robot

@ -181,27 +181,53 @@
<div class="section" id="roadmap">
<h1>2. Roadmap<a class="headerlink" href="#roadmap" title="Permalink to this headline"></a></h1>
<ul class="simple">
<li><p>Guide</p></li>
<li><ul>
<li><p>ENG - in progress (see content below), plan date 31.08.2020 (failed), new plan date march 2021</p></li>
<li><dl class="simple">
<dt>Guide</dt><dd><ul>
<li><dl class="simple">
<dt>ENG - done 2021.03.11</dt><dd><ul>
<li><p>HTML <a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html">|OPEN GITLAB|</a></p></li>
<li><p>MarkDown <a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md">|OPEN GITLAB|</a></p></li>
<li><p>PDF <a href="#id7"><span class="problematic" id="id8">`|WAIT| &lt;&gt;`_</span></a></p></li>
</ul>
</dd>
</dl>
</li>
<li><ul>
<li><p>RUS - queue</p></li>
</ul>
</dd>
</dl>
</li>
<li><p>Tutorial</p></li>
<li><ul>
<li><dl class="simple">
<dt>Tutorial</dt><dd><ul>
<li><p>ENG - queue</p></li>
<li><dl class="simple">
<dt>RUS - in progress</dt><dd><ul>
<li><p>Article: Less cost - no paid RPA <a class="reference external" href="https://habr.com/ru/post/506766/">|OPEN HABR|</a></p></li>
<li><p>Tutorial Desktop UI <a class="reference external" href="https://habr.com/ru/post/509644/">|OPEN HABR|</a>; <a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md">|OPEN GITLAB|</a></p></li>
<li><p>Tutorial Web UI <a class="reference external" href="https://habr.com/ru/post/515310/">|OPEN HABR|</a>; <a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md">|OPEN GITLAB|</a></p></li>
</ul>
</dd>
</dl>
</li>
</ul>
</dd>
</dl>
</li>
<li><dl class="simple">
<dt>Leaflet</dt><dd><ul>
<li><p>ENG queue</p></li>
<li><dl class="simple">
<dt>RUS done 2021.02.23</dt><dd><ul>
<li><p>RUS Leaflet pyOpenRPA v4.pdf <a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/pyOpenRPA/Wiki/RUS_Leaflet/RUS%20Leaflet%20pyOpenRPA%20v4.pdf">|OPEN GITLAB|</a></p></li>
</ul>
</dd>
</dl>
</li>
<li><ul>
<li><p>RUS - queue</p></li>
</ul>
</dd>
</dl>
</li>
<li><p>Dev actions</p></li>
</ul>
<p>Refactoring the arguments in UIDesktop.py (only in new branch pyOpenRPA version. For backward compatibility purpose), plan date -</p>
</div>

@ -186,12 +186,13 @@
<span id="id1"></span><h1>3. Copyrights &amp; Contacts<a class="headerlink" href="#copyrights-contacts" title="Permalink to this headline"></a></h1>
<p>pyOpenRPA is created by Ivan Maslov (Russia).
Use it absolutely for free!</p>
<p>My purpose is to create #IT4Business models all over the world.</p>
<p>#IT4Business homepage - <a class="reference external" href="https://www.facebook.com/RU.IT4Business">https://www.facebook.com/RU.IT4Business</a></p>
<p>#IT4Busines is the methodology which is created for build compact fast and reliable IT function in company.</p>
<p>If you has many IT specialists, very long deadlines for the IT tasks, many bugs in IT software - #IT4Business is for you :)</p>
<p>If you need some IT help - feel free to contact me (prefer e-mail or skype).</p>
<p>If you will find some issue in pyOpenRPA - write about it to me via e-mail/skype/gitlab issue.</p>
<p>My purpose is to create #IT4Business models in the companies.
I can help you to create the new #IT4Business in your company.
#IT4Business homepage - <a class="reference external" href="https://www.facebook.com/RU.IT4Business">https://www.facebook.com/RU.IT4Business</a>
#IT4Busines is the methodology which is created for build compact fast and reliable IT function in company.
If you has many IT specialists, very long deadlines for the IT tasks, many bugs in IT software - #IT4Business is for you :)</p>
<p>If you need some IT help - feel free to contact me (prefer e-mail or skype).
If you will find some issue in pyOpenRPA - write about it to me via e-mail/skype/gitlab issue.</p>
<p>Thank you!</p>
<div class="section" id="ivan-maslov-founder">
<h2>Ivan Maslov (founder)<a class="headerlink" href="#ivan-maslov-founder" title="Permalink to this headline"></a></h2>

@ -94,10 +94,7 @@
</ul>
<p class="caption"><span class="caption-text">ROBOT</span></p>
<ul class="current">
<li class="toctree-l1 current"><a class="current reference internal" href="#">1. Description</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#module-pyOpenRPA.Robot.UIDesktop">pyOpenRPA Robot</a></li>
</ul>
</li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">1. Description</a></li>
<li class="toctree-l1"><a class="reference internal" href="02_Defs.html">2. Defs</a></li>
<li class="toctree-l1"><a class="reference internal" href="03_HowToUse.html">3. How to use</a></li>
<li class="toctree-l1"><a class="reference internal" href="04_Dependencies.html">4. Dependencies</a></li>
@ -183,365 +180,20 @@
<div class="section" id="description">
<h1>1. Description<a class="headerlink" href="#description" title="Permalink to this headline"></a></h1>
<p>pyOpenRPA Robot is the python package.</p>
<div class="section" id="module-pyOpenRPA.Robot.UIDesktop">
<span id="pyopenrpa-robot"></span><h2>pyOpenRPA Robot<a class="headerlink" href="#module-pyOpenRPA.Robot.UIDesktop" title="Permalink to this headline"></a></h2>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.Get_OSBitnessInt">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">Get_OSBitnessInt</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#Get_OSBitnessInt"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.Get_OSBitnessInt" title="Permalink to this definition"></a></dt>
<dd><p>Detect OS bitness.</p>
<dl class="field-list simple">
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p>int 32 or int 64</p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.PWASpecification_Get_PWAApplication">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">PWASpecification_Get_PWAApplication</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inControlSpecificationArray</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#PWASpecification_Get_PWAApplication"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.PWASpecification_Get_PWAApplication" title="Permalink to this definition"></a></dt>
<dd><p>#Backend selection - attribute “backend” (“win32” || “uia”) in 1-st list element</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inControlSpecificationArray</strong> List of dict, dict in pywinauto.find_windows notation</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>process application object</p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.PWASpecification_Get_UIO">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">PWASpecification_Get_UIO</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inControlSpecificationArray</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#PWASpecification_Get_UIO"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.PWASpecification_Get_UIO" title="Permalink to this definition"></a></dt>
<dd><p>#Backend def selection - attribute “backend” (“win32” || “uia”) in 1-st list element
#old name - GetControl</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inControlSpecificationArray</strong> List of dict, dict in pywinauto.find_windows notation</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>list of UIO object</p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelectorSecs_WaitAppear_Bool">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelectorSecs_WaitAppear_Bool</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inSpecificationList</span></em>, <em class="sig-param"><span class="n">inWaitSecs</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelectorSecs_WaitAppear_Bool"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelectorSecs_WaitAppear_Bool" title="Permalink to this definition"></a></dt>
<dd><p>Wait for UI object will appear in GUI for inWaitSecs seconds.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>inSpecificationList</strong> UIOSelector. Example: [{“title”:”notepad”},{“title”:”OK”}]</p></li>
<li><p><strong>inWaitSecs</strong> Float value (seconds) for wait UI element appear in GUI</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>True - UI object will appear. False - else case</p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelectorSecs_WaitDisappear_Bool">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelectorSecs_WaitDisappear_Bool</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inSpecificationList</span></em>, <em class="sig-param"><span class="n">inWaitSecs</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelectorSecs_WaitDisappear_Bool"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelectorSecs_WaitDisappear_Bool" title="Permalink to this definition"></a></dt>
<dd><p>Wait for UI object will disappear in GUI for inWaitSecs seconds.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>inSpecificationList</strong> UIOSelector.
Example: [{“title”:”notepad”},{“title”:”OK”}]</p></li>
<li><p><strong>inWaitSecs</strong> Float value (seconds) for wait UI element disappear in GUI</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>True - UI object will disappear. False - else case</p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelectorUIOActivity_Run_Dict">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelectorUIOActivity_Run_Dict</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inUIOSelector</span></em>, <em class="sig-param"><span class="n">inActionName</span></em>, <em class="sig-param"><span class="n">inArgumentList</span><span class="o">=</span><span class="default_value">None</span></em>, <em class="sig-param"><span class="n">inkwArgumentObject</span><span class="o">=</span><span class="default_value">None</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelectorUIOActivity_Run_Dict"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelectorUIOActivity_Run_Dict" title="Permalink to this definition"></a></dt>
<dd><p>Run the activity in UIO (UI Object)</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>inUIOSelector</strong> UIOSelector - List of items, which contains condition attributes</p></li>
<li><p><strong>inActionName</strong> UIOActivity (name) activity name string from Pywinauto</p></li>
<li><p><strong>inArgumentList</strong> </p></li>
<li><p><strong>inkwArgumentObject</strong> </p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p></p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_Exist_Bool">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_Exist_Bool</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inUIOSelector</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_Exist_Bool"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_Exist_Bool" title="Permalink to this definition"></a></dt>
<dd><p>Check if object is exist by the UIO selector.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inUIOSelector</strong> </p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>True - Object is exist. False - else case</p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_FocusHighlight">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_FocusHighlight</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inUIOSelector</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_FocusHighlight"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_FocusHighlight" title="Permalink to this definition"></a></dt>
<dd><p>Set focus and highlight (draw outline) the element (in app) by the UIO selector.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inUIOSelector</strong> UIOSelector - List of items, which contains condition attributes</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p></p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_GetChildList_UIOList">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_GetChildList_UIOList</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inUIOSelector</span><span class="o">=</span><span class="default_value">None</span></em>, <em class="sig-param"><span class="n">inBackend</span><span class="o">=</span><span class="default_value">'win32'</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_GetChildList_UIOList"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_GetChildList_UIOList" title="Permalink to this definition"></a></dt>
<dd><p>Get list of child UIOs by the parent UIOSelector</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>inUIOSelector</strong> UIOSelector - List of items, which contains condition attributes</p></li>
<li><p><strong>inBackend</strong> “win32” or “uia”</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p></p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_BitnessInt">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_Get_BitnessInt</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inSpecificationList</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_Get_BitnessInt"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_BitnessInt" title="Permalink to this definition"></a></dt>
<dd><p>Detect process bitness by the UI Object UIO Selector.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inSpecificationList</strong> UIOSelector. Example: [{“title”:”notepad”},{“title”:”OK”}]</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>int 32 or int 64</p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_BitnessStr">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_Get_BitnessStr</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inSpecificationList</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_Get_BitnessStr"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_BitnessStr" title="Permalink to this definition"></a></dt>
<dd><p>Detect process bitness by the UI Object UIO Selector.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inSpecificationList</strong> UIOSelector. Example: [{“title”:”notepad”},{“title”:”OK”}]</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>str “32” or str “64”</p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIO">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_Get_UIO</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inSpecificationList</span></em>, <em class="sig-param"><span class="n">inElement</span><span class="o">=</span><span class="default_value">None</span></em>, <em class="sig-param"><span class="n">inFlagRaiseException</span><span class="o">=</span><span class="default_value">True</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_Get_UIO"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIO" title="Permalink to this definition"></a></dt>
<dd><p>Get the pywinauto object by the UIO selector.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>inSpecificationList</strong> </p></li>
<li><p><strong>inElement</strong> </p></li>
<li><p><strong>inFlagRaiseException</strong> </p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p></p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOActivityList">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_Get_UIOActivityList</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inUIOSelector</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_Get_UIOActivityList"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOActivityList" title="Permalink to this definition"></a></dt>
<dd><p>Get the list of the UI object activities</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inUIOSelector</strong> UIOSelector - List of items, which contains condition attributes</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p></p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOInfo">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_Get_UIOInfo</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inUIOSelector</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_Get_UIOInfo"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOInfo" title="Permalink to this definition"></a></dt>
<dd><p>Get the UIO dict of the attributes</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inUIOSelector</strong> UIOSelector - List of items, which contains condition attributes</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p></p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOList">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_Get_UIOList</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inSpecificationList</span></em>, <em class="sig-param"><span class="n">inElement</span><span class="o">=</span><span class="default_value">None</span></em>, <em class="sig-param"><span class="n">inFlagRaiseException</span><span class="o">=</span><span class="default_value">True</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_Get_UIOList"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOList" title="Permalink to this definition"></a></dt>
<dd><p>Get the UIO list by the selector</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>inSpecificationList</strong> UIO Selector</p></li>
<li><p><strong>inElement</strong> Входной элемент - показатель, что не требуется выполнять коннект к процессу</p></li>
<li><p><strong>inFlagRaiseException</strong> Флаг True - выкинуть ошибку в случае обнаружении пустого списка</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p></p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_Highlight">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_Highlight</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inUIOSelector</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_Highlight"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_Highlight" title="Permalink to this definition"></a></dt>
<dd><p>Highlight (draw outline) the element (in app) by the UIO selector.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inUIOSelector</strong> UIOSelector - List of items, which contains condition attributes</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p></p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_SafeOtherGet_Process">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_SafeOtherGet_Process</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inUIOSelector</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_SafeOtherGet_Process"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_SafeOtherGet_Process" title="Permalink to this definition"></a></dt>
<dd><p>Safe get other process or None if destination app is the other/same bitness</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inUIOSelector</strong> UIO Selector of the UI object</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>None or process (of the other bitness)</p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_SearchChildByMouse_UIO">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_SearchChildByMouse_UIO</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inElementSpecification</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_SearchChildByMouse_UIO"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_SearchChildByMouse_UIO" title="Permalink to this definition"></a></dt>
<dd><p>UIOSelector (see description on the top of the document)
#old name - AutomationSearchMouseElement</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inElementSpecification</strong> UIOSelector of the UI Object</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>pywinauto element wrapper instance or None</p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_SearchChildByMouse_UIOTree">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_SearchChildByMouse_UIOTree</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inUIOSelector</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_SearchChildByMouse_UIOTree"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_SearchChildByMouse_UIOTree" title="Permalink to this definition"></a></dt>
<dd><p>!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inUIOSelector</strong> UIOSelector of the UI Object</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p><p>?</p>
</p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelector_TryRestore_Dict">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelector_TryRestore_Dict</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inSpecificationList</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelector_TryRestore_Dict"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelector_TryRestore_Dict" title="Permalink to this definition"></a></dt>
<dd><p>Try to restore (maximize) window, if its minimized. (!IMPORTANT! When use UIA framework minimized windows doesnt appear by the UIOSelector. You need to try restore windows and after that try to get UIO)</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>inSpecificationList</strong> UIOSelector - List of items, which contains condition attributes</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p></p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelectorsSecs_WaitAppear_List">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelectorsSecs_WaitAppear_List</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inSpecificationListList</span></em>, <em class="sig-param"><span class="n">inWaitSecs</span></em>, <em class="sig-param"><span class="n">inFlagWaitAllInMoment</span><span class="o">=</span><span class="default_value">False</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelectorsSecs_WaitAppear_List"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelectorsSecs_WaitAppear_List" title="Permalink to this definition"></a></dt>
<dd><p>Wait for many UI object will appear in GUI for inWaitSecs seconds.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>inSpecificationListList</strong> <p>UIOSelector list.
Example: [</p>
<blockquote>
<div><p>[{“title”:”notepad”},{“title”:”OK”}],
[{“title”:”notepad”},{“title”:”Cancel”}]</p>
</div></blockquote>
<p>]</p>
</p></li>
<li><p><strong>inWaitSecs</strong> Float value (seconds) for wait UI element appear in GUI</p></li>
<li><p><strong>inFlagWaitAllInMoment</strong> True - Wait all UI objects from the UIOSelector list to be appeared</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>List of index, which UI object UIO will be appeared. Example: [1] # Appear only UI object with UIO selector: [{“title”:”notepad”},{“title”:”Cancel”}]</p>
</dd>
</dl>
</dd></dl>
<dl class="py function">
<dt id="pyOpenRPA.Robot.UIDesktop.UIOSelectorsSecs_WaitDisappear_List">
<code class="sig-prename descclassname">pyOpenRPA.Robot.UIDesktop.</code><code class="sig-name descname">UIOSelectorsSecs_WaitDisappear_List</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">inSpecificationListList</span></em>, <em class="sig-param"><span class="n">inWaitSecs</span></em>, <em class="sig-param"><span class="n">inFlagWaitAllInMoment</span><span class="o">=</span><span class="default_value">False</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/pyOpenRPA/Robot/UIDesktop.html#UIOSelectorsSecs_WaitDisappear_List"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pyOpenRPA.Robot.UIDesktop.UIOSelectorsSecs_WaitDisappear_List" title="Permalink to this definition"></a></dt>
<dd><p>Wait for many UI object will disappear in GUI for inWaitSecs seconds.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>inSpecificationListList</strong> <p>UIOSelector list.
Example: [</p>
<blockquote>
<div><p>[{“title”:”notepad”},{“title”:”OK”}],
[{“title”:”notepad”},{“title”:”Cancel”}]</p>
</div></blockquote>
<p>]</p>
</p></li>
<li><p><strong>inWaitSecs</strong> Float value (seconds) for wait UI element disappear in GUI</p></li>
<li><p><strong>inFlagWaitAllInMoment</strong> True - Wait all UI objects from the UIOSelector list to be disappeared.</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>List of index, which UI object UIO will be disappeared. Example: [1] # Disappear only UI object with UIO selector: [{“title”:”notepad”},{“title”:”Cancel”}]</p>
</dd>
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p></p>
</dd>
</dl>
</dd></dl>
<p>pyOpenRPA Robot is the python package which allow you to create best RPA program.</p>
<p>The description of the functions you can find page Defs (see menu)</p>
<p>Here is the example of the pyOpenRPA usage.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># EXAMPLE 1</span>
<span class="kn">from</span> <span class="nn">pyOpenRPA.Robot</span> <span class="kn">import</span> <span class="n">UIDesktop</span>
<span class="n">lNotepadOKButton</span> <span class="o">=</span> <span class="n">UIDesktop</span><span class="o">.</span><span class="n">UIOSelector_Get_UIO</span><span class="p">(</span>
<span class="n">inSpecificationList</span><span class="o">=</span><span class="p">[</span>
<span class="p">{</span><span class="s2">&quot;title&quot;</span><span class="p">:</span><span class="s2">&quot;notepad.exe&quot;</span><span class="p">},{</span><span class="s2">&quot;title&quot;</span><span class="p">:</span><span class="s2">&quot;OK&quot;</span><span class="p">}],</span>
<span class="n">inElement</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">inFlagRaiseException</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">lNotepadOKButton</span><span class="o">.</span><span class="n">click</span><span class="p">()</span>
</pre></div>
</div>
</div>

@ -96,13 +96,6 @@
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="01_Robot.html">1. Description</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">2. Defs</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#desktop-app-ui-access-win32-and-ui-automation-dlls">Desktop app UI access (win32 and UI automation dlls)</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#definitions">Definitions</a></li>
<li class="toctree-l3"><a class="reference internal" href="#what-is-uio">What is UIO?</a></li>
<li class="toctree-l3"><a class="reference internal" href="#uioselector-structure-example">UIOSelector structure &amp; example</a></li>
<li class="toctree-l3"><a class="reference internal" href="#the-uidesktop-module-openrpa-robot-uidesktop-py">The UIDesktop module (OpenRPA/Robot/UIDesktop.py)</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="#references">References</a></li>
</ul>
</li>
@ -190,87 +183,7 @@
<div class="section" id="defs">
<h1>2. Defs<a class="headerlink" href="#defs" title="Permalink to this headline"></a></h1>
<div class="section" id="desktop-app-ui-access-win32-and-ui-automation-dlls">
<h2>Desktop app UI access (win32 and UI automation dlls)<a class="headerlink" href="#desktop-app-ui-access-win32-and-ui-automation-dlls" title="Permalink to this headline"></a></h2>
<div class="section" id="definitions">
<h3>Definitions<a class="headerlink" href="#definitions" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p><strong>UIO</strong> - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]</p></li>
<li><p><strong>UIOSelector</strong> - List of dict (key attributes)</p></li>
<li><p><strong>PWA</strong> - PyWinAuto</p></li>
<li><p><strong>PWASpecification</strong> - List of dict (key attributes in pywinauto.find_window notation)</p></li>
<li><p><strong>UIOTree</strong> - Recursive Dict of Dict … (UI Parent -&gt; Child hierarchy)</p></li>
<li><p><strong>UIOInfo</strong> - Dict of UIO attributes</p></li>
<li><p><strong>UIOActivity</strong> - Activity of the UIO (UI object) from the Pywinauto module</p></li>
<li><p><strong>UIOEI</strong> - UI Object info object</p></li>
</ul>
</div>
<div class="section" id="what-is-uio">
<h3>What is UIO?<a class="headerlink" href="#what-is-uio" title="Permalink to this headline"></a></h3>
<p>UIO is a User Interface Object (pyOpenRPA terminology). For maximum compatibility, this instance is inherited from the object model developed in the [pywinauto library (click to get a list of available class functions)](<a class="reference external" href="https://pywinauto.readthedocs.io/en/latest/code/pywinauto.base_wrapper.html">https://pywinauto.readthedocs.io/en/latest/code/pywinauto.base_wrapper.html</a>).</p>
<p>This approach allows us to implement useful functionality that has already been successfully developed in other libraries, and Supplement it with the missing functionality. In our case, the missing functionality is the ability to dynamically access UIO objects using UIO selectors.</p>
</div>
<div class="section" id="uioselector-structure-example">
<h3>UIOSelector structure &amp; example<a class="headerlink" href="#uioselector-structure-example" title="Permalink to this headline"></a></h3>
<p>&lt;a name=”UIOSelector_Structure_Examples”&gt;&lt;/a&gt;
UIOSelector is the list of condition items for the UIO in GUI. Each item has condition attributes for detect applicable UIO. Here is the description of the available condition attributes in item.</p>
<dl class="simple">
<dt><a href="#id1"><span class="problematic" id="id2">**</span></a>Desciption**&lt;br&gt;</dt><dd><p><a href="#id3"><span class="problematic" id="id4">``</span></a><a href="#id5"><span class="problematic" id="id6">`</span></a></p>
</dd>
</dl>
<dl>
<dt>[</dt><dd><dl class="simple">
<dt>{</dt><dd><p>“depth_start” :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
“depth_end” :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
“ctrl_index” || “index” :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
“title” :: [str] :: the condition for the UIO attribute <em>title</em>,
“title_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>title</em>,
“rich_text” :: [str] :: the condition for the UIO attribute <em>rich_text</em>,
“rich_text_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>rich_text</em>,
“class_name” :: [str] :: the condition for the UIO attribute <em>class_name</em>,
“class_name_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>class_name</em>,
“friendly_class_name” :: [str] :: the condition for the UIO attribute <em>friendly_class_name</em>,
“friendly_class_name_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>friendly_class_name</em>,
“control_type” :: [str] :: the condition for the UIO attribute <em>control_type</em>,
“control_type_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>control_type</em>,
“is_enabled” :: [bool] :: the condition for the UIO attribute <em>is_enabled</em>. If UI object is enabled on GUI,
“is_visible” :: [bool] :: the condition for the UIO attribute <em>is_visible</em>. If UI object is visible on GUI,
“backend” :: [str, “win32” || “uia”] :: the method of UIO extraction (default “win32”). ATTENTION! Current option can be only for the first item of the UIO selector. For the next items this option will be implemented from the first item.</p>
</dd>
</dl>
<p>},
{ … specification next level UIO }</p>
</dd>
</dl>
<dl class="simple">
<dt>]</dt><dd><p><a href="#id7"><span class="problematic" id="id8">``</span></a><a href="#id9"><span class="problematic" id="id10">`</span></a></p>
</dd>
<dt><strong>The UIO selector example</strong></dt><dd><p><a href="#id11"><span class="problematic" id="id12">``</span></a><a href="#id13"><span class="problematic" id="id14">`</span></a></p>
</dd>
</dl>
<dl class="simple">
<dt>[</dt><dd><p>{“class_name”:”CalcFrame”, “backend”:”win32”}, # 1-st level UIO specification
{“title”:”Hex”, “depth_start”:3, “depth_end”: 3} # 3-rd level specification (because of attribute depth_start|depth_stop)</p>
</dd>
</dl>
<dl class="simple">
<dt>]</dt><dd><p><a href="#id15"><span class="problematic" id="id16">``</span></a><a href="#id17"><span class="problematic" id="id18">`</span></a></p>
</dd>
</dl>
</div>
<div class="section" id="the-uidesktop-module-openrpa-robot-uidesktop-py">
<h3>The UIDesktop module (OpenRPA/Robot/UIDesktop.py)<a class="headerlink" href="#the-uidesktop-module-openrpa-robot-uidesktop-py" title="Permalink to this headline"></a></h3>
<p>The UIDesktop is extension of the pywinauto module which provide access to the desktop apps by the <strong>win32</strong> and <strong>ui automation</strong> dll frameworks (big thx to the Microsoft :) ).</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># EXAMPLE 1</span>
<span class="kn">from</span> <span class="nn">pyOpenRPA.Robot</span> <span class="kn">import</span> <span class="n">UIDesktop</span>
<span class="n">UIDesktop</span><span class="o">.</span><span class="n">UIOSelector_Get_UIO</span><span class="p">(</span>
<span class="n">inSpecificationList</span><span class="o">=</span><span class="p">[</span>
<span class="p">{</span><span class="s2">&quot;title&quot;</span><span class="p">:</span><span class="s2">&quot;notepad.exe&quot;</span><span class="p">},{</span><span class="s2">&quot;title&quot;</span><span class="p">:</span><span class="s2">&quot;OK&quot;</span><span class="p">}],</span>
<span class="n">inElement</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">inFlagRaiseException</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<p>Here you can find the functions description for interaction with desktop GUI applications</p>
<span class="target" id="module-pyOpenRPA.Robot.UIDesktop"></span><p><strong>Functions:</strong></p>
<table class="longtable docutils align-default">
<colgroup>
@ -702,13 +615,11 @@ Example: [</p>
</dl>
</dd></dl>
</div>
</div>
<div class="section" id="references">
<h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2>
<p><a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> <a class="footnote-reference brackets" href="#id19" id="id20">1</a></p>
<p><a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> <a class="footnote-reference brackets" href="#id1" id="id2">1</a></p>
<dl class="footnote brackets">
<dt class="label" id="id19"><span class="brackets"><a class="fn-backref" href="#id20">1</a></span></dt>
<dt class="label" id="id1"><span class="brackets"><a class="fn-backref" href="#id2">1</a></span></dt>
<dd><p><a class="reference external" href="http://docutils.sourceforge.net/rst.html">http://docutils.sourceforge.net/rst.html</a></p>
</dd>
</dl>

@ -106,16 +106,17 @@
<li class="toctree-l3"><a class="reference internal" href="#use-in-studio-script-n-a">Use in studio script (n/a)</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="#theory-practice-desktop-app-ui-access-win32-and-ui-automation-dlls">Theory &amp; practice. Desktop app UI access (win32 and UI automation dlls)</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#desktop-app-ui-access-win32-and-ui-automation-dlls">Desktop app UI access (win32 and UI automation dlls)</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#definitions">Definitions</a></li>
<li class="toctree-l3"><a class="reference internal" href="#what-is-uio">What is UIO?</a></li>
<li class="toctree-l3"><a class="reference internal" href="#uioselector-structure-example">UIOSelector structure &amp; example</a></li>
<li class="toctree-l3"><a class="reference internal" href="#the-uidesktop-module-openrpa-robot-uidesktop-py">The UIDesktop module (OpenRPA/Robot/UIDesktop.py)</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id1">The UIDesktop module (OpenRPA/Robot/UIDesktop.py)</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="#theory-practice-web-app-ui-access-selenium">Theory &amp; practice. WEB app UI access (selenium)</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#about">About</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id19">How to use</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id4">How to use</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="#theory-practice-keyboard-mouse-manipulation">Theory &amp; practice. Keyboard &amp; mouse manipulation</a></li>
@ -285,18 +286,20 @@
<p>Here you can find the docs and examples of the OpenRPA desktop (GUI) app access.</p>
</div>
</div>
<div class="section" id="theory-practice-desktop-app-ui-access-win32-and-ui-automation-dlls">
<h2>Theory &amp; practice. Desktop app UI access (win32 and UI automation dlls)<a class="headerlink" href="#theory-practice-desktop-app-ui-access-win32-and-ui-automation-dlls" title="Permalink to this headline"></a></h2>
<div class="section" id="desktop-app-ui-access-win32-and-ui-automation-dlls">
<h2>Desktop app UI access (win32 and UI automation dlls)<a class="headerlink" href="#desktop-app-ui-access-win32-and-ui-automation-dlls" title="Permalink to this headline"></a></h2>
<div class="section" id="definitions">
<h3>Definitions<a class="headerlink" href="#definitions" title="Permalink to this headline"></a></h3>
<p><strong>UIO</strong> - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]&lt;br&gt;
<strong>UIOSelector</strong> - List of dict (key attributes)&lt;br&gt;
<strong>PWA</strong> - PyWinAuto&lt;br&gt;
<strong>PWASpecification</strong> - List of dict (key attributes in pywinauto.find_window notation)&lt;br&gt;
<strong>UIOTree</strong> - Recursive Dict of Dict … (UI Parent -&gt; Child hierarchy)&lt;br&gt;
<strong>UIOInfo</strong> - Dict of UIO attributes&lt;br&gt;
<strong>UIOActivity</strong> - Activity of the UIO (UI object) from the Pywinauto module&lt;br&gt;
<strong>UIOEI</strong> - UI Object info object</p>
<ul class="simple">
<li><p><strong>UIO</strong> - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]</p></li>
<li><p><strong>UIOSelector</strong> - List of dict (key attributes)</p></li>
<li><p><strong>PWA</strong> - PyWinAuto</p></li>
<li><p><strong>PWASpecification</strong> - List of dict (key attributes in pywinauto.find_window notation)</p></li>
<li><p><strong>UIOTree</strong> - Recursive Dict of Dict … (UI Parent -&gt; Child hierarchy)</p></li>
<li><p><strong>UIOInfo</strong> - Dict of UIO attributes</p></li>
<li><p><strong>UIOActivity</strong> - Activity of the UIO (UI object) from the Pywinauto module</p></li>
<li><p><strong>UIOEI</strong> - UI Object info object</p></li>
</ul>
</div>
<div class="section" id="what-is-uio">
<h3>What is UIO?<a class="headerlink" href="#what-is-uio" title="Permalink to this headline"></a></h3>
@ -305,56 +308,57 @@
</div>
<div class="section" id="uioselector-structure-example">
<h3>UIOSelector structure &amp; example<a class="headerlink" href="#uioselector-structure-example" title="Permalink to this headline"></a></h3>
<p>&lt;a name=”UIOSelector_Structure_Examples”&gt;&lt;/a&gt;
UIOSelector is the list of condition items for the UIO in GUI. Each item has condition attributes for detect applicable UIO. Here is the description of the available condition attributes in item.</p>
<dl class="simple">
<dt><strong>Desciption</strong></dt><dd><p><a href="#id1"><span class="problematic" id="id2">``</span></a><a href="#id3"><span class="problematic" id="id4">`</span></a></p>
</dd>
</dl>
<dl>
<dt>[</dt><dd><dl class="simple">
<dt>{</dt><dd><p>“depth_start” :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
“depth_end” :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
“ctrl_index” || “index” :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
“title” :: [str] :: the condition for the UIO attribute <em>title</em>,
“title_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>title</em>,
“rich_text” :: [str] :: the condition for the UIO attribute <em>rich_text</em>,
“rich_text_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>rich_text</em>,
“class_name” :: [str] :: the condition for the UIO attribute <em>class_name</em>,
“class_name_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>class_name</em>,
“friendly_class_name” :: [str] :: the condition for the UIO attribute <em>friendly_class_name</em>,
“friendly_class_name_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>friendly_class_name</em>,
“control_type” :: [str] :: the condition for the UIO attribute <em>control_type</em>,
“control_type_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>control_type</em>,
“is_enabled” :: [bool] :: the condition for the UIO attribute <em>is_enabled</em>. If UI object is enabled on GUI,
“is_visible” :: [bool] :: the condition for the UIO attribute <em>is_visible</em>. If UI object is visible on GUI,
“backend” :: [str, “win32” || “uia”] :: the method of UIO extraction (default “win32”). ATTENTION! Current option can be only for the first item of the UIO selector. For the next items this option will be implemented from the first item.</p>
</dd>
</dl>
<p>},
{ … specification next level UIO }</p>
</dd>
</dl>
<dl class="simple">
<dt>]</dt><dd><p><a href="#id5"><span class="problematic" id="id6">``</span></a><a href="#id7"><span class="problematic" id="id8">`</span></a></p>
</dd>
<dt><strong>The UIO selector example</strong></dt><dd><p><a href="#id9"><span class="problematic" id="id10">``</span></a><a href="#id11"><span class="problematic" id="id12">`</span></a></p>
</dd>
</dl>
<dl class="simple">
<dt>[</dt><dd><p>{“class_name”:”CalcFrame”, “backend”:”win32”}, # 1-st level UIO specification
{“title”:”Hex”, “depth_start”:3, “depth_end”: 3} # 3-rd level specification (because of attribute depth_start|depth_stop)</p>
</dd>
</dl>
<dl class="simple">
<dt>]</dt><dd><p><a href="#id13"><span class="problematic" id="id14">``</span></a><a href="#id15"><span class="problematic" id="id16">`</span></a></p>
</dd>
</dl>
<p>UIOSelector is the list of condition items for the UIO in GUI. Each item has condition attributes for detect applicable UIO. Here is the description of the available condition attributes in item.</p>
<p><strong>Desciption</strong></p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>[
{
&quot;depth_start&quot; :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
&quot;depth_end&quot; :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
&quot;ctrl_index&quot; || &quot;index&quot; :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
&quot;title&quot; :: [str] :: the condition for the UIO attribute *title*,
&quot;title_re&quot; :: [str] :: regular expression (python ver) for the condition for the UIO attribute *title*,
&quot;rich_text&quot; :: [str] :: the condition for the UIO attribute *rich_text*,
&quot;rich_text_re&quot; :: [str] :: regular expression (python ver) for the condition for the UIO attribute *rich_text*,
&quot;class_name&quot; :: [str] :: the condition for the UIO attribute *class_name*,
&quot;class_name_re&quot; :: [str] :: regular expression (python ver) for the condition for the UIO attribute *class_name*,
&quot;friendly_class_name&quot; :: [str] :: the condition for the UIO attribute *friendly_class_name*,
&quot;friendly_class_name_re&quot; :: [str] :: regular expression (python ver) for the condition for the UIO attribute *friendly_class_name*,
&quot;control_type&quot; :: [str] :: the condition for the UIO attribute *control_type*,
&quot;control_type_re&quot; :: [str] :: regular expression (python ver) for the condition for the UIO attribute *control_type*,
&quot;is_enabled&quot; :: [bool] :: the condition for the UIO attribute *is_enabled*. If UI object is enabled on GUI,
&quot;is_visible&quot; :: [bool] :: the condition for the UIO attribute *is_visible*. If UI object is visible on GUI,
&quot;backend&quot; :: [str, &quot;win32&quot; || &quot;uia&quot;] :: the method of UIO extraction (default &quot;win32&quot;). ATTENTION! Current option can be only for the first item of the UIO selector. For the next items this option will be implemented from the first item.
},
{ ... specification next level UIO }
]
</pre></div>
</div>
<p><strong>The UIO selector example</strong></p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="p">[</span>
<span class="p">{</span><span class="s2">&quot;class_name&quot;</span><span class="p">:</span><span class="s2">&quot;CalcFrame&quot;</span><span class="p">,</span> <span class="s2">&quot;backend&quot;</span><span class="p">:</span><span class="s2">&quot;win32&quot;</span><span class="p">},</span> <span class="c1"># 1-st level UIO specification</span>
<span class="p">{</span><span class="s2">&quot;title&quot;</span><span class="p">:</span><span class="s2">&quot;Hex&quot;</span><span class="p">,</span> <span class="s2">&quot;depth_start&quot;</span><span class="p">:</span><span class="mi">3</span><span class="p">,</span> <span class="s2">&quot;depth_end&quot;</span><span class="p">:</span> <span class="mi">3</span><span class="p">}</span> <span class="c1"># 3-rd level specification (because of attribute depth_start|depth_stop)</span>
<span class="p">]</span>
</pre></div>
</div>
</div>
<div class="section" id="the-uidesktop-module-openrpa-robot-uidesktop-py">
<h3>The UIDesktop module (OpenRPA/Robot/UIDesktop.py)<a class="headerlink" href="#the-uidesktop-module-openrpa-robot-uidesktop-py" title="Permalink to this headline"></a></h3>
<p>The UIDesktop is extension of the pywinauto module which provide access to the desktop apps by the <strong>win32</strong> and <strong>ui automation</strong> dll frameworks (big thx to the Microsoft :) ).</p>
<p><a href="#id17"><span class="problematic" id="id18">*</span></a>Naming convention: &lt;InArgument&gt;_&lt;ActivityName&gt;_&lt;OutArgument - if exist&gt;*&lt;br&gt;</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># EXAMPLE 1</span>
<span class="kn">from</span> <span class="nn">pyOpenRPA.Robot</span> <span class="kn">import</span> <span class="n">UIDesktop</span>
<span class="n">UIDesktop</span><span class="o">.</span><span class="n">UIOSelector_Get_UIO</span><span class="p">(</span>
<span class="n">inSpecificationList</span><span class="o">=</span><span class="p">[</span>
<span class="p">{</span><span class="s2">&quot;title&quot;</span><span class="p">:</span><span class="s2">&quot;notepad.exe&quot;</span><span class="p">},{</span><span class="s2">&quot;title&quot;</span><span class="p">:</span><span class="s2">&quot;OK&quot;</span><span class="p">}],</span>
<span class="n">inElement</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">inFlagRaiseException</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="id1">
<h3>The UIDesktop module (OpenRPA/Robot/UIDesktop.py)<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3>
<p>The UIDesktop is extension of the pywinauto module which provide access to the desktop apps by the <strong>win32</strong> and <strong>ui automation</strong> dll frameworks (big thx to the Microsoft :) ).</p>
<p><a href="#id2"><span class="problematic" id="id3">*</span></a>Naming convention: &lt;InArgument&gt;_&lt;ActivityName&gt;_&lt;OutArgument - if exist&gt;*&lt;br&gt;</p>
</div>
</div>
<div class="section" id="theory-practice-web-app-ui-access-selenium">
@ -364,8 +368,8 @@ UIOSelector is the list of condition items for the UIO in GUI. Each item has con
<p>The pyOpenRPA support web app manipulation (by the Selenium lib).
More docs about selenium you can find here (<a class="reference external" href="https://selenium-python.readthedocs.io/">https://selenium-python.readthedocs.io/</a>)</p>
</div>
<div class="section" id="id19">
<h3>How to use<a class="headerlink" href="#id19" title="Permalink to this headline"></a></h3>
<div class="section" id="id4">
<h3>How to use<a class="headerlink" href="#id4" title="Permalink to this headline"></a></h3>
<p>To start use selenium just import selenium modules in the robot tool. Here is the example of the usage.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
<span class="kn">from</span> <span class="nn">selenium.webdriver.common.keys</span> <span class="kn">import</span> <span class="n">Keys</span>

@ -203,7 +203,6 @@
<div class="section" id="how-to-use">
<h1>2. How to use<a class="headerlink" href="#how-to-use" title="Permalink to this headline"></a></h1>
<p>HTML CODE</p>
<div class="section" id="content">
<h2>Content<a class="headerlink" href="#content" title="Permalink to this headline"></a></h2>
<ul class="simple">

@ -3,11 +3,20 @@
####################################
- Guide
- - ENG - in progress (see content below), plan date 31.08.2020 (failed), new plan date march 2021
- - RUS - queue
- ENG - done 2021.03.11
- HTML `|OPEN GITLAB| <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html>`_
- MarkDown `|OPEN GITLAB| <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md>`_
- PDF `|WAIT| <>`_
- RUS - queue
- Tutorial
- - ENG - queue
- - RUS - queue
- Dev actions
- ENG - queue
- RUS - in progress
- Article: Less cost - no paid RPA `|OPEN HABR| <https://habr.com/ru/post/506766/>`_
- Tutorial Desktop UI `|OPEN HABR| <https://habr.com/ru/post/509644/>`_; `|OPEN GITLAB| <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md>`_
- Tutorial Web UI `|OPEN HABR| <https://habr.com/ru/post/515310/>`_; `|OPEN GITLAB| <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md>`_
Refactoring the arguments in UIDesktop.py (only in new branch pyOpenRPA version. For backward compatibility purpose), plan date -
- Leaflet
- ENG queue
- RUS done 2021.02.23
- RUS Leaflet pyOpenRPA v4.pdf `|OPEN GITLAB| <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/pyOpenRPA/Wiki/RUS_Leaflet/RUS%20Leaflet%20pyOpenRPA%20v4.pdf>`_

@ -7,16 +7,13 @@
pyOpenRPA is created by Ivan Maslov (Russia).
Use it absolutely for free!
My purpose is to create #IT4Business models all over the world.
My purpose is to create #IT4Business models in the companies.
I can help you to create the new #IT4Business in your company.
#IT4Business homepage - https://www.facebook.com/RU.IT4Business
#IT4Busines is the methodology which is created for build compact fast and reliable IT function in company.
If you has many IT specialists, very long deadlines for the IT tasks, many bugs in IT software - #IT4Business is for you :)
If you need some IT help - feel free to contact me (prefer e-mail or skype).
If you will find some issue in pyOpenRPA - write about it to me via e-mail/skype/gitlab issue.
Thank you!

@ -2,10 +2,21 @@
1. Description
************************
pyOpenRPA Robot is the python package.
pyOpenRPA Robot is the python package which allow you to create best RPA program.
The description of the functions you can find page 'Defs' (see menu)
pyOpenRPA Robot
##################################
.. automodule:: pyOpenRPA.Robot.UIDesktop
:members:
Here is the example of the pyOpenRPA usage.
.. code-block:: python
# EXAMPLE 1
from pyOpenRPA.Robot import UIDesktop
lNotepadOKButton = UIDesktop.UIOSelector_Get_UIO(
inSpecificationList=[
{"title":"notepad.exe"},{"title":"OK"}],
inElement=None,
inFlagRaiseException=True)
lNotepadOKButton.click()

@ -2,82 +2,7 @@
2. Defs
####################################
****************************************************************************************************
Desktop app UI access (win32 and UI automation dlls)
****************************************************************************************************
Definitions
############################################
- **UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]
- **UIOSelector** - List of dict (key attributes)
- **PWA** - PyWinAuto
- **PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)
- **UIOTree** - Recursive Dict of Dict ... (UI Parent -> Child hierarchy)
- **UIOInfo** - Dict of UIO attributes
- **UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module
- **UIOEI** - UI Object info object
What is UIO?
############################################
UIO is a User Interface Object (pyOpenRPA terminology). For maximum compatibility, this instance is inherited from the object model developed in the [pywinauto library (click to get a list of available class functions)](https://pywinauto.readthedocs.io/en/latest/code/pywinauto.base_wrapper.html).
This approach allows us to implement useful functionality that has already been successfully developed in other libraries, and Supplement it with the missing functionality. In our case, the missing functionality is the ability to dynamically access UIO objects using UIO selectors.
UIOSelector structure & example
############################################
<a name="UIOSelector_Structure_Examples"></a>
UIOSelector is the list of condition items for the UIO in GUI. Each item has condition attributes for detect applicable UIO. Here is the description of the available condition attributes in item.
**Desciption**<br>
```
[
{
"depth_start" :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
"depth_end" :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
"ctrl_index" || "index" :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
"title" :: [str] :: the condition for the UIO attribute *title*,
"title_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *title*,
"rich_text" :: [str] :: the condition for the UIO attribute *rich_text*,
"rich_text_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *rich_text*,
"class_name" :: [str] :: the condition for the UIO attribute *class_name*,
"class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *class_name*,
"friendly_class_name" :: [str] :: the condition for the UIO attribute *friendly_class_name*,
"friendly_class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *friendly_class_name*,
"control_type" :: [str] :: the condition for the UIO attribute *control_type*,
"control_type_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *control_type*,
"is_enabled" :: [bool] :: the condition for the UIO attribute *is_enabled*. If UI object is enabled on GUI,
"is_visible" :: [bool] :: the condition for the UIO attribute *is_visible*. If UI object is visible on GUI,
"backend" :: [str, "win32" || "uia"] :: the method of UIO extraction (default "win32"). ATTENTION! Current option can be only for the first item of the UIO selector. For the next items this option will be implemented from the first item.
},
{ ... specification next level UIO }
]
```
**The UIO selector example**
```
[
{"class_name":"CalcFrame", "backend":"win32"}, # 1-st level UIO specification
{"title":"Hex", "depth_start":3, "depth_end": 3} # 3-rd level specification (because of attribute depth_start|depth_stop)
]
```
The UIDesktop module (OpenRPA/Robot/UIDesktop.py)
########################################################################################
The UIDesktop is extension of the pywinauto module which provide access to the desktop apps by the **win32** and **ui automation** dll frameworks (big thx to the Microsoft :) ).
.. code-block:: python
# EXAMPLE 1
from pyOpenRPA.Robot import UIDesktop
UIDesktop.UIOSelector_Get_UIO(
inSpecificationList=[
{"title":"notepad.exe"},{"title":"OK"}],
inElement=None,
inFlagRaiseException=True)
Here you can find the functions description for interaction with desktop GUI applications
.. automodule:: pyOpenRPA.Robot.UIDesktop
:members:

@ -95,20 +95,20 @@ Use in studio script (n/a)
Here you can find the docs and examples of the OpenRPA desktop (GUI) app access.
****************************************************************************************************
Theory & practice. Desktop app UI access (win32 and UI automation dlls)
Desktop app UI access (win32 and UI automation dlls)
****************************************************************************************************
Definitions
############################################
**UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]<br>
**UIOSelector** - List of dict (key attributes)<br>
**PWA** - PyWinAuto<br>
**PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)<br>
**UIOTree** - Recursive Dict of Dict ... (UI Parent -> Child hierarchy)<br>
**UIOInfo** - Dict of UIO attributes<br>
**UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module<br>
**UIOEI** - UI Object info object
- **UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]
- **UIOSelector** - List of dict (key attributes)
- **PWA** - PyWinAuto
- **PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)
- **UIOTree** - Recursive Dict of Dict ... (UI Parent -> Child hierarchy)
- **UIOInfo** - Dict of UIO attributes
- **UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module
- **UIOEI** - UI Object info object
What is UIO?
@ -120,40 +120,58 @@ This approach allows us to implement useful functionality that has already been
UIOSelector structure & example
############################################
<a name="UIOSelector_Structure_Examples"></a>
UIOSelector is the list of condition items for the UIO in GUI. Each item has condition attributes for detect applicable UIO. Here is the description of the available condition attributes in item.
**Desciption**
```
[
{
"depth_start" :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
"depth_end" :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
"ctrl_index" || "index" :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
"title" :: [str] :: the condition for the UIO attribute *title*,
"title_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *title*,
"rich_text" :: [str] :: the condition for the UIO attribute *rich_text*,
"rich_text_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *rich_text*,
"class_name" :: [str] :: the condition for the UIO attribute *class_name*,
"class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *class_name*,
"friendly_class_name" :: [str] :: the condition for the UIO attribute *friendly_class_name*,
"friendly_class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *friendly_class_name*,
"control_type" :: [str] :: the condition for the UIO attribute *control_type*,
"control_type_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *control_type*,
"is_enabled" :: [bool] :: the condition for the UIO attribute *is_enabled*. If UI object is enabled on GUI,
"is_visible" :: [bool] :: the condition for the UIO attribute *is_visible*. If UI object is visible on GUI,
"backend" :: [str, "win32" || "uia"] :: the method of UIO extraction (default "win32"). ATTENTION! Current option can be only for the first item of the UIO selector. For the next items this option will be implemented from the first item.
},
{ ... specification next level UIO }
]
```
.. code-block:: python
[
{
"depth_start" :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
"depth_end" :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
"ctrl_index" || "index" :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
"title" :: [str] :: the condition for the UIO attribute *title*,
"title_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *title*,
"rich_text" :: [str] :: the condition for the UIO attribute *rich_text*,
"rich_text_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *rich_text*,
"class_name" :: [str] :: the condition for the UIO attribute *class_name*,
"class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *class_name*,
"friendly_class_name" :: [str] :: the condition for the UIO attribute *friendly_class_name*,
"friendly_class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *friendly_class_name*,
"control_type" :: [str] :: the condition for the UIO attribute *control_type*,
"control_type_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *control_type*,
"is_enabled" :: [bool] :: the condition for the UIO attribute *is_enabled*. If UI object is enabled on GUI,
"is_visible" :: [bool] :: the condition for the UIO attribute *is_visible*. If UI object is visible on GUI,
"backend" :: [str, "win32" || "uia"] :: the method of UIO extraction (default "win32"). ATTENTION! Current option can be only for the first item of the UIO selector. For the next items this option will be implemented from the first item.
},
{ ... specification next level UIO }
]
**The UIO selector example**
```
[
{"class_name":"CalcFrame", "backend":"win32"}, # 1-st level UIO specification
{"title":"Hex", "depth_start":3, "depth_end": 3} # 3-rd level specification (because of attribute depth_start|depth_stop)
]
```
.. code-block:: python
[
{"class_name":"CalcFrame", "backend":"win32"}, # 1-st level UIO specification
{"title":"Hex", "depth_start":3, "depth_end": 3} # 3-rd level specification (because of attribute depth_start|depth_stop)
]
The UIDesktop module (OpenRPA/Robot/UIDesktop.py)
########################################################################################
The UIDesktop is extension of the pywinauto module which provide access to the desktop apps by the **win32** and **ui automation** dll frameworks (big thx to the Microsoft :) ).
.. code-block:: python
# EXAMPLE 1
from pyOpenRPA.Robot import UIDesktop
UIDesktop.UIOSelector_Get_UIO(
inSpecificationList=[
{"title":"notepad.exe"},{"title":"OK"}],
inElement=None,
inFlagRaiseException=True)
The UIDesktop module (OpenRPA/Robot/UIDesktop.py)
########################################################################################
The UIDesktop is extension of the pywinauto module which provide access to the desktop apps by the **win32** and **ui automation** dll frameworks (big thx to the Microsoft :) ).

@ -2,15 +2,6 @@
2. How to use
####################################
.. only:: html
HTML CODE
.. only:: markdown
MARKDOWN CODE
Content
=======

@ -21,7 +21,7 @@ Donate
pyOpenRPA is absolutely non-commercial project.
Please donate some $ if pyOpenRPA project is actual for you. Link to online donations.
https://money.yandex.ru/to/4100115560661986
https://yoomoney.ru/to/4100115560661986
**************************************************
About
@ -115,13 +115,14 @@ Wiki structure
**************************************************
In wiki you can use the following docs:
- ENG Guide HTML [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html)
- ENG Guide MarkDown [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md)
- ENG Guide PDF [|WAIT|]()
- ENG Guide HTML `[|OPEN GITLAB|] <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html>`_
- ENG Guide MarkDown `[|OPEN GITLAB|] <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md>`_
- ENG Guide PDF `[|WAIT|] <>`_
- RUS Article: Less cost - no paid RPA [|OPEN HABR|](https://habr.com/ru/post/509644/)
- RUS Tutorial Desktop UI [|OPEN HABR|](https://habr.com/ru/post/509644/); [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md)
- RUS Tutorial Web UI [|OPEN HABR|](https://habr.com/ru/post/515310/); [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md)
- RUS Article: Less cost - no paid RPA `[|OPEN HABR|] <https://habr.com/ru/post/506766/>`_
- RUS Tutorial Desktop UI `[|OPEN HABR|] <https://habr.com/ru/post/509644/>`_; `[|OPEN GITLAB|] <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md>`_
- RUS Tutorial Web UI `[|OPEN HABR|] <https://habr.com/ru/post/515310/>`_; `[|OPEN GITLAB|] <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md>`_
- RUS Leaflet pyOpenRPA v4.pdf `[|OPEN GITLAB|] <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/pyOpenRPA/Wiki/RUS_Leaflet/RUS Leaflet pyOpenRPA v4.pdf>`_
**************************************************
Guide content

@ -210,7 +210,7 @@
<h2 id="G">G</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.Get_OSBitnessInt">Get_OSBitnessInt() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.Get_OSBitnessInt">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.Get_OSBitnessInt">Get_OSBitnessInt() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.GSettingsAutocleaner">GSettingsAutocleaner() (in module pyOpenRPA.Orchestrator.__Orchestrator__)</a>
</li>
@ -236,7 +236,7 @@
<ul>
<li><a href="Orchestrator/02_Defs.html#module-pyOpenRPA.Orchestrator.__Orchestrator__">pyOpenRPA.Orchestrator.__Orchestrator__</a>
</li>
<li><a href="Robot/01_Robot.html#module-pyOpenRPA.Robot.UIDesktop">pyOpenRPA.Robot.UIDesktop</a>, <a href="Robot/02_Defs.html#module-pyOpenRPA.Robot.UIDesktop">[1]</a>
<li><a href="Robot/02_Defs.html#module-pyOpenRPA.Robot.UIDesktop">pyOpenRPA.Robot.UIDesktop</a>
</li>
</ul></li>
</ul></td>
@ -279,9 +279,9 @@
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessStop">ProcessStop() (in module pyOpenRPA.Orchestrator.__Orchestrator__)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.PWASpecification_Get_PWAApplication">PWASpecification_Get_PWAApplication() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.PWASpecification_Get_PWAApplication">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.PWASpecification_Get_PWAApplication">PWASpecification_Get_PWAApplication() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.PWASpecification_Get_UIO">PWASpecification_Get_UIO() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.PWASpecification_Get_UIO">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.PWASpecification_Get_UIO">PWASpecification_Get_UIO() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li>
pyOpenRPA.Orchestrator.__Orchestrator__
@ -294,7 +294,7 @@
pyOpenRPA.Robot.UIDesktop
<ul>
<li><a href="Robot/01_Robot.html#module-pyOpenRPA.Robot.UIDesktop">module</a>, <a href="Robot/02_Defs.html#module-pyOpenRPA.Robot.UIDesktop">[1]</a>
<li><a href="Robot/02_Defs.html#module-pyOpenRPA.Robot.UIDesktop">module</a>
</li>
</ul></li>
<li><a href="Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.PythonStart">PythonStart() (in module pyOpenRPA.Orchestrator.__Orchestrator__)</a>
@ -353,45 +353,45 @@
</li>
<li><a href="Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.UACUpdate">UACUpdate() (in module pyOpenRPA.Orchestrator.__Orchestrator__)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Exist_Bool">UIOSelector_Exist_Bool() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Exist_Bool">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Exist_Bool">UIOSelector_Exist_Bool() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_FocusHighlight">UIOSelector_FocusHighlight() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_FocusHighlight">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_FocusHighlight">UIOSelector_FocusHighlight() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_BitnessInt">UIOSelector_Get_BitnessInt() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_BitnessInt">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_BitnessInt">UIOSelector_Get_BitnessInt() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_BitnessStr">UIOSelector_Get_BitnessStr() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_BitnessStr">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_BitnessStr">UIOSelector_Get_BitnessStr() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIO">UIOSelector_Get_UIO() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIO">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIO">UIOSelector_Get_UIO() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOActivityList">UIOSelector_Get_UIOActivityList() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOActivityList">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOActivityList">UIOSelector_Get_UIOActivityList() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOInfo">UIOSelector_Get_UIOInfo() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOInfo">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOInfo">UIOSelector_Get_UIOInfo() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOList">UIOSelector_Get_UIOList() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOList">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOList">UIOSelector_Get_UIOList() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_GetChildList_UIOList">UIOSelector_GetChildList_UIOList() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_GetChildList_UIOList">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_GetChildList_UIOList">UIOSelector_GetChildList_UIOList() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Highlight">UIOSelector_Highlight() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Highlight">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_Highlight">UIOSelector_Highlight() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_SafeOtherGet_Process">UIOSelector_SafeOtherGet_Process() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_SafeOtherGet_Process">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_SafeOtherGet_Process">UIOSelector_SafeOtherGet_Process() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_SearchChildByMouse_UIO">UIOSelector_SearchChildByMouse_UIO() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_SearchChildByMouse_UIO">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_SearchChildByMouse_UIO">UIOSelector_SearchChildByMouse_UIO() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_SearchChildByMouse_UIOTree">UIOSelector_SearchChildByMouse_UIOTree() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_SearchChildByMouse_UIOTree">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_SearchChildByMouse_UIOTree">UIOSelector_SearchChildByMouse_UIOTree() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_TryRestore_Dict">UIOSelector_TryRestore_Dict() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_TryRestore_Dict">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelector_TryRestore_Dict">UIOSelector_TryRestore_Dict() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorSecs_WaitAppear_Bool">UIOSelectorSecs_WaitAppear_Bool() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorSecs_WaitAppear_Bool">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorSecs_WaitAppear_Bool">UIOSelectorSecs_WaitAppear_Bool() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorSecs_WaitDisappear_Bool">UIOSelectorSecs_WaitDisappear_Bool() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorSecs_WaitDisappear_Bool">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorSecs_WaitDisappear_Bool">UIOSelectorSecs_WaitDisappear_Bool() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorsSecs_WaitAppear_List">UIOSelectorsSecs_WaitAppear_List() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorsSecs_WaitAppear_List">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorsSecs_WaitAppear_List">UIOSelectorsSecs_WaitAppear_List() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorsSecs_WaitDisappear_List">UIOSelectorsSecs_WaitDisappear_List() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorsSecs_WaitDisappear_List">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorsSecs_WaitDisappear_List">UIOSelectorsSecs_WaitDisappear_List() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
<li><a href="Robot/01_Robot.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorUIOActivity_Run_Dict">UIOSelectorUIOActivity_Run_Dict() (in module pyOpenRPA.Robot.UIDesktop)</a>, <a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorUIOActivity_Run_Dict">[1]</a>
<li><a href="Robot/02_Defs.html#pyOpenRPA.Robot.UIDesktop.UIOSelectorUIOActivity_Run_Dict">UIOSelectorUIOActivity_Run_Dict() (in module pyOpenRPA.Robot.UIDesktop)</a>
</li>
</ul></td>
</tr></table>

@ -186,7 +186,7 @@
<h2>Donate<a class="headerlink" href="#donate" title="Permalink to this headline"></a></h2>
<p>pyOpenRPA is absolutely non-commercial project.</p>
<p>Please donate some $ if pyOpenRPA project is actual for you. Link to online donations.
<a class="reference external" href="https://money.yandex.ru/to/4100115560661986">https://money.yandex.ru/to/4100115560661986</a></p>
<a class="reference external" href="https://yoomoney.ru/to/4100115560661986">https://yoomoney.ru/to/4100115560661986</a></p>
</div>
<div class="section" id="about">
<h2>About<a class="headerlink" href="#about" title="Permalink to this headline"></a></h2>
@ -274,12 +274,13 @@ At the time of this writing the pyOpenRPA is successfully using in several big R
<h2>Wiki structure<a class="headerlink" href="#wiki-structure" title="Permalink to this headline"></a></h2>
<p>In wiki you can use the following docs:</p>
<ul class="simple">
<li><p>ENG Guide HTML [<a href="#id1"><span class="problematic" id="id2">|OPEN GITLAB|</span></a>](<a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html">https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html</a>)</p></li>
<li><p>ENG Guide MarkDown [<a href="#id3"><span class="problematic" id="id4">|OPEN GITLAB|</span></a>](<a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md">https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md</a>)</p></li>
<li><p>ENG Guide PDF [<a href="#id5"><span class="problematic" id="id6">|WAIT|</span></a>]()</p></li>
<li><p>RUS Article: Less cost - no paid RPA [<a href="#id7"><span class="problematic" id="id8">|OPEN HABR|</span></a>](<a class="reference external" href="https://habr.com/ru/post/509644/">https://habr.com/ru/post/509644/</a>)</p></li>
<li><p>RUS Tutorial Desktop UI [<a href="#id9"><span class="problematic" id="id10">|OPEN HABR|</span></a>](<a class="reference external" href="https://habr.com/ru/post/509644/">https://habr.com/ru/post/509644/</a>); [<a href="#id11"><span class="problematic" id="id12">|OPEN GITLAB|</span></a>](<a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md">https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md</a>)</p></li>
<li><p>RUS Tutorial Web UI [<a href="#id13"><span class="problematic" id="id14">|OPEN HABR|</span></a>](<a class="reference external" href="https://habr.com/ru/post/515310/">https://habr.com/ru/post/515310/</a>); [<a href="#id15"><span class="problematic" id="id16">|OPEN GITLAB|</span></a>](<a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md">https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md</a>)</p></li>
<li><p>ENG Guide HTML <a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html">[|OPEN GITLAB|]</a></p></li>
<li><p>ENG Guide MarkDown <a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md">[|OPEN GITLAB|]</a></p></li>
<li><p>ENG Guide PDF <a href="#id7"><span class="problematic" id="id8">`[|WAIT|] &lt;&gt;`_</span></a></p></li>
<li><p>RUS Article: Less cost - no paid RPA <a class="reference external" href="https://habr.com/ru/post/506766/">[|OPEN HABR|]</a></p></li>
<li><p>RUS Tutorial Desktop UI <a class="reference external" href="https://habr.com/ru/post/509644/">[|OPEN HABR|]</a>; <a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md">[|OPEN GITLAB|]</a></p></li>
<li><p>RUS Tutorial Web UI <a class="reference external" href="https://habr.com/ru/post/515310/">[|OPEN HABR|]</a>; <a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md">[|OPEN GITLAB|]</a></p></li>
<li><p>RUS Leaflet pyOpenRPA v4.pdf <a class="reference external" href="https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/pyOpenRPA/Wiki/RUS_Leaflet/RUSLeafletpyOpenRPAv4.pdf">[|OPEN GITLAB|]</a></p></li>
</ul>
</div>
<div class="section" id="guide-content">
@ -303,18 +304,14 @@ At the time of this writing the pyOpenRPA is successfully using in several big R
<div class="toctree-wrapper compound">
<p class="caption"><span class="caption-text">ROBOT</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="Robot/01_Robot.html">1. Description</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Robot/01_Robot.html#module-pyOpenRPA.Robot.UIDesktop">pyOpenRPA Robot</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Robot/01_Robot.html">1. Description</a></li>
<li class="toctree-l1"><a class="reference internal" href="Robot/02_Defs.html">2. Defs</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Robot/02_Defs.html#desktop-app-ui-access-win32-and-ui-automation-dlls">Desktop app UI access (win32 and UI automation dlls)</a></li>
<li class="toctree-l2"><a class="reference internal" href="Robot/02_Defs.html#references">References</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Robot/03_HowToUse.html">3. How to use</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Robot/03_HowToUse.html#how-to-execute-rpa-script">How to execute RPA script</a></li>
<li class="toctree-l2"><a class="reference internal" href="Robot/03_HowToUse.html#theory-practice-desktop-app-ui-access-win32-and-ui-automation-dlls">Theory &amp; practice. Desktop app UI access (win32 and UI automation dlls)</a></li>
<li class="toctree-l2"><a class="reference internal" href="Robot/03_HowToUse.html#desktop-app-ui-access-win32-and-ui-automation-dlls">Desktop app UI access (win32 and UI automation dlls)</a></li>
<li class="toctree-l2"><a class="reference internal" href="Robot/03_HowToUse.html#theory-practice-web-app-ui-access-selenium">Theory &amp; practice. WEB app UI access (selenium)</a></li>
<li class="toctree-l2"><a class="reference internal" href="Robot/03_HowToUse.html#theory-practice-keyboard-mouse-manipulation">Theory &amp; practice. Keyboard &amp; mouse manipulation</a></li>
<li class="toctree-l2"><a class="reference internal" href="Robot/03_HowToUse.html#theory-practice-screen-capture-image-recognition">Theory &amp; practice. Screen capture &amp; image recognition</a></li>

File diff suppressed because one or more lines are too long

@ -3,26 +3,52 @@
* Guide
* ENG - done 2021.03.11
*
* ENG - in progress (see content below), plan date 31.08.2020 (failed), new plan date march 2021
* HTML [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html)
*
* RUS - queue
* MarkDown [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md)
* PDF
```
`|WAIT| <>`_
```
* RUS - queue
* Tutorial
* ENG - queue
* RUS - in progress
* Article: Less cost - no paid RPA [|OPEN HABR|](https://habr.com/ru/post/506766/)
* Tutorial Desktop UI [|OPEN HABR|](https://habr.com/ru/post/509644/); [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md)
* Tutorial Web UI [|OPEN HABR|](https://habr.com/ru/post/515310/); [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md)
*
* ENG - queue
* Leaflet
* ENG queue
*
* RUS - queue
* RUS done 2021.02.23
* Dev actions
Refactoring the arguments in UIDesktop.py (only in new branch pyOpenRPA version. For backward compatibility purpose), plan date -
* RUS Leaflet pyOpenRPA v4.pdf [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/pyOpenRPA/Wiki/RUS_Leaflet/RUS%20Leaflet%20pyOpenRPA%20v4.pdf)

@ -3,16 +3,13 @@
pyOpenRPA is created by Ivan Maslov (Russia).
Use it absolutely for free!
My purpose is to create #IT4Business models all over the world.
My purpose is to create #IT4Business models in the companies.
I can help you to create the new #IT4Business in your company.
#IT4Business homepage - [https://www.facebook.com/RU.IT4Business](https://www.facebook.com/RU.IT4Business)
#IT4Busines is the methodology which is created for build compact fast and reliable IT function in company.
If you has many IT specialists, very long deadlines for the IT tasks, many bugs in IT software - #IT4Business is for you :)
If you need some IT help - feel free to contact me (prefer e-mail or skype).
If you will find some issue in pyOpenRPA - write about it to me via e-mail/skype/gitlab issue.
Thank you!

@ -1,413 +1,20 @@
# 1. Description
pyOpenRPA Robot is the python package.
pyOpenRPA Robot is the python package which allow you to create best RPA program.
## pyOpenRPA Robot
The description of the functions you can find page Defs (see menu)
Here is the example of the pyOpenRPA usage.
### pyOpenRPA.Robot.UIDesktop.Get_OSBitnessInt()
Detect OS bitness.
```
# EXAMPLE 1
from pyOpenRPA.Robot import UIDesktop
lNotepadOKButton = UIDesktop.UIOSelector_Get_UIO(
inSpecificationList=[
{"title":"notepad.exe"},{"title":"OK"}],
inElement=None,
inFlagRaiseException=True)
* **Returns**
int 32 or int 64
### pyOpenRPA.Robot.UIDesktop.PWASpecification_Get_PWAApplication(inControlSpecificationArray)
#Backend selection - attribute “backend” (“win32” || “uia”) in 1-st list element
* **Parameters**
**inControlSpecificationArray** List of dict, dict in pywinauto.find_windows notation
* **Returns**
process application object
### pyOpenRPA.Robot.UIDesktop.PWASpecification_Get_UIO(inControlSpecificationArray)
#Backend def selection - attribute “backend” (“win32” || “uia”) in 1-st list element
#old name - GetControl
* **Parameters**
**inControlSpecificationArray** List of dict, dict in pywinauto.find_windows notation
* **Returns**
list of UIO object
### pyOpenRPA.Robot.UIDesktop.UIOSelectorSecs_WaitAppear_Bool(inSpecificationList, inWaitSecs)
Wait for UI object will appear in GUI for inWaitSecs seconds.
* **Parameters**
* **inSpecificationList** UIOSelector. Example: [{“title”:”notepad”},{“title”:”OK”}]
* **inWaitSecs** Float value (seconds) for wait UI element appear in GUI
* **Returns**
True - UI object will appear. False - else case
### pyOpenRPA.Robot.UIDesktop.UIOSelectorSecs_WaitDisappear_Bool(inSpecificationList, inWaitSecs)
Wait for UI object will disappear in GUI for inWaitSecs seconds.
* **Parameters**
* **inSpecificationList** UIOSelector.
Example: [{“title”:”notepad”},{“title”:”OK”}]
* **inWaitSecs** Float value (seconds) for wait UI element disappear in GUI
* **Returns**
True - UI object will disappear. False - else case
### pyOpenRPA.Robot.UIDesktop.UIOSelectorUIOActivity_Run_Dict(inUIOSelector, inActionName, inArgumentList=None, inkwArgumentObject=None)
Run the activity in UIO (UI Object)
* **Parameters**
* **inUIOSelector** UIOSelector - List of items, which contains condition attributes
* **inActionName** UIOActivity (name) activity name string from Pywinauto
* **inArgumentList**
* **inkwArgumentObject**
* **Returns**
### pyOpenRPA.Robot.UIDesktop.UIOSelector_Exist_Bool(inUIOSelector)
Check if object is exist by the UIO selector.
* **Parameters**
**inUIOSelector**
* **Returns**
True - Object is exist. False - else case
### pyOpenRPA.Robot.UIDesktop.UIOSelector_FocusHighlight(inUIOSelector)
Set focus and highlight (draw outline) the element (in app) by the UIO selector.
* **Parameters**
**inUIOSelector** UIOSelector - List of items, which contains condition attributes
* **Returns**
### pyOpenRPA.Robot.UIDesktop.UIOSelector_GetChildList_UIOList(inUIOSelector=None, inBackend='win32')
Get list of child UIOs by the parent UIOSelector
* **Parameters**
* **inUIOSelector** UIOSelector - List of items, which contains condition attributes
* **inBackend** “win32” or “uia”
* **Returns**
### pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_BitnessInt(inSpecificationList)
Detect process bitness by the UI Object UIO Selector.
* **Parameters**
**inSpecificationList** UIOSelector. Example: [{“title”:”notepad”},{“title”:”OK”}]
* **Returns**
int 32 or int 64
### pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_BitnessStr(inSpecificationList)
Detect process bitness by the UI Object UIO Selector.
* **Parameters**
**inSpecificationList** UIOSelector. Example: [{“title”:”notepad”},{“title”:”OK”}]
* **Returns**
str “32” or str “64”
### pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIO(inSpecificationList, inElement=None, inFlagRaiseException=True)
Get the pywinauto object by the UIO selector.
* **Parameters**
* **inSpecificationList**
* **inElement**
* **inFlagRaiseException**
* **Returns**
### pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOActivityList(inUIOSelector)
Get the list of the UI object activities
* **Parameters**
**inUIOSelector** UIOSelector - List of items, which contains condition attributes
* **Returns**
### pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOInfo(inUIOSelector)
Get the UIO dict of the attributes
* **Parameters**
**inUIOSelector** UIOSelector - List of items, which contains condition attributes
* **Returns**
### pyOpenRPA.Robot.UIDesktop.UIOSelector_Get_UIOList(inSpecificationList, inElement=None, inFlagRaiseException=True)
Get the UIO list by the selector
* **Parameters**
* **inSpecificationList** UIO Selector
* **inElement** Входной элемент - показатель, что не требуется выполнять коннект к процессу
* **inFlagRaiseException** Флаг True - выкинуть ошибку в случае обнаружении пустого списка
* **Returns**
### pyOpenRPA.Robot.UIDesktop.UIOSelector_Highlight(inUIOSelector)
Highlight (draw outline) the element (in app) by the UIO selector.
* **Parameters**
**inUIOSelector** UIOSelector - List of items, which contains condition attributes
* **Returns**
### pyOpenRPA.Robot.UIDesktop.UIOSelector_SafeOtherGet_Process(inUIOSelector)
Safe get other process or None if destination app is the other/same bitness
* **Parameters**
**inUIOSelector** UIO Selector of the UI object
* **Returns**
None or process (of the other bitness)
### pyOpenRPA.Robot.UIDesktop.UIOSelector_SearchChildByMouse_UIO(inElementSpecification)
UIOSelector (see description on the top of the document)
#old name - AutomationSearchMouseElement
* **Parameters**
**inElementSpecification** UIOSelector of the UI Object
* **Returns**
pywinauto element wrapper instance or None
### pyOpenRPA.Robot.UIDesktop.UIOSelector_SearchChildByMouse_UIOTree(inUIOSelector)
!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
* **Parameters**
**inUIOSelector** UIOSelector of the UI Object
* **Returns**
?
### pyOpenRPA.Robot.UIDesktop.UIOSelector_TryRestore_Dict(inSpecificationList)
Try to restore (maximize) window, if its minimized. (!IMPORTANT! When use UIA framework minimized windows doesnt appear by the UIOSelector. You need to try restore windows and after that try to get UIO)
* **Parameters**
**inSpecificationList** UIOSelector - List of items, which contains condition attributes
* **Returns**
### pyOpenRPA.Robot.UIDesktop.UIOSelectorsSecs_WaitAppear_List(inSpecificationListList, inWaitSecs, inFlagWaitAllInMoment=False)
Wait for many UI object will appear in GUI for inWaitSecs seconds.
* **Parameters**
* **inSpecificationListList** UIOSelector list.
Example: [
> [{“title”:”notepad”},{“title”:”OK”}],
> [{“title”:”notepad”},{“title”:”Cancel”}]
]
* **inWaitSecs** Float value (seconds) for wait UI element appear in GUI
* **inFlagWaitAllInMoment** True - Wait all UI objects from the UIOSelector list to be appeared
* **Returns**
List of index, which UI object UIO will be appeared. Example: [1] # Appear only UI object with UIO selector: [{“title”:”notepad”},{“title”:”Cancel”}]
### pyOpenRPA.Robot.UIDesktop.UIOSelectorsSecs_WaitDisappear_List(inSpecificationListList, inWaitSecs, inFlagWaitAllInMoment=False)
Wait for many UI object will disappear in GUI for inWaitSecs seconds.
* **Parameters**
* **inSpecificationListList** UIOSelector list.
Example: [
> [{“title”:”notepad”},{“title”:”OK”}],
> [{“title”:”notepad”},{“title”:”Cancel”}]
]
* **inWaitSecs** Float value (seconds) for wait UI element disappear in GUI
* **inFlagWaitAllInMoment** True - Wait all UI objects from the UIOSelector list to be disappeared.
* **Returns**
List of index, which UI object UIO will be disappeared. Example: [1] # Disappear only UI object with UIO selector: [{“title”:”notepad”},{“title”:”Cancel”}]
* **Returns**
lNotepadOKButton.click()
```

@ -1,153 +1,6 @@
# 2. Defs
## Desktop app UI access (win32 and UI automation dlls)
### Definitions
* **UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]
* **UIOSelector** - List of dict (key attributes)
* **PWA** - PyWinAuto
* **PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)
* **UIOTree** - Recursive Dict of Dict … (UI Parent -> Child hierarchy)
* **UIOInfo** - Dict of UIO attributes
* **UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module
* **UIOEI** - UI Object info object
### What is UIO?
UIO is a User Interface Object (pyOpenRPA terminology). For maximum compatibility, this instance is inherited from the object model developed in the [pywinauto library (click to get a list of available class functions)]([https://pywinauto.readthedocs.io/en/latest/code/pywinauto.base_wrapper.html](https://pywinauto.readthedocs.io/en/latest/code/pywinauto.base_wrapper.html)).
This approach allows us to implement useful functionality that has already been successfully developed in other libraries, and Supplement it with the missing functionality. In our case, the missing functionality is the ability to dynamically access UIO objects using UIO selectors.
### UIOSelector structure & example
<a name=”UIOSelector_Structure_Examples”></a>
UIOSelector is the list of condition items for the UIO in GUI. Each item has condition attributes for detect applicable UIO. Here is the description of the available condition attributes in item.
```
**
```
Desciption\*\*<br>
```
``
```
```
`
```
[
{
“depth_start” :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
“depth_end” :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
“ctrl_index” || “index” :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
“title” :: [str] :: the condition for the UIO attribute *title*,
“title_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute *title*,
“rich_text” :: [str] :: the condition for the UIO attribute *rich_text*,
“rich_text_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute *rich_text*,
“class_name” :: [str] :: the condition for the UIO attribute *class_name*,
“class_name_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute *class_name*,
“friendly_class_name” :: [str] :: the condition for the UIO attribute *friendly_class_name*,
“friendly_class_name_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute *friendly_class_name*,
“control_type” :: [str] :: the condition for the UIO attribute *control_type*,
“control_type_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute *control_type*,
“is_enabled” :: [bool] :: the condition for the UIO attribute *is_enabled*. If UI object is enabled on GUI,
“is_visible” :: [bool] :: the condition for the UIO attribute *is_visible*. If UI object is visible on GUI,
“backend” :: [str, “win32” || “uia”] :: the method of UIO extraction (default “win32”). ATTENTION! Current option can be only for the first item of the UIO selector. For the next items this option will be implemented from the first item.
},
{ … specification next level UIO }
]
```
``
```
```
`
```
**The UIO selector example**
```
``
```
```
`
```
[
{“class_name”:”CalcFrame”, “backend”:”win32”}, # 1-st level UIO specification
{“title”:”Hex”, “depth_start”:3, “depth_end”: 3} # 3-rd level specification (because of attribute depth_start|depth_stop)
]
```
``
```
```
`
```
### The UIDesktop module (OpenRPA/Robot/UIDesktop.py)
The UIDesktop is extension of the pywinauto module which provide access to the desktop apps by the **win32** and **ui automation** dll frameworks (big thx to the Microsoft :) ).
```
# EXAMPLE 1
from pyOpenRPA.Robot import UIDesktop
UIDesktop.UIOSelector_Get_UIO(
inSpecificationList=[
{"title":"notepad.exe"},{"title":"OK"}],
inElement=None,
inFlagRaiseException=True)
```
Here you can find the functions description for interaction with desktop GUI applications
**Functions:**

@ -85,118 +85,93 @@ for lItem in GUI.UIOSelector_Get_UIO([{"class_name":"CabinetWClass","backend":"u
Here you can find the docs and examples of the OpenRPA desktop (GUI) app access.
## Theory & practice. Desktop app UI access (win32 and UI automation dlls)
## Desktop app UI access (win32 and UI automation dlls)
### Definitions
**UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]<br>
**UIOSelector** - List of dict (key attributes)<br>
**PWA** - PyWinAuto<br>
**PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)<br>
**UIOTree** - Recursive Dict of Dict … (UI Parent -> Child hierarchy)<br>
**UIOInfo** - Dict of UIO attributes<br>
**UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module<br>
**UIOEI** - UI Object info object
### What is UIO?
* **UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]
UIO is a User Interface Object (pyOpenRPA terminology). For maximum compatibility, this instance is inherited from the object model developed in the [pywinauto library (click to get a list of available class functions)]([https://pywinauto.readthedocs.io/en/latest/code/pywinauto.base_wrapper.html](https://pywinauto.readthedocs.io/en/latest/code/pywinauto.base_wrapper.html)).
This approach allows us to implement useful functionality that has already been successfully developed in other libraries, and Supplement it with the missing functionality. In our case, the missing functionality is the ability to dynamically access UIO objects using UIO selectors.
### UIOSelector structure & example
* **UIOSelector** - List of dict (key attributes)
<a name=”UIOSelector_Structure_Examples”></a>
UIOSelector is the list of condition items for the UIO in GUI. Each item has condition attributes for detect applicable UIO. Here is the description of the available condition attributes in item.
**Desciption**
* **PWA** - PyWinAuto
```
``
```
* **PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)
* **UIOTree** - Recursive Dict of Dict … (UI Parent -> Child hierarchy)
```
`
```
* **UIOInfo** - Dict of UIO attributes
[
{
* **UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module
“depth_start” :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
“depth_end” :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
“ctrl_index” || “index” :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
“title” :: [str] :: the condition for the UIO attribute *title*,
“title_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute *title*,
“rich_text” :: [str] :: the condition for the UIO attribute *rich_text*,
“rich_text_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute *rich_text*,
“class_name” :: [str] :: the condition for the UIO attribute *class_name*,
“class_name_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute *class_name*,
“friendly_class_name” :: [str] :: the condition for the UIO attribute *friendly_class_name*,
“friendly_class_name_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute *friendly_class_name*,
“control_type” :: [str] :: the condition for the UIO attribute *control_type*,
“control_type_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute *control_type*,
“is_enabled” :: [bool] :: the condition for the UIO attribute *is_enabled*. If UI object is enabled on GUI,
“is_visible” :: [bool] :: the condition for the UIO attribute *is_visible*. If UI object is visible on GUI,
“backend” :: [str, “win32” || “uia”] :: the method of UIO extraction (default “win32”). ATTENTION! Current option can be only for the first item of the UIO selector. For the next items this option will be implemented from the first item.
},
{ … specification next level UIO }
* **UIOEI** - UI Object info object
]
### What is UIO?
UIO is a User Interface Object (pyOpenRPA terminology). For maximum compatibility, this instance is inherited from the object model developed in the [pywinauto library (click to get a list of available class functions)]([https://pywinauto.readthedocs.io/en/latest/code/pywinauto.base_wrapper.html](https://pywinauto.readthedocs.io/en/latest/code/pywinauto.base_wrapper.html)).
```
``
```
This approach allows us to implement useful functionality that has already been successfully developed in other libraries, and Supplement it with the missing functionality. In our case, the missing functionality is the ability to dynamically access UIO objects using UIO selectors.
### UIOSelector structure & example
UIOSelector is the list of condition items for the UIO in GUI. Each item has condition attributes for detect applicable UIO. Here is the description of the available condition attributes in item.
```
`
```
**Desciption**
```
[
{
"depth_start" :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
"depth_end" :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
"ctrl_index" || "index" :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
"title" :: [str] :: the condition for the UIO attribute *title*,
"title_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *title*,
"rich_text" :: [str] :: the condition for the UIO attribute *rich_text*,
"rich_text_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *rich_text*,
"class_name" :: [str] :: the condition for the UIO attribute *class_name*,
"class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *class_name*,
"friendly_class_name" :: [str] :: the condition for the UIO attribute *friendly_class_name*,
"friendly_class_name_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *friendly_class_name*,
"control_type" :: [str] :: the condition for the UIO attribute *control_type*,
"control_type_re" :: [str] :: regular expression (python ver) for the condition for the UIO attribute *control_type*,
"is_enabled" :: [bool] :: the condition for the UIO attribute *is_enabled*. If UI object is enabled on GUI,
"is_visible" :: [bool] :: the condition for the UIO attribute *is_visible*. If UI object is visible on GUI,
"backend" :: [str, "win32" || "uia"] :: the method of UIO extraction (default "win32"). ATTENTION! Current option can be only for the first item of the UIO selector. For the next items this option will be implemented from the first item.
},
{ ... specification next level UIO }
]
```
**The UIO selector example**
```
``
```
```
`
```
```
[
{“class_name”:”CalcFrame”, “backend”:”win32”}, # 1-st level UIO specification
{“title”:”Hex”, “depth_start”:3, “depth_end”: 3} # 3-rd level specification (because of attribute depth_start|depth_stop)
{"class_name":"CalcFrame", "backend":"win32"}, # 1-st level UIO specification
{"title":"Hex", "depth_start":3, "depth_end": 3} # 3-rd level specification (because of attribute depth_start|depth_stop)
]
```
```
``
```
### The UIDesktop module (OpenRPA/Robot/UIDesktop.py)
```
`
```
The UIDesktop is extension of the pywinauto module which provide access to the desktop apps by the **win32** and **ui automation** dll frameworks (big thx to the Microsoft :) ).
```
# EXAMPLE 1
from pyOpenRPA.Robot import UIDesktop
UIDesktop.UIOSelector_Get_UIO(
inSpecificationList=[
{"title":"notepad.exe"},{"title":"OK"}],
inElement=None,
inFlagRaiseException=True)
```
### The UIDesktop module (OpenRPA/Robot/UIDesktop.py)

@ -1,7 +1,5 @@
# 2. How to use
MARKDOWN CODE
## Content

@ -17,7 +17,7 @@ contain the root `toctree` directive. -->
pyOpenRPA is absolutely non-commercial project.
Please donate some $ if pyOpenRPA project is actual for you. Link to online donations.
[https://money.yandex.ru/to/4100115560661986](https://money.yandex.ru/to/4100115560661986)
[https://yoomoney.ru/to/4100115560661986](https://yoomoney.ru/to/4100115560661986)
## About
@ -160,70 +160,30 @@ The pyOpenRPA.Agent tool has been developed to maintain robot infrastructure (2+
In wiki you can use the following docs:
* ENG Guide HTML [
```
|OPEN GITLAB|
```
]([https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html))
* ENG Guide MarkDown [
```
|OPEN GITLAB|
```
]([https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md))
* ENG Guide PDF [
```
|WAIT|
```
]()
* ENG Guide HTML [[|OPEN GITLAB|]](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.html)
* RUS Article: Less cost - no paid RPA [
```
|OPEN HABR|
```
]([https://habr.com/ru/post/509644/](https://habr.com/ru/post/509644/))
* ENG Guide MarkDown [[|OPEN GITLAB|]](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md)
* RUS Tutorial Desktop UI [
* ENG Guide PDF
```
|OPEN HABR|
`[|WAIT|] <>`_
```
]([https://habr.com/ru/post/509644/](https://habr.com/ru/post/509644/)); [
```
|OPEN GITLAB|
```
]([https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md))
* RUS Article: Less cost - no paid RPA [[|OPEN HABR|]](https://habr.com/ru/post/506766/)
* RUS Tutorial Web UI [
* RUS Tutorial Desktop UI [[|OPEN HABR|]](https://habr.com/ru/post/509644/); [[|OPEN GITLAB|]](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md)
```
|OPEN HABR|
```
]([https://habr.com/ru/post/515310/](https://habr.com/ru/post/515310/)); [
* RUS Tutorial Web UI [[|OPEN HABR|]](https://habr.com/ru/post/515310/); [[|OPEN GITLAB|]](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md)
```
|OPEN GITLAB|
```
]([https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/WebGUI_Habr/readme.md))
* RUS Leaflet pyOpenRPA v4.pdf [[|OPEN GITLAB|]](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/pyOpenRPA/Wiki/RUS_Leaflet/RUSLeafletpyOpenRPAv4.pdf)
## Guide content
@ -253,15 +213,9 @@ In wiki you can use the following docs:
* 1. Description
* pyOpenRPA Robot
* 2. Defs
* Desktop app UI access (win32 and UI automation dlls)
* References
@ -271,7 +225,7 @@ In wiki you can use the following docs:
* How to execute RPA script
* Theory & practice. Desktop app UI access (win32 and UI automation dlls)
* Desktop app UI access (win32 and UI automation dlls)
* Theory & practice. WEB app UI access (selenium)

Loading…
Cancel
Save