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 MarkDown [|OPEN GITLAB|](Wiki/ENG_Guide/markdown/index.md)
- ENG Guide PDF [|WAIT|]() - 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 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 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 ## Copyrights & Contacts
pyOpenRPA is created by Ivan Maslov (Russia). Use it for free (MIT)! 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 # Def to check inGSettings and update structure to the backward compatibility
# !!! ATTENTION: Backward compatibility has been started from v1.1.13 !!! # !!! 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) # 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): def Update(inGSettings):
lL = inGSettings["Logger"] # Alias for logger lL = inGSettings["Logger"] # Alias for logger
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@ -8,7 +290,7 @@ def Update(inGSettings):
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if "Autocleaner" not in inGSettings: # Add "Autocleaner" structure 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 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 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 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 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 inGSettings["Server"]["RequestTimeoutSecFloat"] = 300 # Time to handle request in seconds
if lL: lL.warning( if lL: lL.warning(
f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Server' > 'RequestTimeoutSecFloat' property") # Log about compatibility 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 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 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 # 1.2.0 - general processor - contains old orchestrator processor + RDPActive processor
import http.client import time, copy, threading
import json # Run processor synchronious
import pdb # inThreadControlDict = {"ThreadExecuteBool":True}
import os def ProcessorRunSync(inGSettings, inRobotRDPThreadControlDict):
import sys """
import subprocess "ProcessorDict": { # Has been changed. New general processor (one threaded) v.1.2.0
import importlib "ActivityList": [ # List of the activities
import psutil
#Input arg
# [
# { # {
# "Type": <RemoteMachineProcessingRun>, # "Def":"DefAliasTest", # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
# host: <localhost>, # "ArgList":[1,2,3], # Args list
# port: <port>, # "ArgDict":{"ttt":1,"222":2,"dsd":3}, # Args dictionary
# bodyObject: <object dict, int, str, list> # "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# }, # },
# { ],
# "Type": "CMDStart", "AliasDefDict": {}, # Storage for def with Str alias. To use it see pyOpenRPA.Orchestrator.ControlPanel
# "Command": "" "CheckIntervalSecFloat": 1.0 # Interval for check gSettings in ProcessorDict > ActivityList
# }, "ExecuteBool": True # Flag to execute thread processor
# { """
# "Type": "OrchestratorRestart" lL = inGSettings["Logger"] # Logger alias
# }, inGSettings["ProcessorDict"]["ThreadIdInt"] = threading.get_ident() # fill Processor thread id
# { while inGSettings["ProcessorDict"]["ExecuteBool"]:
# "Type": "OrchestratorSessionSave" lActivityList = inGSettings["ProcessorDict"]["ActivityList"] # Alias
# }, if len(lActivityList)>0:
# { if lL: lL.debug(f'Processor ActivityList len: {len(lActivityList)}')
# "Type": "GlobalDictKeyListValueSet", lActivityItem = inGSettings["ProcessorDict"]["ActivityList"].pop(0) # Extract the first item from processor queue
# "KeyList": ["key1","key2",...], inRobotRDPThreadControlDict["ThreadExecuteBool"]=False # Stop the RobotRDPActive monitoring
# "Value": <List, Dict, String, int> ActivityListExecute(inGSettings = inGSettings, inActivityList = [lActivityItem]) # execute the activity item
# }, inRobotRDPThreadControlDict["ThreadExecuteBool"] = True # Continue the RobotRDPActive monitoring
# {
# "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)}
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: else:
lDict[lItem2] = {} time.sleep(inGSettings["ProcessorDict"]["CheckIntervalSecFloat"]) # Sleep when list is empty
lDict = lDict[lItem2]
# Set value # Execute ActivityItem list
lDict[lItem["KeyList"][-1]]+=lItem["Value"] # return the def result
lItem["Result"] = True def ActivityListExecute(inGSettings, inActivityList):
########################################################### lL = inGSettings["Logger"] # Logger alias
#Обработка команды GlobalDictKeyListValueGet lResultList = [] # init the result list
###########################################################
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: try:
#Подключить модуль для вызова for lActivityItem in inActivityList: # Iterate throught the activity list
lModule=importlib.import_module(lItem["ModuleName"]) if lL: lL.info(f'pyOpenRPA Processor.ActivityListExecute:: Def:{str(lActivityItem["Def"])}. Parameters are not available to see.')
#Найти функцию lDef = None # Def variable
lFunction=getattr(lModule,lItem["FunctionName"]) if callable(lActivityItem["Def"]): # CHeck if def is callable
lItem["Result"]=lFunction(*lItem.get("ArgList",[]),**lItem.get("ArgDict",{})) 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: except Exception as e:
if lL: lL.exception("Loop activity error: module/function not founded") if lL: lL.exception(f"pyOpenRPA Processor.ActivityListExecute: Exception in def execution - activity will be ignored.") # Logging
################################# lResultList.append(e) # return the generated exception
# Windows logon except Exception as e:
################################# if lL: lL.exception(f"pyOpenRPA Processor.ActivityListExecute: Exception when initialisation - All activity list will be ignored.") # Logging
if lItem["Type"] == "WindowsLogon": return lResultList # return the result list
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
def ActivityListOrDict(inActivityListOrDict): def __ActivityListVerify__(inActivityList):
#Check arg type (list or dict) """
if type(inActivityListOrDict)==list: Verify ActivityList variable - raise exception if input list is not list of dict with structure:
#List activity # "Def":"DefAliasTest", # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
lResult=[] # "ArgList":[1,2,3], # Args list
for lItem in inActivityListOrDict: # "ArgDict":{"ttt":1,"222":2,"dsd":3}, # Args dictionary
lResult.append(Activity(lItem)) # "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
return lResult # "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
if type(inActivityListOrDict)==dict:
#Dict activity
return Activity(inActivityListOrDict)
def CheckIfProcessRunning(processName): :param inActivityList:
''' :return:
Check if there is any running process that contains the given name processName. """
''' # CASE LIST
#Iterate over the all the running process if type(inActivityList) is list:
for proc in psutil.process_iter(): for lItem in inActivityList:
try: # CASE LIST item is LIST
# Check if process name contains the given name string. if type(lItem) is list:
if processName.lower() in proc.name().lower(): raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Your ActivityList item is list too. List of the list :(")
return True # CASE Item is not dict
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): if type(lItem) is not dict:
pass raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Your ActivityList item is is not dict")
return False; # 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 # Exit fullscreen mode
SessionScreenSize_X_Y_W_H(inSessionHex=inSessionHex, inXInt=10, inYInt=10, inWInt=550, SessionScreenSize_X_Y_W_H(inSessionHex=inSessionHex, inXInt=10, inYInt=10, inWInt=550,
inHInt=350) # Prepare little window inHInt=350) # Prepare little window
return lResult
# Check if session is in Full screen mode # Check if session is in Full screen mode
# Return True - is in fullscreen # Return True - is in fullscreen
# example print(Connector.SessionIsFullScreen("")) # example print(Connector.SessionIsFullScreen(""))
@ -305,11 +306,12 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
Clipboard.TextSet(lClipboardTextOld) Clipboard.TextSet(lClipboardTextOld)
lCrosscheckKeyStr = str(random.randrange(999,9999999)) lCrosscheckKeyStr = str(random.randrange(999,9999999))
lRecoveryCMDResponsibleRetryIteratorInt = 0 # Init the retry iterator lRecoveryCMDResponsibleRetryIteratorInt = 0 # Init the retry iterator
lCommandIsTooBigBool = False
lCMDPostFixStr = "" # Case default "RUN"
while lRecoveryCMDResponsibleRetryIteratorInt<gRecoveryCMDResponsibleRetryCountInt: # loop for retry while lRecoveryCMDResponsibleRetryIteratorInt<gRecoveryCMDResponsibleRetryCountInt: # loop for retry
# # # # # # # # # # # # # OPEN WINDOW RUN # # # # # # # # # # # # # # # # # # # # # # # # # # # # OPEN WINDOW RUN # # # # # # # # # # # # # # #
lRecoveryWindowRUNRetryIteratorInt = 0 # Init the retry iterator lRecoveryWindowRUNRetryIteratorInt = 0 # Init the retry iterator
while lRecoveryWindowRUNRetryIteratorInt<gRecoveryWindowRUNRetryCountInt: # loop for retry while lRecoveryWindowRUNRetryIteratorInt<gRecoveryWindowRUNRetryCountInt: # loop for retry
lCMDPostFixStr = "" # Case default "RUN"
if inModeStr == "CROSSCHECK": if inModeStr == "CROSSCHECK":
#lCMDPostFixStr = f"& (echo {lCrosscheckKeyStr} | clip)" #lCMDPostFixStr = f"& (echo {lCrosscheckKeyStr} | clip)"
lCMDPostFixStr = f"| (echo {lCrosscheckKeyStr} | clip)" # Bugfix async set clipboard data 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 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... 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 lInputStr = f"cmd /c ({inCMDCommandStr}) {lCMDPostFixStr}" # Generate the output string for RUN window
if len(lInputStr) <= 259:
keyboard.write(lInputStr) # Write new text 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) time.sleep(gKeyboardHotkeyDelaySecFloat)
# Check if autocomplete # 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 if lClipboardStr == lInputStr: # Cross check the clipboard data and input string
lRecoveryWindowRUNRetryIteratorInt = gRecoveryWindowRUNRetryCountInt # Set final count to block the loop lRecoveryWindowRUNRetryIteratorInt = gRecoveryWindowRUNRetryCountInt # Set final count to block the loop
else: # Failed - wait and retry 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 lRecoveryWindowRUNRetryIteratorInt = lRecoveryWindowRUNRetryIteratorInt + 1 # Increment the iterator
if lRecoveryWindowRUNRetryIteratorInt == gRecoveryWindowRUNRetryCountInt: 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 raise ConnectorExceptions.RUNExistError() # Raise the error
time.sleep(gRecoveryWindowRUNRetryIntervalSecInt) # wait for some seconds before new iteration time.sleep(gRecoveryWindowRUNRetryIntervalSecInt) # wait for some seconds before new iteration
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # RUN CMD # # # # # # # # # # # # # # # # # # # # # # # # # # # # 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 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) if inModeStr == "CROSSCHECK" or inModeStr == "LISTEN": # Get OutStr (Case CROSSCHECK and LISTEN)
lClipboardWaitTimeStartSec = time.time() lClipboardWaitTimeStartSec = time.time()
lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard 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 lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard
time.sleep(0.5) # wait some time for the next operation time.sleep(0.5) # wait some time for the next operation
if lResult["OutStr"] == lClipboardTextOld: # If value hasn't been changed - retry send if lResult["OutStr"] == lClipboardTextOld: # If value hasn't been changed - retry send
lRecoveryCMDResponsibleRetryIteratorInt = lRecoveryCMDResponsibleRetryIteratorInt + 1 # increment the iterator 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 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 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 raise ConnectorExceptions.CMDResponsibleError() # Raise the error
time.sleep(gRecoveryCMDResponsibleRetryIntervalSecInt) # wait for some seconds before new iteration time.sleep(gRecoveryCMDResponsibleRetryIntervalSecInt) # wait for some seconds before new iteration
else: # Data was recieved - do crosscheck else: # Data was recieved - do crosscheck
@ -380,7 +401,7 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
lRecoveryCMDResponsibleRetryIteratorInt = lRecoveryCMDResponsibleRetryIteratorInt + 1 # increment the iterator 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 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 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 raise ConnectorExceptions.CMDResponsibleError() # Raise the error
time.sleep(gRecoveryCMDResponsibleRetryIntervalSecInt) # wait for some seconds before new iteration 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 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 Connector
from . import Processor # Module for process some functions on thr RDP from . import Processor # Module for process some functions on thr RDP
# Main function # Main function
def RobotRDPActive(inGSettings): # inThreadControlDict = {"ThreadExecuteBool":True}
def RobotRDPActive(inGSettings, inThreadControlDict):
# inGSettings = { # inGSettings = {
# ... "RobotRDPActive": {} ... # ... "RobotRDPActive": {} ...
# } # }
@ -36,6 +37,7 @@ def RobotRDPActive(inGSettings):
lResponsibilityCheckLastSec = time.time() # Get current time for check interval lResponsibilityCheckLastSec = time.time() # Get current time for check interval
while lFlagWhile: while lFlagWhile:
try: try:
if inThreadControlDict["ThreadExecuteBool"] == True:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check RDP window is OK - reconnect if connection was lost # Check RDP window is OK - reconnect if connection was lost
lUIOSelectorList = [] lUIOSelectorList = []
@ -65,19 +67,6 @@ def RobotRDPActive(inGSettings):
if lL: lL.exception(f"!!! ATTENTION !!! Unrecognized error") #Logging if lL: lL.exception(f"!!! ATTENTION !!! Unrecognized error") #Logging
pass 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 Connector.SystemRDPWarningClickOk() # Click all warning messages
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check if RDP session is full screen (if is not ignored) # Check if RDP session is full screen (if is not ignored)
@ -93,16 +82,19 @@ def RobotRDPActive(inGSettings):
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]: for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem] lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]): 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, Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"], inXInt=10, inYInt=10,
inWInt=550, inWInt=550,
inHInt=350) # Prepare little window inHInt=350) # Prepare little window
# Set full screen for new 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]) Connector.SessionScreenFull(inSessionHex=lRDPConfigurationDict["SessionHex"], inLogger= inGSettings["Logger"], inRDPConfigurationItem=inGlobalDict["RDPList"][lRDPSessionKeyStrItem])
else: else:
# Check all RDP window and minimize it # Check all RDP window and minimize it
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]: for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem] 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 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"], Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"],
inXInt=10, inYInt=10, inXInt=10, inYInt=10,
inWInt=550, inWInt=550,

@ -11,7 +11,8 @@ from socketserver import ThreadingMixIn
import threading import threading
import json import json
from threading import Thread 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 urllib.parse # decode URL in string
import importlib import importlib
import pdb import pdb
@ -22,9 +23,26 @@ import os #for path operations
from http import cookies from http import cookies
global gSettingsDict global gSettingsDict
from . import ServerSettings from . import ServerSettings
from . import __Orchestrator__
import copy 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 () #Authenticate function ()
# return dict # return dict
# { # {
@ -41,10 +59,10 @@ def AuthenticateVerify(inRequest):
lCookieAuthToken = lCookies.get("AuthToken", "").value lCookieAuthToken = lCookies.get("AuthToken", "").value
if lCookieAuthToken: if lCookieAuthToken:
#Find AuthToken in GlobalDict #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 #Auth Token Has Been Founded
lResult["Domain"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"] lResult["Domain"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"] lResult["User"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
#Set auth token #Set auth token
inRequest.OpenRPA["AuthToken"] = lCookieAuthToken inRequest.OpenRPA["AuthToken"] = lCookieAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"] inRequest.OpenRPA["Domain"] = lResult["Domain"]
@ -63,26 +81,18 @@ def AuthenticateVerify(inRequest):
if "\\" in lUser: if "\\" in lUser:
lDomain = lUser.split("\\")[0] lDomain = lUser.split("\\")[0]
lUser = lUser.split("\\")[1] lUser = lUser.split("\\")[1]
#Try to logon - use processor lLogonBool = __Orchestrator__.OSCredentialsVerify(inUserStr=lUser, inPasswordStr=lPassword, inDomainStr=lDomain)
lLogonResult = Processor.Activity(
{
"Type": "WindowsLogon",
"Domain": lDomain,
"User": lUser,
"Password": lPassword
}
)
#Check result #Check result
if lLogonResult["Result"]: if lLogonBool:
lResult["Domain"] = lLogonResult["Domain"] lResult["Domain"] = lDomain
lResult["User"] = lLogonResult["User"] lResult["User"] = lUser
#Create token #Create token
lAuthToken=str(uuid.uuid1()) lAuthToken=str(uuid.uuid1())
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {} gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"] gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"] gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now() gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
#Set-cookie #Set-cookie
inRequest.OpenRPA["AuthToken"] = lAuthToken inRequest.OpenRPA["AuthToken"] = lAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"] inRequest.OpenRPA["Domain"] = lResult["Domain"]
@ -123,13 +133,14 @@ def UserAccessCheckBefore(inMethod, inRequest):
#go next if user is identified #go next if user is identified
lUserDict = None lUserDict = None
if lAuthToken: if lAuthToken:
lUserDict = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] lUserDict = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
#pdb.set_trace() #pdb.set_trace()
######################################## ########################################
######################################## ########################################
#Check general before rule (without User domain) #Check general before rule (without User domain)
#Check rules #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 #Go next execution if flag is false
if not lResult: if not lResult:
#Check if Method is identical #Check if Method is identical
@ -161,7 +172,9 @@ def UserAccessCheckBefore(inMethod, inRequest):
#Check access by User Domain #Check access by User Domain
#Check rules to find first appicable #Check rules to find first appicable
#Check rules #Check rules
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []): 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 #Go next execution if flag is false
if not lResult: if not lResult:
#Check if Method is identical #Check if Method is identical
@ -186,6 +199,8 @@ def UserAccessCheckBefore(inMethod, inRequest):
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE": elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path: if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
else:
return True
##################################### #####################################
##################################### #####################################
#Return lResult #Return lResult
@ -193,6 +208,8 @@ def UserAccessCheckBefore(inMethod, inRequest):
# HTTPRequestHandler class # HTTPRequestHandler class
class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Def to check User Role access grants # Def to check User Role access grants
def UACClientCheck(self, inRoleKeyList): # Alias
return self.UserRoleAccessAsk(inRoleKeyList=inRoleKeyList)
def UserRoleAccessAsk(self, inRoleKeyList): def UserRoleAccessAsk(self, inRoleKeyList):
lResult = True # Init flag lResult = True # Init flag
lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy
@ -218,7 +235,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
def UserRoleHierarchyGet(self): def UserRoleHierarchyGet(self):
lDomainUpperStr = self.OpenRPA["Domain"].upper() lDomainUpperStr = self.OpenRPA["Domain"].upper()
lUserUpperStr = self.OpenRPA["User"].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 #Tech def
#return {"headers":[],"body":"","statuscode":111} #return {"headers":[],"body":"","statuscode":111}
@ -316,6 +333,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Write content as utf-8 data # Write content as utf-8 data
self.wfile.write(inResponseDict["Body"]) self.wfile.write(inResponseDict["Body"])
def do_GET(self): def do_GET(self):
try:
self.OpenRPA = {} self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None self.OpenRPA["Domain"] = None
@ -331,7 +349,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
##################################### #####################################
lFlagAccessUserBlock=False lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""} lAuthenticateDict = {"Domain": "", "User": ""}
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self) lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]: if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True lFlagAccessUserBlock=True
@ -345,7 +363,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#################################### ####################################
lFlagUserAccess = True lFlagUserAccess = True
#If need user authentication #If need user authentication
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("GET", self) lFlagUserAccess = UserAccessCheckBefore("GET", self)
###################################### ######################################
if lFlagUserAccess: if lFlagUserAccess:
@ -353,7 +371,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
############################ ############################
#New server engine (url from global dict (URLList)) #New server engine (url from global dict (URLList))
############################ ############################
for lURLItem in gSettingsDict["Server"]["URLList"]: for lURLItem in gSettingsDict["ServerDict"]["URLList"]:
#Check if all condition are applied #Check if all condition are applied
lFlagURLIsApplied=False lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET") lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET")
@ -383,8 +401,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
self.send_response(403) self.send_response(403)
# Send headers # Send headers
self.end_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 # POST
def do_POST(self): def do_POST(self):
try:
lL = gSettingsDict["Logger"] lL = gSettingsDict["Logger"]
self.OpenRPA = {} self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None self.OpenRPA["AuthToken"] = None
@ -403,11 +425,10 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
lFlagAccessUserBlock=False lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""} lAuthenticateDict = {"Domain": "", "User": ""}
lIsSuperToken = False # Is supertoken lIsSuperToken = False # Is supertoken
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self) lAuthenticateDict = AuthenticateVerify(self)
# Get Flag is supertoken (True|False) # Get Flag is supertoken (True|False)
lIsSuperToken = gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get( lIsSuperToken = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(self.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
self.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
if not lAuthenticateDict["User"]: if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True lFlagAccessUserBlock=True
if lFlagAccessUserBlock: if lFlagAccessUserBlock:
@ -418,7 +439,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#################################### ####################################
lFlagUserAccess = True lFlagUserAccess = True
#If need user authentication #If need user authentication
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("POST", self) lFlagUserAccess = UserAccessCheckBefore("POST", self)
###################################### ######################################
if lFlagUserAccess: if lFlagUserAccess:
@ -426,7 +447,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
############################ ############################
#New server engine (url from global dict (URLList)) #New server engine (url from global dict (URLList))
############################ ############################
for lURLItem in gSettingsDict["Server"]["URLList"]: for lURLItem in gSettingsDict["ServerDict"]["URLList"]:
#Check if all condition are applied #Check if all condition are applied
lFlagURLIsApplied=False lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST") lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST")
@ -449,9 +470,18 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
self.end_headers() self.end_headers()
# Logging info about processor activity if not SuperToken () # Logging info about processor activity if not SuperToken ()
if not lIsSuperToken: if not lIsSuperToken:
if lL: lL.info(f"Server:: User activity from web. Domain: {self.OpenRPA['Domain']}, Username: {self.OpenRPA['User']}, Activity: {lInputObject}") 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 # Send message back to client
message = json.dumps(Processor.ActivityListOrDict(lInputObject)) message = json.dumps(ProcessorOld.ActivityListOrDict(lInputObject))
# Write content as utf-8 data # Write content as utf-8 data
self.wfile.write(bytes(message, "utf8")) self.wfile.write(bytes(message, "utf8"))
return return
@ -462,6 +492,9 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Send headers # Send headers
self.end_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 #Logging
#!Turn it on to stop print in console #!Turn it on to stop print in console
#def log_message(self, format, *args): #def log_message(self, format, *args):
@ -470,7 +503,7 @@ class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
daemon_threads = True daemon_threads = True
"""Handle requests in a separate thread.""" """Handle requests in a separate thread."""
def finish_request(self, request, client_address): 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 # "super" can not be used because BaseServer is not created from object
HTTPServer.finish_request(self, request, client_address) HTTPServer.finish_request(self, request, client_address)
#inGlobalDict #inGlobalDict
@ -483,7 +516,7 @@ class RobotDaemonServer(Thread):
ServerSettings.SettingsUpdate(inGlobalDict) ServerSettings.SettingsUpdate(inGlobalDict)
def run(self): def run(self):
inServerAddress=""; inServerAddress="";
inPort = gSettingsDict["Server"]["ListenPort"]; inPort = gSettingsDict["ServerDict"]["ListenPort"];
# Server settings # Server settings
# Choose port 8080, for port 80, which is normally used for a http server, you need root access # Choose port 8080, for port 80, which is normally used for a http server, you need root access
server_address = (inServerAddress, inPort) 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 inspect import signature # For detect count of def args
from . import __Orchestrator__
#ControlPanelDict #ControlPanelDict
from desktopmagic.screengrab_win32 import ( from desktopmagic.screengrab_win32 import (
getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage, getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage,
@ -9,163 +11,234 @@ import uuid # generate UUID4
import time # sleep functions import time # sleep functions
import datetime # datetime functions import datetime # datetime functions
import threading # Multi-threading import threading # Multi-threading
from .Web import Basic
# /Orchestrator/RobotRDPActive/ControlPanelDictGet from . import BackwardCompatibility # Support old up to 1.2.0 defs
def RobotRDPActive_ControlPanelDictGet(inRequest,inGlobalDict): from . import Processor
inResponseDict = inRequest.OpenRPAResponseDict from . import SettingsTemplate
lResultDict = { # # # # # # # # # # # #
"DataList":[ # v 1.2.0 Functionallity
# {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False} # # # # # # # # # # # #
] # Generate JS when page init
} def HiddenJSInitGenerate(inRequest, inGSettings):
# Iterate throught the RDP List dUAC = inRequest.UACClientCheck # Alias.
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]: lUACCPTemplateKeyList=["pyOpenRPADict","CPKeyDict"]
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][lRDPSessionKeyStrItem] # Get the configuration dict lL = inGSettings["Logger"] # Alias for logger
lDataItemDict = {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False} # Template lJSInitResultStr = ""
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str lRenderFunctionsRobotDict = inGSettings["CPDict"]
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex for lItemKeyStr in lRenderFunctionsRobotDict:
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"]["FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window lItemDict = lRenderFunctionsRobotDict[lItemKeyStr]
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored lJSInitGeneratorDef = lItemDict.get("JSInitGeneratorDef",None)
lResultDict["DataList"].append(lDataItemDict) lUACBool = dUAC(inRoleKeyList=lUACCPTemplateKeyList+[lItemKeyStr]) # Check if render function is applicable User Access Rights (UAC)
# Send message back to client if lItemKeyStr=="VersionCheck": lUACBool=True # For backward compatibility for the old fron version which not reload page when new orch version is comming
message = json.dumps(lResultDict) if lUACBool: # Run function if UAC is TRUE
# Write content as utf-8 data # JSONGeneratorDef
inResponseDict["Body"] = bytes(message, "utf8") if lJSInitGeneratorDef is not None: # Call def (inRequest, inGSettings) or def (inGSettings)
lJSResult = None
# def to check control panels for selected session lDEFSignature = signature(lJSInitGeneratorDef) # Get signature of the def
def Monitor_ControlPanelDictGet_SessionCheckInit(inRequest,inGlobalDict): lDEFARGLen = len(lDEFSignature.parameters.keys()) # get count of the def args
lL = inGlobalDict["Logger"] # Alias for logger try:
lLifetimeSecFloat = inGlobalDict["Client"]["Session"]["LifetimeSecFloat"] if lDEFARGLen == 1: # def (inGSettings)
lLifetimeRequestSecFloat = inGlobalDict["Client"]["Session"]["LifetimeRequestSecFloat"] lJSResult = lJSInitGeneratorDef(inGSettings)
lControlPanelRefreshIntervalSecFloat = inGlobalDict["Client"]["Session"]["ControlPanelRefreshIntervalSecFloat"] elif lDEFARGLen == 2: # def (inRequest, inGSettings)
lCookieSessionGUIDStr = None # generate the new GUID lJSResult = lJSInitGeneratorDef(inRequest, inGSettings)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # elif lDEFARGLen == 0: # def ()
# Technicaldef - interval check control panels + check actuality of the session by the datetime lJSResult = lJSInitGeneratorDef()
def TechnicalCheck(): if type(lJSResult) is str:
lItemValue = inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr] lJSInitResultStr += "; "+lJSResult # Add delimiter to some cases
# 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: else:
lCookieSessionGUIDStr = TechnicalSessionNew(inSessionGUIDStr = lCookieSessionGUIDStr) # Create new session if lL: lL.warning(f"JSInitGenerator return bad type: {str(type(lJSResult))}, CP Key {lItemKeyStr}")
if lDoWhileBool: # Sleep if we wait hte next iteration except Exception as e:
time.sleep(lControlPanelRefreshIntervalSecFloat) # Sleep to the next iteration if lL: lL.exception(f"Error in control panel JSInitGeneratorDef. CP Key {lItemKeyStr}. Exception are below")
return lJSInitResultStr
def Monitor_ControlPanelDictGet(inRequest,inGlobalDict): # Generate CP HTML + JSON
inResponseDict = inRequest.OpenRPAResponseDict # Return {"Key":{"",""}}
lL = inGlobalDict["Logger"] # Alias for logger def HiddenCPDictGenerate(inRequest, inGSettings):
dUAC = inRequest.UACClientCheck # Alias.
lUACCPTemplateKeyList=["pyOpenRPADict","CPKeyDict"]
lL = inGSettings["Logger"] # Alias for logger
# Create result JSON # Create result JSON
lResultJSON = {"RenderRobotList": [], "RenderRDPList": []} lCPDict = {}
lRenderFunctionsRobotList = inGlobalDict["ControlPanelDict"]["RobotList"] lRenderFunctionsRobotDict = inGSettings["CPDict"]
for lItem in lRenderFunctionsRobotList: for lItemKeyStr in lRenderFunctionsRobotDict:
lUACBool = True # Check if render function is applicable User Access Rights (UAC) lItemDict = lRenderFunctionsRobotDict[lItemKeyStr]
if inGlobalDict["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True: lItemHTMLRenderDef = lItemDict.get("HTMLRenderDef",None)
lUserRights = inGlobalDict["Server"]["AccessUsers"]["RuleDomainUserDict"][(inRequest.OpenRPA["Domain"].upper(),inRequest.OpenRPA["User"].upper())] lItemJSONGeneratorDef = lItemDict.get("JSONGeneratorDef",None)
if len(lUserRights["ControlPanelKeyAllowedList"]) > 0 and lItem["KeyStr"] not in lUserRights["ControlPanelKeyAllowedList"]: lUACBool = dUAC(inRoleKeyList=lUACCPTemplateKeyList+[lItemKeyStr]) # Check if render function is applicable User Access Rights (UAC)
lUACBool = False # UAC Check is not passed - False for user 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 if lUACBool: # Run function if UAC is TRUE
# Выполнить вызов и записать результат lCPItemDict = {"HTMLStr": None, "JSONDict":None}
# Call def (inRequest, inGSettings) or def (inGSettings) # HTMLRenderDef
lItemResultDict = None if lItemHTMLRenderDef is not None: # Call def (inRequest, inGSettings) or def (inGSettings)
lDEFSignature = signature(lItem["RenderFunction"]) # Get signature of the def lHTMLResult = None
lDEFSignature = signature(lItemHTMLRenderDef) # Get signature of the def
lDEFARGLen = len(lDEFSignature.parameters.keys()) # get count of the def args lDEFARGLen = len(lDEFSignature.parameters.keys()) # get count of the def args
try: try:
if lDEFARGLen == 1: # def (inGSettings) if lDEFARGLen == 1: # def (inGSettings)
lItemResultDict = lItem["RenderFunction"](inGlobalDict) lHTMLResult = lItemHTMLRenderDef(inGSettings)
elif lDEFARGLen == 2: # def (inRequest, inGSettings) elif lDEFARGLen == 2: # def (inRequest, inGSettings)
lItemResultDict = lItem["RenderFunction"](inRequest, inGlobalDict) lHTMLResult = lItemHTMLRenderDef(inRequest, inGSettings)
elif lDEFARGLen == 0: # def () elif lDEFARGLen == 0: # def ()
lItemResultDict = lItem["RenderFunction"]() lHTMLResult = lItemHTMLRenderDef()
# RunFunction # RunFunction
lResultJSON["RenderRobotList"].append(lItemResultDict) # 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: except Exception as e:
if lL: lL.exception(f"Error in control panel. CP item {lItem}. Exception is below") 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 # Iterate throught the RDP list
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]: for lRDPSessionKeyStrItem in inGSettings["RobotRDPActive"]["RDPList"]:
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][ # Check UAC
if dUAC(inRoleKeyList=lUACRDPTemplateKeyList+[lRDPSessionKeyStrItem]):
lRDPConfiguration = inGSettings["RobotRDPActive"]["RDPList"][
lRDPSessionKeyStrItem] # Get the configuration dict lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr": "", "SessionHexStr": "", "IsFullScreenBool": False, lDataItemDict = {"SessionKeyStr": "", "SessionHexStr": "", "IsFullScreenBool": False,
"IsIgnoredBool": False} # Template "IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"][ lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGSettings["RobotRDPActive"][
"FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window "FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lResultJSON["RenderRDPList"].append(lDataItemDict) 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
#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
# Send message back to client # Send message back to client
message = json.dumps(lResultJSON) message = json.dumps(lResult)
# Write content as utf-8 data # Write content as utf-8 data
#inResponseDict["Body"] = bytes(message, "utf8") inResponseDict["Body"] = bytes(message, "utf8")
return bytes(message, "utf8") return lResult
# UserAccess get rights hierarchy dict in json
def UserRoleHierarchyGet(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
# Write content as utf-8 data
inResponseDict["Body"] = bytes(lResultStr, "utf8")
#v1.2.0 Send data container to the client from the server
# /pyOpenRPA/ServerLog return {"HashStr" , "ServerLogList": ["row 1", "row 2"]}
# Client: mGlobal.pyOpenRPA.ServerLogListHashStr
# 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 inResponseDict = inRequest.OpenRPAResponseDict
# Create result JSON
lResultDict = inRequest.OpenRPA["DefUserRoleHierarchyGet"]() # Get the User Role Hierarchy list
# Send message back to client # Send message back to client
message = json.dumps(lResultDict) message = json.dumps(lResult)
# Write content as utf-8 data # Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8") inResponseDict["Body"] = bytes(message, "utf8")
return lResult
def GetScreenshot(inRequest,inGlobalDict): def pyOpenRPA_Screenshot(inRequest,inGlobalDict):
# Get Screenshot # Get Screenshot
def SaveScreenshot(inFilePath): def SaveScreenshot(inFilePath):
# grab fullscreen # grab fullscreen
@ -182,6 +255,139 @@ def GetScreenshot(inRequest,inGlobalDict):
inRequest.OpenRPAResponseDict["Body"] = lFileObject.read() inRequest.OpenRPAResponseDict["Body"] = lFileObject.read()
# Закрыть файловый объект # Закрыть файловый объект
lFileObject.close() 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): def SettingsUpdate(inGlobalConfiguration):
import os import os
import pyOpenRPA.Orchestrator 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": "/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": "/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": "/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": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_Monitor_ControlPanelDictGet_SessionCheckInit, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": GetScreenshot, "ResponseContentType": "image/png"}, {"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": "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 return inGlobalConfiguration

@ -1,4 +1,5 @@
var mGlobal={} var mGlobal={}
mGlobal.pyOpenRPA = {}
window.onload=function() { window.onload=function() {
//document.cookie = "SessionGUIDStr=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; //document.cookie = "SessionGUIDStr=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
//Render existing data //Render existing data
@ -121,11 +122,17 @@ $(document).ready(function() {
lCMDCode=$(".openrpa-controller-cmd-run-input")[0].value lCMDCode=$(".openrpa-controller-cmd-run-input")[0].value
///Подготовить конфигурацию ///Подготовить конфигурацию
lData = [ 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({ $.ajax({
type: "POST", type: "POST",
url: 'Utils/Processor', url: '/pyOpenRPA/ActivityListExecute',
data: JSON.stringify(lData), data: JSON.stringify(lData),
success: success:
function(lData,l2,l3) function(lData,l2,l3)
@ -221,7 +228,7 @@ $(document).ready(function() {
} }
//inHostURI: http://localhost:8081 //inHostURI: http://localhost:8081
mGlobal.Monitor.ScreenshotModal.Show=function(inHostURI=" ") { 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() { lScreenshotUpdate=function() {
@ -276,7 +283,22 @@ $(document).ready(function() {
mGlobal.Monitor.fControlPanelRefresh_TechnicalRender = function() mGlobal.Monitor.fControlPanelRefresh_TechnicalRender = function()
{ {
lResponseJSON = mGlobal.Monitor.mDatasetLast lResponseJSON = mGlobal.Monitor.mDatasetLast
if (lResponseJSON!= null) { if (lResponseJSON!= null) {
/// 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 ///Escape onclick
/// RenderRobotList /// RenderRobotList
lResponseJSON["RenderRobotList"].forEach( lResponseJSON["RenderRobotList"].forEach(
@ -307,7 +329,7 @@ $(document).ready(function() {
); );
////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////
///Сформировать HTML код новой таблицы - контрольная панель ///Сформировать HTML код новой таблицы - контрольная панель
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-control-panel",lResponseJSON) lHTMLCode+=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-control-panel",lResponseJSON)
//Присвоить ответ в mGlobal.Monitor.mResponseList //Присвоить ответ в mGlobal.Monitor.mResponseList
mGlobal.Monitor.mResponseList = lResponseJSON mGlobal.Monitor.mResponseList = lResponseJSON
///Set result in mGlobal.DataStorage ///Set result in mGlobal.DataStorage
@ -321,7 +343,7 @@ $(document).ready(function() {
///Прогрузить новую таблицу ///Прогрузить новую таблицу
$(".openrpa-control-panel").html(lHTMLCode) $(".openrpa-control-panel").html(lHTMLCode)
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
///Сформировать HTML код новой таблицы - список RDP /// !RDP List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON) lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON)
//Присвоить ответ в mGlobal.RobotRDPActive.mResponseList //Присвоить ответ в mGlobal.RobotRDPActive.mResponseList
mGlobal.RobotRDPActive.mResponseList = lResponseJSON mGlobal.RobotRDPActive.mResponseList = lResponseJSON
@ -329,72 +351,274 @@ $(document).ready(function() {
$(".openrpa-robotrdpactive-control-panel").html(lHTMLCode) $(".openrpa-robotrdpactive-control-panel").html(lHTMLCode)
///Очистить дерево ///Очистить дерево
//mGlobal.ElementTree.fClear(); //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();
} }
} }
mGlobal.Monitor.mDatasetLast = null }
mGlobal.Monitor.fControlPanelRefresh=function() {
///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 { try {
//var XHR = new XMLHttpRequest();
//XHR.setRequestHeader("Cookies",document.cookie)
///Загрузка данных
//console.log("Request is sent")
//console.log(document.cookie)
$.ajax({ $.ajax({
type: "GET", type: "GET",
headers: {"SessionGUIDStr":mGlobal.SessionGUIDStr}, headers: {},
url: 'Monitor/ControlPanelDictGet', url: 'pyOpenRPA/ServerJSInit',
data: '', data: mGlobal.pyOpenRPA.ServerDataHashStr,
//cache: false, async: false,
//xhr: XHR, 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)
////////////////////////////////////////////////////
/// !RDP List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON["RDPDict"])
//Присвоить ответ в mGlobal.RobotRDPActive.mResponseList
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.pyOpenRPA.ServerDataRefreshDef=function() {
try {
$.ajax({
type: "POST",
headers: {},
url: 'pyOpenRPA/ServerData',
data: mGlobal.pyOpenRPA.ServerDataHashStr,
success: function(lData,l2,l3) { success: function(lData,l2,l3) {
try { try {
var lResponseJSON=JSON.parse(lData) var lResponseJSON=JSON.parse(lData)
mGlobal.Monitor.mDatasetLast = lResponseJSON mGlobal.VersionStr = lResponseJSON["ServerDataDict"]["UserDict"]["VersionStr"]
mGlobal.Monitor.fControlPanelRefresh_TechnicalRender() 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) { catch(error) {
console.log(error)
setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000)
} }
mGlobal.Monitor.fControlPanelRefresh() // recursive //mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive
}, },
dataType: "text", dataType: "text",
error: function(jqXHR, textStatus, errorThrown ) { error: function(jqXHR, textStatus, errorThrown ) {
sleep(3000) setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000)
mGlobal.Monitor.fControlPanelRefresh() // recursive //sleep(3000)
//mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive
} }
}); });
} }
catch(error) { catch(error) {
sleep(3000) setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000)
mGlobal.Monitor.fControlPanelRefresh() // recursive //sleep(3000)
//mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive
} }
//mGlobal.Monitor.fControlPanelRefresh() // recursive
} }
mGlobal.Monitor.fControlPanelRefresh() /////////////////////////////////////////////////////////////
mGlobal.Test=function() { /// v1.2.0 pyOpenRPA ServerLogs
///Обнулить таблицу mGlobal.pyOpenRPA.ServerLogList = null
lData = [ 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()
{ {
"Type":"GlobalDictKeyListValueSet", lResponseJSON = mGlobal.pyOpenRPA.ServerLogList
"key_list":["Storage","Robot_R01"], if (lResponseJSON!= null && mGlobal.pyOpenRPA.ServerLogListDoRenderBool==true) {
"value":{ lText = lResponseJSON.join("\n") /// Code for the processing the text
"RunDateTimeString":"Test1", $("textarea.mGlobal-pyOpenRPA-ServerLogList")[0].value= lText ///Прогрузить новую таблицу
"StepCurrentName":"Test2", mGlobal.pyOpenRPA.ServerLogListScrollBottomDef() //Scroll to the bottom
"StepCurrentDuration":"Test3"
} }
} }
] mGlobal.pyOpenRPA.ServerLogListRefreshDef=function() {
try {
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: 'Utils/Processor', headers: {},
data: JSON.stringify(lData), url: 'pyOpenRPA/ServerLog',
success: data: mGlobal.pyOpenRPA.ServerLogListHashStr,
function(lData,l2,l3) success: function(lData,l2,l3) {
{ try {
//console.log(lData) 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" dataType: "text",
error: function(jqXHR, textStatus, errorThrown ) {
setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,3000)
//sleep(3000)
//mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive
}
}); });
} }
catch(error) {
setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,3000)
//sleep(3000)
//mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive
}
}
/////////////////////////////////////////////////////////////
mGlobal.Monitor.mDatasetLast = null
/////////////////////////////// ///////////////////////////////
///Processor functions ///Processor functions
/////////////////////////////// ///////////////////////////////
@ -615,7 +839,7 @@ $(document).ready(function() {
// UAC Ask // UAC Ask
mGlobal.UserRoleAsk=function(inList) { mGlobal.UserRoleAsk=function(inList) {
var lResult = true; // Init flag 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 // Try to get value from key list
var lKeyValue = lRoleHierarchyDict; // Init the base var lKeyValue = lRoleHierarchyDict; // Init the base
var lListLength = inList.length; var lListLength = inList.length;
@ -641,64 +865,31 @@ $(document).ready(function() {
} }
// Check user roles and update the Orchestrator UI // Check user roles and update the Orchestrator UI
mGlobal.UserRoleUpdate=function() { 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 lUACAsk = mGlobal.UserRoleAsk // Alias
var lResponseList=JSON.parse(lData) //CPKeyDict
mGlobal.WorkingDirectoryPathStr = lResponseList[0]["Result"] if (lUACAsk(["pyOpenRPADict","CPKeyDict"])) { $(".UACClient-pyOpenRPADict-CPKeyDict").show(); }
},
dataType: "text" //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; &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> </div>
<div class="row"> <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"> <h4 class="ui horizontal divider header">
<i class="clipboard list icon"></i> <i class="clipboard list icon"></i>
Dashboard (Robot control panel) Dashboard (Robot control panel)
@ -116,37 +117,7 @@
</div> </div>
<div class="row"> <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>
</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>
</div>
<script class="openrpa-hidden-monitor-table-general" style="display:none" type="text/x-handlebars-template"> <script class="openrpa-hidden-monitor-table-general" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table"> <table class="ui celled table">
<thead> <thead>
@ -220,21 +191,18 @@
</div> </div>
</div> </div>
</script> </script>
</div> <div class="eight wide column openrpa-robotrdpactive-control-panel-general UACClient-pyOpenRPADict-RDPKeyDict" style="display:none;">
<div class="two wide column"> <h2 class="ui header openrpa-rdpactive-title">
</div> <i class="desktop icon"></i>
<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 class="content"> <div class="content">
RDP active list RDP active list
</div> </div>
</h2> </h2>
<div class="openrpa-robotrdpactive-control-panel"></div> <div class="openrpa-robotrdpactive-control-panel"></div>
<script class="openrpa-hidden-robotrdpactive-control-panel" style="display:none" type="text/x-handlebars-template"> <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"> <div class="ui inverted relaxed divided list">
{{#RenderRDPList}} {{#HandlebarsList}}
<div class="item"> <div class="item">
<div class="right floated content"> <div class="right floated content">
<div class="ui button" onclick="mGlobal.Processor.ServerValueAppend(['RobotRDPActive','ActivityList'],{'DefNameStr': 'RDPSessionReconnect', 'ArgList': [], 'ArgDict': {'inRDPSessionKeyStr': '{{{SessionKeyStr}}}'} })" >Reconnect</div> <div class="ui button" onclick="mGlobal.Processor.ServerValueAppend(['RobotRDPActive','ActivityList'],{'DefNameStr': 'RDPSessionReconnect', 'ArgList': [], 'ArgDict': {'inRDPSessionKeyStr': '{{{SessionKeyStr}}}'} })" >Reconnect</div>
@ -258,7 +226,38 @@
{{{SessionHexStr}}} {{{SessionHexStr}}}
</div> </div>
</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>
</div> </div>
</script> </script>
@ -269,6 +268,68 @@
<div class="row openrpa-monitor"> <div class="row openrpa-monitor">
</div> </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"> <div class="row black">
@ -341,11 +402,6 @@
</div> </div>
<div class="content"> <div class="content">
<img src="GetScreenshot" class="ui fluid image"> <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>
<div class="actions"> <div class="actions">
<div class="ui green ok inverted button" onclick="mGlobal.Monitor.ScreenshotModal.Close()"> <div class="ui green ok inverted button" onclick="mGlobal.Monitor.ScreenshotModal.Close()">

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

@ -1,4 +1,5 @@
import sys import sys
lFolderPath = "\\".join(__file__.split("\\")[:-3]) lFolderPath = "\\".join(__file__.split("\\")[:-3])
sys.path.insert(0, lFolderPath) 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 - выкинуть ошибку в случае обнаружении пустого списка #inFlagRaiseException - Флаг True - выкинуть ошибку в случае обнаружении пустого списка
#old name - PywinautoExtElementsGet #old name - PywinautoExtElementsGet
def UIOSelector_Get_UIOList (inSpecificationList,inElement=None,inFlagRaiseException=True): 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) inSpecificationList=copy.deepcopy(inSpecificationList)
lResultList=[] lResultList=[]
@ -232,6 +240,14 @@ def UIOSelector_Get_UIOList (inSpecificationList,inElement=None,inFlagRaiseExcep
#inFlagRaiseException - Флаг True - выкинуть ошибку в случае обнаружении пустого списка #inFlagRaiseException - Флаг True - выкинуть ошибку в случае обнаружении пустого списка
#old name - PywinautoExtElementGet #old name - PywinautoExtElementGet
def UIOSelector_Get_UIO (inSpecificationList,inElement=None,inFlagRaiseException=True): 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 lResult=None
#Получить родительский объект если на вход ничего не поступило #Получить родительский объект если на вход ничего не поступило
lResultList=UIOSelector_Get_UIOList(inSpecificationList,inElement,False) lResultList=UIOSelector_Get_UIOList(inSpecificationList,inElement,False)
@ -247,6 +263,12 @@ def UIOSelector_Get_UIO (inSpecificationList,inElement=None,inFlagRaiseException
#UIOSelector #UIOSelector
#old name - - #old name - -
def UIOSelector_Exist_Bool (inUIOSelector): 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 lResult=False
#Check the bitness #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
@ -280,6 +302,18 @@ def UIOSelector_Exist_Bool (inUIOSelector):
#####Внимание##### #####Внимание#####
##Функция ожидания появления элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться) ##Функция ожидания появления элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться)
def UIOSelectorsSecs_WaitAppear_List (inSpecificationListList,inWaitSecs,inFlagWaitAllInMoment=False): 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 lResultFlag=False
lSecsSleep = 1 #Настроечный параметр lSecsSleep = 1 #Настроечный параметр
lSecsDone = 0 lSecsDone = 0
@ -319,6 +353,19 @@ def UIOSelectorsSecs_WaitAppear_List (inSpecificationListList,inWaitSecs,inFlagW
#####Внимание##### #####Внимание#####
##Функция ожидания пропажи элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться) ##Функция ожидания пропажи элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться)
def UIOSelectorsSecs_WaitDisappear_List (inSpecificationListList,inWaitSecs,inFlagWaitAllInMoment=False): 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 lResultFlag=False
lSecsSleep = 1 #Настроечный параметр lSecsSleep = 1 #Настроечный параметр
lSecsDone = 0 lSecsDone = 0
@ -355,6 +402,13 @@ def UIOSelectorsSecs_WaitDisappear_List (inSpecificationListList,inWaitSecs,inFl
#return: Bool - True - UIO is appear #return: Bool - True - UIO is appear
#old name - - #old name - -
def UIOSelectorSecs_WaitAppear_Bool (inSpecificationList,inWaitSecs): 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) lWaitAppearList=UIOSelectorsSecs_WaitAppear_List([inSpecificationList],inWaitSecs)
lResult=False lResult=False
if len(lWaitAppearList)>0: if len(lWaitAppearList)>0:
@ -367,6 +421,14 @@ def UIOSelectorSecs_WaitAppear_Bool (inSpecificationList,inWaitSecs):
#return: Bool - True - UIO is Disappear #return: Bool - True - UIO is Disappear
#old name - - #old name - -
def UIOSelectorSecs_WaitDisappear_Bool (inSpecificationList,inWaitSecs): 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) lWaitDisappearList=UIOSelectorsSecs_WaitDisappear_List([inSpecificationList],inWaitSecs)
lResult=False lResult=False
if len(lWaitDisappearList)>0: if len(lWaitDisappearList)>0:
@ -378,6 +440,12 @@ def UIOSelectorSecs_WaitDisappear_Bool (inSpecificationList,inWaitSecs):
#old name - None #old name - None
#return None (if Process not found), int 32, or int 64 #return None (if Process not found), int 32, or int 64
def UIOSelector_Get_BitnessInt (inSpecificationList): 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 lResult=None
#Получить объект Application (Для проверки разрядности) #Получить объект Application (Для проверки разрядности)
lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList) lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList)
@ -393,6 +461,12 @@ def UIOSelector_Get_BitnessInt (inSpecificationList):
#old name - None #old name - None
#return None (if Process not found), int 32, or int 64 #return None (if Process not found), int 32, or int 64
def UIOSelector_Get_BitnessStr (inSpecificationList): 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 lResult=None
#Получить объект Application (Для проверки разрядности) #Получить объект Application (Для проверки разрядности)
lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList) lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList)
@ -407,15 +481,23 @@ def UIOSelector_Get_BitnessStr (inSpecificationList):
#old name - None #old name - None
#return int 32, or int 64 #return int 32, or int 64
def Get_OSBitnessInt (): def Get_OSBitnessInt ():
lResult=32; '''
Detect OS bitness.
:return: int 32 or int 64
'''
lResult=32
if pywinauto.sysinfo.is_x64_OS(): if pywinauto.sysinfo.is_x64_OS():
lResult=64; lResult=64
return lResult; 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): 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 #Default value
lResult = None lResult = None
#Go check bitness if selector exists #Go check bitness if selector exists
@ -426,11 +508,14 @@ def UIOSelector_SafeOtherGet_Process(inUIOSelector):
lResult = Utils.ProcessBitness.OtherProcessGet() lResult = Utils.ProcessBitness.OtherProcessGet()
return lResult 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): 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 #Определение backend
lBackend=mDefaultPywinautoBackend lBackend=mDefaultPywinautoBackend
if "backend" in inControlSpecificationArray[0]: if "backend" in inControlSpecificationArray[0]:
@ -440,7 +525,7 @@ def PWASpecification_Get_UIO(inControlSpecificationArray):
inControlSpecificationOriginArray=copy.deepcopy(inControlSpecificationArray) inControlSpecificationOriginArray=copy.deepcopy(inControlSpecificationArray)
inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray) inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив #Выполнить идентификацию объектов, если передан массив
lResultList=[]; lResultList=[]
lTempObject=None lTempObject=None
if len(inControlSpecificationArray) > 0: if len(inControlSpecificationArray) > 0:
#Сформировать выборку элементов, которые подходят под первый уровень спецификации #Сформировать выборку элементов, которые подходят под первый уровень спецификации
@ -477,11 +562,13 @@ def PWASpecification_Get_UIO(inControlSpecificationArray):
lResultList.append(lTempObject) lResultList.append(lTempObject)
return lResultList 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): 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) inControlSpecificationArray=copy.deepcopy(inControlSpecificationArray)
#Определение backend #Определение backend
lBackend=mDefaultPywinautoBackend lBackend=mDefaultPywinautoBackend
@ -492,7 +579,7 @@ def PWASpecification_Get_PWAApplication(inControlSpecificationArray):
inControlSpecificationOriginArray=inControlSpecificationArray inControlSpecificationOriginArray=inControlSpecificationArray
inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray) inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив #Выполнить идентификацию объектов, если передан массив
lResultList=[]; lResultList=[]
lTempObject=None lTempObject=None
if len(inControlSpecificationArray) > 0: if len(inControlSpecificationArray) > 0:
#Выполнить подключение к объекту #Выполнить подключение к объекту
@ -513,10 +600,14 @@ def PWASpecification_Get_PWAApplication(inControlSpecificationArray):
return lTempObject 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): 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 lGUISearchElementSelected=None
#Настройка - частота обновления подсвечивания #Настройка - частота обновления подсвечивания
lTimeSleepSeconds=0.4 lTimeSleepSeconds=0.4
@ -548,17 +639,21 @@ def UIOSelector_SearchChildByMouse_UIO(inElementSpecification):
UIO_Highlight(lElementFounded) UIO_Highlight(lElementFounded)
else: else:
#Была нажата клавиша Ctrl - выйти из цикла #Была нажата клавиша Ctrl - выйти из цикла
lFlagLoop=False; lFlagLoop=False
#Заснуть до следующего цикла #Заснуть до следующего цикла
time.sleep(lTimeSleepSeconds) time.sleep(lTimeSleepSeconds)
#Вернуть результат поиска #Вернуть результат поиска
return lElementFoundedList 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 #old name - AutomationSearchMouseElementHierarchy
def UIOSelector_SearchChildByMouse_UIOTree(inUIOSelector): 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 = [] lItemInfo = []
#Check the bitness #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
@ -687,6 +782,12 @@ def UIOSelector_Get_UIOInfoList (inUIOSelector, inElement=None):
#inSpecificationList - UIOSelector #inSpecificationList - UIOSelector
#old name - PywinautoExtTryToRestore #old name - PywinautoExtTryToRestore
def UIOSelector_TryRestore_Dict(inSpecificationList): 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={} lResult={}
try: try:
#Подготовка взодного массива #Подготовка взодного массива
@ -705,6 +806,12 @@ def UIOSelector_TryRestore_Dict(inSpecificationList):
#inControlSpecificationArray - UIOSelector #inControlSpecificationArray - UIOSelector
#old name - ElementActionGetList #old name - ElementActionGetList
def UIOSelector_Get_UIOActivityList (inUIOSelector): 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 #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None: if lSafeOtherProcess is None:
@ -742,7 +849,18 @@ def UIOSelector_Get_UIOActivityList (inUIOSelector):
#inUIOSelector #inUIOSelector
#inActionName - UIOActivity (name) from Pywinauto #inActionName - UIOActivity (name) from Pywinauto
#old name - ElementRunAction #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={} lResult={}
#Check the bitness #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) 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)!!!!! #!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementGetInfo #old name - ElementGetInfo
def UIOSelector_Get_UIOInfo(inUIOSelector): 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 #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None: if lSafeOtherProcess is None:
#Подготовка входного массива #Подготовка входного массива
inUIOSelector=UIOSelector_SearchUIONormalize_UIOSelector(inUIOSelector) inUIOSelector=UIOSelector_SearchUIONormalize_UIOSelector(inUIOSelector)
#Выполнить идентификацию объектов, если передан массив #Выполнить идентификацию объектов, если передан массив
lResultList=[]; lResultList=[]
if len(inUIOSelector) > 0: if len(inUIOSelector) > 0:
#Получить объект #Получить объект
lTempObject=UIOSelector_Get_UIO(inUIOSelector) lTempObject=UIOSelector_Get_UIO(inUIOSelector)
@ -824,7 +948,8 @@ def UIOSelector_Get_UIOInfo(inUIOSelector):
#inHierarchyList: [{"index":<>,"element":<>}] - technical argument for internal purpose #inHierarchyList: [{"index":<>,"element":<>}] - technical argument for internal purpose
#result -List of dict [{"index":<>,"element":<>}] -- list of element hierarchy specifications #result -List of dict [{"index":<>,"element":<>}] -- list of element hierarchy specifications
#old name - GUISearchElementByRootXY #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 lResultElement = None
lResultElementX1 = 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)!!!!! #!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#inControlSpecificationArray- UIOSelector #inControlSpecificationArray- UIOSelector
#old name - ElementGetChildElementList #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"File!!!!")
#mRobotLogger.info(f"inSelector:{str(inUIOSelector)}, inBackend:{str(inBackend)}") #mRobotLogger.info(f"inSelector:{str(inUIOSelector)}, inBackend:{str(inBackend)}")
#pdb.set_trace() #pdb.set_trace()
@ -1194,7 +1329,7 @@ def BackendStr_GetTopLevelList_UIOInfo(inBackend=mDefaultPywinautoBackend):
lResultList2=[] lResultList2=[]
for lI in lResultList: for lI in lResultList:
lTempObjectInfo=lI lTempObjectInfo=lI
lResultList2.append(UIOEI_Convert_UIOInfo(lI)); lResultList2.append(UIOEI_Convert_UIOInfo(lI))
return lResultList2 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)!!!!! #!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementDrawOutlineNew #old name - ElementDrawOutlineNew
def UIOSelector_Highlight(inUIOSelector): 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 #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None: 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)!!!!! #!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementDrawOutlineNewFocus #old name - ElementDrawOutlineNewFocus
def UIOSelector_FocusHighlight(inUIOSelector): 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 #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None: if lSafeOtherProcess is None:

@ -3,7 +3,7 @@ r"""
The OpenRPA package (from UnicodeLabs) The OpenRPA package (from UnicodeLabs)
""" """
__version__ = 'v1.1.20' __version__ = 'v1.2.0'
__all__ = [] __all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>' __author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'
#from .Core import Robot #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 # Def to check inGSettings and update structure to the backward compatibility
# !!! ATTENTION: Backward compatibility has been started from v1.1.13 !!! # !!! 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) # 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): def Update(inGSettings):
lL = inGSettings["Logger"] # Alias for logger lL = inGSettings["Logger"] # Alias for logger
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@ -8,7 +290,7 @@ def Update(inGSettings):
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if "Autocleaner" not in inGSettings: # Add "Autocleaner" structure 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 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 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 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 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 inGSettings["Server"]["RequestTimeoutSecFloat"] = 300 # Time to handle request in seconds
if lL: lL.warning( if lL: lL.warning(
f"Backward compatibility (v1.1.13 to v1.1.14): Add default 'Server' > 'RequestTimeoutSecFloat' property") # Log about compatibility 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 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 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 # 1.2.0 - general processor - contains old orchestrator processor + RDPActive processor
import http.client import time, copy, threading
import json # Run processor synchronious
import pdb # inThreadControlDict = {"ThreadExecuteBool":True}
import os def ProcessorRunSync(inGSettings, inRobotRDPThreadControlDict):
import sys """
import subprocess "ProcessorDict": { # Has been changed. New general processor (one threaded) v.1.2.0
import importlib "ActivityList": [ # List of the activities
import psutil
#Input arg
# [
# { # {
# "Type": <RemoteMachineProcessingRun>, # "Def":"DefAliasTest", # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
# host: <localhost>, # "ArgList":[1,2,3], # Args list
# port: <port>, # "ArgDict":{"ttt":1,"222":2,"dsd":3}, # Args dictionary
# bodyObject: <object dict, int, str, list> # "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
# }, # },
# { ],
# "Type": "CMDStart", "AliasDefDict": {}, # Storage for def with Str alias. To use it see pyOpenRPA.Orchestrator.ControlPanel
# "Command": "" "CheckIntervalSecFloat": 1.0 # Interval for check gSettings in ProcessorDict > ActivityList
# }, "ExecuteBool": True # Flag to execute thread processor
# { """
# "Type": "OrchestratorRestart" lL = inGSettings["Logger"] # Logger alias
# }, inGSettings["ProcessorDict"]["ThreadIdInt"] = threading.get_ident() # fill Processor thread id
# { while inGSettings["ProcessorDict"]["ExecuteBool"]:
# "Type": "OrchestratorSessionSave" lActivityList = inGSettings["ProcessorDict"]["ActivityList"] # Alias
# }, if len(lActivityList)>0:
# { if lL: lL.debug(f'Processor ActivityList len: {len(lActivityList)}')
# "Type": "GlobalDictKeyListValueSet", lActivityItem = inGSettings["ProcessorDict"]["ActivityList"].pop(0) # Extract the first item from processor queue
# "KeyList": ["key1","key2",...], inRobotRDPThreadControlDict["ThreadExecuteBool"]=False # Stop the RobotRDPActive monitoring
# "Value": <List, Dict, String, int> ActivityListExecute(inGSettings = inGSettings, inActivityList = [lActivityItem]) # execute the activity item
# }, inRobotRDPThreadControlDict["ThreadExecuteBool"] = True # Continue the RobotRDPActive monitoring
# {
# "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)}
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: else:
lDict[lItem2] = {} time.sleep(inGSettings["ProcessorDict"]["CheckIntervalSecFloat"]) # Sleep when list is empty
lDict = lDict[lItem2]
# Set value # Execute ActivityItem list
lDict[lItem["KeyList"][-1]]+=lItem["Value"] # return the def result
lItem["Result"] = True def ActivityListExecute(inGSettings, inActivityList):
########################################################### lL = inGSettings["Logger"] # Logger alias
#Обработка команды GlobalDictKeyListValueGet lResultList = [] # init the result list
###########################################################
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: try:
#Подключить модуль для вызова for lActivityItem in inActivityList: # Iterate throught the activity list
lModule=importlib.import_module(lItem["ModuleName"]) if lL: lL.info(f'pyOpenRPA Processor.ActivityListExecute:: Def:{str(lActivityItem["Def"])}. Parameters are not available to see.')
#Найти функцию lDef = None # Def variable
lFunction=getattr(lModule,lItem["FunctionName"]) if callable(lActivityItem["Def"]): # CHeck if def is callable
lItem["Result"]=lFunction(*lItem.get("ArgList",[]),**lItem.get("ArgDict",{})) 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: except Exception as e:
if lL: lL.exception("Loop activity error: module/function not founded") if lL: lL.exception(f"pyOpenRPA Processor.ActivityListExecute: Exception in def execution - activity will be ignored.") # Logging
################################# lResultList.append(e) # return the generated exception
# Windows logon except Exception as e:
################################# if lL: lL.exception(f"pyOpenRPA Processor.ActivityListExecute: Exception when initialisation - All activity list will be ignored.") # Logging
if lItem["Type"] == "WindowsLogon": return lResultList # return the result list
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
def ActivityListOrDict(inActivityListOrDict): def __ActivityListVerify__(inActivityList):
#Check arg type (list or dict) """
if type(inActivityListOrDict)==list: Verify ActivityList variable - raise exception if input list is not list of dict with structure:
#List activity # "Def":"DefAliasTest", # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
lResult=[] # "ArgList":[1,2,3], # Args list
for lItem in inActivityListOrDict: # "ArgDict":{"ttt":1,"222":2,"dsd":3}, # Args dictionary
lResult.append(Activity(lItem)) # "ArgGSettings": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
return lResult # "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
if type(inActivityListOrDict)==dict:
#Dict activity
return Activity(inActivityListOrDict)
def CheckIfProcessRunning(processName): :param inActivityList:
''' :return:
Check if there is any running process that contains the given name processName. """
''' # CASE LIST
#Iterate over the all the running process if type(inActivityList) is list:
for proc in psutil.process_iter(): for lItem in inActivityList:
try: # CASE LIST item is LIST
# Check if process name contains the given name string. if type(lItem) is list:
if processName.lower() in proc.name().lower(): raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Your ActivityList item is list too. List of the list :(")
return True # CASE Item is not dict
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): if type(lItem) is not dict:
pass raise Exception(f"pyOpenRPA Processor.__ActivityListVerify__: inActivityList has wrong structure! Details: Your ActivityList item is is not dict")
return False; # 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 # Exit fullscreen mode
SessionScreenSize_X_Y_W_H(inSessionHex=inSessionHex, inXInt=10, inYInt=10, inWInt=550, SessionScreenSize_X_Y_W_H(inSessionHex=inSessionHex, inXInt=10, inYInt=10, inWInt=550,
inHInt=350) # Prepare little window inHInt=350) # Prepare little window
return lResult
# Check if session is in Full screen mode # Check if session is in Full screen mode
# Return True - is in fullscreen # Return True - is in fullscreen
# example print(Connector.SessionIsFullScreen("")) # example print(Connector.SessionIsFullScreen(""))
@ -305,11 +306,12 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
Clipboard.TextSet(lClipboardTextOld) Clipboard.TextSet(lClipboardTextOld)
lCrosscheckKeyStr = str(random.randrange(999,9999999)) lCrosscheckKeyStr = str(random.randrange(999,9999999))
lRecoveryCMDResponsibleRetryIteratorInt = 0 # Init the retry iterator lRecoveryCMDResponsibleRetryIteratorInt = 0 # Init the retry iterator
lCommandIsTooBigBool = False
lCMDPostFixStr = "" # Case default "RUN"
while lRecoveryCMDResponsibleRetryIteratorInt<gRecoveryCMDResponsibleRetryCountInt: # loop for retry while lRecoveryCMDResponsibleRetryIteratorInt<gRecoveryCMDResponsibleRetryCountInt: # loop for retry
# # # # # # # # # # # # # OPEN WINDOW RUN # # # # # # # # # # # # # # # # # # # # # # # # # # # # OPEN WINDOW RUN # # # # # # # # # # # # # # #
lRecoveryWindowRUNRetryIteratorInt = 0 # Init the retry iterator lRecoveryWindowRUNRetryIteratorInt = 0 # Init the retry iterator
while lRecoveryWindowRUNRetryIteratorInt<gRecoveryWindowRUNRetryCountInt: # loop for retry while lRecoveryWindowRUNRetryIteratorInt<gRecoveryWindowRUNRetryCountInt: # loop for retry
lCMDPostFixStr = "" # Case default "RUN"
if inModeStr == "CROSSCHECK": if inModeStr == "CROSSCHECK":
#lCMDPostFixStr = f"& (echo {lCrosscheckKeyStr} | clip)" #lCMDPostFixStr = f"& (echo {lCrosscheckKeyStr} | clip)"
lCMDPostFixStr = f"| (echo {lCrosscheckKeyStr} | clip)" # Bugfix async set clipboard data 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 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... 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 lInputStr = f"cmd /c ({inCMDCommandStr}) {lCMDPostFixStr}" # Generate the output string for RUN window
if len(lInputStr) <= 259:
keyboard.write(lInputStr) # Write new text 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) time.sleep(gKeyboardHotkeyDelaySecFloat)
# Check if autocomplete # 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 if lClipboardStr == lInputStr: # Cross check the clipboard data and input string
lRecoveryWindowRUNRetryIteratorInt = gRecoveryWindowRUNRetryCountInt # Set final count to block the loop lRecoveryWindowRUNRetryIteratorInt = gRecoveryWindowRUNRetryCountInt # Set final count to block the loop
else: # Failed - wait and retry 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 lRecoveryWindowRUNRetryIteratorInt = lRecoveryWindowRUNRetryIteratorInt + 1 # Increment the iterator
if lRecoveryWindowRUNRetryIteratorInt == gRecoveryWindowRUNRetryCountInt: 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 raise ConnectorExceptions.RUNExistError() # Raise the error
time.sleep(gRecoveryWindowRUNRetryIntervalSecInt) # wait for some seconds before new iteration time.sleep(gRecoveryWindowRUNRetryIntervalSecInt) # wait for some seconds before new iteration
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # RUN CMD # # # # # # # # # # # # # # # # # # # # # # # # # # # # 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 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) if inModeStr == "CROSSCHECK" or inModeStr == "LISTEN": # Get OutStr (Case CROSSCHECK and LISTEN)
lClipboardWaitTimeStartSec = time.time() lClipboardWaitTimeStartSec = time.time()
lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard 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 lResult["OutStr"] = Clipboard.TextGet() # Get text from clipboard
time.sleep(0.5) # wait some time for the next operation time.sleep(0.5) # wait some time for the next operation
if lResult["OutStr"] == lClipboardTextOld: # If value hasn't been changed - retry send if lResult["OutStr"] == lClipboardTextOld: # If value hasn't been changed - retry send
lRecoveryCMDResponsibleRetryIteratorInt = lRecoveryCMDResponsibleRetryIteratorInt + 1 # increment the iterator 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 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 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 raise ConnectorExceptions.CMDResponsibleError() # Raise the error
time.sleep(gRecoveryCMDResponsibleRetryIntervalSecInt) # wait for some seconds before new iteration time.sleep(gRecoveryCMDResponsibleRetryIntervalSecInt) # wait for some seconds before new iteration
else: # Data was recieved - do crosscheck else: # Data was recieved - do crosscheck
@ -380,7 +401,7 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
lRecoveryCMDResponsibleRetryIteratorInt = lRecoveryCMDResponsibleRetryIteratorInt + 1 # increment the iterator 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 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 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 raise ConnectorExceptions.CMDResponsibleError() # Raise the error
time.sleep(gRecoveryCMDResponsibleRetryIntervalSecInt) # wait for some seconds before new iteration 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 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 Connector
from . import Processor # Module for process some functions on thr RDP from . import Processor # Module for process some functions on thr RDP
# Main function # Main function
def RobotRDPActive(inGSettings): # inThreadControlDict = {"ThreadExecuteBool":True}
def RobotRDPActive(inGSettings, inThreadControlDict):
# inGSettings = { # inGSettings = {
# ... "RobotRDPActive": {} ... # ... "RobotRDPActive": {} ...
# } # }
@ -36,6 +37,7 @@ def RobotRDPActive(inGSettings):
lResponsibilityCheckLastSec = time.time() # Get current time for check interval lResponsibilityCheckLastSec = time.time() # Get current time for check interval
while lFlagWhile: while lFlagWhile:
try: try:
if inThreadControlDict["ThreadExecuteBool"] == True:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check RDP window is OK - reconnect if connection was lost # Check RDP window is OK - reconnect if connection was lost
lUIOSelectorList = [] lUIOSelectorList = []
@ -65,19 +67,6 @@ def RobotRDPActive(inGSettings):
if lL: lL.exception(f"!!! ATTENTION !!! Unrecognized error") #Logging if lL: lL.exception(f"!!! ATTENTION !!! Unrecognized error") #Logging
pass 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 Connector.SystemRDPWarningClickOk() # Click all warning messages
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check if RDP session is full screen (if is not ignored) # Check if RDP session is full screen (if is not ignored)
@ -93,16 +82,19 @@ def RobotRDPActive(inGSettings):
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]: for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem] lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem]
if Connector.SessionIsFullScreen(inSessionHexStr=lRDPConfigurationDictItem["SessionHex"]): 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, Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"], inXInt=10, inYInt=10,
inWInt=550, inWInt=550,
inHInt=350) # Prepare little window inHInt=350) # Prepare little window
# Set full screen for new 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]) Connector.SessionScreenFull(inSessionHex=lRDPConfigurationDict["SessionHex"], inLogger= inGSettings["Logger"], inRDPConfigurationItem=inGlobalDict["RDPList"][lRDPSessionKeyStrItem])
else: else:
# Check all RDP window and minimize it # Check all RDP window and minimize it
for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]: for lRDPSessionKeyStrItem in inGlobalDict["RDPList"]:
lRDPConfigurationDictItem = inGlobalDict["RDPList"][lRDPSessionKeyStrItem] 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 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"], Connector.SessionScreenSize_X_Y_W_H(inSessionHex=lRDPConfigurationDictItem["SessionHex"],
inXInt=10, inYInt=10, inXInt=10, inYInt=10,
inWInt=550, inWInt=550,

@ -11,7 +11,8 @@ from socketserver import ThreadingMixIn
import threading import threading
import json import json
from threading import Thread 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 urllib.parse # decode URL in string
import importlib import importlib
import pdb import pdb
@ -22,9 +23,26 @@ import os #for path operations
from http import cookies from http import cookies
global gSettingsDict global gSettingsDict
from . import ServerSettings from . import ServerSettings
from . import __Orchestrator__
import copy 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 () #Authenticate function ()
# return dict # return dict
# { # {
@ -41,10 +59,10 @@ def AuthenticateVerify(inRequest):
lCookieAuthToken = lCookies.get("AuthToken", "").value lCookieAuthToken = lCookies.get("AuthToken", "").value
if lCookieAuthToken: if lCookieAuthToken:
#Find AuthToken in GlobalDict #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 #Auth Token Has Been Founded
lResult["Domain"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"] lResult["Domain"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"]
lResult["User"] = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"] lResult["User"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"]
#Set auth token #Set auth token
inRequest.OpenRPA["AuthToken"] = lCookieAuthToken inRequest.OpenRPA["AuthToken"] = lCookieAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"] inRequest.OpenRPA["Domain"] = lResult["Domain"]
@ -63,26 +81,18 @@ def AuthenticateVerify(inRequest):
if "\\" in lUser: if "\\" in lUser:
lDomain = lUser.split("\\")[0] lDomain = lUser.split("\\")[0]
lUser = lUser.split("\\")[1] lUser = lUser.split("\\")[1]
#Try to logon - use processor lLogonBool = __Orchestrator__.OSCredentialsVerify(inUserStr=lUser, inPasswordStr=lPassword, inDomainStr=lDomain)
lLogonResult = Processor.Activity(
{
"Type": "WindowsLogon",
"Domain": lDomain,
"User": lUser,
"Password": lPassword
}
)
#Check result #Check result
if lLogonResult["Result"]: if lLogonBool:
lResult["Domain"] = lLogonResult["Domain"] lResult["Domain"] = lDomain
lResult["User"] = lLogonResult["User"] lResult["User"] = lUser
#Create token #Create token
lAuthToken=str(uuid.uuid1()) lAuthToken=str(uuid.uuid1())
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {} gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {}
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"] gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"] gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"]
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False
gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now() gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now()
#Set-cookie #Set-cookie
inRequest.OpenRPA["AuthToken"] = lAuthToken inRequest.OpenRPA["AuthToken"] = lAuthToken
inRequest.OpenRPA["Domain"] = lResult["Domain"] inRequest.OpenRPA["Domain"] = lResult["Domain"]
@ -123,13 +133,14 @@ def UserAccessCheckBefore(inMethod, inRequest):
#go next if user is identified #go next if user is identified
lUserDict = None lUserDict = None
if lAuthToken: if lAuthToken:
lUserDict = gSettingsDict["Server"]["AccessUsers"]["AuthTokensDict"][lAuthToken] lUserDict = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]
#pdb.set_trace() #pdb.set_trace()
######################################## ########################################
######################################## ########################################
#Check general before rule (without User domain) #Check general before rule (without User domain)
#Check rules #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 #Go next execution if flag is false
if not lResult: if not lResult:
#Check if Method is identical #Check if Method is identical
@ -161,7 +172,9 @@ def UserAccessCheckBefore(inMethod, inRequest):
#Check access by User Domain #Check access by User Domain
#Check rules to find first appicable #Check rules to find first appicable
#Check rules #Check rules
for lAccessRuleItem in gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []): 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 #Go next execution if flag is false
if not lResult: if not lResult:
#Check if Method is identical #Check if Method is identical
@ -186,6 +199,8 @@ def UserAccessCheckBefore(inMethod, inRequest):
elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE": elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE":
if lAccessRuleItem["URL"] == inRequest.path: if lAccessRuleItem["URL"] == inRequest.path:
lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict)
else:
return True
##################################### #####################################
##################################### #####################################
#Return lResult #Return lResult
@ -193,6 +208,8 @@ def UserAccessCheckBefore(inMethod, inRequest):
# HTTPRequestHandler class # HTTPRequestHandler class
class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Def to check User Role access grants # Def to check User Role access grants
def UACClientCheck(self, inRoleKeyList): # Alias
return self.UserRoleAccessAsk(inRoleKeyList=inRoleKeyList)
def UserRoleAccessAsk(self, inRoleKeyList): def UserRoleAccessAsk(self, inRoleKeyList):
lResult = True # Init flag lResult = True # Init flag
lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy
@ -218,7 +235,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
def UserRoleHierarchyGet(self): def UserRoleHierarchyGet(self):
lDomainUpperStr = self.OpenRPA["Domain"].upper() lDomainUpperStr = self.OpenRPA["Domain"].upper()
lUserUpperStr = self.OpenRPA["User"].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 #Tech def
#return {"headers":[],"body":"","statuscode":111} #return {"headers":[],"body":"","statuscode":111}
@ -316,6 +333,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Write content as utf-8 data # Write content as utf-8 data
self.wfile.write(inResponseDict["Body"]) self.wfile.write(inResponseDict["Body"])
def do_GET(self): def do_GET(self):
try:
self.OpenRPA = {} self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None self.OpenRPA["Domain"] = None
@ -331,7 +349,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
##################################### #####################################
lFlagAccessUserBlock=False lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""} lAuthenticateDict = {"Domain": "", "User": ""}
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self) lAuthenticateDict = AuthenticateVerify(self)
if not lAuthenticateDict["User"]: if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True lFlagAccessUserBlock=True
@ -345,7 +363,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#################################### ####################################
lFlagUserAccess = True lFlagUserAccess = True
#If need user authentication #If need user authentication
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("GET", self) lFlagUserAccess = UserAccessCheckBefore("GET", self)
###################################### ######################################
if lFlagUserAccess: if lFlagUserAccess:
@ -353,7 +371,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
############################ ############################
#New server engine (url from global dict (URLList)) #New server engine (url from global dict (URLList))
############################ ############################
for lURLItem in gSettingsDict["Server"]["URLList"]: for lURLItem in gSettingsDict["ServerDict"]["URLList"]:
#Check if all condition are applied #Check if all condition are applied
lFlagURLIsApplied=False lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET") lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET")
@ -383,8 +401,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
self.send_response(403) self.send_response(403)
# Send headers # Send headers
self.end_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 # POST
def do_POST(self): def do_POST(self):
try:
lL = gSettingsDict["Logger"] lL = gSettingsDict["Logger"]
self.OpenRPA = {} self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None self.OpenRPA["AuthToken"] = None
@ -403,11 +425,10 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
lFlagAccessUserBlock=False lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""} lAuthenticateDict = {"Domain": "", "User": ""}
lIsSuperToken = False # Is supertoken lIsSuperToken = False # Is supertoken
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self) lAuthenticateDict = AuthenticateVerify(self)
# Get Flag is supertoken (True|False) # Get Flag is supertoken (True|False)
lIsSuperToken = gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get( lIsSuperToken = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(self.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
self.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
if not lAuthenticateDict["User"]: if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True lFlagAccessUserBlock=True
if lFlagAccessUserBlock: if lFlagAccessUserBlock:
@ -418,7 +439,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#################################### ####################################
lFlagUserAccess = True lFlagUserAccess = True
#If need user authentication #If need user authentication
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lFlagUserAccess = UserAccessCheckBefore("POST", self) lFlagUserAccess = UserAccessCheckBefore("POST", self)
###################################### ######################################
if lFlagUserAccess: if lFlagUserAccess:
@ -426,7 +447,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
############################ ############################
#New server engine (url from global dict (URLList)) #New server engine (url from global dict (URLList))
############################ ############################
for lURLItem in gSettingsDict["Server"]["URLList"]: for lURLItem in gSettingsDict["ServerDict"]["URLList"]:
#Check if all condition are applied #Check if all condition are applied
lFlagURLIsApplied=False lFlagURLIsApplied=False
lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST") lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST")
@ -449,9 +470,18 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
self.end_headers() self.end_headers()
# Logging info about processor activity if not SuperToken () # Logging info about processor activity if not SuperToken ()
if not lIsSuperToken: if not lIsSuperToken:
if lL: lL.info(f"Server:: User activity from web. Domain: {self.OpenRPA['Domain']}, Username: {self.OpenRPA['User']}, Activity: {lInputObject}") 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 # Send message back to client
message = json.dumps(Processor.ActivityListOrDict(lInputObject)) message = json.dumps(ProcessorOld.ActivityListOrDict(lInputObject))
# Write content as utf-8 data # Write content as utf-8 data
self.wfile.write(bytes(message, "utf8")) self.wfile.write(bytes(message, "utf8"))
return return
@ -462,6 +492,9 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Send headers # Send headers
self.end_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 #Logging
#!Turn it on to stop print in console #!Turn it on to stop print in console
#def log_message(self, format, *args): #def log_message(self, format, *args):
@ -470,7 +503,7 @@ class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
daemon_threads = True daemon_threads = True
"""Handle requests in a separate thread.""" """Handle requests in a separate thread."""
def finish_request(self, request, client_address): 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 # "super" can not be used because BaseServer is not created from object
HTTPServer.finish_request(self, request, client_address) HTTPServer.finish_request(self, request, client_address)
#inGlobalDict #inGlobalDict
@ -483,7 +516,7 @@ class RobotDaemonServer(Thread):
ServerSettings.SettingsUpdate(inGlobalDict) ServerSettings.SettingsUpdate(inGlobalDict)
def run(self): def run(self):
inServerAddress=""; inServerAddress="";
inPort = gSettingsDict["Server"]["ListenPort"]; inPort = gSettingsDict["ServerDict"]["ListenPort"];
# Server settings # Server settings
# Choose port 8080, for port 80, which is normally used for a http server, you need root access # Choose port 8080, for port 80, which is normally used for a http server, you need root access
server_address = (inServerAddress, inPort) 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 inspect import signature # For detect count of def args
from . import __Orchestrator__
#ControlPanelDict #ControlPanelDict
from desktopmagic.screengrab_win32 import ( from desktopmagic.screengrab_win32 import (
getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage, getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage,
@ -9,163 +11,234 @@ import uuid # generate UUID4
import time # sleep functions import time # sleep functions
import datetime # datetime functions import datetime # datetime functions
import threading # Multi-threading import threading # Multi-threading
from .Web import Basic
# /Orchestrator/RobotRDPActive/ControlPanelDictGet from . import BackwardCompatibility # Support old up to 1.2.0 defs
def RobotRDPActive_ControlPanelDictGet(inRequest,inGlobalDict): from . import Processor
inResponseDict = inRequest.OpenRPAResponseDict from . import SettingsTemplate
lResultDict = { # # # # # # # # # # # #
"DataList":[ # v 1.2.0 Functionallity
# {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False} # # # # # # # # # # # #
] # Generate JS when page init
} def HiddenJSInitGenerate(inRequest, inGSettings):
# Iterate throught the RDP List dUAC = inRequest.UACClientCheck # Alias.
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]: lUACCPTemplateKeyList=["pyOpenRPADict","CPKeyDict"]
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][lRDPSessionKeyStrItem] # Get the configuration dict lL = inGSettings["Logger"] # Alias for logger
lDataItemDict = {"SessionKeyStr":"", "SessionHexStr": "", "IsFullScreenBool": False, "IsIgnoredBool": False} # Template lJSInitResultStr = ""
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str lRenderFunctionsRobotDict = inGSettings["CPDict"]
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex for lItemKeyStr in lRenderFunctionsRobotDict:
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"]["FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window lItemDict = lRenderFunctionsRobotDict[lItemKeyStr]
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored lJSInitGeneratorDef = lItemDict.get("JSInitGeneratorDef",None)
lResultDict["DataList"].append(lDataItemDict) lUACBool = dUAC(inRoleKeyList=lUACCPTemplateKeyList+[lItemKeyStr]) # Check if render function is applicable User Access Rights (UAC)
# Send message back to client if lItemKeyStr=="VersionCheck": lUACBool=True # For backward compatibility for the old fron version which not reload page when new orch version is comming
message = json.dumps(lResultDict) if lUACBool: # Run function if UAC is TRUE
# Write content as utf-8 data # JSONGeneratorDef
inResponseDict["Body"] = bytes(message, "utf8") if lJSInitGeneratorDef is not None: # Call def (inRequest, inGSettings) or def (inGSettings)
lJSResult = None
# def to check control panels for selected session lDEFSignature = signature(lJSInitGeneratorDef) # Get signature of the def
def Monitor_ControlPanelDictGet_SessionCheckInit(inRequest,inGlobalDict): lDEFARGLen = len(lDEFSignature.parameters.keys()) # get count of the def args
lL = inGlobalDict["Logger"] # Alias for logger try:
lLifetimeSecFloat = inGlobalDict["Client"]["Session"]["LifetimeSecFloat"] if lDEFARGLen == 1: # def (inGSettings)
lLifetimeRequestSecFloat = inGlobalDict["Client"]["Session"]["LifetimeRequestSecFloat"] lJSResult = lJSInitGeneratorDef(inGSettings)
lControlPanelRefreshIntervalSecFloat = inGlobalDict["Client"]["Session"]["ControlPanelRefreshIntervalSecFloat"] elif lDEFARGLen == 2: # def (inRequest, inGSettings)
lCookieSessionGUIDStr = None # generate the new GUID lJSResult = lJSInitGeneratorDef(inRequest, inGSettings)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # elif lDEFARGLen == 0: # def ()
# Technicaldef - interval check control panels + check actuality of the session by the datetime lJSResult = lJSInitGeneratorDef()
def TechnicalCheck(): if type(lJSResult) is str:
lItemValue = inGlobalDict["Client"]["Session"]["TechnicalSessionGUIDCache"][lCookieSessionGUIDStr] lJSInitResultStr += "; "+lJSResult # Add delimiter to some cases
# 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: else:
lCookieSessionGUIDStr = TechnicalSessionNew(inSessionGUIDStr = lCookieSessionGUIDStr) # Create new session if lL: lL.warning(f"JSInitGenerator return bad type: {str(type(lJSResult))}, CP Key {lItemKeyStr}")
if lDoWhileBool: # Sleep if we wait hte next iteration except Exception as e:
time.sleep(lControlPanelRefreshIntervalSecFloat) # Sleep to the next iteration if lL: lL.exception(f"Error in control panel JSInitGeneratorDef. CP Key {lItemKeyStr}. Exception are below")
return lJSInitResultStr
def Monitor_ControlPanelDictGet(inRequest,inGlobalDict): # Generate CP HTML + JSON
inResponseDict = inRequest.OpenRPAResponseDict # Return {"Key":{"",""}}
lL = inGlobalDict["Logger"] # Alias for logger def HiddenCPDictGenerate(inRequest, inGSettings):
dUAC = inRequest.UACClientCheck # Alias.
lUACCPTemplateKeyList=["pyOpenRPADict","CPKeyDict"]
lL = inGSettings["Logger"] # Alias for logger
# Create result JSON # Create result JSON
lResultJSON = {"RenderRobotList": [], "RenderRDPList": []} lCPDict = {}
lRenderFunctionsRobotList = inGlobalDict["ControlPanelDict"]["RobotList"] lRenderFunctionsRobotDict = inGSettings["CPDict"]
for lItem in lRenderFunctionsRobotList: for lItemKeyStr in lRenderFunctionsRobotDict:
lUACBool = True # Check if render function is applicable User Access Rights (UAC) lItemDict = lRenderFunctionsRobotDict[lItemKeyStr]
if inGlobalDict["Server"]["AccessUsers"]["FlagCredentialsAsk"] is True: lItemHTMLRenderDef = lItemDict.get("HTMLRenderDef",None)
lUserRights = inGlobalDict["Server"]["AccessUsers"]["RuleDomainUserDict"][(inRequest.OpenRPA["Domain"].upper(),inRequest.OpenRPA["User"].upper())] lItemJSONGeneratorDef = lItemDict.get("JSONGeneratorDef",None)
if len(lUserRights["ControlPanelKeyAllowedList"]) > 0 and lItem["KeyStr"] not in lUserRights["ControlPanelKeyAllowedList"]: lUACBool = dUAC(inRoleKeyList=lUACCPTemplateKeyList+[lItemKeyStr]) # Check if render function is applicable User Access Rights (UAC)
lUACBool = False # UAC Check is not passed - False for user 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 if lUACBool: # Run function if UAC is TRUE
# Выполнить вызов и записать результат lCPItemDict = {"HTMLStr": None, "JSONDict":None}
# Call def (inRequest, inGSettings) or def (inGSettings) # HTMLRenderDef
lItemResultDict = None if lItemHTMLRenderDef is not None: # Call def (inRequest, inGSettings) or def (inGSettings)
lDEFSignature = signature(lItem["RenderFunction"]) # Get signature of the def lHTMLResult = None
lDEFSignature = signature(lItemHTMLRenderDef) # Get signature of the def
lDEFARGLen = len(lDEFSignature.parameters.keys()) # get count of the def args lDEFARGLen = len(lDEFSignature.parameters.keys()) # get count of the def args
try: try:
if lDEFARGLen == 1: # def (inGSettings) if lDEFARGLen == 1: # def (inGSettings)
lItemResultDict = lItem["RenderFunction"](inGlobalDict) lHTMLResult = lItemHTMLRenderDef(inGSettings)
elif lDEFARGLen == 2: # def (inRequest, inGSettings) elif lDEFARGLen == 2: # def (inRequest, inGSettings)
lItemResultDict = lItem["RenderFunction"](inRequest, inGlobalDict) lHTMLResult = lItemHTMLRenderDef(inRequest, inGSettings)
elif lDEFARGLen == 0: # def () elif lDEFARGLen == 0: # def ()
lItemResultDict = lItem["RenderFunction"]() lHTMLResult = lItemHTMLRenderDef()
# RunFunction # RunFunction
lResultJSON["RenderRobotList"].append(lItemResultDict) # 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: except Exception as e:
if lL: lL.exception(f"Error in control panel. CP item {lItem}. Exception is below") 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 # Iterate throught the RDP list
for lRDPSessionKeyStrItem in inGlobalDict["RobotRDPActive"]["RDPList"]: for lRDPSessionKeyStrItem in inGSettings["RobotRDPActive"]["RDPList"]:
lRDPConfiguration = inGlobalDict["RobotRDPActive"]["RDPList"][ # Check UAC
if dUAC(inRoleKeyList=lUACRDPTemplateKeyList+[lRDPSessionKeyStrItem]):
lRDPConfiguration = inGSettings["RobotRDPActive"]["RDPList"][
lRDPSessionKeyStrItem] # Get the configuration dict lRDPSessionKeyStrItem] # Get the configuration dict
lDataItemDict = {"SessionKeyStr": "", "SessionHexStr": "", "IsFullScreenBool": False, lDataItemDict = {"SessionKeyStr": "", "SessionHexStr": "", "IsFullScreenBool": False,
"IsIgnoredBool": False} # Template "IsIgnoredBool": False} # Template
lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str lDataItemDict["SessionKeyStr"] = lRDPSessionKeyStrItem # Session key str
lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex lDataItemDict["SessionHexStr"] = lRDPConfiguration["SessionHex"] # Session Hex
lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGlobalDict["RobotRDPActive"][ lDataItemDict["IsFullScreenBool"] = True if lRDPSessionKeyStrItem == inGSettings["RobotRDPActive"][
"FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window "FullScreenRDPSessionKeyStr"] else False # Check the full screen for rdp window
lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored lDataItemDict["IsIgnoredBool"] = lRDPConfiguration["SessionIsIgnoredBool"] # Is ignored
lResultJSON["RenderRDPList"].append(lDataItemDict) 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
#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
# Send message back to client # Send message back to client
message = json.dumps(lResultJSON) message = json.dumps(lResult)
# Write content as utf-8 data # Write content as utf-8 data
#inResponseDict["Body"] = bytes(message, "utf8") inResponseDict["Body"] = bytes(message, "utf8")
return bytes(message, "utf8") return lResult
# UserAccess get rights hierarchy dict in json
def UserRoleHierarchyGet(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
# Write content as utf-8 data
inResponseDict["Body"] = bytes(lResultStr, "utf8")
#v1.2.0 Send data container to the client from the server
# /pyOpenRPA/ServerLog return {"HashStr" , "ServerLogList": ["row 1", "row 2"]}
# Client: mGlobal.pyOpenRPA.ServerLogListHashStr
# 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 inResponseDict = inRequest.OpenRPAResponseDict
# Create result JSON
lResultDict = inRequest.OpenRPA["DefUserRoleHierarchyGet"]() # Get the User Role Hierarchy list
# Send message back to client # Send message back to client
message = json.dumps(lResultDict) message = json.dumps(lResult)
# Write content as utf-8 data # Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8") inResponseDict["Body"] = bytes(message, "utf8")
return lResult
def GetScreenshot(inRequest,inGlobalDict): def pyOpenRPA_Screenshot(inRequest,inGlobalDict):
# Get Screenshot # Get Screenshot
def SaveScreenshot(inFilePath): def SaveScreenshot(inFilePath):
# grab fullscreen # grab fullscreen
@ -182,6 +255,139 @@ def GetScreenshot(inRequest,inGlobalDict):
inRequest.OpenRPAResponseDict["Body"] = lFileObject.read() inRequest.OpenRPAResponseDict["Body"] = lFileObject.read()
# Закрыть файловый объект # Закрыть файловый объект
lFileObject.close() 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): def SettingsUpdate(inGlobalConfiguration):
import os import os
import pyOpenRPA.Orchestrator 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": "/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": "/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": "/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": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_Monitor_ControlPanelDictGet_SessionCheckInit, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": GetScreenshot, "ResponseContentType": "image/png"}, {"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": "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 return inGlobalConfiguration

@ -1,4 +1,5 @@
var mGlobal={} var mGlobal={}
mGlobal.pyOpenRPA = {}
window.onload=function() { window.onload=function() {
//document.cookie = "SessionGUIDStr=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; //document.cookie = "SessionGUIDStr=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
//Render existing data //Render existing data
@ -121,11 +122,17 @@ $(document).ready(function() {
lCMDCode=$(".openrpa-controller-cmd-run-input")[0].value lCMDCode=$(".openrpa-controller-cmd-run-input")[0].value
///Подготовить конфигурацию ///Подготовить конфигурацию
lData = [ 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({ $.ajax({
type: "POST", type: "POST",
url: 'Utils/Processor', url: '/pyOpenRPA/ActivityListExecute',
data: JSON.stringify(lData), data: JSON.stringify(lData),
success: success:
function(lData,l2,l3) function(lData,l2,l3)
@ -221,7 +228,7 @@ $(document).ready(function() {
} }
//inHostURI: http://localhost:8081 //inHostURI: http://localhost:8081
mGlobal.Monitor.ScreenshotModal.Show=function(inHostURI=" ") { 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() { lScreenshotUpdate=function() {
@ -276,7 +283,22 @@ $(document).ready(function() {
mGlobal.Monitor.fControlPanelRefresh_TechnicalRender = function() mGlobal.Monitor.fControlPanelRefresh_TechnicalRender = function()
{ {
lResponseJSON = mGlobal.Monitor.mDatasetLast lResponseJSON = mGlobal.Monitor.mDatasetLast
if (lResponseJSON!= null) { if (lResponseJSON!= null) {
/// 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 ///Escape onclick
/// RenderRobotList /// RenderRobotList
lResponseJSON["RenderRobotList"].forEach( lResponseJSON["RenderRobotList"].forEach(
@ -307,7 +329,7 @@ $(document).ready(function() {
); );
////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////
///Сформировать HTML код новой таблицы - контрольная панель ///Сформировать HTML код новой таблицы - контрольная панель
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-control-panel",lResponseJSON) lHTMLCode+=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-control-panel",lResponseJSON)
//Присвоить ответ в mGlobal.Monitor.mResponseList //Присвоить ответ в mGlobal.Monitor.mResponseList
mGlobal.Monitor.mResponseList = lResponseJSON mGlobal.Monitor.mResponseList = lResponseJSON
///Set result in mGlobal.DataStorage ///Set result in mGlobal.DataStorage
@ -321,7 +343,7 @@ $(document).ready(function() {
///Прогрузить новую таблицу ///Прогрузить новую таблицу
$(".openrpa-control-panel").html(lHTMLCode) $(".openrpa-control-panel").html(lHTMLCode)
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
///Сформировать HTML код новой таблицы - список RDP /// !RDP List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON) lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON)
//Присвоить ответ в mGlobal.RobotRDPActive.mResponseList //Присвоить ответ в mGlobal.RobotRDPActive.mResponseList
mGlobal.RobotRDPActive.mResponseList = lResponseJSON mGlobal.RobotRDPActive.mResponseList = lResponseJSON
@ -329,72 +351,274 @@ $(document).ready(function() {
$(".openrpa-robotrdpactive-control-panel").html(lHTMLCode) $(".openrpa-robotrdpactive-control-panel").html(lHTMLCode)
///Очистить дерево ///Очистить дерево
//mGlobal.ElementTree.fClear(); //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();
} }
} }
mGlobal.Monitor.mDatasetLast = null }
mGlobal.Monitor.fControlPanelRefresh=function() {
///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 { try {
//var XHR = new XMLHttpRequest();
//XHR.setRequestHeader("Cookies",document.cookie)
///Загрузка данных
//console.log("Request is sent")
//console.log(document.cookie)
$.ajax({ $.ajax({
type: "GET", type: "GET",
headers: {"SessionGUIDStr":mGlobal.SessionGUIDStr}, headers: {},
url: 'Monitor/ControlPanelDictGet', url: 'pyOpenRPA/ServerJSInit',
data: '', data: mGlobal.pyOpenRPA.ServerDataHashStr,
//cache: false, async: false,
//xhr: XHR, 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)
////////////////////////////////////////////////////
/// !RDP List ! Сформировать HTML код новой таблицы - список RDP
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON["RDPDict"])
//Присвоить ответ в mGlobal.RobotRDPActive.mResponseList
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.pyOpenRPA.ServerDataRefreshDef=function() {
try {
$.ajax({
type: "POST",
headers: {},
url: 'pyOpenRPA/ServerData',
data: mGlobal.pyOpenRPA.ServerDataHashStr,
success: function(lData,l2,l3) { success: function(lData,l2,l3) {
try { try {
var lResponseJSON=JSON.parse(lData) var lResponseJSON=JSON.parse(lData)
mGlobal.Monitor.mDatasetLast = lResponseJSON mGlobal.VersionStr = lResponseJSON["ServerDataDict"]["UserDict"]["VersionStr"]
mGlobal.Monitor.fControlPanelRefresh_TechnicalRender() 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) { catch(error) {
console.log(error)
setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000)
} }
mGlobal.Monitor.fControlPanelRefresh() // recursive //mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive
}, },
dataType: "text", dataType: "text",
error: function(jqXHR, textStatus, errorThrown ) { error: function(jqXHR, textStatus, errorThrown ) {
sleep(3000) setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000)
mGlobal.Monitor.fControlPanelRefresh() // recursive //sleep(3000)
//mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive
} }
}); });
} }
catch(error) { catch(error) {
sleep(3000) setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000)
mGlobal.Monitor.fControlPanelRefresh() // recursive //sleep(3000)
//mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive
} }
//mGlobal.Monitor.fControlPanelRefresh() // recursive
} }
mGlobal.Monitor.fControlPanelRefresh() /////////////////////////////////////////////////////////////
mGlobal.Test=function() { /// v1.2.0 pyOpenRPA ServerLogs
///Обнулить таблицу mGlobal.pyOpenRPA.ServerLogList = null
lData = [ 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()
{ {
"Type":"GlobalDictKeyListValueSet", lResponseJSON = mGlobal.pyOpenRPA.ServerLogList
"key_list":["Storage","Robot_R01"], if (lResponseJSON!= null && mGlobal.pyOpenRPA.ServerLogListDoRenderBool==true) {
"value":{ lText = lResponseJSON.join("\n") /// Code for the processing the text
"RunDateTimeString":"Test1", $("textarea.mGlobal-pyOpenRPA-ServerLogList")[0].value= lText ///Прогрузить новую таблицу
"StepCurrentName":"Test2", mGlobal.pyOpenRPA.ServerLogListScrollBottomDef() //Scroll to the bottom
"StepCurrentDuration":"Test3"
} }
} }
] mGlobal.pyOpenRPA.ServerLogListRefreshDef=function() {
try {
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: 'Utils/Processor', headers: {},
data: JSON.stringify(lData), url: 'pyOpenRPA/ServerLog',
success: data: mGlobal.pyOpenRPA.ServerLogListHashStr,
function(lData,l2,l3) success: function(lData,l2,l3) {
{ try {
//console.log(lData) 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" dataType: "text",
error: function(jqXHR, textStatus, errorThrown ) {
setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,3000)
//sleep(3000)
//mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive
}
}); });
} }
catch(error) {
setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,3000)
//sleep(3000)
//mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive
}
}
/////////////////////////////////////////////////////////////
mGlobal.Monitor.mDatasetLast = null
/////////////////////////////// ///////////////////////////////
///Processor functions ///Processor functions
/////////////////////////////// ///////////////////////////////
@ -615,7 +839,7 @@ $(document).ready(function() {
// UAC Ask // UAC Ask
mGlobal.UserRoleAsk=function(inList) { mGlobal.UserRoleAsk=function(inList) {
var lResult = true; // Init flag 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 // Try to get value from key list
var lKeyValue = lRoleHierarchyDict; // Init the base var lKeyValue = lRoleHierarchyDict; // Init the base
var lListLength = inList.length; var lListLength = inList.length;
@ -641,64 +865,31 @@ $(document).ready(function() {
} }
// Check user roles and update the Orchestrator UI // Check user roles and update the Orchestrator UI
mGlobal.UserRoleUpdate=function() { 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 lUACAsk = mGlobal.UserRoleAsk // Alias
var lResponseList=JSON.parse(lData) //CPKeyDict
mGlobal.WorkingDirectoryPathStr = lResponseList[0]["Result"] if (lUACAsk(["pyOpenRPADict","CPKeyDict"])) { $(".UACClient-pyOpenRPADict-CPKeyDict").show(); }
},
dataType: "text" //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; &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> </div>
<div class="row"> <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"> <h4 class="ui horizontal divider header">
<i class="clipboard list icon"></i> <i class="clipboard list icon"></i>
Dashboard (Robot control panel) Dashboard (Robot control panel)
@ -116,37 +117,7 @@
</div> </div>
<div class="row"> <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>
</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>
</div>
<script class="openrpa-hidden-monitor-table-general" style="display:none" type="text/x-handlebars-template"> <script class="openrpa-hidden-monitor-table-general" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table"> <table class="ui celled table">
<thead> <thead>
@ -220,21 +191,18 @@
</div> </div>
</div> </div>
</script> </script>
</div> <div class="eight wide column openrpa-robotrdpactive-control-panel-general UACClient-pyOpenRPADict-RDPKeyDict" style="display:none;">
<div class="two wide column"> <h2 class="ui header openrpa-rdpactive-title">
</div> <i class="desktop icon"></i>
<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 class="content"> <div class="content">
RDP active list RDP active list
</div> </div>
</h2> </h2>
<div class="openrpa-robotrdpactive-control-panel"></div> <div class="openrpa-robotrdpactive-control-panel"></div>
<script class="openrpa-hidden-robotrdpactive-control-panel" style="display:none" type="text/x-handlebars-template"> <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"> <div class="ui inverted relaxed divided list">
{{#RenderRDPList}} {{#HandlebarsList}}
<div class="item"> <div class="item">
<div class="right floated content"> <div class="right floated content">
<div class="ui button" onclick="mGlobal.Processor.ServerValueAppend(['RobotRDPActive','ActivityList'],{'DefNameStr': 'RDPSessionReconnect', 'ArgList': [], 'ArgDict': {'inRDPSessionKeyStr': '{{{SessionKeyStr}}}'} })" >Reconnect</div> <div class="ui button" onclick="mGlobal.Processor.ServerValueAppend(['RobotRDPActive','ActivityList'],{'DefNameStr': 'RDPSessionReconnect', 'ArgList': [], 'ArgDict': {'inRDPSessionKeyStr': '{{{SessionKeyStr}}}'} })" >Reconnect</div>
@ -258,7 +226,38 @@
{{{SessionHexStr}}} {{{SessionHexStr}}}
</div> </div>
</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>
</div> </div>
</script> </script>
@ -269,6 +268,68 @@
<div class="row openrpa-monitor"> <div class="row openrpa-monitor">
</div> </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"> <div class="row black">
@ -341,11 +402,6 @@
</div> </div>
<div class="content"> <div class="content">
<img src="GetScreenshot" class="ui fluid image"> <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>
<div class="actions"> <div class="actions">
<div class="ui green ok inverted button" onclick="mGlobal.Monitor.ScreenshotModal.Close()"> <div class="ui green ok inverted button" onclick="mGlobal.Monitor.ScreenshotModal.Close()">

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

@ -1,4 +1,5 @@
import sys import sys
lFolderPath = "\\".join(__file__.split("\\")[:-3]) lFolderPath = "\\".join(__file__.split("\\")[:-3])
sys.path.insert(0, lFolderPath) 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 - выкинуть ошибку в случае обнаружении пустого списка #inFlagRaiseException - Флаг True - выкинуть ошибку в случае обнаружении пустого списка
#old name - PywinautoExtElementsGet #old name - PywinautoExtElementsGet
def UIOSelector_Get_UIOList (inSpecificationList,inElement=None,inFlagRaiseException=True): 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) inSpecificationList=copy.deepcopy(inSpecificationList)
lResultList=[] lResultList=[]
@ -232,6 +240,14 @@ def UIOSelector_Get_UIOList (inSpecificationList,inElement=None,inFlagRaiseExcep
#inFlagRaiseException - Флаг True - выкинуть ошибку в случае обнаружении пустого списка #inFlagRaiseException - Флаг True - выкинуть ошибку в случае обнаружении пустого списка
#old name - PywinautoExtElementGet #old name - PywinautoExtElementGet
def UIOSelector_Get_UIO (inSpecificationList,inElement=None,inFlagRaiseException=True): 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 lResult=None
#Получить родительский объект если на вход ничего не поступило #Получить родительский объект если на вход ничего не поступило
lResultList=UIOSelector_Get_UIOList(inSpecificationList,inElement,False) lResultList=UIOSelector_Get_UIOList(inSpecificationList,inElement,False)
@ -247,6 +263,12 @@ def UIOSelector_Get_UIO (inSpecificationList,inElement=None,inFlagRaiseException
#UIOSelector #UIOSelector
#old name - - #old name - -
def UIOSelector_Exist_Bool (inUIOSelector): 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 lResult=False
#Check the bitness #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
@ -280,6 +302,18 @@ def UIOSelector_Exist_Bool (inUIOSelector):
#####Внимание##### #####Внимание#####
##Функция ожидания появления элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться) ##Функция ожидания появления элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться)
def UIOSelectorsSecs_WaitAppear_List (inSpecificationListList,inWaitSecs,inFlagWaitAllInMoment=False): 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 lResultFlag=False
lSecsSleep = 1 #Настроечный параметр lSecsSleep = 1 #Настроечный параметр
lSecsDone = 0 lSecsDone = 0
@ -319,6 +353,19 @@ def UIOSelectorsSecs_WaitAppear_List (inSpecificationListList,inWaitSecs,inFlagW
#####Внимание##### #####Внимание#####
##Функция ожидания пропажи элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться) ##Функция ожидания пропажи элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться)
def UIOSelectorsSecs_WaitDisappear_List (inSpecificationListList,inWaitSecs,inFlagWaitAllInMoment=False): 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 lResultFlag=False
lSecsSleep = 1 #Настроечный параметр lSecsSleep = 1 #Настроечный параметр
lSecsDone = 0 lSecsDone = 0
@ -355,6 +402,13 @@ def UIOSelectorsSecs_WaitDisappear_List (inSpecificationListList,inWaitSecs,inFl
#return: Bool - True - UIO is appear #return: Bool - True - UIO is appear
#old name - - #old name - -
def UIOSelectorSecs_WaitAppear_Bool (inSpecificationList,inWaitSecs): 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) lWaitAppearList=UIOSelectorsSecs_WaitAppear_List([inSpecificationList],inWaitSecs)
lResult=False lResult=False
if len(lWaitAppearList)>0: if len(lWaitAppearList)>0:
@ -367,6 +421,14 @@ def UIOSelectorSecs_WaitAppear_Bool (inSpecificationList,inWaitSecs):
#return: Bool - True - UIO is Disappear #return: Bool - True - UIO is Disappear
#old name - - #old name - -
def UIOSelectorSecs_WaitDisappear_Bool (inSpecificationList,inWaitSecs): 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) lWaitDisappearList=UIOSelectorsSecs_WaitDisappear_List([inSpecificationList],inWaitSecs)
lResult=False lResult=False
if len(lWaitDisappearList)>0: if len(lWaitDisappearList)>0:
@ -378,6 +440,12 @@ def UIOSelectorSecs_WaitDisappear_Bool (inSpecificationList,inWaitSecs):
#old name - None #old name - None
#return None (if Process not found), int 32, or int 64 #return None (if Process not found), int 32, or int 64
def UIOSelector_Get_BitnessInt (inSpecificationList): 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 lResult=None
#Получить объект Application (Для проверки разрядности) #Получить объект Application (Для проверки разрядности)
lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList) lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList)
@ -393,6 +461,12 @@ def UIOSelector_Get_BitnessInt (inSpecificationList):
#old name - None #old name - None
#return None (if Process not found), int 32, or int 64 #return None (if Process not found), int 32, or int 64
def UIOSelector_Get_BitnessStr (inSpecificationList): 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 lResult=None
#Получить объект Application (Для проверки разрядности) #Получить объект Application (Для проверки разрядности)
lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList) lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList)
@ -407,15 +481,23 @@ def UIOSelector_Get_BitnessStr (inSpecificationList):
#old name - None #old name - None
#return int 32, or int 64 #return int 32, or int 64
def Get_OSBitnessInt (): def Get_OSBitnessInt ():
lResult=32; '''
Detect OS bitness.
:return: int 32 or int 64
'''
lResult=32
if pywinauto.sysinfo.is_x64_OS(): if pywinauto.sysinfo.is_x64_OS():
lResult=64; lResult=64
return lResult; 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): 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 #Default value
lResult = None lResult = None
#Go check bitness if selector exists #Go check bitness if selector exists
@ -426,11 +508,14 @@ def UIOSelector_SafeOtherGet_Process(inUIOSelector):
lResult = Utils.ProcessBitness.OtherProcessGet() lResult = Utils.ProcessBitness.OtherProcessGet()
return lResult 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): 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 #Определение backend
lBackend=mDefaultPywinautoBackend lBackend=mDefaultPywinautoBackend
if "backend" in inControlSpecificationArray[0]: if "backend" in inControlSpecificationArray[0]:
@ -440,7 +525,7 @@ def PWASpecification_Get_UIO(inControlSpecificationArray):
inControlSpecificationOriginArray=copy.deepcopy(inControlSpecificationArray) inControlSpecificationOriginArray=copy.deepcopy(inControlSpecificationArray)
inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray) inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив #Выполнить идентификацию объектов, если передан массив
lResultList=[]; lResultList=[]
lTempObject=None lTempObject=None
if len(inControlSpecificationArray) > 0: if len(inControlSpecificationArray) > 0:
#Сформировать выборку элементов, которые подходят под первый уровень спецификации #Сформировать выборку элементов, которые подходят под первый уровень спецификации
@ -477,11 +562,13 @@ def PWASpecification_Get_UIO(inControlSpecificationArray):
lResultList.append(lTempObject) lResultList.append(lTempObject)
return lResultList 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): 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) inControlSpecificationArray=copy.deepcopy(inControlSpecificationArray)
#Определение backend #Определение backend
lBackend=mDefaultPywinautoBackend lBackend=mDefaultPywinautoBackend
@ -492,7 +579,7 @@ def PWASpecification_Get_PWAApplication(inControlSpecificationArray):
inControlSpecificationOriginArray=inControlSpecificationArray inControlSpecificationOriginArray=inControlSpecificationArray
inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray) inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив #Выполнить идентификацию объектов, если передан массив
lResultList=[]; lResultList=[]
lTempObject=None lTempObject=None
if len(inControlSpecificationArray) > 0: if len(inControlSpecificationArray) > 0:
#Выполнить подключение к объекту #Выполнить подключение к объекту
@ -513,10 +600,14 @@ def PWASpecification_Get_PWAApplication(inControlSpecificationArray):
return lTempObject 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): 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 lGUISearchElementSelected=None
#Настройка - частота обновления подсвечивания #Настройка - частота обновления подсвечивания
lTimeSleepSeconds=0.4 lTimeSleepSeconds=0.4
@ -548,17 +639,21 @@ def UIOSelector_SearchChildByMouse_UIO(inElementSpecification):
UIO_Highlight(lElementFounded) UIO_Highlight(lElementFounded)
else: else:
#Была нажата клавиша Ctrl - выйти из цикла #Была нажата клавиша Ctrl - выйти из цикла
lFlagLoop=False; lFlagLoop=False
#Заснуть до следующего цикла #Заснуть до следующего цикла
time.sleep(lTimeSleepSeconds) time.sleep(lTimeSleepSeconds)
#Вернуть результат поиска #Вернуть результат поиска
return lElementFoundedList 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 #old name - AutomationSearchMouseElementHierarchy
def UIOSelector_SearchChildByMouse_UIOTree(inUIOSelector): 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 = [] lItemInfo = []
#Check the bitness #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
@ -687,6 +782,12 @@ def UIOSelector_Get_UIOInfoList (inUIOSelector, inElement=None):
#inSpecificationList - UIOSelector #inSpecificationList - UIOSelector
#old name - PywinautoExtTryToRestore #old name - PywinautoExtTryToRestore
def UIOSelector_TryRestore_Dict(inSpecificationList): 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={} lResult={}
try: try:
#Подготовка взодного массива #Подготовка взодного массива
@ -705,6 +806,12 @@ def UIOSelector_TryRestore_Dict(inSpecificationList):
#inControlSpecificationArray - UIOSelector #inControlSpecificationArray - UIOSelector
#old name - ElementActionGetList #old name - ElementActionGetList
def UIOSelector_Get_UIOActivityList (inUIOSelector): 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 #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None: if lSafeOtherProcess is None:
@ -742,7 +849,18 @@ def UIOSelector_Get_UIOActivityList (inUIOSelector):
#inUIOSelector #inUIOSelector
#inActionName - UIOActivity (name) from Pywinauto #inActionName - UIOActivity (name) from Pywinauto
#old name - ElementRunAction #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={} lResult={}
#Check the bitness #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) 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)!!!!! #!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementGetInfo #old name - ElementGetInfo
def UIOSelector_Get_UIOInfo(inUIOSelector): 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 #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None: if lSafeOtherProcess is None:
#Подготовка входного массива #Подготовка входного массива
inUIOSelector=UIOSelector_SearchUIONormalize_UIOSelector(inUIOSelector) inUIOSelector=UIOSelector_SearchUIONormalize_UIOSelector(inUIOSelector)
#Выполнить идентификацию объектов, если передан массив #Выполнить идентификацию объектов, если передан массив
lResultList=[]; lResultList=[]
if len(inUIOSelector) > 0: if len(inUIOSelector) > 0:
#Получить объект #Получить объект
lTempObject=UIOSelector_Get_UIO(inUIOSelector) lTempObject=UIOSelector_Get_UIO(inUIOSelector)
@ -824,7 +948,8 @@ def UIOSelector_Get_UIOInfo(inUIOSelector):
#inHierarchyList: [{"index":<>,"element":<>}] - technical argument for internal purpose #inHierarchyList: [{"index":<>,"element":<>}] - technical argument for internal purpose
#result -List of dict [{"index":<>,"element":<>}] -- list of element hierarchy specifications #result -List of dict [{"index":<>,"element":<>}] -- list of element hierarchy specifications
#old name - GUISearchElementByRootXY #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 lResultElement = None
lResultElementX1 = 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)!!!!! #!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#inControlSpecificationArray- UIOSelector #inControlSpecificationArray- UIOSelector
#old name - ElementGetChildElementList #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"File!!!!")
#mRobotLogger.info(f"inSelector:{str(inUIOSelector)}, inBackend:{str(inBackend)}") #mRobotLogger.info(f"inSelector:{str(inUIOSelector)}, inBackend:{str(inBackend)}")
#pdb.set_trace() #pdb.set_trace()
@ -1194,7 +1329,7 @@ def BackendStr_GetTopLevelList_UIOInfo(inBackend=mDefaultPywinautoBackend):
lResultList2=[] lResultList2=[]
for lI in lResultList: for lI in lResultList:
lTempObjectInfo=lI lTempObjectInfo=lI
lResultList2.append(UIOEI_Convert_UIOInfo(lI)); lResultList2.append(UIOEI_Convert_UIOInfo(lI))
return lResultList2 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)!!!!! #!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementDrawOutlineNew #old name - ElementDrawOutlineNew
def UIOSelector_Highlight(inUIOSelector): 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 #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None: 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)!!!!! #!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementDrawOutlineNewFocus #old name - ElementDrawOutlineNewFocus
def UIOSelector_FocusHighlight(inUIOSelector): 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 #Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None: if lSafeOtherProcess is None:

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

@ -3,11 +3,20 @@
#################################### ####################################
- Guide - Guide
- - ENG - in progress (see content below), plan date 31.08.2020 (failed), new plan date march 2021 - ENG - done 2021.03.11
- - RUS - queue - 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 - Tutorial
- - ENG - queue - ENG - queue
- - RUS - queue - RUS - in progress
- Dev actions - 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). pyOpenRPA is created by Ivan Maslov (Russia).
Use it absolutely for free! 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 #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. #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 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 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. If you will find some issue in pyOpenRPA - write about it to me via e-mail/skype/gitlab issue.
Thank you! Thank you!

@ -2,10 +2,21 @@
1. Description 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 Here is the example of the pyOpenRPA usage.
##################################
.. automodule:: pyOpenRPA.Robot.UIDesktop .. code-block:: python
:members:
# 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 2. Defs
#################################### ####################################
**************************************************************************************************** Here you can find the functions description for interaction with desktop GUI applications
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)
.. automodule:: pyOpenRPA.Robot.UIDesktop .. automodule:: pyOpenRPA.Robot.UIDesktop
:members: :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. 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 Definitions
############################################ ############################################
**UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]<br> - **UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]
**UIOSelector** - List of dict (key attributes)<br> - **UIOSelector** - List of dict (key attributes)
**PWA** - PyWinAuto<br> - **PWA** - PyWinAuto
**PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)<br> - **PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)
**UIOTree** - Recursive Dict of Dict ... (UI Parent -> Child hierarchy)<br> - **UIOTree** - Recursive Dict of Dict ... (UI Parent -> Child hierarchy)
**UIOInfo** - Dict of UIO attributes<br> - **UIOInfo** - Dict of UIO attributes
**UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module<br> - **UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module
**UIOEI** - UI Object info object - **UIOEI** - UI Object info object
What is UIO? What is UIO?
@ -120,11 +120,12 @@ This approach allows us to implement useful functionality that has already been
UIOSelector structure & example 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. 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** **Desciption**
```
.. code-block:: python
[ [
{ {
"depth_start" :: [int, start from 1] :: the depth index, where to start check the condition list (default 1), "depth_start" :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
@ -146,14 +147,31 @@ UIOSelector is the list of condition items for the UIO in GUI. Each item has con
}, },
{ ... specification next level UIO } { ... specification next level UIO }
] ]
```
**The UIO selector example** **The UIO selector example**
```
.. code-block:: python
[ [
{"class_name":"CalcFrame", "backend":"win32"}, # 1-st level UIO specification {"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) {"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 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 :) ). 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 2. How to use
#################################### ####################################
.. only:: html
HTML CODE
.. only:: markdown
MARKDOWN CODE
Content Content
======= =======

@ -115,13 +115,14 @@ Wiki structure
************************************************** **************************************************
In wiki you can use the following docs: 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 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 MarkDown `[|OPEN GITLAB|] <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md>`_
- ENG Guide PDF [|WAIT|]() - 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|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md) - 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 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 Guide content

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

@ -181,27 +181,53 @@
<div class="section" id="roadmap"> <div class="section" id="roadmap">
<h1>2. Roadmap<a class="headerlink" href="#roadmap" title="Permalink to this headline"></a></h1> <h1>2. Roadmap<a class="headerlink" href="#roadmap" title="Permalink to this headline"></a></h1>
<ul class="simple"> <ul class="simple">
<li><p>Guide</p></li> <li><dl class="simple">
<li><ul> <dt>Guide</dt><dd><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>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> </ul>
</dd>
</dl>
</li> </li>
<li><ul>
<li><p>RUS - queue</p></li> <li><p>RUS - queue</p></li>
</ul> </ul>
</dd>
</dl>
</li> </li>
<li><p>Tutorial</p></li> <li><dl class="simple">
<li><ul> <dt>Tutorial</dt><dd><ul>
<li><p>ENG - queue</p></li> <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> </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>
<li><ul>
<li><p>RUS - queue</p></li>
</ul> </ul>
</dd>
</dl>
</li> </li>
<li><p>Dev actions</p></li>
</ul> </ul>
<p>Refactoring the arguments in UIDesktop.py (only in new branch pyOpenRPA version. For backward compatibility purpose), plan date -</p>
</div> </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> <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). <p>pyOpenRPA is created by Ivan Maslov (Russia).
Use it absolutely for free!</p> Use it absolutely for free!</p>
<p>My purpose is to create #IT4Business models all over the world.</p> <p>My purpose is to create #IT4Business models in the companies.
<p>#IT4Business homepage - <a class="reference external" href="https://www.facebook.com/RU.IT4Business">https://www.facebook.com/RU.IT4Business</a></p> I can help you to create the new #IT4Business in your company.
<p>#IT4Busines is the methodology which is created for build compact fast and reliable IT function in company.</p> #IT4Business homepage - <a class="reference external" href="https://www.facebook.com/RU.IT4Business">https://www.facebook.com/RU.IT4Business</a>
<p>If you has many IT specialists, very long deadlines for the IT tasks, many bugs in IT software - #IT4Business is for you :)</p> #IT4Busines is the methodology which is created for build compact fast and reliable IT function in company.
<p>If you need some IT help - feel free to contact me (prefer e-mail or skype).</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 will find some issue in pyOpenRPA - write about it to me via e-mail/skype/gitlab issue.</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> <p>Thank you!</p>
<div class="section" id="ivan-maslov-founder"> <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> <h2>Ivan Maslov (founder)<a class="headerlink" href="#ivan-maslov-founder" title="Permalink to this headline"></a></h2>

@ -94,10 +94,7 @@
</ul> </ul>
<p class="caption"><span class="caption-text">ROBOT</span></p> <p class="caption"><span class="caption-text">ROBOT</span></p>
<ul class="current"> <ul class="current">
<li class="toctree-l1 current"><a class="current reference internal" href="#">1. Description</a><ul> <li class="toctree-l1 current"><a class="current reference internal" href="#">1. Description</a></li>
<li class="toctree-l2"><a class="reference internal" href="#module-pyOpenRPA.Robot.UIDesktop">pyOpenRPA Robot</a></li>
</ul>
</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="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="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> <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"> <div class="section" id="description">
<h1>1. Description<a class="headerlink" href="#description" title="Permalink to this headline"></a></h1> <h1>1. Description<a class="headerlink" href="#description" title="Permalink to this headline"></a></h1>
<p>pyOpenRPA Robot is the python package.</p> <p>pyOpenRPA Robot is the python package which allow you to create best RPA program.</p>
<div class="section" id="module-pyOpenRPA.Robot.UIDesktop"> <p>The description of the functions you can find page Defs (see menu)</p>
<span id="pyopenrpa-robot"></span><h2>pyOpenRPA Robot<a class="headerlink" href="#module-pyOpenRPA.Robot.UIDesktop" title="Permalink to this headline"></a></h2> <p>Here is the example of the pyOpenRPA usage.</p>
<dl class="py function"> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># EXAMPLE 1</span>
<dt id="pyOpenRPA.Robot.UIDesktop.Get_OSBitnessInt"> <span class="kn">from</span> <span class="nn">pyOpenRPA.Robot</span> <span class="kn">import</span> <span class="n">UIDesktop</span>
<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> <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>
<dl class="field-list simple"> <span class="n">inSpecificationList</span><span class="o">=</span><span class="p">[</span>
<dt class="field-odd">Returns</dt> <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>
<dd class="field-odd"><p>int 32 or int 64</p> <span class="n">inElement</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
</dd> <span class="n">inFlagRaiseException</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</dl>
</dd></dl> <span class="n">lNotepadOKButton</span><span class="o">.</span><span class="n">click</span><span class="p">()</span>
</pre></div>
<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>
</div> </div>
</div> </div>

@ -96,13 +96,6 @@
<ul class="current"> <ul class="current">
<li class="toctree-l1"><a class="reference internal" href="01_Robot.html">1. Description</a></li> <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-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> <li class="toctree-l2"><a class="reference internal" href="#references">References</a></li>
</ul> </ul>
</li> </li>
@ -190,87 +183,7 @@
<div class="section" id="defs"> <div class="section" id="defs">
<h1>2. Defs<a class="headerlink" href="#defs" title="Permalink to this headline"></a></h1> <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"> <p>Here you can find the functions description for interaction with desktop GUI applications</p>
<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>
<span class="target" id="module-pyOpenRPA.Robot.UIDesktop"></span><p><strong>Functions:</strong></p> <span class="target" id="module-pyOpenRPA.Robot.UIDesktop"></span><p><strong>Functions:</strong></p>
<table class="longtable docutils align-default"> <table class="longtable docutils align-default">
<colgroup> <colgroup>
@ -702,13 +615,11 @@ Example: [</p>
</dl> </dl>
</dd></dl> </dd></dl>
</div>
</div>
<div class="section" id="references"> <div class="section" id="references">
<h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2> <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"> <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><p><a class="reference external" href="http://docutils.sourceforge.net/rst.html">http://docutils.sourceforge.net/rst.html</a></p>
</dd> </dd>
</dl> </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> <li class="toctree-l3"><a class="reference internal" href="#use-in-studio-script-n-a">Use in studio script (n/a)</a></li>
</ul> </ul>
</li> </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="#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="#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="#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="#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> </ul>
</li> </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-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="#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> </ul>
</li> </li>
<li class="toctree-l2"><a class="reference internal" href="#theory-practice-keyboard-mouse-manipulation">Theory &amp; practice. Keyboard &amp; mouse manipulation</a></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> <p>Here you can find the docs and examples of the OpenRPA desktop (GUI) app access.</p>
</div> </div>
</div> </div>
<div class="section" id="theory-practice-desktop-app-ui-access-win32-and-ui-automation-dlls"> <div class="section" id="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> <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"> <div class="section" id="definitions">
<h3>Definitions<a class="headerlink" href="#definitions" title="Permalink to this headline"></a></h3> <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; <ul class="simple">
<strong>UIOSelector</strong> - List of dict (key attributes)&lt;br&gt; <li><p><strong>UIO</strong> - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]</p></li>
<strong>PWA</strong> - PyWinAuto&lt;br&gt; <li><p><strong>UIOSelector</strong> - List of dict (key attributes)</p></li>
<strong>PWASpecification</strong> - List of dict (key attributes in pywinauto.find_window notation)&lt;br&gt; <li><p><strong>PWA</strong> - PyWinAuto</p></li>
<strong>UIOTree</strong> - Recursive Dict of Dict … (UI Parent -&gt; Child hierarchy)&lt;br&gt; <li><p><strong>PWASpecification</strong> - List of dict (key attributes in pywinauto.find_window notation)</p></li>
<strong>UIOInfo</strong> - Dict of UIO attributes&lt;br&gt; <li><p><strong>UIOTree</strong> - Recursive Dict of Dict … (UI Parent -&gt; Child hierarchy)</p></li>
<strong>UIOActivity</strong> - Activity of the UIO (UI object) from the Pywinauto module&lt;br&gt; <li><p><strong>UIOInfo</strong> - Dict of UIO attributes</p></li>
<strong>UIOEI</strong> - UI Object info object</p> <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>
<div class="section" id="what-is-uio"> <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> <h3>What is UIO?<a class="headerlink" href="#what-is-uio" title="Permalink to this headline"></a></h3>
@ -305,56 +308,57 @@
</div> </div>
<div class="section" id="uioselector-structure-example"> <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> <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; <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>
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>
<dl class="simple"> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span>[
<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> &quot;depth_start&quot; :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
</dl> &quot;depth_end&quot; :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1),
<dl> &quot;ctrl_index&quot; || &quot;index&quot; :: [int, starts from 0] :: the index of the UIO in parent UIO child list,
<dt>[</dt><dd><dl class="simple"> &quot;title&quot; :: [str] :: the condition for the UIO attribute *title*,
<dt>{</dt><dd><p>“depth_start” :: [int, start from 1] :: the depth index, where to start check the condition list (default 1), &quot;title_re&quot; :: [str] :: regular expression (python ver) for the condition for the UIO attribute *title*,
“depth_end” :: [int, start from 1] :: the depth index, where to stop check the condition list (default 1), &quot;rich_text&quot; :: [str] :: the condition for the UIO attribute *rich_text*,
“ctrl_index” || “index” :: [int, starts from 0] :: the index of the UIO in parent UIO child list, &quot;rich_text_re&quot; :: [str] :: regular expression (python ver) for the condition for the UIO attribute *rich_text*,
“title” :: [str] :: the condition for the UIO attribute <em>title</em>, &quot;class_name&quot; :: [str] :: the condition for the UIO attribute *class_name*,
“title_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>title</em>, &quot;class_name_re&quot; :: [str] :: regular expression (python ver) for the condition for the UIO attribute *class_name*,
“rich_text” :: [str] :: the condition for the UIO attribute <em>rich_text</em>, &quot;friendly_class_name&quot; :: [str] :: the condition for the UIO attribute *friendly_class_name*,
“rich_text_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>rich_text</em>, &quot;friendly_class_name_re&quot; :: [str] :: regular expression (python ver) for the condition for the UIO attribute *friendly_class_name*,
“class_name” :: [str] :: the condition for the UIO attribute <em>class_name</em>, &quot;control_type&quot; :: [str] :: the condition for the UIO attribute *control_type*,
“class_name_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>class_name</em>, &quot;control_type_re&quot; :: [str] :: regular expression (python ver) for the condition for the UIO attribute *control_type*,
“friendly_class_name” :: [str] :: the condition for the UIO attribute <em>friendly_class_name</em>, &quot;is_enabled&quot; :: [bool] :: the condition for the UIO attribute *is_enabled*. If UI object is enabled on GUI,
“friendly_class_name_re” :: [str] :: regular expression (python ver) for the condition for the UIO attribute <em>friendly_class_name</em>, &quot;is_visible&quot; :: [bool] :: the condition for the UIO attribute *is_visible*. If UI object is visible on GUI,
“control_type” :: [str] :: the condition for the UIO attribute <em>control_type</em>, &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.
“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, { ... specification next level UIO }
“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> </pre></div>
</dd> </div>
</dl> <p><strong>The UIO selector example</strong></p>
<p>}, <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="p">[</span>
{ … specification next level UIO }</p> <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>
</dd> <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>
</dl> <span class="p">]</span>
<dl class="simple"> </pre></div>
<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> </div>
</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>
</div> </div>
<div class="section" id="the-uidesktop-module-openrpa-robot-uidesktop-py"> <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> <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>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> </div>
<div class="section" id="theory-practice-web-app-ui-access-selenium"> <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). <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> 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>
<div class="section" id="id19"> <div class="section" id="id4">
<h3>How to use<a class="headerlink" href="#id19" title="Permalink to this headline"></a></h3> <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> <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> <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> <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"> <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> <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"> <div class="section" id="content">
<h2>Content<a class="headerlink" href="#content" title="Permalink to this headline"></a></h2> <h2>Content<a class="headerlink" href="#content" title="Permalink to this headline"></a></h2>
<ul class="simple"> <ul class="simple">

@ -3,11 +3,20 @@
#################################### ####################################
- Guide - Guide
- - ENG - in progress (see content below), plan date 31.08.2020 (failed), new plan date march 2021 - ENG - done 2021.03.11
- - RUS - queue - 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 - Tutorial
- - ENG - queue - ENG - queue
- - RUS - queue - RUS - in progress
- Dev actions - 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). pyOpenRPA is created by Ivan Maslov (Russia).
Use it absolutely for free! 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 #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. #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 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 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. If you will find some issue in pyOpenRPA - write about it to me via e-mail/skype/gitlab issue.
Thank you! Thank you!

@ -2,10 +2,21 @@
1. Description 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 Here is the example of the pyOpenRPA usage.
##################################
.. automodule:: pyOpenRPA.Robot.UIDesktop .. code-block:: python
:members:
# 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 2. Defs
#################################### ####################################
**************************************************************************************************** Here you can find the functions description for interaction with desktop GUI applications
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)
.. automodule:: pyOpenRPA.Robot.UIDesktop .. automodule:: pyOpenRPA.Robot.UIDesktop
:members: :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. 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 Definitions
############################################ ############################################
**UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]<br> - **UIO** - UI Object (class of pywinauto UI object) [pywinauto.base_wrapper]
**UIOSelector** - List of dict (key attributes)<br> - **UIOSelector** - List of dict (key attributes)
**PWA** - PyWinAuto<br> - **PWA** - PyWinAuto
**PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)<br> - **PWASpecification** - List of dict (key attributes in pywinauto.find_window notation)
**UIOTree** - Recursive Dict of Dict ... (UI Parent -> Child hierarchy)<br> - **UIOTree** - Recursive Dict of Dict ... (UI Parent -> Child hierarchy)
**UIOInfo** - Dict of UIO attributes<br> - **UIOInfo** - Dict of UIO attributes
**UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module<br> - **UIOActivity** - Activity of the UIO (UI object) from the Pywinauto module
**UIOEI** - UI Object info object - **UIOEI** - UI Object info object
What is UIO? What is UIO?
@ -120,11 +120,12 @@ This approach allows us to implement useful functionality that has already been
UIOSelector structure & example 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. 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** **Desciption**
```
.. code-block:: python
[ [
{ {
"depth_start" :: [int, start from 1] :: the depth index, where to start check the condition list (default 1), "depth_start" :: [int, start from 1] :: the depth index, where to start check the condition list (default 1),
@ -146,14 +147,31 @@ UIOSelector is the list of condition items for the UIO in GUI. Each item has con
}, },
{ ... specification next level UIO } { ... specification next level UIO }
] ]
```
**The UIO selector example** **The UIO selector example**
```
.. code-block:: python
[ [
{"class_name":"CalcFrame", "backend":"win32"}, # 1-st level UIO specification {"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) {"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 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 :) ). 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 2. How to use
#################################### ####################################
.. only:: html
HTML CODE
.. only:: markdown
MARKDOWN CODE
Content Content
======= =======

@ -21,7 +21,7 @@ Donate
pyOpenRPA is absolutely non-commercial project. pyOpenRPA is absolutely non-commercial project.
Please donate some $ if pyOpenRPA project is actual for you. Link to online donations. 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 About
@ -115,13 +115,14 @@ Wiki structure
************************************************** **************************************************
In wiki you can use the following docs: 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 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 MarkDown `[|OPEN GITLAB|] <https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md>`_
- ENG Guide PDF [|WAIT|]() - 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|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/RUS_Tutorial/DesktopGUI_Habr/index.md) - 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 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 Guide content

@ -210,7 +210,7 @@
<h2 id="G">G</h2> <h2 id="G">G</h2>
<table style="width: 100%" class="indextable genindextable"><tr> <table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul> <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>
<li><a href="Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.GSettingsAutocleaner">GSettingsAutocleaner() (in module pyOpenRPA.Orchestrator.__Orchestrator__)</a> <li><a href="Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.GSettingsAutocleaner">GSettingsAutocleaner() (in module pyOpenRPA.Orchestrator.__Orchestrator__)</a>
</li> </li>
@ -236,7 +236,7 @@
<ul> <ul>
<li><a href="Orchestrator/02_Defs.html#module-pyOpenRPA.Orchestrator.__Orchestrator__">pyOpenRPA.Orchestrator.__Orchestrator__</a> <li><a href="Orchestrator/02_Defs.html#module-pyOpenRPA.Orchestrator.__Orchestrator__">pyOpenRPA.Orchestrator.__Orchestrator__</a>
</li> </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> </li>
</ul></li> </ul></li>
</ul></td> </ul></td>
@ -279,9 +279,9 @@
<td style="width: 33%; vertical-align: top;"><ul> <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><a href="Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.ProcessStop">ProcessStop() (in module pyOpenRPA.Orchestrator.__Orchestrator__)</a>
</li> </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>
<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>
<li> <li>
pyOpenRPA.Orchestrator.__Orchestrator__ pyOpenRPA.Orchestrator.__Orchestrator__
@ -294,7 +294,7 @@
pyOpenRPA.Robot.UIDesktop pyOpenRPA.Robot.UIDesktop
<ul> <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> </li>
</ul></li> </ul></li>
<li><a href="Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.PythonStart">PythonStart() (in module pyOpenRPA.Orchestrator.__Orchestrator__)</a> <li><a href="Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.PythonStart">PythonStart() (in module pyOpenRPA.Orchestrator.__Orchestrator__)</a>
@ -353,45 +353,45 @@
</li> </li>
<li><a href="Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.UACUpdate">UACUpdate() (in module pyOpenRPA.Orchestrator.__Orchestrator__)</a> <li><a href="Orchestrator/02_Defs.html#pyOpenRPA.Orchestrator.__Orchestrator__.UACUpdate">UACUpdate() (in module pyOpenRPA.Orchestrator.__Orchestrator__)</a>
</li> </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>
<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>
<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>
<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>
<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>
<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>
<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>
<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> </li>
</ul></td> </ul></td>
<td style="width: 33%; vertical-align: top;"><ul> <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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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> </li>
</ul></td> </ul></td>
</tr></table> </tr></table>

@ -186,7 +186,7 @@
<h2>Donate<a class="headerlink" href="#donate" title="Permalink to this headline"></a></h2> <h2>Donate<a class="headerlink" href="#donate" title="Permalink to this headline"></a></h2>
<p>pyOpenRPA is absolutely non-commercial project.</p> <p>pyOpenRPA is absolutely non-commercial project.</p>
<p>Please donate some $ if pyOpenRPA project is actual for you. Link to online donations. <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>
<div class="section" id="about"> <div class="section" id="about">
<h2>About<a class="headerlink" href="#about" title="Permalink to this headline"></a></h2> <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> <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> <p>In wiki you can use the following docs:</p>
<ul class="simple"> <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 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 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 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="#id5"><span class="problematic" id="id6">|WAIT|</span></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 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 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 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 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 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>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> </ul>
</div> </div>
<div class="section" id="guide-content"> <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"> <div class="toctree-wrapper compound">
<p class="caption"><span class="caption-text">ROBOT</span></p> <p class="caption"><span class="caption-text">ROBOT</span></p>
<ul> <ul>
<li class="toctree-l1"><a class="reference internal" href="Robot/01_Robot.html">1. Description</a><ul> <li class="toctree-l1"><a class="reference internal" href="Robot/01_Robot.html">1. Description</a></li>
<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/02_Defs.html">2. Defs</a><ul> <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> <li class="toctree-l2"><a class="reference internal" href="Robot/02_Defs.html#references">References</a></li>
</ul> </ul>
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="Robot/03_HowToUse.html">3. How to use</a><ul> <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#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-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-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> <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

@ -4,25 +4,51 @@
* Guide * 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)
* MarkDown [|OPEN GITLAB|](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md)
* PDF
```
`|WAIT| <>`_
```
*
* RUS - queue * RUS - queue
* Tutorial * Tutorial
*
* ENG - queue * ENG - queue
* * RUS - in progress
* RUS - queue
* 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)
* Leaflet
* ENG 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). pyOpenRPA is created by Ivan Maslov (Russia).
Use it absolutely for free! 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) #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. #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 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 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. If you will find some issue in pyOpenRPA - write about it to me via e-mail/skype/gitlab issue.
Thank you! Thank you!

@ -1,413 +1,20 @@
# 1. Description # 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** lNotepadOKButton.click()
```
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**

@ -1,153 +1,6 @@
# 2. Defs # 2. Defs
## Desktop app UI access (win32 and UI automation dlls) Here you can find the functions description for interaction with desktop GUI applications
### 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)
```
**Functions:** **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. 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 ### 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** - List of dict (key attributes)
### UIOSelector structure & example
<a name=”UIOSelector_Structure_Examples”></a> * **PWA** - PyWinAuto
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**
* **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), * **UIOEI** - UI Object info object
“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.
}, ### What is UIO?
{ … specification next level 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** **The UIO selector example**
```
``
```
```
`
``` ```
[ [
{"class_name":"CalcFrame", "backend":"win32"}, # 1-st level UIO specification
{“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)
{“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) ### The UIDesktop module (OpenRPA/Robot/UIDesktop.py)

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

@ -17,7 +17,7 @@ contain the root `toctree` directive. -->
pyOpenRPA is absolutely non-commercial project. pyOpenRPA is absolutely non-commercial project.
Please donate some $ if pyOpenRPA project is actual for you. Link to online donations. 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 ## 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: In wiki you can use the following docs:
* ENG Guide HTML [ * ENG Guide HTML [[|OPEN GITLAB|]](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/html/index.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|
```
]()
* RUS Article: Less cost - no paid RPA [ * ENG Guide MarkDown [[|OPEN GITLAB|]](https://gitlab.com/UnicodeLabs/OpenRPA/-/tree/master/Wiki/ENG_Guide/markdown/index.md)
```
|OPEN HABR|
```
]([https://habr.com/ru/post/509644/](https://habr.com/ru/post/509644/))
* 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 ## Guide content
@ -253,15 +213,9 @@ In wiki you can use the following docs:
* 1. Description * 1. Description
* pyOpenRPA Robot
* 2. Defs * 2. Defs
* Desktop app UI access (win32 and UI automation dlls)
* References * References
@ -271,7 +225,7 @@ In wiki you can use the following docs:
* How to execute RPA script * 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) * Theory & practice. WEB app UI access (selenium)

Loading…
Cancel
Save