From 5b9274570fd35555061479d359a02020c4d0c628 Mon Sep 17 00:00:00 2001 From: Ivan Maslov Date: Mon, 10 Oct 2022 21:36:35 +0300 Subject: [PATCH] =?UTF-8?q?v1.3.1=20=D1=80=D0=B5=D0=BB=D0=B8=D0=B7!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../INSTALLER | 0 .../pyOpenRPA-1.3.1.dist-info}/METADATA | 4 +- .../RECORD | 71 +- .../REQUESTED | 0 .../WHEEL | 0 .../top_level.txt | 0 .../Lib/site-packages/pyOpenRPA/Agent/A2O.py | 2 +- .../Lib/site-packages/pyOpenRPA/Agent/O2A.py | 2 +- .../Orchestrator/BackwardCompatibility.py | 4 +- .../Orchestrator/Managers/ControlPanel.py | 6 +- .../Orchestrator/Managers/Process.py | 38 +- .../pyOpenRPA/Orchestrator/Server.py | 870 ++++----------- .../pyOpenRPA/Orchestrator/ServerBC.py | 424 ++++++++ .../pyOpenRPA/Orchestrator/ServerSettings.py | 226 ++-- .../pyOpenRPA/Orchestrator/Web/Index.js | 992 ------------------ .../pyOpenRPA/Orchestrator/Web/Index.xhtml | 499 --------- .../pyOpenRPA/Orchestrator/Web/favicon.ico | Bin 112922 -> 0 bytes .../Orchestrator/__Orchestrator__.py | 250 +++-- .../Semantic-UI-CSS-master/semantic.min.css | 2 +- .../pyOpenRPA/Resources/Web/orpa/footer.xhtml | 19 +- .../pyOpenRPA/Resources/Web/orpa/header.xhtml | 35 +- .../pyOpenRPA/Resources/Web/orpa/orc.js | 228 +--- .../pyOpenRPA/Resources/Web/orpa/orc.xhtml | 42 +- .../pyOpenRPA/Resources/Web/orpa/std.xhtml} | 191 +--- .../site-packages/pyOpenRPA/Robot/Audio.py | 407 +++++++ .../site-packages/pyOpenRPA/Robot/Keyboard.py | 4 + .../site-packages/pyOpenRPA/Robot/UIWeb.py | 32 +- .../site-packages/pyOpenRPA/Studio/Studio.py | 69 +- .../pyOpenRPA/Studio/Web/favicon.ico | Bin 112922 -> 0 bytes .../site-packages/pyOpenRPA/Tools/Debugger.py | 1 + .../pyOpenRPA/Utils/Dictionary.py | 43 + .../Lib/site-packages/pyOpenRPA/Utils/Disk.py | 11 + .../site-packages/pyOpenRPA/Utils/Network.py | 17 + .../Lib/site-packages/pyOpenRPA/Utils/Text.py | 7 + .../Lib/site-packages/pyOpenRPA/__init__.py | 2 +- .../INSTALLER | 0 .../pyOpenRPA-1.3.1.dist-info}/METADATA | 4 +- .../RECORD | 71 +- .../REQUESTED | 0 .../WHEEL | 0 .../top_level.txt | 0 .../Lib/site-packages/pyOpenRPA/Agent/A2O.py | 2 +- .../Lib/site-packages/pyOpenRPA/Agent/O2A.py | 2 +- .../Orchestrator/BackwardCompatibility.py | 4 +- .../Orchestrator/Managers/ControlPanel.py | 6 +- .../Orchestrator/Managers/Process.py | 38 +- .../pyOpenRPA/Orchestrator/Server.py | 870 ++++----------- .../pyOpenRPA/Orchestrator/ServerBC.py | 424 ++++++++ .../pyOpenRPA/Orchestrator/ServerSettings.py | 226 ++-- .../pyOpenRPA/Orchestrator/Web/Index.js | 992 ------------------ .../pyOpenRPA/Orchestrator/Web/Index.xhtml | 499 --------- .../pyOpenRPA/Orchestrator/Web/favicon.ico | Bin 112922 -> 0 bytes .../Orchestrator/__Orchestrator__.py | 250 +++-- .../Semantic-UI-CSS-master/semantic.min.css | 2 +- .../pyOpenRPA/Resources/Web/orpa/footer.xhtml | 19 +- .../pyOpenRPA/Resources/Web/orpa/header.xhtml | 35 +- .../pyOpenRPA/Resources/Web/orpa/orc.js | 228 +--- .../pyOpenRPA/Resources/Web/orpa/orc.xhtml | 42 +- .../pyOpenRPA/Resources/Web/orpa/std.xhtml} | 191 +--- .../site-packages/pyOpenRPA/Robot/Audio.py | 407 +++++++ .../site-packages/pyOpenRPA/Robot/Keyboard.py | 4 + .../site-packages/pyOpenRPA/Robot/UIWeb.py | 32 +- .../site-packages/pyOpenRPA/Studio/Studio.py | 69 +- .../pyOpenRPA/Studio/Web/favicon.ico | Bin 112922 -> 0 bytes .../site-packages/pyOpenRPA/Tools/Debugger.py | 1 + .../pyOpenRPA/Utils/Dictionary.py | 43 + .../Lib/site-packages/pyOpenRPA/Utils/Disk.py | 11 + .../site-packages/pyOpenRPA/Utils/Network.py | 17 + .../Lib/site-packages/pyOpenRPA/Utils/Text.py | 7 + .../Lib/site-packages/pyOpenRPA/__init__.py | 2 +- Sources/GuideSphinx/Robot/08_audio.rst | 2 +- Sources/GuideSphinx/make_RUS_Guide_PDF.cmd | 2 +- Sources/pyOpenRPA/__init__.py | 2 +- .../Keyboard-checkpoint.ipynb | 470 +++++++++ .../.ipynb_checkpoints/Mouse-checkpoint.ipynb | 131 +++ .../.ipynb_checkpoints/Web-checkpoint.ipynb | 215 ++++ .../Jupyter-notebooks/Modules/Keyboard.ipynb | 4 +- Tools/Jupyter-notebooks/Modules/Mouse.ipynb | 4 +- Tools/Jupyter-notebooks/Modules/Web.ipynb | 4 +- .../.ipynb_checkpoints/Robot-checkpoint.ipynb | 429 ++------ .../doctrees/01_HowToInstall.doctree | Bin 26720 -> 26734 bytes .../doctrees/03_Copyrights_Contacts.doctree | Bin 31779 -> 31793 bytes Wiki/RUS_Guide/doctrees/Agent/02_Defs.doctree | Bin 65528 -> 66041 bytes .../Orchestrator/01_Orchestrator.doctree | Bin 25275 -> 26079 bytes .../doctrees/Orchestrator/02_Defs.doctree | Bin 861965 -> 908536 bytes .../Orchestrator/03_gSettingsTemplate.doctree | Bin 50966 -> 50980 bytes .../doctrees/Orchestrator/04_HowToUse.doctree | Bin 11707 -> 19376 bytes .../doctrees/Orchestrator/05_UAC.doctree | Bin 16162 -> 16176 bytes .../RUS_Guide/doctrees/Robot/01_Robot.doctree | Bin 30079 -> 32085 bytes .../doctrees/Robot/02_uidesktop.doctree | Bin 429529 -> 431377 bytes .../RUS_Guide/doctrees/Robot/03_uiweb.doctree | Bin 204781 -> 206319 bytes .../doctrees/Robot/04_keyboard.doctree | Bin 131396 -> 133304 bytes .../doctrees/Robot/05_clipboard.doctree | Bin 21443 -> 21611 bytes .../RUS_Guide/doctrees/Robot/06_mouse.doctree | Bin 121632 -> 122080 bytes .../doctrees/Robot/07_screen.doctree | Bin 277039 -> 278159 bytes .../doctrees/Robot/08_HowToUse.doctree | Bin 22031 -> 0 bytes .../RUS_Guide/doctrees/Robot/08_audio.doctree | Bin 0 -> 107734 bytes .../doctrees/Robot/09_HowToUse.doctree | Bin 0 -> 26435 bytes .../doctrees/Studio/01_Studio.doctree | Bin 13487 -> 13501 bytes .../doctrees/Studio/02_HowToUse.doctree | Bin 33099 -> 33068 bytes Wiki/RUS_Guide/doctrees/Tools/02_Defs.doctree | Bin 18521 -> 18801 bytes Wiki/RUS_Guide/doctrees/environment.pickle | Bin 604784 -> 641841 bytes Wiki/RUS_Guide/doctrees/index.doctree | Bin 74512 -> 74551 bytes Wiki/RUS_Guide/html/.buildinfo | 2 +- Wiki/RUS_Guide/html/01_HowToInstall.html | 11 +- .../html/03_Copyrights_Contacts.html | 11 +- Wiki/RUS_Guide/html/Agent/02_Defs.html | 11 +- .../html/Orchestrator/01_Orchestrator.html | 13 +- Wiki/RUS_Guide/html/Orchestrator/02_Defs.html | 200 ++-- .../Orchestrator/03_gSettingsTemplate.html | 11 +- .../html/Orchestrator/04_HowToUse.html | 94 +- Wiki/RUS_Guide/html/Orchestrator/05_UAC.html | 11 +- Wiki/RUS_Guide/html/Robot/01_Robot.html | 16 +- Wiki/RUS_Guide/html/Robot/02_uidesktop.html | 11 +- Wiki/RUS_Guide/html/Robot/03_uiweb.html | 41 +- Wiki/RUS_Guide/html/Robot/04_keyboard.html | 13 +- Wiki/RUS_Guide/html/Robot/05_clipboard.html | 11 +- Wiki/RUS_Guide/html/Robot/06_mouse.html | 11 +- Wiki/RUS_Guide/html/Robot/07_screen.html | 15 +- Wiki/RUS_Guide/html/Robot/08_audio.html | 529 ++++++++++ .../{08_HowToUse.html => 09_HowToUse.html} | 34 +- Wiki/RUS_Guide/html/Studio/01_Studio.html | 15 +- Wiki/RUS_Guide/html/Studio/02_HowToUse.html | 13 +- Wiki/RUS_Guide/html/Tools/02_Defs.html | 11 +- Wiki/RUS_Guide/html/_modules/index.html | 10 +- .../_modules/pyOpenRPA/Agent/__Agent__.html | 9 +- .../Orchestrator/__Orchestrator__.html | 267 +++-- .../html/_modules/pyOpenRPA/Robot/Audio.html | 663 ++++++++++++ .../_modules/pyOpenRPA/Robot/Clipboard.html | 9 +- .../_modules/pyOpenRPA/Robot/Keyboard.html | 13 +- .../html/_modules/pyOpenRPA/Robot/Mouse.html | 9 +- .../html/_modules/pyOpenRPA/Robot/Screen.html | 9 +- .../_modules/pyOpenRPA/Robot/UIDesktop.html | 9 +- .../html/_modules/pyOpenRPA/Robot/UIWeb.html | 41 +- .../_modules/pyOpenRPA/Tools/Debugger.html | 10 +- .../_modules/pyOpenRPA/Tools/StopSafe.html | 9 +- .../Orchestrator/01_Orchestrator.rst.txt | 4 + .../_sources/Orchestrator/04_HowToUse.rst.txt | 6 +- .../html/_sources/Robot/01_Robot.rst.txt | 4 + .../html/_sources/Robot/08_audio.rst.txt | 55 + ...8_HowToUse.rst.txt => 09_HowToUse.rst.txt} | 19 +- .../html/_sources/Studio/02_HowToUse.rst.txt | 2 +- .../html/_static/documentation_options.js | 2 +- Wiki/RUS_Guide/html/genindex.html | 79 +- Wiki/RUS_Guide/html/index.html | 31 +- Wiki/RUS_Guide/html/objects.inv | Bin 2946 -> 3114 bytes Wiki/RUS_Guide/html/py-modindex.html | 14 +- Wiki/RUS_Guide/html/search.html | 9 +- Wiki/RUS_Guide/html/searchindex.js | 2 +- Wiki/RUS_Guide/markdown/01_HowToInstall.md | 2 +- .../markdown/03_Copyrights_Contacts.md | 2 +- Wiki/RUS_Guide/markdown/Agent/02_Defs.md | 2 +- .../markdown/Orchestrator/01_Orchestrator.md | 6 +- .../markdown/Orchestrator/02_Defs.md | 224 +++- .../Orchestrator/03_gSettingsTemplate.md | 2 +- .../markdown/Orchestrator/04_HowToUse.md | 76 +- .../RUS_Guide/markdown/Orchestrator/05_UAC.md | 2 +- Wiki/RUS_Guide/markdown/Robot/01_Robot.md | 8 +- Wiki/RUS_Guide/markdown/Robot/02_uidesktop.md | 2 +- Wiki/RUS_Guide/markdown/Robot/03_uiweb.md | 32 +- Wiki/RUS_Guide/markdown/Robot/04_keyboard.md | 6 +- Wiki/RUS_Guide/markdown/Robot/05_clipboard.md | 2 +- Wiki/RUS_Guide/markdown/Robot/06_mouse.md | 2 +- Wiki/RUS_Guide/markdown/Robot/07_screen.md | 2 +- Wiki/RUS_Guide/markdown/Robot/08_audio.md | 306 ++++++ .../Robot/{08_HowToUse.md => 09_HowToUse.md} | 23 +- Wiki/RUS_Guide/markdown/Studio/01_Studio.md | 2 +- Wiki/RUS_Guide/markdown/Studio/02_HowToUse.md | 4 +- Wiki/RUS_Guide/markdown/Tools/02_Defs.md | 2 +- Wiki/RUS_Guide/markdown/index.md | 26 +- Wiki/RUS_Guide/pdf/pyOpenRPA_Guide_RUS.pdf | Bin 1499373 -> 1703717 bytes v1.3.0 => v1.3.1 | 0 172 files changed, 6995 insertions(+), 6366 deletions(-) rename Resources/WPy32-3720/python-3.7.2/Lib/site-packages/{pyOpenRPA-1.3.0.dist-info => pyOpenRPA-1.3.1.dist-info}/INSTALLER (100%) rename Resources/{WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.3.0.dist-info => WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info}/METADATA (99%) rename Resources/WPy32-3720/python-3.7.2/Lib/site-packages/{pyOpenRPA-1.3.0.dist-info => pyOpenRPA-1.3.1.dist-info}/RECORD (92%) rename Resources/WPy32-3720/python-3.7.2/Lib/site-packages/{pyOpenRPA-1.3.0.dist-info => pyOpenRPA-1.3.1.dist-info}/REQUESTED (100%) rename Resources/WPy32-3720/python-3.7.2/Lib/site-packages/{pyOpenRPA-1.3.0.dist-info => pyOpenRPA-1.3.1.dist-info}/WHEEL (100%) rename Resources/WPy32-3720/python-3.7.2/Lib/site-packages/{pyOpenRPA-1.3.0.dist-info => pyOpenRPA-1.3.1.dist-info}/top_level.txt (100%) create mode 100644 Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/ServerBC.py delete mode 100755 Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.js delete mode 100755 Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.xhtml delete mode 100755 Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/favicon.ico rename Resources/{WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Studio/Web/Index.xhtml => WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/std.xhtml} (82%) mode change 100755 => 100644 create mode 100644 Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Robot/Audio.py delete mode 100755 Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Studio/Web/favicon.ico create mode 100644 Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Utils/Dictionary.py create mode 100644 Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Utils/Disk.py create mode 100644 Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Utils/Network.py create mode 100644 Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Utils/Text.py rename Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/{pyOpenRPA-1.3.0.dist-info => pyOpenRPA-1.3.1.dist-info}/INSTALLER (100%) rename Resources/{WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.0.dist-info => WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.3.1.dist-info}/METADATA (99%) rename Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/{pyOpenRPA-1.3.0.dist-info => pyOpenRPA-1.3.1.dist-info}/RECORD (92%) rename Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/{pyOpenRPA-1.3.0.dist-info => pyOpenRPA-1.3.1.dist-info}/REQUESTED (100%) rename Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/{pyOpenRPA-1.3.0.dist-info => pyOpenRPA-1.3.1.dist-info}/WHEEL (100%) rename Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/{pyOpenRPA-1.3.0.dist-info => pyOpenRPA-1.3.1.dist-info}/top_level.txt (100%) create mode 100644 Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Orchestrator/ServerBC.py delete mode 100755 Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.js delete mode 100755 Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.xhtml delete mode 100755 Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Orchestrator/Web/favicon.ico rename Resources/{WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Studio/Web/Index.xhtml => WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/std.xhtml} (82%) mode change 100755 => 100644 create mode 100644 Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Robot/Audio.py delete mode 100755 Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Studio/Web/favicon.ico create mode 100644 Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Utils/Dictionary.py create mode 100644 Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Utils/Disk.py create mode 100644 Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Utils/Network.py create mode 100644 Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Utils/Text.py create mode 100644 Tools/Jupyter-notebooks/Modules/.ipynb_checkpoints/Keyboard-checkpoint.ipynb create mode 100644 Tools/Jupyter-notebooks/Modules/.ipynb_checkpoints/Mouse-checkpoint.ipynb create mode 100644 Tools/Jupyter-notebooks/Modules/.ipynb_checkpoints/Web-checkpoint.ipynb delete mode 100755 Wiki/RUS_Guide/doctrees/Robot/08_HowToUse.doctree create mode 100644 Wiki/RUS_Guide/doctrees/Robot/08_audio.doctree create mode 100644 Wiki/RUS_Guide/doctrees/Robot/09_HowToUse.doctree create mode 100644 Wiki/RUS_Guide/html/Robot/08_audio.html rename Wiki/RUS_Guide/html/Robot/{08_HowToUse.html => 09_HowToUse.html} (88%) mode change 100755 => 100644 create mode 100644 Wiki/RUS_Guide/html/_modules/pyOpenRPA/Robot/Audio.html create mode 100644 Wiki/RUS_Guide/html/_sources/Robot/08_audio.rst.txt rename Wiki/RUS_Guide/html/_sources/Robot/{08_HowToUse.rst.txt => 09_HowToUse.rst.txt} (81%) mode change 100755 => 100644 create mode 100644 Wiki/RUS_Guide/markdown/Robot/08_audio.md rename Wiki/RUS_Guide/markdown/Robot/{08_HowToUse.md => 09_HowToUse.md} (80%) mode change 100755 => 100644 rename v1.3.0 => v1.3.1 (100%) diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/INSTALLER b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/INSTALLER similarity index 100% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/INSTALLER rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/INSTALLER diff --git a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/METADATA b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/METADATA similarity index 99% rename from Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/METADATA rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/METADATA index bc6bd5d2..51ef28a3 100644 --- a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/METADATA +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/METADATA @@ -1,13 +1,12 @@ Metadata-Version: 2.1 Name: pyOpenRPA -Version: 1.3.0 +Version: 1.3.1 Summary: The powerful open source RPA platform for business Home-page: https://pyopenrpa.ru/ Author: Ivan Maslov Author-email: Ivan.Maslov@pyopenrpa.ru License: Текст лицензии см. в файле: LICENSE.PDF (в корне) или по адресу: https://pyopenrpa.ru/license/oferta.pdf Keywords: pyOpenRPA OpenRPA RPA Robot Automation Robotization OpenSource IT4Business -Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: License :: Free For Educational Use Classifier: License :: Free For Home Use @@ -92,4 +91,3 @@ Ivan Maslov contacts (CEO & FOUNDER): - Web: https://pyopenrpa.ru/ - Telegram: https://t.me/pyopenrpa - WhatsApp | Telegram: +7 906 722 39 25 | @IvanMaslov - diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/RECORD b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/RECORD similarity index 92% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/RECORD rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/RECORD index b8017eec..941c38f3 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/RECORD +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/RECORD @@ -1,11 +1,17 @@ -pyOpenRPA-1.3.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -pyOpenRPA-1.3.0.dist-info/METADATA,sha256=V-qwlFCJ26LQShABSS0p5Tm9vxOXMYqrahL40zkthnI,4378 -pyOpenRPA-1.3.0.dist-info/RECORD,, -pyOpenRPA-1.3.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pyOpenRPA-1.3.0.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97 -pyOpenRPA-1.3.0.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10 -pyOpenRPA/Agent/A2O.py,sha256=PlIZZCTnVrYF2i6DSAi_KbzZfc2gtcBPmOerrEZq68U,1718 -pyOpenRPA/Agent/O2A.py,sha256=o-5JF-415L69-vCg0COzK79sWs4btJwOkt53pqVhu0U,6210 +pyOpenRPA-1.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pyOpenRPA-1.3.1.dist-info/METADATA,sha256=oy_kdDRYfQHXr9MUOp_vO-WZ9AOOGvtMKIfYDanGAHY,4359 +pyOpenRPA-1.3.1.dist-info/RECORD,, +pyOpenRPA-1.3.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pyOpenRPA-1.3.1.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97 +pyOpenRPA-1.3.1.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10 +pyOpenRPA/.idea/inspectionProfiles/profiles_settings.xml,sha256=YXLFmX7rPNGcnKK1uX1uKYPN0fpgskYNe7t0BV7cqkY,174 +pyOpenRPA/.idea/misc.xml,sha256=V-fQnOz-bYEZULgfbFgm-8mURphZrKfXMSd0wKjeEyA,188 +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=6tJZehshdK4And6tEoUvkIB0KE7waL_NnTSkTYYAeFA,3802 +pyOpenRPA/Agent/A2O.py,sha256=iSjYhWS2GrL6vdJ0Gc9PVtgfiqzqVwBc5jX0HsOrFdo,1713 +pyOpenRPA/Agent/O2A.py,sha256=DpFWS1uKfFNsuyiSwj5LLI862oe58aJbQilRv3Hgm9o,6205 pyOpenRPA/Agent/Processor.py,sha256=xNZfQ_HcV-qm_x90tBLKYJqvnENiTqHSoUk2LhDfqWQ,6346 pyOpenRPA/Agent/__Agent__.py,sha256=rUvtEGEmlsd3ZujkQnPhL3mGaALmM2iNvfWBoF0Puc4,15167 pyOpenRPA/Agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 @@ -17,12 +23,12 @@ pyOpenRPA/Agent/__pycache__/__init__.cpython-37.pyc,, pyOpenRPA/Agent/readme.md,sha256=QF_Bnv204OK3t1JUEhjfICkxFmSdX6bvaRl_HI6lH9I,19 pyOpenRPA/Info.md,sha256=u4Nv-PjniSF0Zlbtr6jEJX2vblK3_1zhSLNUgOdtDaA,85 pyOpenRPA/LICENSE.pdf,sha256=8L-9X_kCCt8yWvjy0E_xV-C6Im79hZnH7WcfZHRz8uM,4322139 -pyOpenRPA/Orchestrator/BackwardCompatibility.py,sha256=IqVZygd8ab9X1gBfP7WImQrYqKy8snCSbThqrvdT5f0,39633 +pyOpenRPA/Orchestrator/BackwardCompatibility.py,sha256=cYsvzgtjpGtD1qW8GRIq7WjHktsPZ0kefN47g9awhDc,39641 pyOpenRPA/Orchestrator/ControlPanel.py,sha256=OzS8HjG__8OZgqhajr8L8owyugXPuSLWHLtXuKdEP78,103 pyOpenRPA/Orchestrator/Core.py,sha256=OHa3mSC3_wRAizqrWBVjlR6ln4-xVVvBpOSnWl6qVvY,529 -pyOpenRPA/Orchestrator/Managers/ControlPanel.py,sha256=PZzh_RUke8bIMGghCXTnEuTYICCwW71r2xXk7iTdUnU,17345 +pyOpenRPA/Orchestrator/Managers/ControlPanel.py,sha256=VJoWVZoGE0dOQ-_jeezG8NNsk0mETUrJQztE8AfqxBY,17531 pyOpenRPA/Orchestrator/Managers/Git.py,sha256=VCXXc-enJhvrAJvYc8jHK9GcGe02meMdszU0tlJDHiQ,12879 -pyOpenRPA/Orchestrator/Managers/Process.py,sha256=4LJNMrt61AJKI3p7SeXnUSEpA61BtqWVxaVYxYS_BaI,42221 +pyOpenRPA/Orchestrator/Managers/Process.py,sha256=JW6cMsgAKmTtSkNMlW7zHhLh3N8lBdZI95wDadxCgtw,42537 pyOpenRPA/Orchestrator/Managers/__init__.py,sha256=4my0XiwmI_QLRQVhOzNvWTggCosF3tb2yRxGkehOCq0,71 pyOpenRPA/Orchestrator/Managers/__pycache__/ControlPanel.cpython-37.pyc,, pyOpenRPA/Orchestrator/Managers/__pycache__/Git.cpython-37.pyc,, @@ -62,8 +68,9 @@ 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=eYiXKvWsiBG_kfHtzdNX4Zu2xL2DjkJZXqBfqOgHAk4,38600 -pyOpenRPA/Orchestrator/ServerSettings.py,sha256=wZe5aEUJOWYol8WzKUQBRq9JEnXj0Z39554PAIoqvbw,34326 +pyOpenRPA/Orchestrator/Server.py,sha256=kejcfciuREYHc8Wl0ZgO6_1Kim0QtgfugPWYQq3VD54,12723 +pyOpenRPA/Orchestrator/ServerBC.py,sha256=hwaFRtw1XN3D1rankd2HwH139-z5vfYvXO1I9skF0bI,23719 +pyOpenRPA/Orchestrator/ServerSettings.py,sha256=1mHElwL46J_dT3qTF3-DaP_u4HekC4C5uGv2rRSngHc,35111 pyOpenRPA/Orchestrator/SettingsTemplate.py,sha256=dVL-JZpAUQP3LLXE_7IUuE7RkLTYBAA-RX4e5FZ_DU0,21499 pyOpenRPA/Orchestrator/Timer.py,sha256=HvYtEeH2Q5WVVjgds9XaBpWRmvZgwgBXurJDdVVq_T0,2097 pyOpenRPA/Orchestrator/Utils/LoggerHandlerDumpLogList.py,sha256=hD47TiOuKR-G8IWu9lJD2kG28qlH7YZV63i3qv1N5Dk,681 @@ -71,11 +78,8 @@ pyOpenRPA/Orchestrator/Utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM pyOpenRPA/Orchestrator/Utils/__pycache__/LoggerHandlerDumpLogList.cpython-37.pyc,, pyOpenRPA/Orchestrator/Utils/__pycache__/__init__.cpython-37.pyc,, pyOpenRPA/Orchestrator/Web/Basic.py,sha256=pPH55rPwZz1ktpzNIcC51jeV2MgZI10Zf0Q0DncihDw,7757 -pyOpenRPA/Orchestrator/Web/Index.js,sha256=YACiZAvjr6NmFlDhQu6urkJp49BX7L8WJU9p-MeIlCI,43508 -pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=5JUAs5rEiU0XtHM9QO6EdNMBGt-W6QOVGY7xJ_HLPFM,19257 pyOpenRPA/Orchestrator/Web/__pycache__/Basic.cpython-37.pyc,, -pyOpenRPA/Orchestrator/Web/favicon.ico,sha256=6S8XwSQ_3FXPpaX6zYkf8uUewVXO9bHnrrDHEoWrEgw,112922 -pyOpenRPA/Orchestrator/__Orchestrator__.py,sha256=LmEhNQkdK5SEIqql0ZM9PrjKgQ4-aQOiOheX83GbqmQ,207494 +pyOpenRPA/Orchestrator/__Orchestrator__.py,sha256=E7kysFDJmcmBejKt8_0pk624U6ohLqM32CjvJ-FysoQ,214440 pyOpenRPA/Orchestrator/__init__.py,sha256=nJhjYtBXKOUNX_yNu1rRFk5y9cDz6AFiL0M6KgX_utQ,207 pyOpenRPA/Orchestrator/__main__.py,sha256=czJrc7_57WiO3EPIYfPeF_LG3pZsQVmuAYgbl_YXcVU,273 pyOpenRPA/Orchestrator/__pycache__/BackwardCompatibility.cpython-37.pyc,, @@ -84,6 +88,7 @@ pyOpenRPA/Orchestrator/__pycache__/Core.cpython-37.pyc,, pyOpenRPA/Orchestrator/__pycache__/Processor.cpython-37.pyc,, pyOpenRPA/Orchestrator/__pycache__/ProcessorOld.cpython-37.pyc,, pyOpenRPA/Orchestrator/__pycache__/Server.cpython-37.pyc,, +pyOpenRPA/Orchestrator/__pycache__/ServerBC.cpython-37.pyc,, pyOpenRPA/Orchestrator/__pycache__/ServerSettings.cpython-37.pyc,, pyOpenRPA/Orchestrator/__pycache__/SettingsTemplate.cpython-37.pyc,, pyOpenRPA/Orchestrator/__pycache__/Timer.cpython-37.pyc,, @@ -243,7 +248,7 @@ pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/package.js,sha256=BHq6qGCSMdDXDGJ 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.css,sha256=o4apE2I4Au57fkNgduz1J0rhbTPc04IlvCzBmEeapGE,628944 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 @@ -264,11 +269,12 @@ pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/themes/default/assets/fonts/outli 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/orpa/favicon.ico,sha256=6S8XwSQ_3FXPpaX6zYkf8uUewVXO9bHnrrDHEoWrEgw,112922 -pyOpenRPA/Resources/Web/orpa/footer.xhtml,sha256=5aNthu2jsINqpgo_BS8UDbRWhA3rlRtlQZIILv_4hKo,3190 -pyOpenRPA/Resources/Web/orpa/header.xhtml,sha256=pqVM-N53bz4_DzbG4PoN7B7N7XECZWZe12qVlc68ylk,3617 +pyOpenRPA/Resources/Web/orpa/footer.xhtml,sha256=xB-uUWvzdgD686l8rXWYOzwp3y7DKnZrvJeBS0ClPLI,3482 +pyOpenRPA/Resources/Web/orpa/header.xhtml,sha256=kJF-9Ea9DV2v6Y3F0r3FvF3odfYmw14F5_SAbbq2uyk,3658 pyOpenRPA/Resources/Web/orpa/logo.png,sha256=7rulXo_C57xJQEaYWmAkChxXb6xbDW2zq-werzVbDbc,4899 -pyOpenRPA/Resources/Web/orpa/orc.js,sha256=qlzbbewXWDFbNhNHVVvMEYQFyQbRA7zEHoeaV38fJoQ,43558 -pyOpenRPA/Resources/Web/orpa/orc.xhtml,sha256=x6NdMv6HrjUt0rZsz61dJeMl3DNte1KkEULQRkGfsJg,19098 +pyOpenRPA/Resources/Web/orpa/orc.js,sha256=aVKy_YTcpcOUiXcUyE1hyW7lpSmfFJY3sVjgEgMdXrw,38487 +pyOpenRPA/Resources/Web/orpa/orc.xhtml,sha256=6WQ5fidSF8EW8PzqZ9AMVptVVCJAzQleqEFqfRIqQvo,19324 +pyOpenRPA/Resources/Web/orpa/std.xhtml,sha256=lNg0WRW-sM5J2EGCkqtwqtOzv5n21KFZ8vHv9KlquEY,43547 pyOpenRPA/Resources/Web/orpa/styleset/Lato-Bold.woff2,sha256=roj8DXqWGDL4CVJ9ML05g6aGbUL2alat4j9UNoFZTbY,184912 pyOpenRPA/Resources/Web/orpa/styleset/Lato-Italic.woff2,sha256=RGV2Xy9u3c2tNP_XyrVZ5WvA515F4ZL4XpVisHcUgdw,195704 pyOpenRPA/Resources/Web/orpa/styleset/Lato-Regular.woff2,sha256=mDsMrzNuhUIhT8FwGaT8XgNghkuSgGyhTVXB_BwsWg8,182708 @@ -303,8 +309,9 @@ pyOpenRPA/Resources/Web/orpa/styleset/sidebar.js,sha256=fnype3guWOx0kmyP7rL2I0mk pyOpenRPA/Resources/Web/orpa/styleset/transition.js,sha256=esNkWoCwl6ksZewJkNDMLKCE4nDTdJZDJW3tdE7dlAo,36070 pyOpenRPA/Resources/Web/orpa/styleset/visibility.js,sha256=ulme0GrsuqHAHXTQunq96J0mESTl6Lux8msdK1_fcm4,44174 pyOpenRPA/Resources/Web/orpa/styleset/white-image.png,sha256=D7WJFGDtAIp_OXUU6Tz4zeYm_1yHRd8u7aTu0F35Kcw,5951 +pyOpenRPA/Robot/Audio.py,sha256=kHvFnb3t_vnw-NjfSf1zaL3w1Th-984KMx1S8-6BX5I,22176 pyOpenRPA/Robot/Clipboard.py,sha256=QXClSH1ccCl8KfKbMY1Wk_SynEgfDZqZ_0h-OZYn4kA,1962 -pyOpenRPA/Robot/Keyboard.py,sha256=3RCogucSWPCtq7YbFKIUvJOSBvFE04P6Lo3hjCGUHi8,26071 +pyOpenRPA/Robot/Keyboard.py,sha256=0pe4C5vqYD9LRBm61dZmJ39lyNoI0BXMLCA0bWjvm8I,26589 pyOpenRPA/Robot/Mouse.py,sha256=R-2q5Q-nDhvvQjcQxFz8FRM9tHjhPUKdnK3KuPc_OZw,16361 pyOpenRPA/Robot/OrchestratorConnector.py,sha256=JUtdiUXCruqUqBD19gJBl9jk_b-tpWWx_v3MfBoKzoQ,20445 pyOpenRPA/Robot/README.md,sha256=bwiTAygxuMZzBlwpsndw2QgxA2smIjUyOPZnsnR341k,1623 @@ -312,7 +319,7 @@ pyOpenRPA/Robot/Screen.py,sha256=nH80ghKw7OseNF_fVwfUrih0y9o1Ul2VPEl_WT5b598,454 pyOpenRPA/Robot/SettingsTemplate.py,sha256=Rp5XPeV2I4tCS2uf4Zkqm_ERJ6pZMg4-e5_lMqGJYLk,1453 pyOpenRPA/Robot/Test.py,sha256=qXr990nXiFZX5SNv6QN9GLb_U4HZRmJnbZR2qSnwilY,2878 pyOpenRPA/Robot/UIDesktop.py,sha256=WLy8wUVDFSUN5S7hXUjijQIH0B71c5tj-pBCVex7uFc,125314 -pyOpenRPA/Robot/UIWeb.py,sha256=c3VA8IG2ELuGaWskyFFCbJalBKdDON2sjWhvHjR-2Dk,32353 +pyOpenRPA/Robot/UIWeb.py,sha256=DLr6cPvFdUmGMTKGLVrksaVKHqBmbxzFkkT4qT0WLfo,32589 pyOpenRPA/Robot/Utils/JSONNormalize.py,sha256=aIuVzuZDazhxkCOzoOjfhHVz66mp2FWdfPv5E7KWF5Y,3890 pyOpenRPA/Robot/Utils/ProcessBitness.py,sha256=NvzuTxNWL_EMmdU1Isu0bUck1Iud0Kkzn8GsVCzIAAM,4591 pyOpenRPA/Robot/Utils/ProcessCommunicator.py,sha256=8GfmLnOvAdosmt7YNT86uEV9cjhKippssCX62wOMJwM,8039 @@ -328,6 +335,7 @@ pyOpenRPA/Robot/Utils/__pycache__/__init__.cpython-37.pyc,, pyOpenRPA/Robot/Window.py,sha256=UJl-sg4RvvJ35aG9jZOzqGVwE15XK7qPHqoOBD13xFk,431 pyOpenRPA/Robot/__init__.py,sha256=eYyMsU33rGlEZcsO-MH9UtXs47UcTCtg4Uc4lxKmmQo,255 pyOpenRPA/Robot/__main__.py,sha256=xtzw5siZZJV2Nmn-zXPZY5u3Tk0wxe-l8lxq3VPEEiI,2029 +pyOpenRPA/Robot/__pycache__/Audio.cpython-37.pyc,, pyOpenRPA/Robot/__pycache__/Clipboard.cpython-37.pyc,, pyOpenRPA/Robot/__pycache__/Keyboard.cpython-37.pyc,, pyOpenRPA/Robot/__pycache__/Mouse.cpython-37.pyc,, @@ -343,10 +351,8 @@ 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=6He68tum4IyMSOv9VXsH2hmvMDnnCf4CDI66L7Wpl_Q,8739 +pyOpenRPA/Studio/Studio.py,sha256=pf9feDUyvKRJfhREkxK9uN49dWawYdn3ImkdxuH5mM0,18518 pyOpenRPA/Studio/ValueVerify.py,sha256=ObskxU4fOMoCGw74_nzYt6-a5jjrAckb3sdBLYyhYxY,777 -pyOpenRPA/Studio/Web/Index.xhtml,sha256=X_fLnzxdcJ8ML9VRORpaMmQwlu1Pcr0CR2Krzt65Hes,48119 -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,, @@ -357,7 +363,7 @@ pyOpenRPA/Studio/__pycache__/ValueVerify.cpython-37.pyc,, pyOpenRPA/Studio/__pycache__/__init__.cpython-37.pyc,, pyOpenRPA/Studio/__pycache__/__main__.cpython-37.pyc,, pyOpenRPA/Tools/CrossOS.py,sha256=6yq7cit6dgs0KCk6zknoy699r7a3gC0UrnYYe-ZrobM,3539 -pyOpenRPA/Tools/Debugger.py,sha256=2slOSaPnUAwfDlyjhaqqhhchXUBgEKQImTzXagJt4Jw,535 +pyOpenRPA/Tools/Debugger.py,sha256=nLDzlghYnRghULjGze6_yVg5Du25I8K5s3uhFw1hh3w,570 pyOpenRPA/Tools/License.py,sha256=r4z9HExUzpk2Q_6WhzgUnHlOPPHK1MLevtdlLwtZ7Hk,10378 pyOpenRPA/Tools/RobotDB/ExcelCom.py,sha256=hp0dvXOEC7Au00ueh7pqxkdixV-PC-km7tCt-wRunYs,343 pyOpenRPA/Tools/RobotDB/HowToUse,sha256=TUXPZAFcse-PSlKFM6jcaYuuZZEmXOSSvgeqrbmIDoc,1473 @@ -401,7 +407,14 @@ pyOpenRPA/Tools/__pycache__/StopSafe.cpython-37.pyc,, pyOpenRPA/Tools/__pycache__/Template.cpython-37.pyc,, pyOpenRPA/Tools/__pycache__/Usage.cpython-37.pyc,, pyOpenRPA/Tools/__pycache__/__init__.cpython-37.pyc,, +pyOpenRPA/Utils/Dictionary.py,sha256=dXmsFZoufUxpf_f_grQIsWcto1qwLCRrxN6m93NJCu8,2261 +pyOpenRPA/Utils/Disk.py,sha256=MKD9nIGKNOJeQow1qGDTEz-GffkFbWaNxf3Hj76AyTo,364 +pyOpenRPA/Utils/Network.py,sha256=UHTvc_ut_Fimeg-tBISUYPgkLKQTBkte3EsIh8BW7a8,600 pyOpenRPA/Utils/Render.py,sha256=VCU5cCCwyCFvMmRQwq7MGllgqzeDAp_s8om3UChIoPk,6703 +pyOpenRPA/Utils/Text.py,sha256=ZFIIPaCB8lJ7kwF9bwpVR-lmf_p1o6jz8npBdl_7eNc,214 +pyOpenRPA/Utils/__pycache__/Dictionary.cpython-37.pyc,, +pyOpenRPA/Utils/__pycache__/Disk.cpython-37.pyc,, pyOpenRPA/Utils/__pycache__/Render.cpython-37.pyc,, -pyOpenRPA/__init__.py,sha256=adiLDsNcgYHaK1h_sStFVU0UEQpYGgFRvPiLmmrtvnU,155 +pyOpenRPA/Utils/__pycache__/Text.cpython-37.pyc,, +pyOpenRPA/__init__.py,sha256=Uj0nKJ5lCErziv4h_RMQxX1M13lF_oHY2NJIJ9UndSI,155 pyOpenRPA/__pycache__/__init__.cpython-37.pyc,, diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/REQUESTED b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/REQUESTED similarity index 100% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/REQUESTED rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/REQUESTED diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/WHEEL b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/WHEEL similarity index 100% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/WHEEL rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/WHEEL diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/top_level.txt b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/top_level.txt similarity index 100% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.0.dist-info/top_level.txt rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.3.1.dist-info/top_level.txt diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Agent/A2O.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Agent/A2O.py index 3f302476..45cef04d 100755 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Agent/A2O.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Agent/A2O.py @@ -15,7 +15,7 @@ def _A2ODataSend(inGSettings, inDataDict): lProtocolStr= "https" if inGSettings["OrchestratorDict"]["IsHTTPSBool"] else "http" lHostStr = inGSettings["OrchestratorDict"]["HostStr"] lPortInt = inGSettings["OrchestratorDict"]["PortInt"] - lURLStr=f"{lProtocolStr}://{lHostStr}:{lPortInt}/pyOpenRPA/Agent/A2O" + lURLStr=f"{lProtocolStr}://{lHostStr}:{lPortInt}/orpa/agent/a2o" lResponse = requests.post(url= lURLStr, cookies = {"AuthToken":inGSettings["OrchestratorDict"]["SuperTokenStr"]}, json=inDataDict, timeout=inGSettings["A2ODict"]["ConnectionTimeoutSecFloat"]) except Exception as e: if lL: lL.exception(f"A2O Error handler.") diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Agent/O2A.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Agent/O2A.py index 3780cb81..f1a61771 100755 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Agent/O2A.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Agent/O2A.py @@ -30,7 +30,7 @@ def O2A_Loop(inGSettings): lProtocolStr= "https" if inGSettings["OrchestratorDict"]["IsHTTPSBool"] else "http" lHostStr = inGSettings["OrchestratorDict"]["HostStr"] lPortInt = inGSettings["OrchestratorDict"]["PortInt"] - lURLStr=f"{lProtocolStr}://{lHostStr}:{lPortInt}/pyOpenRPA/Agent/O2A" + lURLStr=f"{lProtocolStr}://{lHostStr}:{lPortInt}/orpa/agent/o2a" lDataDict = { "HostNameUpperStr": inGSettings["AgentDict"]["HostNameUpperStr"], "UserUpperStr": inGSettings["AgentDict"]["UserUpperStr"], "ActivityLastGUIDStr": lActivityLastGUIDStr} lResponse = requests.post(url= lURLStr, cookies = {"AuthToken":inGSettings["OrchestratorDict"]["SuperTokenStr"]}, json=lDataDict, timeout=inGSettings["O2ADict"]["ConnectionTimeoutSecFloat"]) lCEPhaseFastTimeLastGoodFloat = time.time() diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/BackwardCompatibility.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/BackwardCompatibility.py index 841d272d..66cbcf54 100755 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/BackwardCompatibility.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/BackwardCompatibility.py @@ -540,5 +540,5 @@ def Update(inGSettings): # "URLIndexStr" if "URLIndexStr" not in inGSettings["ServerDict"]: inGSettings["ServerDict"]["URLIndexStr"] = "/" - if lL: lL.warning( - f"Обратная совместимость (v1.2.11 -> v1.2.12): ServerDict > URLIndexStr и URLIndexStr = /") # Log about compatibility \ No newline at end of file + if lL: lL.warning( + f"Обратная совместимость (v1.2.11 -> v1.2.12): ServerDict > URLIndexStr и URLIndexStr = /") # Log about compatibility \ No newline at end of file diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Managers/ControlPanel.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Managers/ControlPanel.py index 3ad49fed..22e8a715 100755 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Managers/ControlPanel.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Managers/ControlPanel.py @@ -86,9 +86,9 @@ class ControlPanel(): if inControlPanelNameStr in Orchestrator.GSettingsGet()["ServerDict"]["ControlPanelDict"]: raise Exception(f"Ошибка: Ранее уже была инициализирована панель управления с идентификатором: {inControlPanelNameStr}. Устраните ошибку и перезапустите оркестратор") Orchestrator.GSettingsGet()["ServerDict"]["ControlPanelDict"][inControlPanelNameStr] = self + self.mControlPanelNameStr = inControlPanelNameStr # Set the name of the control panel self.RefreshHTMLJinja2TemplatePathSet(inJinja2TemplatePathStr = inRefreshHTMLJinja2TemplatePathStr) self.mJinja2TemplateRefreshBool = inJinja2TemplateRefreshBool - self.mControlPanelNameStr = inControlPanelNameStr # Set the name of the control panel self.mRobotNameStr = inRobotNameStr # Set the robot name for robot it execute def Jinja2DataUpdateDictSet(self, inJinja2DataUpdateDict): @@ -116,7 +116,7 @@ class ControlPanel(): self.mRefreshHTMLJinja2Env = jinja2.Environment(loader=self.mRefreshHTMLJinja2Loader, trim_blocks=True) self.mRefreshHTMLJinja2Template = self.mRefreshHTMLJinja2Env.get_template(lTemplateFileNameStr) except Exception as e: - Orchestrator.OrchestratorLoggerGet().exception("Ошибка при инициализации Jinja2") + Orchestrator.OrchestratorLoggerGet().exception(f"Ошибка при инициализации Jinja2 ({inJinja2TemplatePathStr}). Панель управления: {self.mControlPanelNameStr}") def RefreshHTMLJinja2StrGenerate(self, inDataDict): """ @@ -145,7 +145,7 @@ class ControlPanel(): self.mInitJSJinja2Env = jinja2.Environment(loader=self.mInitJSJinja2Loader, trim_blocks=True) self.mInitJSJinja2Template = self.mInitJSJinja2Env.get_template(lTemplateFileNameStr) except Exception as e: - Orchestrator.OrchestratorLoggerGet().exception("Ошибка при инициализации Jinja2") + Orchestrator.OrchestratorLoggerGet().exception(f"Ошибка при инициализации Jinja2 ({inJinja2TemplatePathStr}). Панель управления: {self.mControlPanelNameStr}") def InitJSJinja2StrGenerate(self, inDataDict): """ diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Managers/Process.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Managers/Process.py index 392c735b..977c5b94 100755 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Managers/Process.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Managers/Process.py @@ -393,7 +393,7 @@ class Process(): lL.info(f"Модуль Managers.Process ({self.mAgentHostNameStr}, {self.mAgentUserNameStr}, {self.mProcessNameWOExeStr}): Состояние процесса изменилось на {self.mStatusStr})") - def StatusCheck(self): + def StatusCheck(self, inTimeoutSecFloat=9.0, inRaiseExceptionBool=False): """ Check if process is alive. The def will save the manual flag is exists. Don't wait mute but set mute if it is not set. @@ -405,21 +405,27 @@ class Process(): #self.MuteWait() self.mAgentMuteBool=True lGUIDStr = __Orchestrator__.AgentActivityItemAdd(inHostNameStr=self.mAgentHostNameStr,inUserStr=self.mAgentUserNameStr,inActivityItemDict=lActivityItemUserProcessList) - lUserProcessList = __Orchestrator__.AgentActivityItemReturnGet(inGUIDStr=lGUIDStr) - if self.mProcessNameWOExeStr.upper() in lUserProcessList: - if self.mStatusStr == "1_STOPPED_MANUAL": self.mStatusStr = "5_STARTED_MANUAL"; lLogBool=True - if self.mStatusStr == "0_STOPPED": self.mStatusStr = "4_STARTED"; lLogBool=True - if self.mStatusStr is None: self.mStatusStr = "4_STARTED"; lLogBool=True - else: - if self.mStatusStr == "2_STOP_SAFE": self.mStatusStr = "0_STOPPED"; lLogBool = True - if self.mStatusStr == "3_STOP_SAFE_MANUAL": self.mStatusStr = "1_STOPPED_MANUAL"; lLogBool = True - if self.mStatusStr == "5_STARTED_MANUAL": self.mStatusStr = "1_STOPPED_MANUAL"; lLogBool=True - if self.mStatusStr == "4_STARTED": self.mStatusStr = "0_STOPPED"; lLogBool=True - if self.mStatusStr is None: self.mStatusStr = "0_STOPPED"; lLogBool=True - # Log info about process - if lLogBool == True: self.StatusChangeLog() - self.mAgentMuteBool = False - return self.mStatusStr + try: + lUserProcessList = __Orchestrator__.AgentActivityItemReturnGet(inGUIDStr=lGUIDStr,inTimeoutSecFloat=inTimeoutSecFloat) + if self.mProcessNameWOExeStr.upper() in lUserProcessList: + if self.mStatusStr == "1_STOPPED_MANUAL": self.mStatusStr = "5_STARTED_MANUAL"; lLogBool=True + if self.mStatusStr == "0_STOPPED": self.mStatusStr = "4_STARTED"; lLogBool=True + if self.mStatusStr is None: self.mStatusStr = "4_STARTED"; lLogBool=True + else: + if self.mStatusStr == "2_STOP_SAFE": self.mStatusStr = "0_STOPPED"; lLogBool = True + if self.mStatusStr == "3_STOP_SAFE_MANUAL": self.mStatusStr = "1_STOPPED_MANUAL"; lLogBool = True + if self.mStatusStr == "5_STARTED_MANUAL": self.mStatusStr = "1_STOPPED_MANUAL"; lLogBool=True + if self.mStatusStr == "4_STARTED": self.mStatusStr = "0_STOPPED"; lLogBool=True + if self.mStatusStr is None: self.mStatusStr = "0_STOPPED"; lLogBool=True + # Log info about process + if lLogBool == True: self.StatusChangeLog() + self.mAgentMuteBool = False + return self.mStatusStr + except Exception as e: + self.mAgentMuteBool=False + if inRaiseExceptionBool: raise e + else: return "TIMEOUT" + def StatusCheckStart(self): """ Check process status and run it if auto stopped self.mStatusStr is "0_STOPPED" diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Server.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Server.py index d702c4bb..27765796 100755 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Server.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Server.py @@ -6,685 +6,221 @@ # lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None} # self.OpenRPAResponseDict = lResponseDict -from http.server import BaseHTTPRequestHandler, HTTPServer -from socketserver import ThreadingMixIn +#from http.client import HTTPException import threading -import json -from threading import Thread -import inspect from pyOpenRPA.Tools import CrossOS -from . import Processor # Add new processor -from . import ProcessorOld # Support old processor - deprecated defs only for backward compatibility -import urllib.parse # decode URL in string -import importlib -import pdb -import base64 -import uuid -import datetime -import os #for path operations -from http import cookies -gSettingsDict = {} -from . import ServerSettings -from . import __Orchestrator__ -import copy -import mimetypes -mimetypes.add_type("font/woff2",".woff2") -mimetypes.add_type("text/javascript",".js") -gCacheDict = {} +from http import cookies +from . import ServerBC + +# объявление import +from fastapi import FastAPI, Form, Request, HTTPException, Depends, Header, Response, Body +from fastapi.responses import PlainTextResponse, HTMLResponse, FileResponse +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates +from pydantic import BaseModel +import uvicorn +import io +from starlette.responses import StreamingResponse +from typing import Union +from pyOpenRPA import __version__ -# 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 - -# Tool to merge complex dictionaries - no exceptions, just overwrite dict 2 in dict 1 -def __ComplexDictMerge2to1Overwrite__(in1Dict, in2Dict): - """ - Merge in2Dict in in1Dict. In conflict override and get value from dict 2 +import base64 +import uuid +import datetime - :param in1Dict: Source dict. Save the link (structure) - :param in2Dict: New data dict - :return: Merged dict 1 - """ - 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): - __ComplexDictMerge2to1Overwrite__(in1Dict[lKeyStr], in2Dict[lKeyStr]) +# ИНИЦИАЛИЗАЦИЯ FASTAPI! +app = FastAPI( + title = "pyOpenRPA (ORPA) Orchestrator", + description = "Сервер оркестратора pyOpenRPA Orchestrator", + version = __version__, + openapi_url="/orpa/fastapi/openapi.json", + docs_url = "/orpa/fastapi/docs", + redoc_url = "/orpa/fastapi/redoc", + swagger_ui_oauth2_redirect_url = "/orpa/fastapi/docs/oauth2-redirect", + ) + +def IdentifyAuthorize(inRequest:Request, inResponse:Response, + inCookiesStr: Union[str, None] = Header(default=None,alias="Cookie"), + inAuthorizationStr: Union[str, None] = Header(default="",alias="Authorization")): + if __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False)==True: + lResult={"Domain": "", "User": ""} + ###################################### + #Way 1 - try to find AuthToken + lCookies = cookies.SimpleCookie(inCookiesStr) # inRequest.headers.get("Cookie", "") + __Orchestrator__.GSettingsGet() + lHeaderAuthorization = inAuthorizationStr.split(" ") + if "AuthToken" in lCookies: + lCookieAuthToken = lCookies.get("AuthToken", "").value + if lCookieAuthToken: + #Find AuthToken in GlobalDict + if lCookieAuthToken in __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}): + #Auth Token Has Been Founded + lResult["Domain"] = __Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"] + lResult["User"] = __Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"] + #Set auth token + mOpenRPA={} + mOpenRPA["AuthToken"] = lCookieAuthToken + mOpenRPA["Domain"] = lResult["Domain"] + mOpenRPA["User"] = lResult["User"] + mOpenRPA["IsSuperToken"] = __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(mOpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False) + return lCookieAuthToken + ###################################### + #Way 2 - try to logon + if len(lHeaderAuthorization) == 2: + llHeaderAuthorizationDecodedUserPasswordList = base64.b64decode(lHeaderAuthorization[1]).decode("utf-8").split( + ":") + lUser = llHeaderAuthorizationDecodedUserPasswordList[0] + lPassword = llHeaderAuthorizationDecodedUserPasswordList[1] + lDomain = "" + if "\\" in lUser: + lDomain = lUser.split("\\")[0] + lUser = lUser.split("\\")[1] + lLogonBool = __Orchestrator__.OSCredentialsVerify(inUserStr=lUser, inPasswordStr=lPassword, inDomainStr=lDomain) + #Check result + if lLogonBool: + lResult["Domain"] = lDomain + lResult["User"] = lUser + #Create token + lAuthToken=str(uuid.uuid1()) + __Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {} + __Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"] + __Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"] + __Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False + __Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now() + #Set-cookie + inResponse.set_cookie(key="AuthToken",value=lAuthToken) + mOpenRPA={} + mOpenRPA["AuthToken"] = lAuthToken + mOpenRPA["Domain"] = lResult["Domain"] + mOpenRPA["User"] = lResult["User"] + mOpenRPA["IsSuperToken"] = __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(mOpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False) + return lAuthToken + #inRequest.OpenRPASetCookie = {} + #New engine of server + #inRequest.OpenRPAResponseDict["SetCookies"]["AuthToken"] = lAuthToken else: - in1Dict[lKeyStr] = in2Dict[lKeyStr] + raise HTTPException(status_code=401, detail="Попытка авторизации не прошла успешно (неверная пара логин / пароль)", headers={}) + ###################################### else: - in1Dict[lKeyStr] = in2Dict[lKeyStr] - return in1Dict + raise HTTPException(status_code=401, detail="Попытка авторизации не прошла успешно (неполная пара логин / пароль)", headers={'Content-type':'text/html', 'WWW-Authenticate':'Basic'}) + else: return None # Credentials are not required - return none + + + +lRouteList =[] +for lItem in app.router.routes: + lRouteList.append(lItem) +app.router.routes=[] +for lItem in lRouteList: + app.add_api_route( + path=lItem.path, + endpoint=lItem.endpoint, + methods=["GET"], + dependencies=[Depends(IdentifyAuthorize)], + tags=["FastAPI"] + ) + + +from . import ServerSettings + +def BackwardCompatibility(inRequest:Request, inResponse:Response, inBodyStr:str = Body(""), inAuthTokenStr = None): + lHTTPRequest = ServerBC.HTTPRequestOld(inRequest=inRequest, inResponse=inResponse, inAuthTokenStr=inAuthTokenStr) + lHTTPRequest.path = inRequest.url.path + lHTTPRequest.body = inBodyStr + lHTTPRequest.client_address = [inRequest.client.host] + threading.current_thread().request = lHTTPRequest + lResult = lHTTPRequest.do_GET(inBodyStr=inBodyStr) + if lResult is None: + lResult = lHTTPRequest.do_POST(inBodyStr=inBodyStr) + if lHTTPRequest.OpenRPAResponseDict["Headers"]["Content-type"] != None: + return StreamingResponse(io.BytesIO(lResult), media_type=lHTTPRequest.OpenRPAResponseDict["Headers"]["Content-type"]) + +#WRAPPERS! +def BackwardCompatibityWrapperAuth(inRequest:Request, inResponse:Response, inBodyStr:str = Body(""), + inAuthTokenStr:str=Depends(ServerSettings.IdentifyAuthorize)): # Old from v1.3.1 (updated to FastAPI) + return BackwardCompatibility(inRequest = inRequest, inResponse = inResponse, inBodyStr = inBodyStr, inAuthTokenStr=inAuthTokenStr) +def BackwardCompatibityWrapperNoAuth(inRequest:Request, inResponse:Response, inBodyStr:str = Body("")): # Old from v1.3.1 (updated to FastAPI) + return BackwardCompatibility(inRequest = inRequest, inResponse = inResponse, inBodyStr = inBodyStr, inAuthTokenStr=None) +def BackwardCompatibityBeginWrapperAuth(inBeginTokenStr, inRequest:Request, inResponse:Response, inBodyStr:str = Body(""), + inAuthTokenStr:str=Depends(ServerSettings.IdentifyAuthorize)): # Old from v1.3.1 (updated to FastAPI) + return BackwardCompatibility(inRequest = inRequest, inResponse = inResponse, inBodyStr = inBodyStr, inAuthTokenStr=inAuthTokenStr) +def BackwardCompatibityBeginWrapperNoAuth(inBeginTokenStr, inRequest:Request, inResponse:Response, inBodyStr:str = Body("")): # Old from v1.3.1 (updated to FastAPI) + return BackwardCompatibility(inRequest = inRequest, inResponse = inResponse, inBodyStr = inBodyStr, inAuthTokenStr=None) -#Authenticate function () -# return dict -# { -# "Domain": "", #Empty if Auth is not success -# "User": "" #Empty if Auth is not success -# } -def AuthenticateVerify(inRequest): - lResult={"Domain": "", "User": ""} - ###################################### - #Way 1 - try to find AuthToken - lCookies = cookies.SimpleCookie(inRequest.headers.get("Cookie", "")) - global gSettingsDict - #pdb.set_trace() - if "AuthToken" in lCookies: - lCookieAuthToken = lCookies.get("AuthToken", "").value - if lCookieAuthToken: - #Find AuthToken in GlobalDict - if lCookieAuthToken in gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}): - #Auth Token Has Been Founded - lResult["Domain"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["Domain"] - lResult["User"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"] - #Set auth token - inRequest.OpenRPA["AuthToken"] = lCookieAuthToken - inRequest.OpenRPA["Domain"] = lResult["Domain"] - inRequest.OpenRPA["User"] = lResult["User"] - #Exit earlier - return lResult - ###################################### - #Way 2 - try to logon - lHeaderAuthorization = inRequest.headers.get("Authorization", "").split(" ") - if len(lHeaderAuthorization) == 2: - llHeaderAuthorizationDecodedUserPasswordList = base64.b64decode(lHeaderAuthorization[1]).decode("utf-8").split( - ":") - lUser = llHeaderAuthorizationDecodedUserPasswordList[0] - lPassword = llHeaderAuthorizationDecodedUserPasswordList[1] - lDomain = "" - if "\\" in lUser: - lDomain = lUser.split("\\")[0] - lUser = lUser.split("\\")[1] - lLogonBool = __Orchestrator__.OSCredentialsVerify(inUserStr=lUser, inPasswordStr=lPassword, inDomainStr=lDomain) - #Check result - if lLogonBool: - lResult["Domain"] = lDomain - lResult["User"] = lUser - #Create token - lAuthToken=str(uuid.uuid1()) - gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken] = {} - gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["Domain"] = lResult["Domain"] - gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["User"] = lResult["User"] - gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["FlagDoNotExpire"] = False - gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken]["TokenDatetime"] = datetime.datetime.now() - #Set-cookie - inRequest.OpenRPA["AuthToken"] = lAuthToken - inRequest.OpenRPA["Domain"] = lResult["Domain"] - inRequest.OpenRPA["User"] = lResult["User"] - inRequest.OpenRPASetCookie = {} - #New engine of server - inRequest.OpenRPAResponseDict["SetCookies"]["AuthToken"] = lAuthToken - #inRequest.OpenRPAResponse["Set-Cookie"]=[]lResult["Set-Cookie"] = lAuthToken - #pdb.set_trace() - #inRequest.send_header("Set-Cookie:", f"AuthToken={lAuthToken}") - ###################################### - return lResult -def AuthenticateBlock(inRequest): - # Send response status code - inRequest.send_response(401) - # Send headers - inRequest.send_header('Content-type', 'text/html') - inRequest.send_header('WWW-Authenticate', 'Basic') # Always ask login pass - inRequest.end_headers() - # Write content as utf-8 data - inRequest.wfile.write(bytes("", "utf8")) -#Check access before execute the action -#return bool True - go execute, False - dont execute -def UserAccessCheckBefore(inMethod, inRequest): - # Help def - Get access flag from dict - #pdb.set_trace() - global gSettingsDict - def HelpGetFlag(inAccessRuleItem, inRequest, inGlobalDict, inAuthenticateDict): - if "FlagAccess" in inAccessRuleItem: - return inAccessRuleItem["FlagAccess"] - elif "FlagAccessDefRequestGlobalAuthenticate" in inAccessRuleItem: - return inAccessRuleItem["FlagAccessDefRequestGlobalAuthenticate"](inRequest, inGlobalDict, - inAuthenticateDict) - ########################################## - inMethod=inMethod.upper() - #Prepare result false - lResult = False - lAuthToken = inRequest.OpenRPA["AuthToken"] - #go next if user is identified - lUserDict = None - if lAuthToken: - lUserDict = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken] - #pdb.set_trace() - ######################################## - ######################################## - #Check general before rule (without User domain) - #Check rules - inRuleMatchURLList = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []) - for lAccessRuleItem in inRuleMatchURLList: - #Go next execution if flag is false - if not lResult: - #Check if Method is identical - if lAccessRuleItem["Method"].upper() == inMethod: - #check Match type variant: BeginWith - if lAccessRuleItem["MatchType"].upper() == "BEGINWITH": - lURLPath = inRequest.path - lURLPath = lURLPath.upper() - if lURLPath.startswith(lAccessRuleItem["URL"].upper()): - lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) - # check Match type variant: Contains - elif lAccessRuleItem["MatchType"].upper() == "CONTAINS": - lURLPath = inRequest.path - lURLPath = lURLPath.upper() - if lURLPath.contains(lAccessRuleItem["URL"].upper()): - lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) - # check Match type variant: Equal - elif lAccessRuleItem["MatchType"].upper() == "EQUAL": - if lAccessRuleItem["URL"].upper() == inRequest.path.upper(): - lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) - # check Match type variant: EqualCase - elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE": - if lAccessRuleItem["URL"] == inRequest.path: - lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) - ######################################### - ######################################### - #Do check if lResult is false - if not lResult: - #Check access by User Domain - #Check rules to find first appicable - #Check rules - lMethodMatchURLList = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []) - if len(lMethodMatchURLList) > 0: - for lAccessRuleItem in lMethodMatchURLList: - #Go next execution if flag is false - if not lResult: - #Check if Method is identical - if lAccessRuleItem["Method"].upper() == inMethod: - #check Match type variant: BeginWith - if lAccessRuleItem["MatchType"].upper() == "BEGINWITH": - lURLPath = inRequest.path - lURLPath = lURLPath.upper() - if lURLPath.startswith(lAccessRuleItem["URL"].upper()): - lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) - #check Match type variant: Contains - elif lAccessRuleItem["MatchType"].upper() == "CONTAINS": - lURLPath = inRequest.path - lURLPath = lURLPath.upper() - if lURLPath.contains(lAccessRuleItem["URL"].upper()): - lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) - # check Match type variant: Equal - elif lAccessRuleItem["MatchType"].upper() == "EQUAL": - if lAccessRuleItem["URL"].upper() == inRequest.path.upper(): - lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) - # check Match type variant: EqualCase - elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE": - if lAccessRuleItem["URL"] == inRequest.path: - lResult = HelpGetFlag(lAccessRuleItem, inRequest, gSettingsDict, lUserDict) - else: - return True - ##################################### - ##################################### - #Return lResult - return lResult -# HTTPRequestHandler class -class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): - # Def to check User Role access grants - def UACClientCheck(self, inRoleKeyList): # Alias - return self.UserRoleAccessAsk(inRoleKeyList=inRoleKeyList) - def UserRoleAccessAsk(self, inRoleKeyList): - lResult = True # Init flag - lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy - # Try to get value from key list - lKeyValue = lRoleHierarchyDict # Init the base - for lItem in inRoleKeyList: - if type(lKeyValue) is dict: - if lItem in lKeyValue: # Has key - lKeyValue = lKeyValue[lItem] # Get the value and go to the next loop iteration - else: # Else branch - true or false - if len(lKeyValue)>0: # False - if Dict has some elements - lResult = False # Set the False Flag - else: - lResult = True # Set the True flag - break # Stop the loop - else: # Has element with no detalization - return True - lResult = True # Set the flag - break # Close the loop - return lResult # Return the result - # Def to get hierarchy of the current user roles - # if return {} - all is available - def UserRoleHierarchyGet(self): - #global gSettingsDict - lDomainUpperStr = self.OpenRPA["Domain"].upper() - lUserUpperStr = self.OpenRPA["User"].upper() - return gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lDomainUpperStr, lUserUpperStr), {}).get("RoleHierarchyAllowedDict", {}) - #Tech def - #return {"headers":[],"body":"","statuscode":111} - def URLItemCheckDo(self, inURLItem, inMethod, inOnlyFlagUACBool = False): - global gSettingsDict - ############################### - #Tech sub def - do item - ################################ - def URLItemDo(inURLItem,inRequest,inGlobalDict): - global gCacheDict - inResponseDict = inRequest.OpenRPAResponseDict - inResponseDict["Headers"]["Content-type"]= None - #Set status code 200 - inResponseDict["StatusCode"] = 200 - #Content-type - if "ResponseContentType" in inURLItem: - inResponseDict["Headers"]["Content-type"] = inURLItem["ResponseContentType"] - #If file path is set - if "ResponseFilePath" in inURLItem: - # Check cache - if inURLItem.get("UseCacheBool",False) == True: - if inURLItem["ResponseFilePath"] in gCacheDict: - # Write content as utf-8 data - inResponseDict["Body"] = gCacheDict[inURLItem["ResponseFilePath"]] +from . import __Orchestrator__ +import mimetypes +mimetypes.add_type("font/woff2",".woff2") +mimetypes.add_type("text/javascript",".js") +from typing import Union + +def InitFastAPI(): + global app + lL = __Orchestrator__.OrchestratorLoggerGet() + __Orchestrator__.GSettingsGet()["ServerDict"]["ServerThread"] = app + ServerSettings.SettingsUpdate() + BCURLUpdate() + +def BCURLUpdate(): + for lConnectItemDict in __Orchestrator__.GSettingsGet()["ServerDict"]["URLList"]: + if "BCBool" not in lConnectItemDict: + if "ResponseFolderPath" in lConnectItemDict: + app.mount(lConnectItemDict["URL"], + StaticFiles(directory=CrossOS.PathStr(lConnectItemDict["ResponseFolderPath"])), + name=lConnectItemDict["URL"].replace('/',"_")) + else: + if lConnectItemDict.get("MatchType") in ["EqualCase", "Equal","EqualNoParam"]: + if lConnectItemDict.get("UACBool",True): + app.add_api_route( + path=lConnectItemDict["URL"], + endpoint=BackwardCompatibityWrapperAuth, + response_class=PlainTextResponse, + methods=[lConnectItemDict["Method"]], + tags=["BackwardCompatibility"] + ) else: - if os.path.exists(inURLItem["ResponseFilePath"]) and os.path.isfile(inURLItem["ResponseFilePath"]): - lFileObject = open(CrossOS.PathStr(inURLItem["ResponseFilePath"]), "rb") - # Write content as utf-8 data - gCacheDict[inURLItem["ResponseFilePath"]] = lFileObject.read() - inResponseDict["Body"] = gCacheDict[inURLItem["ResponseFilePath"]] - # Закрыть файловый объект - lFileObject.close() - else: inResponseDict["Headers"]["Content-type"]= "application/x-empty"; inResponseDict["StatusCode"] = 204 # NOCONTENT - else: - if os.path.exists(inURLItem["ResponseFilePath"]) and os.path.isfile(inURLItem["ResponseFilePath"]): - lFileObject = open(CrossOS.PathStr(inURLItem["ResponseFilePath"]), "rb") - # Write content as utf-8 data - inResponseDict["Body"] = lFileObject.read() - # Закрыть файловый объект - lFileObject.close() - else: inResponseDict["Headers"]["Content-type"]= "application/x-empty"; inResponseDict["StatusCode"] = 204 # NOCONTENT - # detect MIME type if none - if inResponseDict["Headers"]["Content-type"] is None: - inResponseDict["Headers"]["Content-type"]= mimetypes.guess_type(inURLItem["ResponseFilePath"])[0] - #If function is set - if "ResponseDefRequestGlobal" in inURLItem: - lDef = inURLItem["ResponseDefRequestGlobal"] - lDefSignature = inspect.signature(lDef) - if len(lDefSignature.parameters) == 2: - inURLItem["ResponseDefRequestGlobal"](inRequest, inGlobalDict) - elif len(lDefSignature.parameters) == 1: - inURLItem["ResponseDefRequestGlobal"](inRequest) - else: - inURLItem["ResponseDefRequestGlobal"]() - if "ResponseFolderPath" in inURLItem: - - #lRequestPath = inRequest.path - lRequestPath = urllib.parse.unquote(inRequest.path) - if inURLItem["URL"][-1]!="/": inURLItem["URL"]+= "/" # Fix for settings - lFilePathSecondPart = lRequestPath.replace(inURLItem["URL"],"") - lFilePathSecondPart = lFilePathSecondPart.split("?")[0] - lFilePath = CrossOS.PathStr(os.path.join(inURLItem["ResponseFolderPath"],lFilePathSecondPart)) - #print(f"File full path {lFilePath}") - #Check if file exist - if os.path.exists(lFilePath) and os.path.isfile(lFilePath): - # Check cache - if inURLItem.get("UseCacheBool",False) == True: - if lFilePath in gCacheDict: - # Write content as utf-8 data - inResponseDict["Body"] = gCacheDict[lFilePath] - else: - lFileObject = open(lFilePath, "rb") - # Write content as utf-8 data - gCacheDict[lFilePath] = lFileObject.read() - inResponseDict["Body"] = gCacheDict[lFilePath] - # Закрыть файловый объект - lFileObject.close() + app.add_api_route( + path=lConnectItemDict["URL"], + endpoint=BackwardCompatibityWrapperNoAuth, + response_class=PlainTextResponse, + methods=[lConnectItemDict["Method"]], + tags=["BackwardCompatibility"] + ) + elif lConnectItemDict.get("MatchType") in ["BeginWith", "Contains"]: + lURLStr = lConnectItemDict["URL"] + if lURLStr[-1]!="/": lURLStr+="/" + lURLStr+="{inBeginTokenStr}" + if lConnectItemDict.get("UACBool",True): + app.add_api_route( + path=lURLStr, + endpoint=BackwardCompatibityBeginWrapperAuth, + response_class=PlainTextResponse, + methods=[lConnectItemDict["Method"]], + tags=["BackwardCompatibility"] + ) else: - lFileObject = open(lFilePath, "rb") - # Write content as utf-8 data - inResponseDict["Body"] = lFileObject.read() - # Закрыть файловый объект - lFileObject.close() - # detect MIME type if none - if inResponseDict["Headers"]["Content-type"] is None: - inResponseDict["Headers"]["Content-type"]= mimetypes.guess_type(lFilePath)[0] - else: - inResponseDict["Headers"]["Content-type"]= "application/x-empty"; inResponseDict["StatusCode"] = 204 # NOCONTENT - # If No content-type - if inResponseDict["Headers"]["Content-type"] is None: - inResponseDict["Headers"]["Content-type"]= "application/octet-stream" - ############################################## - # UAC Check - if inOnlyFlagUACBool == True and inURLItem.get("UACBool",None) in [None, True]: - return False - if inURLItem["Method"].upper() == inMethod.upper(): - # check Match type variant: BeginWith - if inURLItem["MatchType"].upper() == "BEGINWITH": - lURLPath = urllib.parse.unquote(self.path) - lURLPath = lURLPath.upper() - if lURLPath.startswith(inURLItem["URL"].upper()): - URLItemDo(inURLItem, self, gSettingsDict) - return True - # check Match type variant: Contains - elif inURLItem["MatchType"].upper() == "CONTAINS": - lURLPath = urllib.parse.unquote(self.path) - lURLPath = lURLPath.upper() - if lURLPath.contains(inURLItem["URL"].upper()): - URLItemDo(inURLItem, self, gSettingsDict) - return True - # check Match type variant: Equal - elif inURLItem["MatchType"].upper() == "EQUAL": - if inURLItem["URL"].upper() == urllib.parse.unquote(self.path).upper(): - URLItemDo(inURLItem, self, gSettingsDict) - return True - # check Match type variant: EqualNoParam - elif inURLItem["MatchType"].upper() == "EQUALNOPARAM": - if inURLItem["URL"].upper() == urllib.parse.unquote(self.path).upper().split("?")[0]: - URLItemDo(inURLItem, self, gSettingsDict) - return True - # check Match type variant: EqualCase - elif inURLItem["MatchType"].upper() == "EQUALCASE": - if inURLItem["URL"] == urllib.parse.unquote(self.path): - URLItemDo(inURLItem, self, gSettingsDict) - return True - return False - #ResponseContentTypeFile - def SendResponseContentTypeFile(self, inContentType, inFilePath): - # Send response status code - self.send_response(200) - # Send headers - self.send_header('Content-type', inContentType) - #Check if var exist - if hasattr(self, "OpenRPASetCookie"): - self.send_header("Set-Cookie", f"AuthToken={self.OpenRPA['AuthToken']}") - self.end_headers() - lFileObject = open(inFilePath, "rb") - # Write content as utf-8 data - self.wfile.write(lFileObject.read()) - #Закрыть файловый объект - lFileObject.close() - # ResponseContentTypeFile - def ResponseDictSend(self): - lL = gSettingsDict["Logger"] - inResponseDict = self.OpenRPAResponseDict - # Send response status code - self.send_response(inResponseDict["StatusCode"]) - # Send headers - for lItemKey, lItemValue in inResponseDict["Headers"].items(): - self.send_header(lItemKey, lItemValue) - # Send headers: Set-Cookie - for lItemKey, lItemValue in inResponseDict["SetCookies"].items(): - self.send_header("Set-Cookie", f"{lItemKey}={lItemValue}") - #Close headers section in response - try: - self.end_headers() - # Write content as utf-8 data - self.wfile.write(inResponseDict["Body"]) - except (ConnectionResetError, ConnectionAbortedError) as e: - if lL: lL.warning(f"SERVER: Connection was forcibly closed by the client side - OK for the network interactions (ConnectionResetError: [WinError 10054] or ConnectionAbortedError: [WinError 10053])") + app.add_api_route( + path=lURLStr, + endpoint=BackwardCompatibityBeginWrapperNoAuth, + response_class=PlainTextResponse, + methods=[lConnectItemDict["Method"]], + tags=["BackwardCompatibility"] + ) + lConnectItemDict["BCBool"]=True + +def InitUvicorn(inHostStr=None, inPortInt=None, inSSLCertPathStr=None, inSSLKeyPathStr=None, inSSLPasswordStr=None): + if inHostStr is None: inHostStr="0.0.0.0" + if inPortInt is None: inPortInt=1024 + if inSSLCertPathStr != None: inSSLCertPathStr=CrossOS.PathStr(inSSLCertPathStr) + if inSSLKeyPathStr != None: inSSLKeyPathStr=CrossOS.PathStr(inSSLKeyPathStr) + global app + lL = __Orchestrator__.OrchestratorLoggerGet() + #uvicorn.run('pyOpenRPA.Orchestrator.Server:app', host='0.0.0.0', port=1024) + uvicorn.run(app, host=inHostStr, port=inPortInt,ssl_keyfile=inSSLKeyPathStr,ssl_certfile=inSSLCertPathStr,ssl_keyfile_password=inSSLPasswordStr) + if lL and inSSLKeyPathStr != None: lL.info(f"Сервер инициализирован успешно (с поддержкой SSL):: Слушает URL: {inHostStr}, Слушает порт: {inPortInt}, Путь к файлу сертификата (.pem, base64): {inSSLCertPathStr}") + if lL and inSSLKeyPathStr == None: lL.info(f"Сервер инициализирован успешно (без поддержки SSL):: Слушает URL: {inHostStr}, Слушает порт: {inPortInt}") - def do_GET(self): - try: - global gSettingsDict - #self.timeout=gSettingsDict["ServerDict"]["RequestTimeoutSecFloat"] - self.request.settimeout(gSettingsDict["ServerDict"]["RequestTimeoutSecFloat"]) - threading.current_thread().request = self - self.OpenRPA = {} - self.OpenRPA["AuthToken"] = None - self.OpenRPA["Domain"] = None - self.OpenRPA["User"] = None - self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def - self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def - # Prepare result dict - lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None} - self.OpenRPAResponseDict = lResponseDict - ############################ - #First - all with Flag UACBool - ############################ - for lURLItem in gSettingsDict["ServerDict"]["URLList"]: - #Check if all condition are applied - lFlagURLIsApplied=False - lFlagURLIsApplied=self.URLItemCheckDo(inURLItem=lURLItem, inMethod="GET", inOnlyFlagUACBool=True) - if lFlagURLIsApplied: - self.ResponseDictSend() - return - ##################################### - #Do authentication - #Check if authentication is turned on - ##################################### - lFlagAccessUserBlock=False - lAuthenticateDict = {"Domain": "", "User": ""} - if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): - lAuthenticateDict = AuthenticateVerify(self) - if not lAuthenticateDict["User"]: - lFlagAccessUserBlock=True - # Logging - # gSettingsDict["Logger"].info(f"HTTP request /. Domain: {lAuthenticateDict['Domain']}, User: {lAuthenticateDict['User']}") - if lFlagAccessUserBlock: - AuthenticateBlock(self) - ##################################### - else: - #Check the user access (if flag) - #################################### - lFlagUserAccess = True - #If need user authentication - if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): - lFlagUserAccess = UserAccessCheckBefore("GET", self) - ###################################### - if lFlagUserAccess: - if CrossOS.IS_WINDOWS_BOOL: lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1]) - if CrossOS.IS_LINUX_BOOL: lOrchestratorFolder = "/".join(__file__.split("/")[:-1]) - ############################ - #New server engine (url from global dict (URLList)) - ############################ - for lURLItem in gSettingsDict["ServerDict"]["URLList"]: - #Check if all condition are applied - lFlagURLIsApplied=False - lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET") - if lFlagURLIsApplied: - self.ResponseDictSend() - return - #Monitor - if self.path == '/Monitor/JSONDaemonListGet': - # Send response status code - self.send_response(200) - # Send headers - self.send_header('Content-type','application/json') - self.end_headers() - # Send message back to client - message = json.dumps(gSettingsDict) - # Write content as utf-8 data - self.wfile.write(bytes(message, "utf8")) - #Filemanager function - if self.path.lower().startswith('/filemanager/'): - lFileURL=self.path[13:] - # check if file in FileURL - File Path Mapping Dict - if lFileURL.lower() in gSettingsDict["FileManager"]["FileURLFilePathDict"]: - self.SendResponseContentTypeFile('application/octet-stream', gSettingsDict["FileManager"]["FileURLFilePathDict"][lFileURL]) - else: - #Set access denied code - # Send response status code - self.send_response(403) - # Send headers - self.end_headers() - except BrokenPipeError as e: - lL = gSettingsDict["Logger"] - if lL: lL.warning(f"Сервер (do_GET): Возникла ошибка сети - BrokenPipeError: [Errno 32] Broken pipe. Сервер продолжает работу") - except Exception as e: - lL = gSettingsDict["Logger"] - if lL: lL.exception(f"Сервер (do_GET): Неопознанная ошибка сети - см. текст ошибки. Сервер продолжает работу") - # POST - def do_POST(self): - try: - global gSettingsDict - #self.timeout=gSettingsDict["ServerDict"]["RequestTimeoutSecFloat"] - self.request.settimeout(gSettingsDict["ServerDict"]["RequestTimeoutSecFloat"]) - threading.current_thread().request = self - lL = gSettingsDict["Logger"] - self.OpenRPA = {} - self.OpenRPA["AuthToken"] = None - self.OpenRPA["Domain"] = None - self.OpenRPA["User"] = None - self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def - self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def - # Prepare result dict - #pdb.set_trace() - lResponseDict = {"Headers": {}, "SetCookies":{}, "Body": b"", "StatusCode": None} - self.OpenRPAResponseDict = lResponseDict - ############################ - #First - all with Flag UACBool - ############################ - for lURLItem in gSettingsDict["ServerDict"]["URLList"]: - #Check if all condition are applied - lFlagURLIsApplied=False - lFlagURLIsApplied=self.URLItemCheckDo(inURLItem=lURLItem, inMethod="POST", inOnlyFlagUACBool=True) - if lFlagURLIsApplied: - self.ResponseDictSend() - return - ##################################### - #Do authentication - #Check if authentication is turned on - ##################################### - lFlagAccessUserBlock=False - lAuthenticateDict = {"Domain": "", "User": ""} - lIsSuperToken = False # Is supertoken - if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): - lAuthenticateDict = AuthenticateVerify(self) - # Get Flag is supertoken (True|False) - lIsSuperToken = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(self.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False) - if not lAuthenticateDict["User"]: - lFlagAccessUserBlock=True - if lFlagAccessUserBlock: - AuthenticateBlock(self) - ##################################### - else: - #Check the user access (if flag) - #################################### - lFlagUserAccess = True - #If need user authentication - if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): - lFlagUserAccess = UserAccessCheckBefore("POST", self) - ###################################### - if lFlagUserAccess: - lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1]) - ############################ - #New server engine (url from global dict (URLList)) - ############################ - for lURLItem in gSettingsDict["ServerDict"]["URLList"]: - #Check if all condition are applied - lFlagURLIsApplied=False - lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST") - if lFlagURLIsApplied: - self.ResponseDictSend() - return - #Централизованная функция получения запросов/отправки - if self.path == '/Utils/Processor': - #ReadRequest - lInputObject={} - if self.headers.get('Content-Length') is not None: - lInputByteArrayLength = int(self.headers.get('Content-Length')) - lInputByteArray=self.rfile.read(lInputByteArrayLength) - #Превращение массива байт в объект - lInputObject=json.loads(lInputByteArray.decode('utf8')) - # Send response status code - self.send_response(200) - # Send headers - self.send_header('Content-type','application/json') - self.end_headers() - # Logging info about processor activity if not SuperToken () - if not lIsSuperToken: - lActivityTypeListStr = "" - try: - if type(lInputObject) is list: - for lActivityItem in lInputObject: - lActivityTypeListStr+=f"{lActivityItem['Type']}; " - else: - lActivityTypeListStr += f"{lInputObject['Type']}" - except Exception as e: - lActivityTypeListStr = "Has some error with Activity Type read" - if lL: lL.info(f"Сервер:: !ВНИМАНИЕ! /Utils/Processor через некоторое время перестанет поддерживаться. Используйте /pyOpenRPA/Processor или /pyOpenRPA/ActivityListExecute. Активность поступила от пользователя. Домен: {self.OpenRPA['Domain']}, Логин: {self.OpenRPA['User']}, Тип активности: {lActivityTypeListStr}") - # Send message back to client - message = json.dumps(ProcessorOld.ActivityListOrDict(lInputObject)) - # Write content as utf-8 data - self.wfile.write(bytes(message, "utf8")) - return - else: - #Set access denied code - # Send response status code - self.send_response(403) - # Send headers - self.end_headers() - return - except BrokenPipeError as e: - lL = gSettingsDict["Logger"] - if lL: lL.warning(f"Сервер (do_POST): Возникла ошибка сети - BrokenPipeError: [Errno 32] Broken pipe. Сервер продолжает работу") - except Exception as e: - lL = gSettingsDict["Logger"] - if lL: lL.exception(f"Сервер (do_POST): Неопознанная ошибка сети - см. текст ошибки. Сервер продолжает работу") - #Logging - #!Turn it on to stop print in console - #def log_message(self, format, *args): - # return - - - -class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): - daemon_threads = True - """Handle requests in a separate thread.""" - def finish_request(self, request, client_address): - try: - global gSettingsDict - request.settimeout(gSettingsDict["ServerDict"]["RequestTimeoutSecFloat"]) - # "super" can not be used because BaseServer is not created from object - HTTPServer.finish_request(self, request, client_address) - except ConnectionResetError as e: - lL = gSettingsDict["Logger"] - if lL: lL.warning(f"Сервер (finish_request): Возникла ошибка сети - ConnectionResetError: [Errno 104] Connection reset by peer. Сервер продолжает работу") - except Exception as e: - lL = gSettingsDict["Logger"] - if lL: lL.exception(f"Сервер (finish_request): Неопознанная ошибка сети - см. текст ошибки. Сервер продолжает работу") - -#inGlobalDict -# "JSONConfigurationDict": -import ssl -class RobotDaemonServer(Thread): - def __init__(self,name,inGlobalDict): - Thread.__init__(self) - self.name = name - # Update the global dict - ServerSettings.SettingsUpdate(inGlobalDict) - def run(self): - global gSettingsDict - lL = gSettingsDict.get("Logger",None) - try: - lServerDict = gSettingsDict["ServerDict"]["ListenDict"][self.name] - lAddressStr=lServerDict["AddressStr"] - lPortInt=lServerDict["PortInt"] - lCertFilePathStr = lServerDict["CertFilePEMPathStr"] - lKeyFilePathStr = lServerDict["KeyFilePathStr"] - if lCertFilePathStr == "": lCertFilePathStr = None - if lKeyFilePathStr == "": lKeyFilePathStr = None - # Server settings - # Choose port 8080, for port 80, which is normally used for a http server, you need root access - server_address = (lAddressStr, lPortInt) - #httpd = HTTPServer(server_address, testHTTPServer_RequestHandler) - #httpd.serve_forever() - httpd = ThreadedHTTPServer(server_address, testHTTPServer_RequestHandler) - if lCertFilePathStr is not None: - if lKeyFilePathStr is not None: - httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True, certfile=lCertFilePathStr, keyfile=lKeyFilePathStr) - else: - httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True, certfile=lCertFilePathStr) - if lL: lL.info(f"Сервер инициализирован успешно (с поддержкой SSL):: Наименование: {self.name}, Слушает URL: {lAddressStr}, Слушает порт: {lPortInt}, Путь к файлу сертификата (.pem): {lCertFilePathStr}") - else: - if lL: lL.info(f"Сервер инициализирован успешно (без поддержки SSL):: Наименование: {self.name}, Слушает URL: {lAddressStr}, Слушает порт: {lPortInt}") - #print('Starting server, use to stop') - httpd.serve_forever() - except Exception as e: - if lL: lL.exception(f"Сервер:: Ошибка при инициализации - обратитесь в тех. поддержку pyOpenRPA") diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/ServerBC.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/ServerBC.py new file mode 100644 index 00000000..ff444f18 --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/ServerBC.py @@ -0,0 +1,424 @@ +import inspect +from pyOpenRPA.Tools import CrossOS +import urllib.parse # decode URL in string +import os #for path operations +from . import __Orchestrator__ +import mimetypes +mimetypes.add_type("font/woff2",".woff2") +mimetypes.add_type("application/javascript",".js") + +# объявление import +from fastapi import FastAPI, Form, Request, HTTPException, Depends, Header, Response, Body + +gCacheDict = {} + + +# 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 + +# Tool to merge complex dictionaries - no exceptions, just overwrite dict 2 in dict 1 +def __ComplexDictMerge2to1Overwrite__(in1Dict, in2Dict): + """ + Merge in2Dict in in1Dict. In conflict override and get value from dict 2 + + :param in1Dict: Source dict. Save the link (structure) + :param in2Dict: New data dict + :return: Merged dict 1 + """ + 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): + __ComplexDictMerge2to1Overwrite__(in1Dict[lKeyStr], in2Dict[lKeyStr]) + else: + in1Dict[lKeyStr] = in2Dict[lKeyStr] + else: + in1Dict[lKeyStr] = in2Dict[lKeyStr] + return in1Dict + + +def AuthenticateBlock(inRequest): + raise HTTPException(status_code=401, detail="here is the details", headers={'Content-type':'text/html', 'WWW-Authenticate':'Basic'}) + +#Check access before execute the action +#return bool True - go execute, False - dont execute +def UserAccessCheckBefore(inMethod, inRequest): + # Help def - Get access flag from dict + #pdb.set_trace() + def HelpGetFlag(inAccessRuleItem, inRequest, inGlobalDict, inAuthenticateDict): + if "FlagAccess" in inAccessRuleItem: + return inAccessRuleItem["FlagAccess"] + elif "FlagAccessDefRequestGlobalAuthenticate" in inAccessRuleItem: + return inAccessRuleItem["FlagAccessDefRequestGlobalAuthenticate"](inRequest, inGlobalDict, + inAuthenticateDict) + ########################################## + inMethod=inMethod.upper() + #Prepare result false + lResult = False + lAuthToken = inRequest.OpenRPA["AuthToken"] + #go next if user is identified + lUserDict = None + #print(f"lAuthToken: {lAuthToken}") + if lAuthToken: + lUserDict = __Orchestrator__.GSettingsGet()["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken] + #print(f"lUserDict: {lUserDict}") + #pdb.set_trace() + ######################################## + ######################################## + #Check general before rule (without User domain) + #Check rules + inRuleMatchURLList = __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("RuleMethodMatchURLBeforeList", []) + for lAccessRuleItem in inRuleMatchURLList: + #Go next execution if flag is false + if not lResult: + #Check if Method is identical + if lAccessRuleItem["Method"].upper() == inMethod: + #check Match type variant: BeginWith + if lAccessRuleItem["MatchType"].upper() == "BEGINWITH": + lURLPath = inRequest.path + lURLPath = lURLPath.upper() + if lURLPath.startswith(lAccessRuleItem["URL"].upper()): + lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict) + # check Match type variant: Contains + elif lAccessRuleItem["MatchType"].upper() == "CONTAINS": + lURLPath = inRequest.path + lURLPath = lURLPath.upper() + if lURLPath.contains(lAccessRuleItem["URL"].upper()): + lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict) + # check Match type variant: Equal + elif lAccessRuleItem["MatchType"].upper() == "EQUAL": + if lAccessRuleItem["URL"].upper() == inRequest.path.upper(): + lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict) + # check Match type variant: EqualCase + elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE": + if lAccessRuleItem["URL"] == inRequest.path: + lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict) + ######################################### + ######################################### + #Do check if lResult is false + if not lResult: + #Check access by User Domain + #Check rules to find first appicable + #Check rules + lMethodMatchURLList = __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lUserDict["Domain"].upper(), lUserDict["User"].upper()), {}).get("MethodMatchURLBeforeList", []) + if len(lMethodMatchURLList) > 0: + for lAccessRuleItem in lMethodMatchURLList: + #Go next execution if flag is false + if not lResult: + #Check if Method is identical + if lAccessRuleItem["Method"].upper() == inMethod: + #check Match type variant: BeginWith + if lAccessRuleItem["MatchType"].upper() == "BEGINWITH": + lURLPath = inRequest.path + lURLPath = lURLPath.upper() + if lURLPath.startswith(lAccessRuleItem["URL"].upper()): + lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict) + #check Match type variant: Contains + elif lAccessRuleItem["MatchType"].upper() == "CONTAINS": + lURLPath = inRequest.path + lURLPath = lURLPath.upper() + if lURLPath.contains(lAccessRuleItem["URL"].upper()): + lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict) + # check Match type variant: Equal + elif lAccessRuleItem["MatchType"].upper() == "EQUAL": + if lAccessRuleItem["URL"].upper() == inRequest.path.upper(): + lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict) + # check Match type variant: EqualCase + elif lAccessRuleItem["MatchType"].upper() == "EQUALCASE": + if lAccessRuleItem["URL"] == inRequest.path: + lResult = HelpGetFlag(lAccessRuleItem, inRequest, __Orchestrator__.GSettingsGet(), lUserDict) + else: + return True + ##################################### + ##################################### + #Return lResult + return lResult + +class HTTPRequestOld(): + mRequest:Request = None + mResponse:Response = None + OpenRPA: dict = {} + headers={} + + def __init__(self,inRequest,inResponse,inAuthTokenStr): + self.mRequest = inRequest + self.mResponse = inResponse + if inAuthTokenStr != None: + self.OpenRPA = {} + self.OpenRPA["IsSuperToken"] = __Orchestrator__.WebUserIsSuperToken(inAuthTokenStr=inAuthTokenStr) + self.OpenRPA["AuthToken"] = inAuthTokenStr + self.OpenRPA["Domain"] = __Orchestrator__.WebUserDomainGet(inAuthTokenStr=inAuthTokenStr) + self.OpenRPA["User"] = __Orchestrator__.WebUserLoginGet(inAuthTokenStr=inAuthTokenStr) + else: self.OpenRPA = {"IsSuperToken":False, "AuthToken":None, "Domain":None, "User":None} + self.headers=inRequest.headers + + # Def to check User Role access grants + def UACClientCheck(self, inRoleKeyList): # Alias + return self.UserRoleAccessAsk(inRoleKeyList=inRoleKeyList) + def UserRoleAccessAsk(self, inRoleKeyList): + lResult = True # Init flag + lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy + # Try to get value from key list + lKeyValue = lRoleHierarchyDict # Init the base + for lItem in inRoleKeyList: + if type(lKeyValue) is dict: + if lItem in lKeyValue: # Has key + lKeyValue = lKeyValue[lItem] # Get the value and go to the next loop iteration + else: # Else branch - true or false + if len(lKeyValue)>0: # False - if Dict has some elements + lResult = False # Set the False Flag + else: + lResult = True # Set the True flag + break # Stop the loop + else: # Has element with no detalization - return True + lResult = True # Set the flag + break # Close the loop + return lResult # Return the result + + # Def to get hierarchy of the current user roles + # if return {} - all is available + def UserRoleHierarchyGet(self): + try: + lDomainUpperStr = self.OpenRPA["Domain"].upper() + lUserUpperStr = self.OpenRPA["User"].upper() + return __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lDomainUpperStr, lUserUpperStr), {}).get("RoleHierarchyAllowedDict", {}) + except Exception as e: + return {} + #Tech def + #return {"headers":[],"body":"","statuscode":111} + def URLItemCheckDo(self, inURLItem, inMethod, inOnlyFlagUACBool = False): + ############################### + #Tech sub def - do item + ################################ + def URLItemDo(inURLItem,inRequest,inGlobalDict): + global gCacheDict + inResponseDict = inRequest.OpenRPAResponseDict + inResponseDict["Headers"]["Content-type"]= None + #Set status code 200 + inResponseDict["StatusCode"] = 200 + #Content-type + if "ResponseContentType" in inURLItem: + inResponseDict["Headers"]["Content-type"] = inURLItem["ResponseContentType"] + #If file path is set + if "ResponseFilePath" in inURLItem: + # Check cache + if inURLItem.get("UseCacheBool",False) == True: + if inURLItem["ResponseFilePath"] in gCacheDict: + # Write content as utf-8 data + inResponseDict["Body"] = gCacheDict[inURLItem["ResponseFilePath"]] + else: + if os.path.exists(inURLItem["ResponseFilePath"]) and os.path.isfile(inURLItem["ResponseFilePath"]): + lFileObject = open(CrossOS.PathStr(inURLItem["ResponseFilePath"]), "rb") + # Write content as utf-8 data + gCacheDict[inURLItem["ResponseFilePath"]] = lFileObject.read() + inResponseDict["Body"] = gCacheDict[inURLItem["ResponseFilePath"]] + # Закрыть файловый объект + lFileObject.close() + else: inResponseDict["Headers"]["Content-type"]= "application/x-empty"; inResponseDict["StatusCode"] = 204 # NOCONTENT + else: + if os.path.exists(inURLItem["ResponseFilePath"]) and os.path.isfile(inURLItem["ResponseFilePath"]): + lFileObject = open(CrossOS.PathStr(inURLItem["ResponseFilePath"]), "rb") + # Write content as utf-8 data + inResponseDict["Body"] = lFileObject.read() + # Закрыть файловый объект + lFileObject.close() + else: inResponseDict["Headers"]["Content-type"]= "application/x-empty"; inResponseDict["StatusCode"] = 204 # NOCONTENT + # detect MIME type if none + if inResponseDict["Headers"]["Content-type"] is None: + inResponseDict["Headers"]["Content-type"]= mimetypes.guess_type(inURLItem["ResponseFilePath"])[0] + #If function is set + if "ResponseDefRequestGlobal" in inURLItem: + lDef = inURLItem["ResponseDefRequestGlobal"] + lDefSignature = inspect.signature(lDef) + if len(lDefSignature.parameters) == 2: + inURLItem["ResponseDefRequestGlobal"](inRequest, inGlobalDict) + elif len(lDefSignature.parameters) == 1: + inURLItem["ResponseDefRequestGlobal"](inRequest) + else: + inURLItem["ResponseDefRequestGlobal"]() + if "ResponseFolderPath" in inURLItem: + #lRequestPath = inRequest.path + lRequestPath = urllib.parse.unquote(inRequest.path) + if inURLItem["URL"][-1]!="/": inURLItem["URL"]+= "/" # Fix for settings + lFilePathSecondPart = lRequestPath.replace(inURLItem["URL"],"") + lFilePathSecondPart = lFilePathSecondPart.split("?")[0] + lFilePath = CrossOS.PathStr(os.path.join(inURLItem["ResponseFolderPath"],lFilePathSecondPart)) + #print(f"File full path {lFilePath}") + #Check if file exist + if os.path.exists(lFilePath) and os.path.isfile(lFilePath): + # Check cache + if inURLItem.get("UseCacheBool",False) == True: + if lFilePath in gCacheDict: + # Write content as utf-8 data + inResponseDict["Body"] = gCacheDict[lFilePath] + else: + lFileObject = open(lFilePath, "rb") + # Write content as utf-8 data + gCacheDict[lFilePath] = lFileObject.read() + inResponseDict["Body"] = gCacheDict[lFilePath] + # Закрыть файловый объект + lFileObject.close() + else: + lFileObject = open(lFilePath, "rb") + # Write content as utf-8 data + inResponseDict["Body"] = lFileObject.read() + # Закрыть файловый объект + lFileObject.close() + # detect MIME type if none + if inResponseDict["Headers"]["Content-type"] is None: + inResponseDict["Headers"]["Content-type"]= mimetypes.guess_type(lFilePath)[0] + else: + inResponseDict["Headers"]["Content-type"]= "application/x-empty"; inResponseDict["StatusCode"] = 204 # NOCONTENT + # If No content-type + if inResponseDict["Headers"]["Content-type"] is None: + inResponseDict["Headers"]["Content-type"]= "application/octet-stream" + ############################################## + # UAC Check + if inOnlyFlagUACBool == True and inURLItem.get("UACBool",None) in [None, True]: + return False + if inURLItem["Method"].upper() == inMethod.upper(): + # check Match type variant: BeginWith + if inURLItem["MatchType"].upper() == "BEGINWITH": + lURLPath = urllib.parse.unquote(self.path) + lURLPath = lURLPath.upper() + if lURLPath.startswith(inURLItem["URL"].upper()): + URLItemDo(inURLItem, self, __Orchestrator__.GSettingsGet()) + return True + # check Match type variant: Contains + elif inURLItem["MatchType"].upper() == "CONTAINS": + lURLPath = urllib.parse.unquote(self.path) + lURLPath = lURLPath.upper() + if lURLPath.contains(inURLItem["URL"].upper()): + URLItemDo(inURLItem, self, __Orchestrator__.GSettingsGet()) + return True + # check Match type variant: Equal + elif inURLItem["MatchType"].upper() == "EQUAL": + if inURLItem["URL"].upper() == urllib.parse.unquote(self.path).upper(): + URLItemDo(inURLItem, self, __Orchestrator__.GSettingsGet()) + return True + # check Match type variant: EqualNoParam + elif inURLItem["MatchType"].upper() == "EQUALNOPARAM": + if inURLItem["URL"].upper() == urllib.parse.unquote(self.path).upper().split("?")[0]: + URLItemDo(inURLItem, self, __Orchestrator__.GSettingsGet()) + return True + # check Match type variant: EqualCase + elif inURLItem["MatchType"].upper() == "EQUALCASE": + if inURLItem["URL"] == urllib.parse.unquote(self.path): + URLItemDo(inURLItem, self, __Orchestrator__.GSettingsGet()) + return True + return False + #ResponseContentTypeFile + def SendResponseContentTypeFile(self, inContentType, inFilePath): + inResponseDict = self.OpenRPAResponseDict + self.mResponse.status_code = 200 + # Send headers + self.mResponse.headers["Content-type"]=inContentType + #Check if var exist + if hasattr(self, "OpenRPASetCookie"): + self.mResponse.set_cookie(key='AuthToken',value=self.OpenRPA['AuthToken']) + lFileObject = open(inFilePath, "rb") + # Write content as utf-8 data + lFileBytes = lFileObject.read() + #Закрыть файловый объект + lFileObject.close() + return lFileBytes + # ResponseContentTypeFile + def ResponseDictSend(self): + inResponseDict = self.OpenRPAResponseDict + self.mResponse.status_code = inResponseDict["StatusCode"] + # Send headers + for lItemKey, lItemValue in inResponseDict["Headers"].items(): + self.mResponse.headers[lItemKey]=lItemValue + # Send headers: Set-Cookie + for lItemKey, lItemValue in inResponseDict["SetCookies"].items(): + self.mResponse.set_cookie(key=lItemKey,value=lItemValue) + self.send_header("Set-Cookie", f"{lItemKey}={lItemValue}") + return inResponseDict["Body"] + + def do_GET(self, inBodyStr): + try: + try: + self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def + self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def + except Exception as e: + pass + # Prepare result dict + lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None, "BodyIsText":True} + self.OpenRPAResponseDict = lResponseDict + #Check the user access (if flag, UAC) + #################################### + lFlagUserAccess = True + #If need user authentication + if __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): + if self.OpenRPA["AuthToken"] != None: + lFlagUserAccess = UserAccessCheckBefore("GET", self) + ###################################### + if lFlagUserAccess: + if CrossOS.IS_WINDOWS_BOOL: lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1]) + if CrossOS.IS_LINUX_BOOL: lOrchestratorFolder = "/".join(__file__.split("/")[:-1]) + ############################ + #New server engine (url from global dict (URLList)) + ############################ + for lURLItem in __Orchestrator__.GSettingsGet()["ServerDict"]["URLList"]: + #Check if all condition are applied + lFlagURLIsApplied=False + lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "GET") + if lFlagURLIsApplied: + return self.ResponseDictSend() + else: + raise HTTPException(status_code=403, detail="here is the details", headers={}) + except Exception as e: + lL = __Orchestrator__.OrchestratorLoggerGet() + if lL: lL.exception(f"Сервер (do_GET): Неопознанная ошибка сети - см. текст ошибки. Сервер продолжает работу") + # POST + def do_POST(self, inBodyStr): + try: + lL = __Orchestrator__.OrchestratorLoggerGet() + try: + self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def + self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def + except Exception as e: + pass + # Prepare result dict + #pdb.set_trace() + lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None, "BodyIsText":True} + self.OpenRPAResponseDict = lResponseDict + #Check the user access (if flag) + #################################### + lFlagUserAccess = True + #If need user authentication + if __Orchestrator__.GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): + if self.OpenRPA["AuthToken"] != None: + lFlagUserAccess = UserAccessCheckBefore("POST", self) + ###################################### + if lFlagUserAccess: + lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1]) + ############################ + #New server engine (url from global dict (URLList)) + ############################ + for lURLItem in __Orchestrator__.GSettingsGet()["ServerDict"]["URLList"]: + #Check if all condition are applied + lFlagURLIsApplied=False + lFlagURLIsApplied=self.URLItemCheckDo(lURLItem, "POST") + if lFlagURLIsApplied: + return self.ResponseDictSend() + else: + raise HTTPException(status_code=403, detail="here is the details", headers={}) + except Exception as e: + lL = __Orchestrator__.OrchestratorLoggerGet() + if lL: lL.exception(f"Сервер, обратная совместимость (do_POST): Неопознанная ошибка сети - см. текст ошибки. Сервер продолжает работу") + diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/ServerSettings.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/ServerSettings.py index cf22e826..448415c9 100755 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/ServerSettings.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/ServerSettings.py @@ -1,6 +1,7 @@ import json, os import copy from . import __Orchestrator__ +from .Server import app,IdentifyAuthorize # FAST API SERVER #ControlPanelDict from pyOpenRPA.Tools import CrossOS if CrossOS.IS_WINDOWS_BOOL: #CrossOS @@ -20,6 +21,16 @@ from ..Tools import Usage from . import BackwardCompatibility # Support old up to 1.2.0 defs from . import Processor from . import SettingsTemplate +from fastapi import FastAPI, Form, Request, HTTPException, Depends, Header, Response, Body +from fastapi.responses import PlainTextResponse, HTMLResponse, FileResponse +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates +from pydantic import BaseModel +import io +from starlette.responses import StreamingResponse +from typing import Union +from fastapi.responses import JSONResponse + # # # # # # # # # # # # # v 1.2.0 Functionallity @@ -118,14 +129,8 @@ def HiddenAgentDictGenerate(inRequest, inGSettings): # 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')) + lValueStr = inRequest.body # Generate ServerDataDict lFlagDoGenerateBool = True while lFlagDoGenerateBool: @@ -168,12 +173,7 @@ def pyOpenRPA_ServerJSInit(inRequest,inGSettings): # 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')) + lValueStr = inRequest.body # Generate ServerDataDict lFlagDoGenerateBool = True while lFlagDoGenerateBool: @@ -193,59 +193,60 @@ def pyOpenRPA_ServerLog(inRequest,inGSDict): inResponseDict["Body"] = bytes(message, "utf8") return lResult -def pyOpenRPA_Screenshot(inRequest,inGlobalDict): +# Get thread list /orpa/threads +@app.get(path="/orpa/client/screenshot-get",response_class=PlainTextResponse,tags=["Client"]) +def pyOpenRPA_Screenshot(): # Get Screenshot def SaveScreenshot(inFilePath): - # grab fullscreen - # Save the entire virtual screen as a PNsG lScreenshot = getScreenAsImage() - lScreenshot.save('Screenshot.png', format='png') - # lScreenshot = ScreenshotSecondScreen.grab_screen() - # save image file - # lScreenshot.save('screenshot.png') + lScreenshot.save('screenshot.png', format='png') # Сохранить файл на диск if CrossOS.IS_WINDOWS_BOOL: - SaveScreenshot("Screenshot.png") - lFileObject = open("Screenshot.png", "rb") + SaveScreenshot("screenshot.png") + lFileObject = open("screenshot.png", "rb") # Write content as utf-8 data - inRequest.OpenRPAResponseDict["Body"] = lFileObject.read() + lImage = lFileObject.read() # Закрыть файловый объект lFileObject.close() else: - pyscreeze._screenshot_linux(imageFilename='Screenshot.png') - lFileObject = open("Screenshot.png", "rb") + pyscreeze._screenshot_linux(imageFilename='screenshot.png') + lFileObject = open("screenshot.png", "rb") # Write content as utf-8 data - inRequest.OpenRPAResponseDict["Body"] = lFileObject.read() + lImage = lFileObject.read() # Закрыть файловый объект lFileObject.close() + return StreamingResponse(io.BytesIO(lImage), media_type="image/png") # 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"] +# body inauthtoken JSON +@app.post(path="/orpa/api/processor-queue-add",response_class=JSONResponse,tags=["API"]) +def pyOpenRPA_Processor(inRequest:Request, inAuthTokenStr:str = Depends(IdentifyAuthorize), inBodyStr:str = Body("")): + inGSettings = __Orchestrator__.GSettingsGet() + lL = __Orchestrator__.OrchestratorLoggerGet() # 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')) + lValueStr = inBodyStr + # Превращение массива байт в объект + lInput = json.loads(lValueStr) + lResult=[] # 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): + if not __Orchestrator__.WebUserIsSuperToken(inAuthTokenStr=inAuthTokenStr): lActivityTypeListStr = "" try: for lActivityItem in lInput: lActivityTypeListStr += f"{lActivityItem['Def']}; " except Exception as e: lActivityTypeListStr = "Ошибка чтения типа активности" - lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inRequest=inRequest,inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_Processor") + lHostStr = __Orchestrator__.WebRequestHostGet(inRequest=inRequest) + lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inAuthTokenStr=inAuthTokenStr, inHostStr = lHostStr,inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_Processor") if lL: lL.info(lWebAuditMessageStr) # Separate into 2 lists - sync and async lSyncActvityList = [] lAsyncActivityList = [] for lActivityItem in lInput: + lResult.append(__Orchestrator__.ProcessorActivityItemAppend(inActivityItemDict=lActivityItem)) if lInput.get("ThreadBool", False) == False: lSyncActvityList.append(lActivityItem) else: @@ -259,14 +260,16 @@ def pyOpenRPA_Processor(inRequest, inGSettings): lThread = threading.Thread(target=Processor.ActivityListExecute, kwargs=lActivityItemArgsDict) lThread.start() else: + lResult=__Orchestrator__.ProcessorActivityItemAppend(inActivityItemDict=lInput) # Logging info about processor activity if not SuperToken () - if not __Orchestrator__.WebUserIsSuperToken(inRequest=inRequest, inGSettings=inGSettings): + if not __Orchestrator__.WebUserIsSuperToken(inAuthTokenStr=inAuthTokenStr): lActivityTypeListStr = "" try: lActivityTypeListStr = lInput['Def'] except Exception as e: lActivityTypeListStr = "Ошибка чтения типа активности" - lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inRequest=inRequest,inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_Processor") + lHostStr = __Orchestrator__.WebRequestHostGet(inRequest=inRequest) + lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inAuthTokenStr=inAuthTokenStr, inHostStr = lHostStr, inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_Processor") if lL: lL.info(lWebAuditMessageStr) if lInput.get("ThreadBool",False) == False: # Append in list @@ -275,61 +278,65 @@ def pyOpenRPA_Processor(inRequest, inGSettings): lActivityItemArgsDict = {"inGSettings": inGSettings, "inActivityList": [lInput]} lThread = threading.Thread(target=Processor.ActivityListExecute, kwargs=lActivityItemArgsDict) lThread.start() + return lResult + # Execute activity list -def pyOpenRPA_ActivityListExecute(inRequest, inGSettings): +@app.post(path="/orpa/api/activity-list-execute",response_class=JSONResponse,tags=["API"]) +def pyOpenRPA_ActivityListExecute(inRequest:Request, inAuthTokenStr:str = Depends(IdentifyAuthorize), inBodyStr:str = Body("")): # 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')) + inGSettings = __Orchestrator__.GSettingsGet() + lL = __Orchestrator__.OrchestratorLoggerGet() + lValueStr = inBodyStr + # Превращение массива байт в объект + lInput = json.loads(lValueStr) # 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): + if not __Orchestrator__.WebUserIsSuperToken(inAuthTokenStr=inAuthTokenStr): lActivityTypeListStr = "" try: for lActivityItem in lInput: lActivityTypeListStr += f"{lActivityItem['Def']}; " except Exception as e: lActivityTypeListStr = "Ошибка чтения типа активности" - lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inRequest=inRequest,inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_ActivityListExecute") + lHostStr = __Orchestrator__.WebRequestHostGet(inRequest=inRequest) + lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inAuthTokenStr=inAuthTokenStr, inHostStr = lHostStr,inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_ActivityListExecute") if lL: lL.info(lWebAuditMessageStr) # Execution lResultList = Processor.ActivityListExecute(inGSettings = inGSettings, inActivityList = lInput) - inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lResultList), "utf8") + return lResultList + #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): + if not __Orchestrator__.WebUserIsSuperToken(inAuthTokenStr=inAuthTokenStr): lActivityTypeListStr = "" try: lActivityTypeListStr = lInput['Def'] except Exception as e: lActivityTypeListStr = "Ошибка чтения типа активности" - lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inRequest=inRequest, + lHostStr = __Orchestrator__.WebRequestHostGet(inRequest=inRequest) + lWebAuditMessageStr = __Orchestrator__.WebAuditMessageCreate(inAuthTokenStr=inAuthTokenStr, inHostStr = lHostStr, inOperationCodeStr=lActivityTypeListStr, inMessageStr="pyOpenRPA_ActivityListExecute") if lL: lL.info(lWebAuditMessageStr) # Execution lResultList = Processor.ActivityListExecute(inGSettings = inGSettings, inActivityList = [lInput]) - inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lResultList[0]), "utf8") + return lResultList + #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 +@app.post(path="/orpa/agent/o2a",response_class=JSONResponse,tags=["Agent"]) +def pyOpenRPA_Agent_O2A(inRequest:Request, inAuthTokenStr:str = Depends(IdentifyAuthorize), inBodyDict = Body({})): + inGSettings = __Orchestrator__.GSettingsGet() + lL = __Orchestrator__.OrchestratorLoggerGet() lConnectionLifetimeSecFloat = inGSettings["ServerDict"]["AgentConnectionLifetimeSecFloat"] # 300.0 # 5 min * 60 sec 300.0 lActivityItemLifetimeLimitSecFloat = inGSettings["ServerDict"]["AgentActivityLifetimeSecFloat"] lAgentLoopSleepSecFloat = inGSettings["ServerDict"]["AgentLoopSleepSecFloat"] 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')) + #lValueStr = inBodyDict + # Превращение массива байт в объект + lInput = inBodyDict#json.loads(lValueStr) # Check if item is created lAgentDictItemKeyTurple = (lInput["HostNameUpperStr"],lInput["UserUpperStr"]) if lAgentDictItemKeyTurple not in inGSettings["AgentDict"]: @@ -380,12 +387,12 @@ def pyOpenRPA_Agent_O2A(inRequest, inGSettings): for lItemDict in lReturnActivityItemList: if "CreatedByDatetime" in lItemDict: del lItemDict["CreatedByDatetime"] - inRequest.OpenRPAResponseDict["Body"] = bytes(json.dumps(lReturnActivityItemList), "utf8") # Log full version if bytes size is less than limit . else short - lBodyLenInt = len(inRequest.OpenRPAResponseDict["Body"]) + lBodyLenInt = len(lReturnActivityItemList) lAgentLimitLogSizeBytesInt = inGSettings["ServerDict"]["AgentLimitLogSizeBytesInt"] if lL: lL.debug(f"ActivityItem to Agent ({lInput['HostNameUpperStr']}, {lInput['UserUpperStr']}): Item count: {len(lReturnActivityItemList)}, bytes size: {lBodyLenInt}") - lDoLoopBool = False # CLose the connection + lThisAgentDict["ConnectionCountInt"] -= 1 # Connection go to be closed - decrement the connection count + return lReturnActivityItemList else: # Nothing to send - sleep for the next iteration time.sleep(lAgentLoopSleepSecFloat) else: # no queue item - sleep for the next iteration @@ -394,42 +401,43 @@ def pyOpenRPA_Agent_O2A(inRequest, inGSettings): if lL: lL.exception("pyOpenRPA_Agent_O2A Exception!") lThisAgentDict["ConnectionCountInt"] -= 1 # Connection go to be closed - decrement the connection count -def pyOpenRPA_Debugging_HelperDefList(inRequest, inGSettings): +@app.get(path="/orpa/api/helper-def-list/{inTokenStr}",response_class=JSONResponse,tags=["API"]) +def pyOpenRPA_Debugging_HelperDefList(inRequest:Request, inAuthTokenStr:str = Depends(IdentifyAuthorize), inBodyStr:str = Body("")): # Parse query lResultDict = { "success": True, "results": [] } # Get the path - lPathSplitList = __Orchestrator__.WebRequestParsePath(inRequest=inRequest).split('/') + lPathSplitList = inRequest.url.path.split('/') lQueryStr = None if "HelperDefList" != lPathSplitList[-1] and "" != lPathSplitList[-1]: lQueryStr = lPathSplitList[-1] if lQueryStr != "" and lQueryStr is not None: lDefList = __Orchestrator__.ActivityItemHelperDefList(inDefQueryStr=lQueryStr) for lDefStr in lDefList: lResultDict["results"].append({"name": lDefStr, "value": lDefStr, "text": lDefStr}) - __Orchestrator__.WebRequestResponseSend(inRequest=inRequest, inResponeStr=json.dumps(lResultDict)) + return lResultDict -def pyOpenRPA_Debugging_HelperDefAutofill(inRequest, inGSettings): +@app.get(path="/orpa/api/helper-def-autofill/{inTokenStr}",response_class=JSONResponse,tags=["API"]) +def pyOpenRPA_Debugging_HelperDefAutofill(inRequest:Request, inAuthTokenStr:str = Depends(IdentifyAuthorize), inBodyStr:str = Body("")): # Parse query # Get the path - lPathSplitList = __Orchestrator__.WebRequestParsePath(inRequest=inRequest).split('/') + lPathSplitList = inRequest.url.path.split('/') lQueryStr = None if "HelperDefAutofill" != lPathSplitList[-1] and "" != lPathSplitList[-1]: lQueryStr = lPathSplitList[-1] lResultDict = __Orchestrator__.ActivityItemHelperDefAutofill(inDef = lQueryStr) - __Orchestrator__.WebRequestResponseSend(inRequest=inRequest, inResponeStr=json.dumps(lResultDict)) + return lResultDict # See docs in Agent (pyOpenRPA.Agent.A2O) -def pyOpenRPA_Agent_A2O(inRequest, inGSettings): - lL = inGSettings["Logger"] +@app.post(path="/orpa/agent/a2o",response_class=JSONResponse,tags=["Agent"]) +def pyOpenRPA_Agent_A2O(inRequest:Request, inAuthTokenStr:str = Depends(IdentifyAuthorize), inBodyDict = Body({})): + inGSettings = __Orchestrator__.GSettingsGet() + lL = __Orchestrator__.OrchestratorLoggerGet() # 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')) - lAgentDictItemKeyTurple = (lInput["HostNameUpperStr"], lInput["UserUpperStr"]) + #lValueStr = inBodyStr + # Превращение массива байт в объект + lInput = inBodyDict#json.loads(lValueStr) + lAgentDictItemKeyTurple = (lInput["HostNameUpperStr"], lInput["UserUpperStr"]) if "LogList" in lInput: for lLogItemStr in lInput["LogList"]: inGSettings["Logger"].info(lLogItemStr) @@ -460,14 +468,14 @@ def pyOpenRPA_Agent_A2O(inRequest, inGSettings): from pyOpenRPA.Utils.Render import Render lFileStr = CrossOS.PathJoinList(CrossOS.PathSplitList(__file__)[:-2] + ["Resources","Web","orpa","orc.xhtml"]) gRender = Render(inTemplatePathStr=lFileStr,inTemplateRefreshBool=True) - +from pyOpenRPA import __version__ def pyOpenRPA_Index(): # Пример использования global gRender - lStr = gRender.Generate(inDataDict={"title":"ОРКЕСТРАТОР PYOPENRPA", "subtitle":"ПАНЕЛЬ УПРАВЛЕНИЯ"}) + lStr = gRender.Generate(inDataDict={"title":"ОРКЕСТРАТОР PYOPENRPA", "subtitle":"ПАНЕЛЬ УПРАВЛЕНИЯ", "version":__version__}) __Orchestrator__.WebRequestResponseSend(inResponeStr=lStr,inContentTypeStr="text/html") -def SettingsUpdate(inGlobalConfiguration): +def SettingsUpdate(): import os import pyOpenRPA.Orchestrator gSettingsDict = __Orchestrator__.GSettingsGet() @@ -487,32 +495,36 @@ def SettingsUpdate(inGlobalConfiguration): #Orchestrator basic dependencies # Index page in server.py because of special settings {"Method":"GET", "URL": gSettingsDict["ServerDict"]["URLIndexStr"],"MatchType": "EqualNoParam", "ResponseDefRequestGlobal": pyOpenRPA_Index}, {"Method":"GET", "URL": "/metadata.json", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\orpa\\metadata.json"), "ResponseContentType": "application/json"}, - {"Method":"GET", "URL": "/Index.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "Web\\Index.js"), "ResponseContentType": "text/javascript"}, - {"Method":"GET", "URL": "/orpa/Resources/", "MatchType": "BeginWith", "ResponseFolderPath": os.path.join(lOrchestratorFolder, "..\\Resources"),"UACBool":False, "UseCacheBool": True}, - {"Method":"GET", "URL": "/3rdParty/Semantic-UI-CSS-master/semantic.min.css", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\semantic.min.css"), "ResponseContentType": "text/css", "UACBool":False, "UseCacheBool": True}, - {"Method":"GET", "URL": "/3rdParty/Semantic-UI-CSS-master/semantic.min.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\semantic.min.js"), "ResponseContentType": "application/javascript", "UACBool":False, "UseCacheBool": True}, - {"Method":"GET", "URL": "/3rdParty/jQuery/jquery-3.1.1.min.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\jQuery\\jquery-3.1.1.min.js"), "ResponseContentType": "application/javascript", "UACBool":False, "UseCacheBool": True}, - {"Method":"GET", "URL": "/3rdParty/Google/LatoItalic.css", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Google\\LatoItalic.css"), "ResponseContentType": "font/css", "UACBool":False, "UseCacheBool": True}, - {"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", "UACBool":False, "UseCacheBool": True}, - {"Method":"GET", "URL": "/themes/default/", "MatchType": "BeginWith", "ResponseFolderPath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\themes\\default"),"UACBool":False, "UseCacheBool": True}, - {"Method":"GET", "URL": "/favicon.ico", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "Web\\favicon.ico"), "ResponseContentType": "image/x-icon", "UACBool":False, "UseCacheBool": True}, - {"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", "UACBool":False, "UseCacheBool": True}, - {"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_Monitor_ControlPanelDictGet_SessionCheckInit, "ResponseContentType": "application/json"}, - {"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": pyOpenRPA_Screenshot, "ResponseContentType": "image/png"}, - {"Method": "GET", "URL": "/pyOpenRPA_logo.png", "MatchType": "Equal", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\pyOpenRPA_logo.png"), "ResponseContentType": "image/png", "UACBool":False, "UseCacheBool": True}, - {"Method": "POST", "URL": "/Orchestrator/UserRoleHierarchyGet", "MatchType": "Equal","ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_UserRoleHierarchyGet, "ResponseContentType": "application/json"}, + #{"Method":"GET", "URL": "/Index.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "Web\\Index.js"), "ResponseContentType": "text/javascript"}, + {"Method":"GET", "URL": "/orpa/resources/", "MatchType": "BeginWith", "ResponseFolderPath": os.path.join(lOrchestratorFolder, "..\\Resources"),"UACBool":False, "UseCacheBool": True}, + {"Method":"GET", "URL": "/orpa/client/resources/", "MatchType": "BeginWith", "ResponseFolderPath": os.path.join(lOrchestratorFolder, "Web"),"UACBool":False, "UseCacheBool": True}, + + #{"Method":"GET", "URL": "/3rdParty/Semantic-UI-CSS-master/semantic.min.css", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\semantic.min.css"), "ResponseContentType": "text/css", "UACBool":False, "UseCacheBool": True}, + #{"Method":"GET", "URL": "/3rdParty/Semantic-UI-CSS-master/semantic.min.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\semantic.min.js"), "ResponseContentType": "application/javascript", "UACBool":False, "UseCacheBool": True}, + #{"Method":"GET", "URL": "/3rdParty/jQuery/jquery-3.1.1.min.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\jQuery\\jquery-3.1.1.min.js"), "ResponseContentType": "application/javascript", "UACBool":False, "UseCacheBool": True}, + #{"Method":"GET", "URL": "/3rdParty/Google/LatoItalic.css", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Google\\LatoItalic.css"), "ResponseContentType": "font/css", "UACBool":False, "UseCacheBool": True}, + #{"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", "UACBool":False, "UseCacheBool": True}, + #{"Method":"GET", "URL": "/themes/default/", "MatchType": "BeginWith", "ResponseFolderPath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Semantic-UI-CSS-master\\themes\\default"),"UACBool":False, "UseCacheBool": True}, + {"Method":"GET", "URL": "/favicon.ico", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\orpa\\favicon.ico"), "ResponseContentType": "image/x-icon", "UACBool":False, "UseCacheBool": True}, + #{"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", "UACBool":False, "UseCacheBool": True}, + #{"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": BackwardCompatibility.v1_2_0_Monitor_ControlPanelDictGet_SessionCheckInit, "ResponseContentType": "application/json"}, + #{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": pyOpenRPA_Screenshot, "ResponseContentType": "image/png"}, + #{"Method": "GET", "URL": "/pyOpenRPA_logo.png", "MatchType": "Equal", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\pyOpenRPA_logo.png"), "ResponseContentType": "image/png", "UACBool":False, "UseCacheBool": True}, + {"Method": "POST", "URL": "/orpa/client/user-role-hierarchy-get", "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"}, - {"Method": "GET", "URL": "/pyOpenRPA/Debugging/HelperDefList/", "MatchType": "BeginWith","ResponseDefRequestGlobal": pyOpenRPA_Debugging_HelperDefList, "ResponseContentType": "application/json"}, - {"Method": "GET", "URL": "/pyOpenRPA/Debugging/HelperDefAutofill/", "MatchType": "BeginWith","ResponseDefRequestGlobal": pyOpenRPA_Debugging_HelperDefAutofill, "ResponseContentType": "application/json"}, + {"Method": "POST", "URL": "/orpa/client/server-data", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerData, "ResponseContentType": "application/json"}, + {"Method": "GET", "URL": "/orpa/client/server-js-init", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerJSInit, "ResponseContentType": "application/javascript"}, + {"Method": "POST", "URL": "/orpa/client/server-log", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ServerLog, "ResponseContentType": "application/json"}, + #{"Method": "GET", "URL": "/orpa/client/screenshot-get", "MatchType": "Equal", "ResponseDefRequestGlobal": pyOpenRPA_Screenshot, "ResponseContentType": "image/png"}, + # API + #{"Method": "POST", "URL": "/orpa/api/processor-queue-add", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Processor, "ResponseContentType": "application/json"}, + #{"Method": "POST", "URL": "/orpa/api/activity-list-execute", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_ActivityListExecute, "ResponseContentType": "application/json"}, + #{"Method": "GET", "URL": "/orpa/api/helper-def-list/", "MatchType": "BeginWith","ResponseDefRequestGlobal": pyOpenRPA_Debugging_HelperDefList, "ResponseContentType": "application/json"}, + #{"Method": "GET", "URL": "/orpa/api/helper-def-autofill/", "MatchType": "BeginWith","ResponseDefRequestGlobal": pyOpenRPA_Debugging_HelperDefAutofill, "ResponseContentType": "application/json"}, + # AGENT + #{"Method": "POST", "URL": "/orpa/agent/o2a", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Agent_O2A, "ResponseContentType": "application/json"}, + #{"Method": "POST", "URL": "/orpa/agent/a2o", "MatchType": "Equal","ResponseDefRequestGlobal": pyOpenRPA_Agent_A2O, "ResponseContentType": "application/json"} ] Usage.Process(inComponentStr="Orchestrator") - inGlobalConfiguration["ServerDict"]["URLList"]=inGlobalConfiguration["ServerDict"]["URLList"]+lURLList - return inGlobalConfiguration + gSettingsDict["ServerDict"]["URLList"]=gSettingsDict["ServerDict"]["URLList"]+lURLList + return gSettingsDict diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.js b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.js deleted file mode 100755 index 07fe9ab2..00000000 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.js +++ /dev/null @@ -1,992 +0,0 @@ -var mGlobal={} -mGlobal.pyOpenRPA = {} -window.onload=function() { - //document.cookie = "SessionGUIDStr=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; - //Render existing data - //mGlobal.Monitor.fControlPanelRefresh_TechnicalRender() -} -$(document).ready(function() { - document.cookie = "SessionGUIDStr=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; - console.log("Cookie is deleted") - // fix main menu to page on passing - $('.main.menu').visibility({ - type: 'fixed' - }); - $('.overlay').visibility({ - type: 'fixed', - offset: 80 - }); - - // lazy load images - $('.image').visibility({ - type: 'image', - transition: 'vertical flip in', - duration: 500 - }); - - // show dropdown on hover - $('.main.menu .ui.dropdown').dropdown({ - on: 'hover' - }); - function clone(obj) { - var copy; - - // Handle the 3 simple types, and null or undefined - if (null == obj || "object" != typeof obj) return obj; - - // Handle Date - if (obj instanceof Date) { - copy = new Date(); - copy.setTime(obj.getTime()); - return copy; - } - - // Handle Array - if (obj instanceof Array) { - copy = []; - for (var i = 0, len = obj.length; i < len; i++) { - copy[i] = clone(obj[i]); - } - return copy; - } - - // Handle Object - if (obj instanceof Object) { - copy = {}; - for (var attr in obj) { - if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]); - } - return copy; - } - throw new Error("Unable to copy obj! Its type isn't supported."); - } - //For data storage key - mGlobal["DataStorage"] = {} - // Clear the session cookie - - String.prototype.replaceAll = function(search, replace){ - return this.split(search).join(replace); - } - mGlobal.GeneralGenerateHTMLCodeHandlebars=function(inInnerTemplateSelector,inData) { - lHTMLTemplate=$(inInnerTemplateSelector)[0].innerHTML - //console.log(lHTMLTemplate) - //Компиляция - var template = Handlebars.compile(lHTMLTemplate); - //Вставка данных - var lHTMLResult = template(inData); - return lHTMLResult - } - mGlobal.GeneralGenerateHTMLCode=function(inTemplateHTMLSelector,inItemDictionary,inKeywordPrefix="::",inKeywordPostfix="::") { - ///Получить заготовку - lTemplateHTMLCode=$(inTemplateHTMLSelector)[0].outerHTML - ///Определить ключь экранирования специальных ключевых слов - ///Выполнить циклические замены, если там есть пожходящие ключи - lResultHTMLCode=lTemplateHTMLCode - for(var lKey in inItemDictionary) { - lHTMLKey=inKeywordPrefix+lKey+inKeywordPostfix; - lResultHTMLCode=lResultHTMLCode.replaceAll(lHTMLKey,inItemDictionary[lKey]) - } - ///Вернуть результат - return lResultHTMLCode - } - ////////////////////////// - /////Info JS module - ////////////////////////// - mGlobal.Info={}; - - mGlobal.Info.TableActivityLogScheduleListRefresh=function() { - - } - ////////////////////////// - /////Controller JS module - ////////////////////////// - mGlobal.Controller={}; - - mGlobal.Controller.CMDRunText=function(inCMDText) { - ///Подготовить конфигурацию - lData = [ - {"Type":"CMDStart", "Command": inCMDText} - ] - ///Обнулить таблицу - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3){}, - dataType: "text" - }); - } - mGlobal.Controller.CMDRun=function() { - ///Обнулить таблицу - lCMDCode=$(".openrpa-controller-cmd-run-input")[0].value - ///Подготовить конфигурацию - lData = [ - { - "Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"]) - "ArgList":[], // Args list - "ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary - "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList) - "ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList) - } - ] - $.ajax({ - type: "POST", - url: '/pyOpenRPA/ActivityListExecute', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///Отправить запрос на формирование таблицы - //lHTMLCode=console.log("CMDRun result: "+lResponseJSON[0].result) - }, - dataType: "text" - }); - } - mGlobal.Controller.CMDRunGUILogout=function() { - ///Обнулить таблицу - lCMDCode="for /f \"skip=1 tokens=2\" %s in ('query user %USERNAME%') do (tscon \\dest:console)" - //lCMDCode = lCMDCode.replace(/\\n/g, "\\n") - // .replace(/\\'/g, "\\'") - // .replace(/\\"/g, '\\"') - // .replace(/\\&/g, "\\&") - // .replace(/\\r/g, "\\r") - // .replace(/\\t/g, "\\t") - // .replace(/\\b/g, "\\b") - // .replace(/\\f/g, "\\f") - // .replace('"', "\\\""); - ///Подготовить конфигурацию - lData = [ - {"Type":"CMDStart", "Command": lCMDCode } - ] - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///Отправить запрос на формирование таблицы - //lHTMLCode=console.log("CMDRun result: "+lResponseJSON[0].result) - }, - dataType: "text" - }); - } - ///Restart PC - mGlobal.Controller.PCRestart = function () { - mGlobal.Controller.OrchestratorSessionSave() - mGlobal.Controller.CMDRunText("shutdown -r") - } - ///Orchestrator save session - mGlobal.Controller.OrchestratorSessionSave=function() { - ///Подготовить конфигурацию - lData = [ - {"Type":"OrchestratorSessionSave"} - ] - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - }, - dataType: "text" - }); - } - ///Перезагрузить Orchestrator - mGlobal.Controller.OrchestratorRestart=function() { - ///Подготовить конфигурацию - lData = [ - {"Type":"OrchestratorRestart"} - ] - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - }, - dataType: "text" - }); - } - mGlobal.Controller.OrchestratorGITPullRestart = function() { - mGlobal.Controller.OrchestratorSessionSave() //Save current RDP list session - mGlobal.Controller.CMDRunText("timeout 3 & taskkill /f /im OpenRPA_Orchestrator.exe & timeout 2 & cd "+mGlobal.WorkingDirectoryPathStr+" & git reset --hard & git pull & pyOpenRPA.Orchestrator_x64_administrator_startup.cmd"); - } - ////////////////////////// - /////Monitor JS module - ////////////////////////// - mGlobal.Monitor={}; - mGlobal.Monitor.ScreenshotModal={}; - mGlobal.Monitor.GenerateUniqueID=function(inPrefix="tempUID=") { - return inPrefix+Math.round(Math.random()*1000)+"-"+Math.round(Math.random()*10000)+"-"+Math.round(Math.random()*1000) - } - //inHostURI: http://localhost:8081 - mGlobal.Monitor.ScreenshotModal.Show=function(inHostURI=" ") { - $('.ui.modal.daemon-screenshot').modal({'onHide':function (inElement) {mGlobal.Monitor.ScreenshotModal.Close();} }).modal('show'); - - //Функция обновления картинки - lScreenshotUpdate=function() { - lScreenshotSrc=inHostURI+"/GetScreenshot?"+mGlobal.Monitor.GenerateUniqueID() - $(".daemon-screenshot img").attr('src', lScreenshotSrc); - } - - mGlobal.Monitor.ScreenshotModal.timerId=setInterval(lScreenshotUpdate,1500) - } - mGlobal.Monitor.ScreenshotModal.Close=function() { - clearInterval(mGlobal.Monitor.ScreenshotModal.timerId); - } - ///Monitor - mGlobal.Monitor.DaemonList={} - mGlobal.Monitor.DaemonList.fRefreshTable=function() { - ///Загрузка данных - $.ajax({ - type: "GET", - url: 'Monitor/JSONDaemonListGet', - data: '', - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///Сформировать HTML код новой таблицы - lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-monitor-table-general",lResponseJSON) - ///Очистить дерево - //mGlobal.ElementTree.fClear(); - ///Прогрузить новую таблицу - $(".openrpa-monitor").html(lHTMLCode) - }, - dataType: "text" - }); - } - //////////////////////////////// - ///////Control panel - /////////////////////////////// - ///Refresh control panel - function sleep(ms) { - ms += new Date().getTime(); - while (new Date() < ms){} - } - function uuidv4() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); - } - mGlobal.SessionGUIDStr = uuidv4() // Generate uuid4 of the session - //console.log(uuidv4()); - mGlobal.RobotRDPActive = {} - mGlobal.Monitor.fControlPanelRefresh_TechnicalRender = function() - { - lResponseJSON = mGlobal.Monitor.mDatasetLast - - 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 - /// RenderRobotList - lResponseJSON["RenderRobotList"].forEach( - function(lItem){ - if ('FooterButtonX2List' in lItem) { - /// FooterButtonX2List - lItem["FooterButtonX2List"].forEach( - function(lItem2){ - if ('OnClick' in lItem) { - lOnClickEscaped = lItem["OnClick"]; - lOnClickEscaped = lOnClickEscaped.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); - lItem["OnClick"] = lOnClickEscaped; - } - } - ); - /// FooterButtonX1List - lItem["FooterButtonX1List"].forEach( - function(lItem2){ - if ('OnClick' in lItem) { - lOnClickEscaped = lItem["OnClick"]; - lOnClickEscaped = lOnClickEscaped.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); - lItem["OnClick"] = lOnClickEscaped; - } - } - ); - } - } - ); - ////////////////////////////////////////////////////////// - ///Сформировать HTML код новой таблицы - контрольная панель - lHTMLCode+=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-control-panel",lResponseJSON) - //Присвоить ответ в mGlobal.Monitor.mResponseList - mGlobal.Monitor.mResponseList = lResponseJSON - ///Set result in mGlobal.DataStorage - lResponseJSON["RenderRobotList"].forEach( - function(lItem){ - if ('DataStorageKey' in lItem) { - mGlobal["DataStorage"][lItem['DataStorageKey']]=lItem - } - } - ) - ///Прогрузить новую таблицу - $(".openrpa-control-panel").html(lHTMLCode) - //////////////////////////////////////////////////// - /// !RDP List ! Сформировать HTML код новой таблицы - список RDP - lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON) - //Присвоить ответ в mGlobal.RobotRDPActive.mResponseList - mGlobal.RobotRDPActive.mResponseList = lResponseJSON - ///Прогрузить новую таблицу - $(".openrpa-robotrdpactive-control-panel").html(lHTMLCode) - ///Очистить дерево - //mGlobal.ElementTree.fClear(); - //////////////////////////////////////////////////// - /// !UserAgent List ! Сформировать HTML код новой таблицы - список RDP - lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".pyOpenRPA-Agent-ListTemplate",lResponseJSON) - //Присвоить ответ в mGlobal.RobotRDPActive.mResponseList - mGlobal.RobotRDPActive.mResponseList = lResponseJSON - ///Прогрузить новую таблицу - $(".pyOpenRPA-Agent-List").html(lHTMLCode) - ///Очистить дерево - //mGlobal.ElementTree.fClear(); - } - } - } - - ///v 1.2.0 pyOpenRPA - /// Execute ActivityItem - mGlobal.pyOpenRPA.ActivityItemExecute=function(inActivityItem) { - ///EXAMPLE - // { - // "Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"]) - // "ArgList":[], // Args list - // "ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary - // "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList) - // "ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList) - // } - ///Подготовить конфигурацию - lData = [inActivityItem] - $.ajax({ - type: "POST", - url: '/pyOpenRPA/ActivityListExecute', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - console.log(lResponseJSON) - }, - dataType: "text" - }); - } - /// Execute ActivityList - mGlobal.pyOpenRPA.ActivityListExecute=function(inActivityList) { - ///EXAMPLE - // [{ - // "Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"]) - // "ArgList":[], // Args list - // "ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary - // "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList) - // "ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList) - // }] - ///Подготовить конфигурацию - lData = inActivityList - $.ajax({ - type: "POST", - url: '/pyOpenRPA/ActivityListExecute', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - console.log(lResponseJSON) - }, - dataType: "text" - }); - } - /// Add ActivityList in processor queue - mGlobal.pyOpenRPA.ProcessorQueueAdd=function(inActivityList) { - ///EXAMPLE - // [{ - // "Def":"OSCMD", // def link or def alias (look gSettings["Processor"]["AliasDefDict"]) - // "ArgList":[], // Args list - // "ArgDict":{"inCMDStr":lCMDCode,"inRunAsyncBool":false}, // Args dictionary - // "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList) - // "ArgLogger": "inLogger" // Name of GSettings attribute: str (ArgDict) or index (for ArgList) - // }] - ///Подготовить конфигурацию - lData = inActivityList - $.ajax({ - type: "POST", - url: '/pyOpenRPA/ProcessorQueueAdd', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - console.log(lResponseJSON) - }, - dataType: "text" - }); - } - - /// v1.2.0 pyOpenRPA ServerJSInit - mGlobal.pyOpenRPA.ServerJSInitDef=function() { - try { - $.ajax({ - type: "GET", - headers: {}, - url: 'pyOpenRPA/ServerJSInit', - data: mGlobal.pyOpenRPA.ServerDataHashStr, - async: false, - success: function(lJSText) { - try { - eval(lJSText) - } - catch(error) { - console.log(error) - } - }, - dataType: "text", - error: function(jqXHR, textStatus, errorThrown ) { - console.log(textStatus) - } - }); - } - catch(error) { - console.log(error) - } - } - - /// v1.2.0 pyOpenRPA ServerData - mGlobal.pyOpenRPA.ServerDataDict = null - mGlobal.pyOpenRPA.ServerDataHashStr = "" - mGlobal.pyOpenRPA.ServerDataRefreshDef_TechnicalRender = function() - { - lResponseJSON = mGlobal.pyOpenRPA.ServerDataDict - if (lResponseJSON!= null) { - /// New version of control panels - lHTMLCode = '
' - for (var lKeyStr in lResponseJSON["CPDict"]){ - lCPDict = lResponseJSON["CPDict"][lKeyStr] - /// Render HTML - if ("HTMLStr" in lCPDict) { - lHTMLCode+=lCPDict["HTMLStr"] - } - } - lHTMLCode += '
' - ///Прогрузить новую таблицу - $(".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) { - try { - var lResponseJSON=JSON.parse(lData) - mGlobal.VersionStr = lResponseJSON["ServerDataDict"]["UserDict"]["VersionStr"] - mGlobal.pyOpenRPA.ServerDataDict = lResponseJSON["ServerDataDict"] - mGlobal.pyOpenRPA.ServerDataHashStr = lResponseJSON["HashStr"] - mGlobal.pyOpenRPA.ServerDataRefreshDef_TechnicalRender() - mGlobal.UserRoleUpdate(); - setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,600) // If LOGS are update every ms - set some limit in ms on the client side - //mGlobal.pyOpenRPA.ServerDataRefreshDef() // Go to the next call - } - catch(error) { - console.log(error) - setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000) - } - //mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive - }, - dataType: "text", - error: function(jqXHR, textStatus, errorThrown ) { - setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000) - //sleep(3000) - //mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive - } - }); - } - catch(error) { - setTimeout(mGlobal.pyOpenRPA.ServerDataRefreshDef,3000) - //sleep(3000) - //mGlobal.pyOpenRPA.ServerDataRefreshDef() // recursive - } - } - ///////////////////////////////////////////////////////////// - /// v1.2.0 pyOpenRPA ServerLogs - mGlobal.pyOpenRPA.ServerLogList = null - mGlobal.pyOpenRPA.ServerLogListHashStr = "" - mGlobal.pyOpenRPA.ServerLogListDoRenderBool = true - ///Turn OFF rendering - mGlobal.pyOpenRPA.ServerLogListDoRenderFalse = function() { - ///Set unfreeze button - $("a.mGlobal-pyOpenRPA-ServerLogListDoRender").html("Unfreeze textarea") - $("a.mGlobal-pyOpenRPA-ServerLogListDoRender").attr("onclick","mGlobal.pyOpenRPA.ServerLogListDoRenderTrue()") - $("textarea.mGlobal-pyOpenRPA-ServerLogList").css("background-color","#b9e2e8") - mGlobal.pyOpenRPA.ServerLogListDoRenderBool = false - } - ///Turn ON rendering - mGlobal.pyOpenRPA.ServerLogListDoRenderTrue = function() { - mGlobal.pyOpenRPA.ServerLogListDoRenderBool = true - ///Render last data - mGlobal.pyOpenRPA.ServerLogListRefreshDef_TechnicalRender() - ///Set unfreeze button - $("a.mGlobal-pyOpenRPA-ServerLogListDoRender").html("Freeze textarea") - $("a.mGlobal-pyOpenRPA-ServerLogListDoRender").attr("onclick","mGlobal.pyOpenRPA.ServerLogListDoRenderFalse()") - $("textarea.mGlobal-pyOpenRPA-ServerLogList").css("background-color","") - - } - mGlobal.pyOpenRPA.ServerLogListScrollBottomDef = function() { - var lTA = $("textarea.mGlobal-pyOpenRPA-ServerLogList")[0]; - lTA.scrollTop = lTA.scrollHeight; - } - mGlobal.pyOpenRPA.ServerLogListRefreshDef_TechnicalRender = function() - { - lResponseJSON = mGlobal.pyOpenRPA.ServerLogList - if (lResponseJSON!= null && mGlobal.pyOpenRPA.ServerLogListDoRenderBool==true) { - lText = lResponseJSON.join("\n") /// Code for the processing the text - $("textarea.mGlobal-pyOpenRPA-ServerLogList")[0].value= lText ///Прогрузить новую таблицу - mGlobal.pyOpenRPA.ServerLogListScrollBottomDef() //Scroll to the bottom - } - } - mGlobal.pyOpenRPA.ServerLogListRefreshDef=function() { - try { - $.ajax({ - type: "POST", - headers: {}, - url: 'pyOpenRPA/ServerLog', - data: mGlobal.pyOpenRPA.ServerLogListHashStr, - success: function(lData,l2,l3) { - try { - var lResponseJSON=JSON.parse(lData) - mGlobal.pyOpenRPA.ServerLogList = lResponseJSON["ServerLogList"] - mGlobal.pyOpenRPA.ServerLogListHashStr = lResponseJSON["HashStr"] - mGlobal.pyOpenRPA.ServerLogListRefreshDef_TechnicalRender() - } - catch(error) { - } - setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,600) // If LOGS are update every ms - set some limit in ms on the client side - //mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive - }, - dataType: "text", - error: function(jqXHR, textStatus, errorThrown ) { - setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,3000) - //sleep(3000) - //mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive - } - }); - } - catch(error) { - setTimeout(mGlobal.pyOpenRPA.ServerLogListRefreshDef,3000) - //sleep(3000) - //mGlobal.pyOpenRPA.ServerLogListRefreshDef() // recursive - } - } - ///////////////////////////////////////////////////////////// - - - mGlobal.Monitor.mDatasetLast = null - - /////////////////////////////// - ///Processor functions - /////////////////////////////// - mGlobal.Processor = {} - mGlobal.Processor.ServerValueAppend = function(inKeyList,inValue) { - lData = [ - { - "Type":"GlobalDictKeyListValueAppend", - "KeyList": inKeyList, - "Value": inValue - } - ] - ///Обнулить таблицу - $('.ui.modal.basic .content').html(""); - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///TODO Show error if exist error - }, - dataType: "text" - }); - } - mGlobal.Processor.ServerValueSet = function(inKeyList,inValue) { - lData = [ - { - "Type":"GlobalDictKeyListValueSet", - "KeyList": inKeyList, - "Value": inValue - } - ] - ///Обнулить таблицу - $('.ui.modal.basic .content').html(""); - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///TODO Show error if exist error - }, - dataType: "text" - }); - } - mGlobal.Processor.ServerValueOperatorPlus = function(inKeyList,inValue) { - lData = [ - { - "Type":"GlobalDictKeyListValueOperator+", - "KeyList": inKeyList, - "Value": inValue - } - ] - ///Обнулить таблицу - $('.ui.modal.basic .content').html(""); - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///TODO Show error if exist error - }, - dataType: "text" - }); - } - mGlobal.Processor.Send = function(inData) { - lData = inData - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///TODO Show error if exist error - }, - dataType: "text" - }); - } - mGlobal.Server= {} - mGlobal.Server.JSONGet=function(inMethod, inURL, inDataJSON, inCallback) - { - $.ajax({ - type: inMethod, - url: inURL, - data: JSON.stringify(inDataJSON), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - inCallback(lResponseJSON) - }, - dataType: "text" - }); - } - - ///////////////// - ///Modal - /////////////////// - mGlobal.Modal={} - ///////////////////////////////////////////////////// - mGlobal.Modal.TableFilter={} - mGlobal.Modal.TableFilter.Show=function(inJSON) { - //{ - // "Title":"", - // "Headers":["Header1","Header2"], - // "Rows": [["Cell1","Cell2"],["Cell2-1","Cell2-2"]], - // "FilterOnKeyUp": "" //Fill here in function - //} - //Set js handler to Search field - inJSON["FilterOnKeyUp"]="mGlobal.Modal.TableFilter.FilterUpdate(this.value);" - ///Set value - mGlobal.Modal.TableFilter.mDataJSON = inJSON - //Render HTML - lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-handlebar-template-table-filter",inJSON); - ///Установить HTML код - $('.ui.modal.basic .content').html(lHTMLCode); - $('.ui.modal.basic').modal('show'); - //DO widest modal for table with scroll x - $("div.ui.basic.modal.transition.visible.active.scrolling")[0].style["width"]="1300px" - $("div.ui.basic.modal.transition.visible.active.scrolling")[0].style["overflow"]="scroll" - } - //Service function - mGlobal.Modal.TableFilter.FilterUpdate=function(inFilterValue) { - //Get JSON, apply filter, clone data - lDataJSON = clone(mGlobal.Modal.TableFilter.mDataJSON) - delete lDataJSON["Rows"] - lDataJSON["Rows"]=[] - //Filter code [any occurence in the row is ok for push! ] - mGlobal.Modal.TableFilter.mDataJSON["Rows"].forEach( - function(inElement) { - lFlagElementAppend = false - inElement.forEach( - function(inElement2) { - if (String(inElement2).includes(inFilterValue)) { - lFlagElementAppend = true - } - } - ) - if (lFlagElementAppend) { - lDataJSON["Rows"].push(inElement) - } - } - ) - //Clear Filter Title property (fixed in html) - delete lDataJSON["FilterOnKeyUp"] - delete lDataJSON["Title"] - //Search the table element [replace only table html] - lElement = $('.ui.modals.active .content table.table')[0] - lElementParentElement = lElement.parentNode - lElement.parentNode.removeChild(lElement); - //Render HTML - lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-handlebar-template-table-filter",lDataJSON); - ///Установить HTML код - lElementParentElement.insertAdjacentHTML("beforeend",lHTMLCode); - } - ///////////////////////////////////////////////////////////// - mGlobal.Modal.ListFilter={} - mGlobal.Modal.ListFilter.Show=function(inJSON) { - //{ - // "Title":"", - // "List":[{"Header":"","Description":""}], - // "FilterOnKeyUp": "" //Fill here in function - //} - //Set js handler to Search field - inJSON["FilterOnKeyUp"]="mGlobal.Modal.ListFilter.FilterUpdate(this.value);" - ///Set value - mGlobal.Modal.ListFilter.mDataJSON = inJSON - //Render HTML - lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-handlebar-template-list-filter",inJSON); - ///Установить HTML код - $('.ui.modal.basic .content').html(lHTMLCode); - $('.ui.modal.basic').modal('show'); - } - //Service function - mGlobal.Modal.ListFilter.FilterUpdate=function(inFilterValue) { - //Get JSON, apply filter, clone data - lDataJSON = clone(mGlobal.Modal.ListFilter.mDataJSON) - delete lDataJSON["List"] - lDataJSON["List"]=[] - //Filter code [any occurence in the row is ok for push! ] - mGlobal.Modal.ListFilter.mDataJSON["List"].forEach( - function(inElement) { - lFlagElementAppend = false - if (String(inElement["Header"]).includes(inFilterValue)) { - lFlagElementAppend = true - } - if (String(inElement["Description"]).includes(inFilterValue)) { - lFlagElementAppend = true - } - if (lFlagElementAppend) { - lDataJSON["List"].push(inElement) - } - } - ) - //Clear Filter Title property (fixed in html) - delete lDataJSON["FilterOnKeyUp"] - delete lDataJSON["Title"] - //Search the table element [replace only table html] - lElement = $('.ui.modals.active .content div.ui.inverted.segment')[0] - lElementParentElement = lElement.parentNode - lElement.parentNode.removeChild(lElement); - //Render HTML - lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-handlebar-template-list-filter",lDataJSON); - ///Установить HTML код - lElementParentElement.insertAdjacentHTML("beforeend",lHTMLCode); - } - mGlobal.UserRoleHierarchyDict = null // Put here the user role hierarchy - // UAC Ask - mGlobal.UserRoleAsk=function(inList) { - var lResult = true; // Init flag - var lRoleHierarchyDict = mGlobal.pyOpenRPA.ServerDataDict.UserDict.UACClientDict; // get the Hierarchy - // Try to get value from key list - var lKeyValue = lRoleHierarchyDict; // Init the base - var lListLength = inList.length; - for (var i = 0; i 0) { // false - if Dict has some elements - lResult = false; // Set the False Flag - } else { - lResult = true; // Set the true flag - } - break; // Stop the loop - } - } else { // Has element with no detalization - return true - lResult = true; // Set the flag - break; // Close the loop - } - } - return lResult; // Return the result - } - // Check user roles and update the Orchestrator UI - mGlobal.UserRoleUpdate=function() { - var lUACAsk = mGlobal.UserRoleAsk // Alias - //CPKeyDict - if (lUACAsk(["pyOpenRPADict","CPKeyDict"])) { $(".UACClient-pyOpenRPADict-CPKeyDict").show(); } - - //RDPKeyDict - if (lUACAsk(["pyOpenRPADict","RDPKeyDict"])) { $(".UACClient-pyOpenRPADict-RDPKeyDict").show(); } - - //AgentKeyDict - if (lUACAsk(["pyOpenRPADict","AgentKeyDict"])) { $(".UACClient-pyOpenRPADict-AgentKeyDict").show(); } - - // AdminDict - if (lUACAsk(["pyOpenRPADict","AdminDict","LogViewerBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-LogViewerBool").show(); } - if (lUACAsk(["pyOpenRPADict","AdminDict","CMDInputBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-CMDInputBool").show(); } - if (lUACAsk(["pyOpenRPADict","AdminDict","ScreenshotViewerBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-ScreenshotViewerBool").show(); } - if (lUACAsk(["pyOpenRPADict","AdminDict","RestartOrchestratorBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorBool").show(); } - if (lUACAsk(["pyOpenRPADict","AdminDict","RestartOrchestratorGITPullBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-RestartOrchestratorGITPullBool").show(); } - if (lUACAsk(["pyOpenRPADict","AdminDict","RestartPCBool"])) { $(".UACClient-pyOpenRPADict-AdminDict-RestartPCBool").show(); } - if (lUACAsk(["pyOpenRPADict","AdminDict","Debugging"])) { $(".UACClient-pyOpenRPADict-AdminDict-Debugging").show(); } - - } - - /// v1.2.0 pyOpenRPA Init defs - 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 - mGlobal.pyOpenRPA.ServerJSInitDef(); // Recieve JS from server (if exist) and then call anothe url ServerData - //$('.ui.dropdown').dropdown(); - - //////////////////////////////////////////// - // 1.2.7 Debugging - /// Execute ActivityItem - - // Debugging onchange def autofill init - var lDropdownOnChange = function(inEvent){ - //lValueStr = inEvent.target.value - lValueStr = inEvent - $.ajax({ - type: "GET", - url: '/pyOpenRPA/Debugging/HelperDefAutofill/'+lValueStr, - data: null, - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - console.log("HelperDefAutofill:") - console.log(lResponseJSON) - //ArgDict merge - var lArgDictTargetDict = lResponseJSON["ArgDict"] - var lArgDictStr = $(".mGlobal-pyOpenRPA-Debugging-ArgDict")[0].value - if (lArgDictStr !="" && lArgDictStr !=null) { - lArgDictLastDict = JSON.parse(lArgDictStr) - lArgDictTargetDict = mGlobal.pyOpenRPA.DebuggingAutofillMerge(lArgDictTargetDict, lArgDictLastDict) - } - - $(".mGlobal-pyOpenRPA-Debugging-ArgList")[0].value = JSON.stringify(lResponseJSON["ArgList"]) - $(".mGlobal-pyOpenRPA-Debugging-ArgDict")[0].value = JSON.stringify(lArgDictTargetDict) - $(".mGlobal-pyOpenRPA-Debugging-ArgGSettingsStr")[0].value = JSON.stringify(lResponseJSON["ArgGSettingsStr"]) - $(".mGlobal-pyOpenRPA-Debugging-ArgLoggerStr")[0].value = JSON.stringify(lResponseJSON["ArgLoggerStr"]) - - }, - dataType: "text" - }); - } - //$('.ui.dropdown.mGlobal-pyOpenRPA-Debugging-Def-Dropdown')[0].onchange=lDropdownOnChange - - - - mGlobal.pyOpenRPA.DebuggingExecute=function() { - ///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) - // } - ///Подготовить конфигурацию - lArgListStr = $(".mGlobal-pyOpenRPA-Debugging-ArgList")[0].value - lArgDictStr = $(".mGlobal-pyOpenRPA-Debugging-ArgDict")[0].value - lArgGSettingsStr = $(".mGlobal-pyOpenRPA-Debugging-ArgGSettingsStr")[0].value - lArgLoggerStr = $(".mGlobal-pyOpenRPA-Debugging-ArgLoggerStr")[0].value - lActivityItem = { - "Def":$(".mGlobal-pyOpenRPA-Debugging-Def")[0].value, // def link or def alias (look gSettings["Processor"]["AliasDefDict"]) - "ArgList":(lArgListStr == "" ? [] : JSON.parse(lArgListStr)), // Args list - "ArgDict":(lArgDictStr == "" ? {} : JSON.parse(lArgDictStr)), // Args dictionary - "ArgGSettingsStr": (lArgGSettingsStr == "" ? null : lArgGSettingsStr), // Name of GSettings attribute: str (ArgDict) or index (for ArgList) - "ArgLoggerStr": (lArgLoggerStr == "" ? null : lArgLoggerStr) // Name of GSettings attribute: str (ArgDict) or index (for ArgList) - } - lData = [lActivityItem] - $.ajax({ - type: "POST", - url: '/pyOpenRPA/ActivityListExecute', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - console.log(lResponseJSON) - $(".mGlobal-pyOpenRPA-Debugging-Output")[0].value = JSON.stringify(lResponseJSON[0]) - }, - dataType: "text" - }); - } - mGlobal.pyOpenRPA.DebuggingAutofillMerge=function(inTargetDict, inLastDict) { - // Merge 2 dict (get values from Last dict if key exists in new dict - for (const [lKeyStr, lValue] of Object.entries(inTargetDict)) { - //Check if key exists in LastDict - if (lKeyStr in inLastDict) { - inTargetDict[lKeyStr] = inLastDict[lKeyStr] - } - } - return inTargetDict - } - // 1.2.7 Debugging toolbox init - $('.ui.dropdown.mGlobal-pyOpenRPA-Debugging-Def-Dropdown') - .dropdown({ - apiSettings: { - // this url parses query server side and returns filtered results - url: '/pyOpenRPA/Debugging/HelperDefList/{query}' - }, - onChange: lDropdownOnChange - }) - ; -}); \ No newline at end of file diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.xhtml b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.xhtml deleted file mode 100755 index a1253bde..00000000 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.xhtml +++ /dev/null @@ -1,499 +0,0 @@ - - - - - pyOpenRPA Orchestrator - - - - - - - - - -
-
-
- -     -

pyOpenRPA

-
by Ivan Maslov
-     -     -     -     -     -

ORCHESTRATOR WEB GUI

-
-
-
- -
- -
- - - - - - - -
- - -
- -
-
-
-

- -
- Administration -
-

- -
-
- -
-
-

- - Logs -

- - - Freeze textarea - -
-
- - -

- - Controls -

-
- - - - -
- -
- - - -
-
- - - - - - - - diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/favicon.ico b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/favicon.ico deleted file mode 100755 index 867515cfe56ec3b6ff5e0aff4bfa34868df05627..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112922 zcmeHQO{gVD6~2Q)vNBmoc9Ugx5yE{FaPf2}x*0bz;3f-&!Hq7|ycdxB-V0%f2qXA2 zDuEF(hDacRAcLa5ClQ_!$RJq^3g$gg97zHZ!6XauroQez_tvdj)m^9RRCo2y8}3y1 z=~L&NI`wt^_37%_?1K9D?6WiV|AVs+|MJ4@qqEuUA@x(F*{3g*bagoU!t)nquY6=y z{BS<~xjpds;?jeUKY8gB`-k(r{iFHy{iB^@`t2R<+*ZfSrk~=wLwTz7hLU$s$Xz^w zDw_T#4{Uj0v3U4?g_p~~%KqWbEnmDf;nDZ{3b)XIbm_`h7xM?UjGPFA_P`2*s_knV ze@vX-m@qnAC>DKX#u#kEYSor1jP6_>ZY>SJWEc+?{qfQKtf|g>cKvQKzMaOSy#O)# z<;RcakEuF4?HSG*=S#Nop#9uCoL`;Bp!vb`iN*Y5s&1a!JDR^|tGhAKP=1V2@~fS3 zS@iYA&ZDX>UK|7F7-c-(dvgA%aUr4m(w1|UV!be^&tueYZ{=5O3e%h@Fl4CN zH41SUr>pu3g@wMAyF}?pA$T8N~hqjK1@~Al5v-Q2#r*>kp74-&O4kbRbh__Yck;LP>Z@sac ze*Qjq?)k5YwC8x9(f8QQ6nF%-v%urq{+Q_6UMWnL?PY&)S*?YOwvW`-c2~!LHSUKq z<2+BCN@9|5*|&Z?^?arqOqzHk{N;~JX-t;5?9aTXTz^bEpJ^MD|9#7a#}b$Cy_GjE zQ(%&Cnfp3XTkDUlV)D&;Jg#hcJ6~L;!elv?%6I*;dR{oF_Y-d2`liTuv8=n{t|{R; z2->6Ep6FD2kBO`~xgm@p+rZ-(+ezGa7+ba(-!_DI44=OKndLv<_+!%ck;a!}X&Wu& zJZ@tiUhQet>ovDF@i^9YlJJ>&zYWZ@v1U*D`j~$E`=49B^N-hCX&>!eOix1tl6ul&jz(&CY~@y|M5@0wADTmj!b@^bILoV>%KN*y;Al2 z*ZSZ?$=FBW5o?)s<@UkgyT%?FKYZq~TA6kFhI$R_-P}32@pY_5cd_ovAQ{TNXTyv+K{hiJ>zvqo; zPtmTXvtvEZ4bdSP`v^Qj9>)$7i^Vx}4-DHH6UT-@@v85BG_{q8!OXSHXwRf#!_m%i z@d&?IF&VHQrnwfMtIw0$bvQq0!lbg{IJq6FZn-)nV;_M>j7PaPfL{uekfT4d46$Vx zdFE$zn9TLL4d%mAvEi7fhvHGkq`s#>3{EMwV;K12w>2nt-CmYC#*s_LK4MP+tY^m5 zKjBXblaL2o#@ZEArtb5)_Zpt3U=4+E5R>9Lk3_w1+OXd1Vw1jpx7(L4 zalhnLcN|;l;xg2=Z1(+05&OvTlZ$s7V-qf2zT(hr>*qPeNn)*JyYBgI4`dww=6g|n zwdq$WyIgW&=3l0*Jv-lutITCADH;2SdY7&j7nUUHcVvYsz} z|FtR4Hm2-)EGZfLsJB_te${2CJ{}t`^)Y4FW64x_1ZMh-N!ZVc50Nfw2l7^9%Kf8D zS31yNtj);oL%KZ=k}g;3w$UbkG`Q5hWv}|}*5h|2V{vWuNVM)T>5g9`8+}sXvMJtJ zx~y%>Lp&NiXKZ_ZBN_YHRG-p*ZPI7EF4Y$dJvLaM=ipen?p*TP#3S(GvLlpk!(0;$ zeS*}O8Mqv33?}B;t9G)bcuB;D{rxYmh^>b=VIdbx68@!diE<4Umv}d^tymz*SX>`0 z5)a`)DkZs`RM#!}Ehy~uq01h^F=B+;c=raek8l3%wN~3l!i;o1kz7t{+93ICU}&+y zYHo8i^)p4uSX>Sch}XnJ>^aHhq&A&7Khw9_+a7IxeP6|%r_zVD3#nM#(7CI0**I7v zUY8BI#y+|1ZH0cgb5rTLkwTYbEbi@Be_pJwQyp_s>9TQj6K|ajImU?A*_-^@;m)lT z-xb0AFBOZ6xhnaA>X?&KUa6F$n|PaaOWwZ&hz&lLUN4vIkFZCYUY}IQoK(**am>+8 zygqt!dgsW;-c&r*TKTb*{Fh!@h|R5S^GT{>PAXM4lEcwWyp*>om7EXuHwJTlru-y= zNy+sM*SZ_kF(+-p0rxsbH}P_G0GD0A!_Ki+o)?%baJh_;jrR-4|FLP^^NA4IG3B!5 zZNmo1=L`Le!HmPC)blc*=eTX)!G=Sf)|L&xCHmhGeP$lulCvk0Ufzz5gZA`8T!G|1 zq&{(2rmua@rG4t7)8q-YK{8&YUon_r?WAP;=z~Ypt6A4R=b?CT<@3>L^0;LA(1FXg z_t^BYDkG>`L88-LcHS5~vJfv)Od3Y;eGV9vsoNSazeRP^UQo2b_ zTWfEmuibQhD)qeE=b3HnvjwxRea@x*>7&!+k+uQyOdT=jwr6H3Z1$9?`fU}jrphSs z!x+Won^-);K9}q|x-&GtZSchu8t;tADt#o zlgyCorVi=zu5d};ti`+DA%1B)Pl(^8ZOp+2lqtjxZXStwDcAqBx0;%JpK|kd!O!(6 z_@(X4!3LBm#Ey_WE#va;Y99=Nb#v*ux5*3fsZCA{Ee9K5e~2BSd9Zg0;u~W8=9hQ< ztvmHT?VewrZpM*hTZm67uT+|Y4Jb>99Wi-gp1(1Ce}mddmFF@eUkmq(9s40Zl`dBf zHlR!)cEsjE92nvoqAu>S>NvaLOXNOx!&;?q!Fu6#Mz0NX$@|k&nOW!zbU;mfinBTpZ+DW8Ru^7HKgz%ZZ@i`CC zQvv{n?jg#+R0FCih`XY4dXvjp{)vZPI7EE~Q(SW7E?_)AM7GktTlM z>k_fS=2(*2%-qM6zCP0V^m>pu)@A!1OXxLa`0CdAOc|2^YtMj>J#n5&6zQ;Cw*mJ};e-mFs4CdBYk}#S3n6k+yw(GWf zh@shZG|^)8x$-vYv|V?}(qjv4`8c$oZ?0O#l7vY-|E}I;%(AWI_=b30^$V@zNc6>G_g-at&>liQWsc#|{p))iqtBMtSFg@zlM_qR<@+A{>I`{jpKM^^QGJ&Q zG3A84x>WLAMqfYp@KL!rsgGO^4@Woga^(B+l59@uD;sPP^UYD#;I?3gvp}Okwar6^!ojlt$&OVr2JXZQv-$vH)=Q^(TmG&H`Zjb$JWsIef zZ#ikKPBTA8H}RS>B+f}TCk@f-gG)SP#9k;&`FAl+bm7lNPyHO>lNWl8qn~&~b=B>I86JxD>?or-k5r@kDaolWa~Z zr8`CrXZ^>8SM>WiKLd~PPe@)428cIAPg5R}%}JYNws9Tnj4rHk=sC5OZTPKD2L}Vh zTPH8{8p-CQp}M5>nSoK(->#j#WyNw`e;o$oIE6RMMg z0pbnSRhN%sbJ99_$*-w+al(>RTCP`yeM={KdDZjTwsdeXK)fkzBiWoZg&jUJu}50y zdSnxRmHuArm*L~5P#z8jh&NPMT|Sb{N$cdLyr%DO(S)&(>lmk|v_E&*91IX|iZYRG zPMX4wCYgwv2*DXA57s-!yf(za0P!}}TgY{i%}GP_#O9$rPB|D0;qA*lY_a~d<>z34 zcx`fGX(XGI#_9~nzuG4)1ZSK)nD3}IIp{l$0p)6K{^DaB2Lr_GBbUoVvNg4ocKQ>99b1*=>lKM#&$>yY#H*xCR)1nSXlGnyIw&Y-dcvE12 zWOLFKb{H~SA49sZJf^WF2Lr@w)SGpD$mJo~oRq7B%iq-)(uK>hj4e4BAYN|W`tXx% zPU<5!n5W}0qzjj7edtDn&y|;Cb5fVASh{+)_nZq8Inakb=iy+0 zcw_6_mY-yEQk$G;+TqSE%qeofUY!jJm$#zJnrXYq!2t25@CC`{q|$caS#}@r2&}@+ zq2iK*0pgX$0_2fwPAX|fiN}ZUuWOrfyH>vQxN}?54>`!eo-(#z7AH6c+EO_gSw_Sj+{Hn|73Yw&FeW!SB6}zTw8Srn6c9xu0RL5X5T^X}*s4 z`xO>h-@VSgp2lcjv6fVPAE21C_v&3r^vgwisMZyyzInLlE#~c+VpPZAG;ba*2AfI- zjF$cUe6RYB-*F4$QH%$b9yKOZb7knCFxXU6({*?N@vRuY0XM6kTDPz81WeWa3cRiJ zUAmInet0?7^0NB--)we)j^9^?(lKnlr#jK-|1Qe1C@*OAgMxmaNmtVGS7})DpBLoW zY`4g;rXN)FQqYS2|B5{O&?Y|^%D+weIgv{RD>(-%dZB>mEAg{Z0nsb#k*O#F(Mu)Pd4Zm zSM-Aox-zuVyFrGbC4Ixp!qAegc?~(0=Sn*M*Z+vVX+8>2@}KL>>Ug)JpBVIu4fF$p z|GtXfAgh8EdW~YCV6}9kxF~SJkN-CR>glE%lp_i`=bJ***={ZUWQ+e|!SA9UZ1LY$ z@Vn?+?6Z3ceg}Qaoywu$chR@psT>M^27Ly8{LH^P`nLOLvppq%OFuW2s`E$HPlEn{ zl5?Vd=ARTD8`2$^!qs_Kbc-nyY4U*80|!=WcX&Rr*n|7XMi04v&n@yH$3}lNfX;3A zT>S4_>;%n4x3u#GuZ3RQFSz;_7k#;HXKlZ>JlM)m-*295@z?ju=Ue<`zrXG11$?=5 z(YGDFEcjjYEk{@5nJvdvonMEZCwfZ}Gn_ zYFW{Z0E)&er4Y%>t~)=bHsstn_XeiU~<&&xWCx zAyxDZLot^lx^B=#jef2fx~tK3gBBWHGiYOeq$!5lm0rz58}qN_TJi1%|5`D~YdNbD z8}q@Hf= inTimeoutSecFloat: + raise Exception(f"Orchestrator.AgentActivityItemReturnGet !ВНИМАНИЕ! ПРЕВЫШЕНО ВРЕМЯ ОЖИДАНИЯ ОТВЕТА") # Return the result return inGSettings["AgentActivityReturnDict"][inGUIDStr]["Return"] else: - raise Exception(f"__Orchestrator__.AgentActivityItemReturnGet !ATTENTION! Use this function only after Orchestrator initialization! Before orchestrator init exception will be raised.") + raise Exception(f"Orchestrator.AgentActivityItemReturnGet !ВНИМАНИЕ! ФУНКЦИЯ МОЖЕТ БЫТЬ ЗАПУЩЕНА ТОЛЬКО ПОСЛЕ ИНИЦИАЛИЗАЦИИ!") def AgentOSCMD(inHostNameStr, inUserStr, inCMDStr, inRunAsyncBool=True, inSendOutputToOrchestratorLogsBool=True, inCMDEncodingStr="cp1251", inGSettings=None, inCaptureBool=True): """L+,W+: Отправка команды командной строки на сессию, где работает pyOpenRPA.Agent. Результат выполнения команды можно выводить в лог оркестратора. @@ -533,6 +542,7 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inLogger = None): # New call if inRunAsyncBool: lThread = threading.Thread(target=_CMDRunAndListenLogs, kwargs={"inCMDStr":inCMDStr, "inLogger":inLogger}) + lThread.setName("OSCMD_ACTIVITY") lThread.start() lResultStr="Список ActivityList был запущен в асинхронном режиме - захватить содержимое невозможно" else: @@ -592,6 +602,7 @@ def OrchestratorThreadStart(inDef, *inArgList, **inArgDict): :return: threading.Thread экземпляр """ lDefThread = threading.Thread(target=inDef,args=inArgList,kwargs=inArgDict) + lDefThread.setName(f"ORCHESTRATOR_THREAD_{str(inDef).upper()}") lDefThread.start() return lDefThread @@ -638,7 +649,7 @@ def OrchestratorRerunAsAdmin(): else: print(f"Уже запущено с правами администратора!") -def OrchestratorPySearchInit(inGlobPatternStr, inDefStr = None, inDefArgNameGSettingsStr = None, inAsyncInitBool = False): +def OrchestratorPySearchInit(inGlobPatternStr, inDefStr = None, inDefArgNameGSettingsStr = None, inAsyncInitBool = False, inPackageLevelInt = 0): """L+,W+: Выполнить поиск и инициализацию пользовательских .py файлов в Оркестраторе (например панелей управления роботов) Добавляет инициализированный модуль в пространство sys.modules как imported (имя модуля = имя файла без расширения). @@ -668,20 +679,32 @@ def OrchestratorPySearchInit(inGlobPatternStr, inDefStr = None, inDefArgNameGSet :param inDefStr: ОПЦИОНАЛЬНО Строковое наименование функции. Преимущественно для обратной совместимости :param inDefArgNameGSettingsStr: ОПЦИОНАЛЬНО Наименование аргумента, в который требуется передать GSettings (если необходимо) :param inAsyncInitBool: ОПЦИОНАЛЬНО True - Инициализация py модулей в отдельных параллельных потоках - псевдопараллельное выполнение. False - последовательная инициализация + :param inPackageLevelInt: ОПЦИОНАЛЬНО Уровень вложенности модуля в пакет. По умолчанию 0 (не является модулем пакета) :return: Сведения об инициализированных модулях в структуре: { "ModuleNameStr":{"PyPathStr": "", "Module": ...}, ...} """ inGlobPatternStr = CrossOS.PathStr(inGlobPatternStr) + # # # # # # # # - def __execute__(inResultDict, inPyPathItemStr, inDefStr = None, inDefArgNameGSettingsStr = None): + def __execute__(inResultDict, inPyPathItemStr, inDefStr = None, inDefArgNameGSettingsStr = None, inPackageLevelInt=0): try: lPyPathItemStr = inPyPathItemStr + CrossOS.PathSplitList(inPathStr=lPyPathItemStr)[-1*inPackageLevelInt-1:-1] lModuleNameStr = os.path.basename(lPyPathItemStr)[0:-3] - lTechSpecification = importlib.util.spec_from_file_location(lModuleNameStr, lPyPathItemStr) - lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification) - sys.modules[lModuleNameStr] = lTechModuleFromSpec # Add initialized module in sys - python will not init this module enought - lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec) + if inPackageLevelInt==0: + lTechSpecification = importlib.util.spec_from_file_location(lModuleNameStr, lPyPathItemStr) + lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification) + sys.modules[lModuleNameStr] = lTechModuleFromSpec # Add initialized module in sys - python will not init this module enought + lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec) + else: + lPrePackagePathStr=CrossOS.PathStr("\\".join(CrossOS.PathSplitList(inPathStr=lPyPathItemStr)[:-1-inPackageLevelInt])) + lPackageNameStr=".".join(CrossOS.PathSplitList(inPathStr=lPyPathItemStr)[-inPackageLevelInt-1:-1]) + lModuleNameStr=os.path.basename(lPyPathItemStr)[0:-3] + sys.path.insert(0,lPrePackagePathStr) + lTechSpecification = importlib.import_module(f".{lModuleNameStr}", lPackageNameStr) + lTechModuleFromSpec=sys.modules[f"{lPackageNameStr}.{lModuleNameStr}"] + lModuleNameStr= f"{lPackageNameStr}.{lModuleNameStr}" lItemDict = {"ModuleNameStr": lModuleNameStr, "PyPathStr": lPyPathItemStr, "Module": lTechModuleFromSpec} - if lL: lL.info(f"Модуль .py {lModuleNameStr} был успешно инициализирован") + if lL: lL.info(f"Модуль .py {lModuleNameStr} был успешно инициализирован. Путь к файлу: {lPyPathItemStr}") inResultDict[lModuleNameStr]=lItemDict # Backward compatibility to call def with gsettings when init if inDefStr is not None and inDefStr != "": @@ -691,7 +714,7 @@ def OrchestratorPySearchInit(inGlobPatternStr, inDefStr = None, inDefArgNameGSet lArgDict = {inDefArgNameGSettingsStr:GSettingsGet()} lDef(**lArgDict) except Exception as e: - if lL: lL.exception(f"Exception when init the .py file {os.path.abspath(lPyPathItemStr)}") + if lL: lL.exception(f"Ошибка при инициализации .py файла: {os.path.abspath(lPyPathItemStr)}") # # # # # # # # lResultDict = {} @@ -703,11 +726,12 @@ def OrchestratorPySearchInit(inGlobPatternStr, inDefStr = None, inDefArgNameGSet # ASYNC EXECUTION lThreadInit = threading.Thread(target=__execute__,kwargs={ "inResultDict":lResultDict, "inPyPathItemStr": lPyPathItemStr, - "inDefStr": inDefStr, "inDefArgNameGSettingsStr": inDefArgNameGSettingsStr}, daemon=True) + "inDefStr": inDefStr, "inDefArgNameGSettingsStr": inDefArgNameGSettingsStr, "inPackageLevelInt":inPackageLevelInt}, daemon=True) + lThreadInit.setName("PY_SEARCH_MODULE_INIT") lThreadInit.start() else: # SYNC EXECUTION - __execute__(inResultDict=lResultDict, inPyPathItemStr=lPyPathItemStr, inDefStr = inDefStr, inDefArgNameGSettingsStr = inDefArgNameGSettingsStr) + __execute__(inResultDict=lResultDict, inPyPathItemStr=lPyPathItemStr, inDefStr = inDefStr, inDefArgNameGSettingsStr = inDefArgNameGSettingsStr, inPackageLevelInt=inPackageLevelInt) return lResultDict def OrchestratorSessionSave(inGSettings=None): @@ -785,7 +809,7 @@ def OrchestratorSessionRestore(inGSettings=None): inGSettings["StorageDict"] = {} with open('_SessionLast_StorageDict.pickle', 'rb') as lFile: lStorageDictDumpDict = pickle.load(lFile) - Server.__ComplexDictMerge2to1Overwrite__(in1Dict=inGSettings["StorageDict"], + Dictionary.MergeNoException(in1Dict=inGSettings["StorageDict"], in2Dict=lStorageDictDumpDict) # Merge dict 2 into dict 1 if lL: lL.warning(f"Словарь StorageDict был восстановлен из прошлой сессии оркестратора") os.remove("_SessionLast_StorageDict.pickle") # remove the temp file @@ -797,13 +821,13 @@ def OrchestratorSessionRestore(inGSettings=None): inGSettings["ManagersProcessDict"] = {} with open('_SessionLast_GSettings.pickle', 'rb') as lFile: lStorageDictDumpDict = pickle.load(lFile) - Server.__ComplexDictMerge2to1Overwrite__(in1Dict=inGSettings, + Dictionary.MergeNoException(in1Dict=inGSettings, in2Dict=lStorageDictDumpDict) # Merge dict 2 into dict 1 if lL: lL.warning(f"Словарь GSettings был восстановлен из прошлой сессии оркестратора") os.remove("_SessionLast_GSettings.pickle") # remove the temp file def UACKeyListCheck(inRequest, inRoleKeyList) -> bool: - """L+,W+: Проверить права доступа для пользователя запроса по списку ключей до права. + """L+,W+: [ПРЕКРАЩЕНИЕ ПОДДЕРЖКИ В 1.3.2, см. WebUserUACCheck] Проверить права доступа для пользователя запроса по списку ключей до права. .. code-block:: python @@ -818,8 +842,8 @@ def UACKeyListCheck(inRequest, inRoleKeyList) -> bool: return inRequest.UACClientCheck(inRoleKeyList=inRoleKeyList) def UACUserDictGet(inRequest) -> dict: - """L+,W+: Вернуть UAC (User Access Control) словарь доступов для пользователя, который отправил запрос. Пустой словарь - супердоступ (доступ ко всему) - + """L+,W+: [ПРЕКРАЩЕНИЕ ПОДДЕРЖКИ В 1.3.2, см. WebUserUACHierarchyGet] Вернуть UAC (User Access Control) словарь доступов для пользователя, который отправил запрос. Пустой словарь - супердоступ (доступ ко всему) + :param inRequest: Экземпляр request (from http.server import BaseHTTPRequestHandler) :return: Словарь доступов пользователя. Пустой словарь - супердоступ (доступ ко всему) """ @@ -855,7 +879,7 @@ def UACUpdate(inADLoginStr, inADStr="", inADIsDefaultBool=True, inURLList=None, # Check RoleHierarchyAllowedDict in gSettings for the old role hierarchy - include in result. if lUserTurple in inGSettings["ServerDict"]["AccessUsers"]["RuleDomainUserDict"] and "RoleHierarchyAllowedDict" in inGSettings["ServerDict"]["AccessUsers"]["RuleDomainUserDict"][lUserTurple]: lRoleHierarchyAllowedOLDDict = inGSettings["ServerDict"]["AccessUsers"]["RuleDomainUserDict"][lUserTurple]["RoleHierarchyAllowedDict"] - Server.__ComplexDictMerge2to1__(in1Dict=inRoleHierarchyAllowedDict, in2Dict=lRoleHierarchyAllowedOLDDict) # Merge dict 2 into dict 1 + Dictionary.Merge(in1Dict=inRoleHierarchyAllowedDict, in2Dict=lRoleHierarchyAllowedOLDDict) # Merge dict 2 into dict 1 # Create Access item lRuleDomainUserDict = { @@ -916,6 +940,7 @@ def WebURLConnectDef(inMethodStr, inURLStr, inMatchTypeStr, inDef, inContentType "UACBool": inUACBool } inGSettings["ServerDict"]["URLList"].append(lURLItemDict) + Server.BCURLUpdate() def WebURLConnectFolder(inMethodStr, inURLStr, inMatchTypeStr, inFolderPathStr, inGSettings = None, inUACBool = None, inUseCacheBool= False): @@ -946,6 +971,7 @@ def WebURLConnectFolder(inMethodStr, inURLStr, inMatchTypeStr, inFolderPathStr, "UseCacheBool": inUseCacheBool } inGSettings["ServerDict"]["URLList"].append(lURLItemDict) + Server.BCURLUpdate() def WebURLConnectFile(inMethodStr, inURLStr, inMatchTypeStr, inFilePathStr, inContentTypeStr=None, inGSettings = None, inUACBool = None, inUseCacheBool = False): @@ -974,12 +1000,13 @@ def WebURLConnectFile(inMethodStr, inURLStr, inMatchTypeStr, inFilePathStr, inCo "UseCacheBool": inUseCacheBool } inGSettings["ServerDict"]["URLList"].append(lURLItemDict) + Server.BCURLUpdate() -def WebListenCreate(inServerKeyStr="Default", inAddressStr="", inPortInt=80, inCertFilePEMPathStr=None, inKeyFilePathStr=None, inGSettings = None): +def WebListenCreate(inServerKeyStr="Default", inAddressStr="0.0.0.0", inPortInt=1024, inCertFilePEMPathStr=None, inKeyFilePathStr=None, inGSettings = None): """L+,W+: Настроить веб-сервер Оркестратора. - :param inAddressStr: IP адрес для прослушивания. Если "", то прослушивать запросы со всех сетевых карт. Если "127.0.0.1", то слушать запросы только с той ОС, на которой работает Оркестратор - :param inPortInt: Номер порта для прослушивания. Если HTTP - 80; Если HTTPS - 443. По умолчанию 80. Допускается установка других портов + :param inAddressStr: IP адрес для прослушивания. Если "0.0.0.0", то прослушивать запросы со всех сетевых карт. Если "127.0.0.1", то слушать запросы только с той ОС, на которой работает Оркестратор + :param inPortInt: Номер порта для прослушивания. Если HTTP - 80; Если HTTPS - 443. По умолчанию 1024 (Связано с тем, что в линукс можно устанавливать порты выше 1000). Допускается установка других портов :param inCertFilePEMPathStr: Путь файлу сертификата, сгенерированного в .pem (base64) формате. Обязателен при использовании защищенного HTTPS/SSL соединения. :param inKeyFilePathStr: Путь к файлу закрытого ключа в base64 формате :param inGSettings: Глобальный словарь настроек Оркестратора (синглтон) @@ -1015,8 +1042,18 @@ def WebCPUpdate(inCPKeyStr, inHTMLRenderDef=None, inJSONGeneratorDef=None, inJSI if inJSInitGeneratorDef is not None: lCPManager.mBackwardCompatibilityJSDef = inJSInitGeneratorDef -def WebAuditMessageCreate(inRequest=None, inOperationCodeStr="-", inMessageStr="-"): - """L+,W+: Создание сообщения ИТ аудита с такими сведениями как (Домен, IP, логин и тд.). Данная функция особенно актуальна в том случае, если требуется реализовать дополнительные меры контроля ИТ системы. +def WebRequestHostGet(inRequest) -> str: + """L+,W+: Получить наименование хоста, с которого поступил запрос + + :param inRequest: Экземпляр fastapi.Request, по умолчанию None + :type inRequest: fastapi.Request, опционально + :return: Наименование хоста + :rtype: str + """ + return inRequest.client.host + +def WebAuditMessageCreate(inAuthTokenStr:str = None, inHostStr:str=None, inOperationCodeStr:str="-", inMessageStr:str="-"): + """L+,W+: [ИЗМЕНЕНИЕ В 1.3.1] Создание сообщения ИТ аудита с такими сведениями как (Домен, IP, логин и тд.). Данная функция особенно актуальна в том случае, если требуется реализовать дополнительные меры контроля ИТ системы. .. code-block:: python @@ -1031,47 +1068,44 @@ def WebAuditMessageCreate(inRequest=None, inOperationCodeStr="-", inMessageStr=" # Логгирование сообщения lLogger.info(lWebAuditMessageStr) - :param inRequest: Экземпляр HTTP request. Опционален, если сообщение фиксируется из под потока, который был инициирован запросом пользователя + :param inAuthTokenStr: Токен авторизации пользователя / бота, по умолчанию None (не установлен) + :type inAuthTokenStr: str, опционально + :param inHostStr: IP адрес хоста пользователя / бота, по умолчанию None (не установлен) + :type inHostStr: str, опционально :param inOperationCodeStr: Код операции, который принят в компании в соответствии с регламентными процедурами :param inMessageStr: Дополнительное сообщение, которое необходимо отправить в сообщение об ИТ аудите :return: Формат сообщения: "WebAudit :: DOMAIN\\USER@101.121.123.12 :: operation code :: message" """ try: - if inRequest is None: inRequest = WebRequestGet() - lClientIPStr = inRequest.client_address[0] - lUserDict = WebUserInfoGet(inRequest=inRequest) - lDomainUpperStr = lUserDict["DomainUpperStr"] - lUserLoginStr = lUserDict["UserNameUpperStr"] - lResultStr = f"ВебАудит :: {lDomainUpperStr}\\\\{lUserLoginStr}@{lClientIPStr} :: {inOperationCodeStr} :: {inMessageStr}" + lDomainUpperStr = WebUserDomainGet(inAuthTokenStr=inAuthTokenStr).upper() + lUserLoginStr = WebUserLoginGet(inAuthTokenStr=inAuthTokenStr).upper() + lResultStr = f"ВебАудит :: {lDomainUpperStr}\\\\{lUserLoginStr}@{inHostStr} :: {inOperationCodeStr} :: {inMessageStr}" except Exception as e: print(str(e)) # Has no logger - must be dead alg branch lResultStr = inMessageStr return lResultStr def WebRequestParseBodyBytes(inRequest=None): - """L+,W+: Извлечь данные в байт виде из тела (body) HTTP запроса. + """L+,W+: [ПРЕКРАЩЕНИЕ ПОДДЕРЖКИ В 1.3.1, см. FASTAPI] Извлечь данные в байт виде из тела (body) HTTP запроса. :param inRequest: Экземпляр HTTP request. Опционален, если сообщение фиксируется из под потока, который был инициирован запросом пользователя :return: Строка байт b'' или None (если тело запроса было пустым) """ if inRequest is None: inRequest = WebRequestGet() lBodyBytes=None - if inRequest.headers.get('Content-Length') is not None: - lInputByteArrayLength = int(inRequest.headers.get('Content-Length')) - lBodyBytes = inRequest.rfile.read(lInputByteArrayLength) - return lBodyBytes + return inRequest.body.encode("utf8") def WebRequestParseBodyStr(inRequest=None): - """L+,W+: Извлечь данные в виде строки из тела (body) HTTP запроса. + """L+,W+: [ПРЕКРАЩЕНИЕ ПОДДЕРЖКИ В 1.3.1, см. FASTAPI] Извлечь данные в виде строки из тела (body) HTTP запроса. :param inRequest: Экземпляр HTTP request. Опционален, если сообщение фиксируется из под потока, который был инициирован запросом пользователя :return: Текстовая строка '' или None (если тело запроса было пустым) """ if inRequest is None: inRequest = WebRequestGet() - return WebRequestParseBodyBytes(inRequest=inRequest).decode('utf-8') + return inRequest.body def WebRequestParseBodyJSON(inRequest=None): - """L+,W+: Извлечь из тела (body) запроса HTTP JSON данные и преобразовать в Dict / List структуры языка Python. + """L+,W+: [ПРЕКРАЩЕНИЕ ПОДДЕРЖКИ В 1.3.1, см. FASTAPI] Извлечь из тела (body) запроса HTTP JSON данные и преобразовать в Dict / List структуры языка Python. :param inRequest: Экземпляр HTTP request. Опционален, если сообщение фиксируется из под потока, который был инициирован запросом пользователя :return: Словарь (dict), список (list) или None (если тело запроса было пустым) @@ -1080,7 +1114,7 @@ def WebRequestParseBodyJSON(inRequest=None): return json.loads(WebRequestParseBodyStr(inRequest=inRequest)) def WebRequestParsePath(inRequest=None): - """L+,W+: Извлечь декодированный URL путь из HTTP запроса пользователя в формате строки. + """L+,W+: [ПРЕКРАЩЕНИЕ ПОДДЕРЖКИ В 1.3.1, см. FASTAPI] Извлечь декодированный URL путь из HTTP запроса пользователя в формате строки. :param inRequest: Экземпляр HTTP request. Опционален, если сообщение фиксируется из под потока, который был инициирован запросом пользователя :return: str, пример: /pyOpenRPA/Debugging/DefHelper @@ -1089,7 +1123,7 @@ def WebRequestParsePath(inRequest=None): return urllib.parse.unquote(inRequest.path) def WebRequestParseFile(inRequest=None): - """L+,W+: Извлечь файл (наименование + содержимое в виде строки байт b'') из HTTP запроса пользователя. + """L+,W+: [ПРЕКРАЩЕНИЕ ПОДДЕРЖКИ В 1.3.1, см. FASTAPI] Извлечь файл (наименование + содержимое в виде строки байт b'') из HTTP запроса пользователя. :param inRequest: Экземпляр HTTP request. Опционален, если сообщение фиксируется из под потока, который был инициирован запросом пользователя :return: Кортеж формата (FileNameStr, FileBodyBytes) or (None, None), если файл не был обнаружен @@ -1115,7 +1149,7 @@ def WebRequestParseFile(inRequest=None): return lResultTurple def WebRequestResponseSend(inResponeStr, inRequest=None, inContentTypeStr: str = None, inHeadersDict: dict = None): - """L+,W+: Установить ответ на HTTP запрос пользователя. + """L+,W+: [ПРЕКРАЩЕНИЕ ПОДДЕРЖКИ В 1.3.1, см. FASTAPI] Установить ответ на HTTP запрос пользователя. :param inResponeStr: Тело ответа (строка) :param inRequest: Экземпляр HTTP request. Опционален, если сообщение фиксируется из под потока, который был инициирован запросом пользователя @@ -1131,46 +1165,104 @@ def WebRequestResponseSend(inResponeStr, inRequest=None, inContentTypeStr: str = def WebRequestGet(): - """L+,W+: Вернуть экземпляр HTTP запроса, если функция вызвана в потоке, который был порожден для отработки HTTP запроса пользователя. + """L+,W+: [ПРЕКРАЩЕНИЕ ПОДДЕРЖКИ В 1.3.2] Вернуть экземпляр HTTP запроса, если функция вызвана в потоке, который был порожден для отработки HTTP запроса пользователя. """ lCurrentThread = threading.current_thread() if hasattr(lCurrentThread, "request"): return lCurrentThread.request +def WebUserLoginGet(inAuthTokenStr: str=None) -> str: + """L+,W+: Получить логин авторизованного пользователя. Если авторизация не производилась - вернуть None + + :param inAuthTokenStr: Токен авторизации пользователя / бота, по умолчанию None (не установлен) + :type inAuthTokenStr: str, опционально + :return: Логин пользователя + :rtype: str + """ + if inAuthTokenStr is None: return None + inGS = GSettingsGet() # Get the global settings + return inGS.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(inAuthTokenStr, {}).get("User", None) + +def WebUserDomainGet(inAuthTokenStr: str=None) -> str: + """L+,W+: Получить домен авторизованного пользователя. Если авторизация не производилась - вернуть None + + :param inAuthTokenStr: Токен авторизации пользователя / бота, по умолчанию None (не установлен) + :type inAuthTokenStr: str, опционально + :return: Домен пользователя + :rtype: str + """ + if inAuthTokenStr is None: return None + inGS = GSettingsGet() # Get the global settings + return inGS.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(inAuthTokenStr, {}).get("Domain", None) + + def WebUserInfoGet(inRequest=None): - """L+,W+: Информация о пользователе, который отправил HTTP запрос. + """L+,W+: [ПРЕКРАЩЕНИЕ ПОДДЕРЖКИ В 1.3.2, см. WebUserLoginGet, WebUserDomainGet] Информация о пользователе, который отправил HTTP запрос. :param inRequest: Экземпляр HTTP request. Опционален, если сообщение фиксируется из под потока, который был инициирован запросом пользователя :return: Сведения в формате {"DomainUpperStr": "PYOPENRPA", "UserNameUpperStr": "IVAN.MASLOV"} """ if inRequest is None: inRequest = WebRequestGet() - lDomainUpperStr = inRequest.OpenRPA["Domain"].upper() - lUserUpperStr = inRequest.OpenRPA["User"].upper() - return {"DomainUpperStr": lDomainUpperStr, "UserNameUpperStr": lUserUpperStr} + try: + lDomainUpperStr = inRequest.OpenRPA["Domain"].upper() + lUserUpperStr = inRequest.OpenRPA["User"].upper() + return {"DomainUpperStr": lDomainUpperStr, "UserNameUpperStr": lUserUpperStr} + except Exception as e: + return {"DomainUpperStr": None, "UserNameUpperStr": None} -def WebUserIsSuperToken(inRequest = None, inGSettings = None): - """L+,W+: Проверить, авторизован ли HTTP запрос с помощью супер токена (токен, который не истекает). +def WebUserIsSuperToken(inAuthTokenStr: str=None): + """L+,W+: [ИЗМЕНЕНИЕ В 1.3.1] Проверить, авторизован ли HTTP запрос с помощью супер токена (токен, который не истекает). - :param inRequest: Экземпляр HTTP request. Опционален, если сообщение фиксируется из под потока, который был инициирован запросом пользователя - :param inGSettings: Глобальный словарь настроек Оркестратора (синглтон) - :return: True - является супертокеном; False - не является супертокеном + :param inAuthTokenStr: Токен авторизации пользователя / бота, по умолчанию None (не установлен) + :type inAuthTokenStr: str, опционально + :return: True - является супертокеном; False - не является супертокеном; None - авторизация не производилась """ - if inRequest is None: inRequest = WebRequestGet() - inGSettings = GSettingsGet(inGSettings=inGSettings) # Set the global settings + if inAuthTokenStr is None: return None + inGSettings = GSettingsGet() # Get the global settings lIsSuperTokenBool = False # Get Flag is supertoken (True|False) - lIsSuperTokenBool = inGSettings.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(inRequest.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False) + lIsSuperTokenBool = inGSettings.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(inAuthTokenStr, {}).get("FlagDoNotExpire", False) return lIsSuperTokenBool -def WebUserUACHierarchyGet(inRequest = None): - """L+,W+: Вернуть словарь доступа UAC в отношении пользователя, который выполнил HTTP запрос inRequest +def WebUserUACHierarchyGet(inAuthTokenStr: str=None) -> dict: + """L+,W+: [ИЗМЕНЕНИЕ В 1.3.1] Вернуть словарь доступа UAC в отношении пользователя, который выполнил HTTP запрос inRequest - :param inRequest: Экземпляр HTTP request. Опционален, если сообщение фиксируется из под потока, который был инициирован запросом пользователя + :param inAuthTokenStr: Токен авторизации пользователя / бота, по умолчанию None (не установлен) + :type inAuthTokenStr: str, опционально :return: UAC словарь доступа или {}, что означает полный доступ """ - if inRequest is None: inRequest = WebRequestGet() - return inRequest.UserRoleHierarchyGet() + lDomainUpperStr = WebUserDomainGet(inAuthTokenStr=inAuthTokenStr).upper() + lUserUpperStr = WebUserLoginGet(inAuthTokenStr=inAuthTokenStr).upper() + if lUserUpperStr is None: return {} + else: return GSettingsGet().get("ServerDict", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lDomainUpperStr, lUserUpperStr), {}).get("RoleHierarchyAllowedDict", {}) +def WebUserUACCheck(inAuthTokenStr:str=None, inKeyList:list=None) -> bool: + """L+,W+: Проверить UAC доступ списка ключей для пользователя + + :param inAuthTokenStr: Токен авторизации пользователя / бота, по умолчанию None (не установлен) + :type inAuthTokenStr: str, опционально + :return: True - доступ имеется, False - доступа нет + :rtype: bool + """ + if inAuthTokenStr is None: return True # Если авторизации не происходило - супердоступ + lResult = True # Init flag + lRoleHierarchyDict = WebUserUACHierarchyGet(inAuthTokenStr=inAuthTokenStr) # get the Hierarchy + # Try to get value from key list + lKeyValue = lRoleHierarchyDict # Init the base + for lItem in inKeyList: + if type(lKeyValue) is dict: + if lItem in lKeyValue: # Has key + lKeyValue = lKeyValue[lItem] # Get the value and go to the next loop iteration + else: # Else branch - true or false + if len(lKeyValue)>0: # False - if Dict has some elements + lResult = False # Set the False Flag + else: + lResult = True # Set the True flag + break # Stop the loop + else: # Has element with no detalization - return True + lResult = True # Set the flag + break # Close the loop + return lResult # Return the result ## GSettings defs @@ -1193,7 +1285,7 @@ def GSettingsGet(inGSettings=None): global GSettings # identify the global variable # Merge dictionaries if some new dictionary has come if inGSettings is not None and GSettings is not inGSettings: - GSettings = Server.__ComplexDictMerge2to1Overwrite__(in1Dict = inGSettings, in2Dict = GSettings) + GSettings = Dictionary.MergeNoException(in1Dict = inGSettings, in2Dict = GSettings) return GSettings # Return the result def GSettingsKeyListValueSet(inValue, inKeyList=None, inGSettings = None): @@ -1962,6 +2054,7 @@ def ProcessDefIntervalCall(inDef, inIntervalSecFloat, inIntervalAsyncBool=False, lThread2 = threading.Thread(target=inDef, args=inDefArgList, kwargs=inDefArgDict) + lThread2.setName("INTERVAL_CALL_DEF") lThread2.start() except Exception as e: if inLogger: inLogger.exception( @@ -1976,6 +2069,7 @@ def ProcessDefIntervalCall(inDef, inIntervalSecFloat, inIntervalAsyncBool=False, "inIntervalAsyncBool": inIntervalAsyncBool, "inDefArgList": inDefArgList, "inDefArgDict": inDefArgDict, "inLogger": inLogger, "inDefArgGSettingsNameStr":inDefArgGSettingsNameStr , "inDefArgLoggerNameStr":inDefArgLoggerNameStr}) + lThread.setName("INTERVAL_CALL_EXECUTOR") lThread.start() else: __Execute__(inGSettings=inGSettings, inDef=inDef, inIntervalSecFloat=inIntervalSecFloat, inIntervalAsyncBool=inIntervalAsyncBool, @@ -2710,8 +2804,6 @@ def Orchestrator(inGSettings=None, inDumpRestoreBool = True, inRunAsAdministrato Processor.gSettingsDict = gSettingsDict Timer.gSettingsDict = gSettingsDict Timer.Processor.gSettingsDict = gSettingsDict - Server.gSettingsDict = gSettingsDict - Server.ProcessorOld.gSettingsDict = gSettingsDict # Backward compatibility #Backward compatibility - restore in Orc def if old def if inDumpRestoreBool == True: @@ -2732,7 +2824,7 @@ def Orchestrator(inGSettings=None, inDumpRestoreBool = True, inRunAsAdministrato # 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:") + if lL: lL.exception(f"Ошибка при инициализации .py файлов в оркестраторе '{lModuleFilePathItem}'") # Turn on backward compatibility BackwardCompatibility.Update(inGSettings= gSettingsDict) @@ -2752,18 +2844,10 @@ def Orchestrator(inGSettings=None, inDumpRestoreBool = True, inRunAsAdministrato #Инициализация настроечных параметров gSettingsDict["ServerDict"]["WorkingDirectoryPathStr"] = os.getcwd() # Set working directory in g settings - #Инициализация сервера (инициализация всех интерфейсов) - lListenDict = gSettingsDict.get("ServerDict",{}).get("ListenDict",{}) - for lItemKeyStr in lListenDict: - lItemDict = lListenDict[lItemKeyStr] - lThreadServer = Server.RobotDaemonServer(lItemKeyStr, gSettingsDict) - lThreadServer.start() - gSettingsDict["ServerDict"]["ServerThread"] = lThreadServer - lItemDict["ServerInstance"] = lThreadServer - # Init the RobotScreenActive in another thread lRobotScreenActiveThread = threading.Thread(target= Monitor.CheckScreen) lRobotScreenActiveThread.daemon = True # Run the thread in daemon mode. + lRobotScreenActiveThread.setName("SCREEN_ACTIVE") lRobotScreenActiveThread.start() # Start the thread execution. if lL: lL.info("Модуль активного рабочего стола инициализирован") #Logging @@ -2771,12 +2855,14 @@ def Orchestrator(inGSettings=None, inDumpRestoreBool = True, inRunAsAdministrato lRobotRDPThreadControlDict = {"ThreadExecuteBool":True} # inThreadControlDict = {"ThreadExecuteBool":True} lRobotRDPActiveThread = threading.Thread(target= RobotRDPActive.RobotRDPActive, kwargs={"inGSettings":gSettingsDict, "inThreadControlDict":lRobotRDPThreadControlDict}) lRobotRDPActiveThread.daemon = True # Run the thread in daemon mode. + lRobotRDPActiveThread.setName("RDP_CONNECT") lRobotRDPActiveThread.start() # Start the thread execution. if lL: lL.info("Модуль подключения по РДП инициализированн") #Logging # Init autocleaner in another thread lAutocleanerThread = threading.Thread(target= GSettingsAutocleaner, kwargs={"inGSettings":gSettingsDict}) lAutocleanerThread.daemon = True # Run the thread in daemon mode. + lAutocleanerThread.setName("AUTOCLEANER") lAutocleanerThread.start() # Start the thread execution. if lL: lL.info("Модуль автоочистки инициализирован") #Logging @@ -2791,24 +2877,28 @@ def Orchestrator(inGSettings=None, inDumpRestoreBool = True, inRunAsAdministrato # Processor thread lProcessorThread = threading.Thread(target= Processor.ProcessorRunSync, kwargs={"inGSettings":gSettingsDict, "inRobotRDPThreadControlDict":lRobotRDPThreadControlDict}) lProcessorThread.daemon = True # Run the thread in daemon mode. + lProcessorThread.setName("PROCESSOR") lProcessorThread.start() # Start the thread execution. if lL: lL.info("Модуль процессора инициализирован") #Logging # Processor monitor thread lProcessorMonitorThread = threading.Thread(target= Processor.ProcessorMonitorRunSync, kwargs={"inGSettings":gSettingsDict}) lProcessorMonitorThread.daemon = True # Run the thread in daemon mode. + lProcessorMonitorThread.setName("PROCESSOR_MONITOR") lProcessorMonitorThread.start() # Start the thread execution. if lL: lL.info("Модуль контроля процессора инициализирован") #Logging # Scheduler loop lSchedulerThread = threading.Thread(target= __deprecated_orchestrator_loop__) lSchedulerThread.daemon = True # Run the thread in daemon mode. + lSchedulerThread.setName("SCHEDULER_OLD") lSchedulerThread.start() # Start the thread execution. if lL: lL.info("Модуль расписания (старая версия) инициализирован") #Logging # Schedule (new) loop lScheduleThread = threading.Thread(target= __schedule_loop__) lScheduleThread.daemon = True # Run the thread in daemon mode. + lScheduleThread.setName("SCHEDULER_NEW") lScheduleThread.start() # Start the thread execution. if lL: lL.info("Модуль расписания (новая версия) инициализирован") #Logging @@ -2817,11 +2907,22 @@ def Orchestrator(inGSettings=None, inDumpRestoreBool = True, inRunAsAdministrato lProcess = inGSettings["ManagersProcessDict"][lProcessKeyTuple] lProcess.StatusCheckIntervalRestore() lThread = threading.Thread(target= lProcess.StatusRestore) + lThread.setName("MANAGER_PROCESS_RESTORE") lThread.start() + # Init debug thread (run if "init_dubug" file exists) Debugger.LiveDebugCheckThread(inGSettings=GSettingsGet()) + #Инициализация сервера (инициализация всех интерфейсов) + Server.InitFastAPI() + lListenDict = gSettingsDict.get("ServerDict",{}).get("ListenDict",{}) + for lItemKeyStr in lListenDict: + lItemDict = lListenDict[lItemKeyStr] + lItemDict["ServerInstance"]=Server.app + Server.InitUvicorn(inHostStr=lItemDict["AddressStr"], inPortInt=lItemDict["PortInt"], inSSLCertPathStr=lItemDict["CertFilePEMPathStr"], inSSLKeyPathStr=lItemDict["KeyFilePathStr"], inSSLPasswordStr=None) + + def __schedule_loop__(): while True: schedule.run_pending() @@ -2889,6 +2990,7 @@ def __deprecated_orchestrator_loop__(): lThread = threading.Thread(target=Processor.ActivityListExecute, kwargs={"inGSettings": inGSettings, "inActivityList": lItem["ActivityList"]}) + lThread.setName("SCHEDULER_OLD_ACTIVITY") lThread.start() lIterationLastDateTime = datetime.datetime.now() # Set the new datetime for the new processor activity except Exception as e: diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.min.css b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.min.css index 5e8b6e8d..3408fb51 100755 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.min.css +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/Semantic-UI-CSS-master/semantic.min.css @@ -8,7 +8,7 @@ * http://opensource.org/licenses/MIT * */ -@import url(/3rdParty/Google/LatoItalic.css); +@import url(/orpa/resources/Web/Google/LatoItalic.css); /*@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic&subset=latin);*//*! * # Semantic UI 2.4.0 - Reset * http://github.com/semantic-org/semantic-ui/ diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/footer.xhtml b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/footer.xhtml index 13d498d5..52d682df 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/footer.xhtml +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/footer.xhtml @@ -14,6 +14,7 @@

Интересный факт

Портал pyOpenRPA сделан на оркестраторе pyOpenRPA за 7 дней - присоединяйся к сильной стороне!

+

pyOpenRPA - роботы помогут!

Контактная информация

@@ -30,6 +31,8 @@
- - - - - - - - \ No newline at end of file + + + + + + + + \ No newline at end of file diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/header.xhtml b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/header.xhtml index 45e1d7c0..bf933b79 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/header.xhtml +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/header.xhtml @@ -1,21 +1,21 @@ - - + + - - - - - + + + + + - - - - - - - - + + + + + + + +
@@ -82,12 +82,13 @@
- +

{{title}} -

+
{{version}}
+

{{subtitle}} diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/orc.js b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/orc.js index 86af9523..22774de9 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/orc.js +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/orc.js @@ -101,22 +101,6 @@ $(document).ready(function() { /////Controller JS module ////////////////////////// mGlobal.Controller={}; - - mGlobal.Controller.CMDRunText=function(inCMDText) { - ///Подготовить конфигурацию - lData = [ - {"Type":"CMDStart", "Command": inCMDText} - ] - ///Обнулить таблицу - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3){}, - dataType: "text" - }); - } mGlobal.Controller.CMDRun=function() { ///Обнулить таблицу lCMDCode=$(".openrpa-controller-cmd-run-input")[0].value @@ -132,37 +116,7 @@ $(document).ready(function() { ] $.ajax({ type: "POST", - url: '/pyOpenRPA/ActivityListExecute', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///Отправить запрос на формирование таблицы - //lHTMLCode=console.log("CMDRun result: "+lResponseJSON[0].result) - }, - dataType: "text" - }); - } - mGlobal.Controller.CMDRunGUILogout=function() { - ///Обнулить таблицу - lCMDCode="for /f \"skip=1 tokens=2\" %s in ('query user %USERNAME%') do (tscon \\dest:console)" - //lCMDCode = lCMDCode.replace(/\\n/g, "\\n") - // .replace(/\\'/g, "\\'") - // .replace(/\\"/g, '\\"') - // .replace(/\\&/g, "\\&") - // .replace(/\\r/g, "\\r") - // .replace(/\\t/g, "\\t") - // .replace(/\\b/g, "\\b") - // .replace(/\\f/g, "\\f") - // .replace('"', "\\\""); - ///Подготовить конфигурацию - lData = [ - {"Type":"CMDStart", "Command": lCMDCode } - ] - $.ajax({ - type: "POST", - url: 'Utils/Processor', + url: '/orpa/api/activity-list-execute', data: JSON.stringify(lData), success: function(lData,l2,l3) @@ -174,51 +128,33 @@ $(document).ready(function() { dataType: "text" }); } + ///Restart PC mGlobal.Controller.PCRestart = function () { mGlobal.Controller.OrchestratorSessionSave() mGlobal.Controller.CMDRunText("shutdown -r") } - ///Orchestrator save session - mGlobal.Controller.OrchestratorSessionSave=function() { - ///Подготовить конфигурацию - lData = [ - {"Type":"OrchestratorSessionSave"} - ] - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - }, - dataType: "text" - }); + mGlobal.Controller.OrchestratorGITPullRestart = function() { + mGlobal.Controller.OrchestratorSessionSave() //Save current RDP list session + mGlobal.Controller.CMDRunText("timeout 3 & taskkill /f /im OpenRPA_Orchestrator.exe & timeout 2 & cd "+mGlobal.WorkingDirectoryPathStr+" & git reset --hard & git pull & pyOpenRPA.Orchestrator_x64_administrator_startup.cmd"); } - ///Перезагрузить Orchestrator mGlobal.Controller.OrchestratorRestart=function() { ///Подготовить конфигурацию lData = [ - {"Type":"OrchestratorRestart"} + { + "Def":"OrchestratorRestart", // def link or def alias (look gSettings["Processor"]["AliasDefDict"]) + "ArgList":[], // Args list + "ArgDict":{}, // Args dictionary + "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList) + "ArgLogger": null // Name of GSettings attribute: str (ArgDict) or index (for ArgList) + } ] $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - }, - dataType: "text" + type: "POST", + url: '/orpa/api/activity-list-execute', + data: JSON.stringify(lData) }); } - mGlobal.Controller.OrchestratorGITPullRestart = function() { - mGlobal.Controller.OrchestratorSessionSave() //Save current RDP list session - mGlobal.Controller.CMDRunText("timeout 3 & taskkill /f /im OpenRPA_Orchestrator.exe & timeout 2 & cd "+mGlobal.WorkingDirectoryPathStr+" & git reset --hard & git pull & pyOpenRPA.Orchestrator_x64_administrator_startup.cmd"); - } ////////////////////////// /////Monitor JS module ////////////////////////// @@ -228,12 +164,12 @@ $(document).ready(function() { return inPrefix+Math.round(Math.random()*1000)+"-"+Math.round(Math.random()*10000)+"-"+Math.round(Math.random()*1000) } //inHostURI: http://localhost:8081 - mGlobal.Monitor.ScreenshotModal.Show=function(inHostURI=" ") { + mGlobal.Monitor.ScreenshotModal.Show=function(inHostURI="") { $('.ui.modal.daemon-screenshot').modal({'onHide':function (inElement) {mGlobal.Monitor.ScreenshotModal.Close();} }).modal('show'); //Функция обновления картинки lScreenshotUpdate=function() { - lScreenshotSrc=inHostURI+"/GetScreenshot?"+mGlobal.Monitor.GenerateUniqueID() + lScreenshotSrc=inHostURI+"/orpa/client/screenshot-get?"+mGlobal.Monitor.GenerateUniqueID() $(".daemon-screenshot img").attr('src', lScreenshotSrc); } @@ -244,26 +180,7 @@ $(document).ready(function() { } ///Monitor mGlobal.Monitor.DaemonList={} - mGlobal.Monitor.DaemonList.fRefreshTable=function() { - ///Загрузка данных - $.ajax({ - type: "GET", - url: 'Monitor/JSONDaemonListGet', - data: '', - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///Сформировать HTML код новой таблицы - lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-monitor-table-general",lResponseJSON) - ///Очистить дерево - //mGlobal.ElementTree.fClear(); - ///Прогрузить новую таблицу - $(".openrpa-monitor").html(lHTMLCode) - }, - dataType: "text" - }); - } + //////////////////////////////// ///////Control panel /////////////////////////////// @@ -380,7 +297,7 @@ $(document).ready(function() { lData = [inActivityItem] $.ajax({ type: "POST", - url: '/pyOpenRPA/ActivityListExecute', + url: '/orpa/api/activity-list-execute', data: JSON.stringify(lData), success: function(lData,l2,l3) @@ -405,7 +322,7 @@ $(document).ready(function() { lData = inActivityList $.ajax({ type: "POST", - url: '/pyOpenRPA/ActivityListExecute', + url: '/orpa/api/activity-list-execute', data: JSON.stringify(lData), success: function(lData,l2,l3) @@ -430,7 +347,7 @@ $(document).ready(function() { lData = inActivityList $.ajax({ type: "POST", - url: '/pyOpenRPA/ProcessorQueueAdd', + url: '/orpa/api/processor-queue-add', data: JSON.stringify(lData), success: function(lData,l2,l3) @@ -448,7 +365,7 @@ $(document).ready(function() { $.ajax({ type: "GET", headers: {}, - url: 'pyOpenRPA/ServerJSInit', + url: '/orpa/client/server-js-init', data: mGlobal.pyOpenRPA.ServerDataHashStr, async: false, success: function(lJSText) { @@ -512,7 +429,7 @@ $(document).ready(function() { $.ajax({ type: "POST", headers: {}, - url: 'pyOpenRPA/ServerData', + url: '/orpa/client/server-data', data: mGlobal.pyOpenRPA.ServerDataHashStr, success: function(lData,l2,l3) { try { @@ -587,7 +504,7 @@ $(document).ready(function() { $.ajax({ type: "POST", headers: {}, - url: 'pyOpenRPA/ServerLog', + url: '/orpa/client/server-log', data: mGlobal.pyOpenRPA.ServerLogListHashStr, success: function(lData,l2,l3) { try { @@ -624,90 +541,7 @@ $(document).ready(function() { ///Processor functions /////////////////////////////// mGlobal.Processor = {} - mGlobal.Processor.ServerValueAppend = function(inKeyList,inValue) { - lData = [ - { - "Type":"GlobalDictKeyListValueAppend", - "KeyList": inKeyList, - "Value": inValue - } - ] - ///Обнулить таблицу - $('.ui.modal.basic .content').html(""); - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///TODO Show error if exist error - }, - dataType: "text" - }); - } - mGlobal.Processor.ServerValueSet = function(inKeyList,inValue) { - lData = [ - { - "Type":"GlobalDictKeyListValueSet", - "KeyList": inKeyList, - "Value": inValue - } - ] - ///Обнулить таблицу - $('.ui.modal.basic .content').html(""); - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///TODO Show error if exist error - }, - dataType: "text" - }); - } - mGlobal.Processor.ServerValueOperatorPlus = function(inKeyList,inValue) { - lData = [ - { - "Type":"GlobalDictKeyListValueOperator+", - "KeyList": inKeyList, - "Value": inValue - } - ] - ///Обнулить таблицу - $('.ui.modal.basic .content').html(""); - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///TODO Show error if exist error - }, - dataType: "text" - }); - } - mGlobal.Processor.Send = function(inData) { - lData = inData - $.ajax({ - type: "POST", - url: 'Utils/Processor', - data: JSON.stringify(lData), - success: - function(lData,l2,l3) - { - var lResponseJSON=JSON.parse(lData) - ///TODO Show error if exist error - }, - dataType: "text" - }); - } + mGlobal.Server= {} mGlobal.Server.JSONGet=function(inMethod, inURL, inDataJSON, inCallback) { @@ -904,7 +738,7 @@ $(document).ready(function() { lValueStr = inEvent $.ajax({ type: "GET", - url: '/pyOpenRPA/Debugging/HelperDefAutofill/'+lValueStr, + url: '/orpa/api/helper-def-autofill/'+lValueStr, data: null, success: function(lData,l2,l3) @@ -957,7 +791,7 @@ $(document).ready(function() { lData = [lActivityItem] $.ajax({ type: "POST", - url: '/pyOpenRPA/ActivityListExecute', + url: '/orpa/api/activity-list-execute', data: JSON.stringify(lData), success: function(lData,l2,l3) @@ -984,9 +818,15 @@ $(document).ready(function() { .dropdown({ apiSettings: { // this url parses query server side and returns filtered results - url: '/pyOpenRPA/Debugging/HelperDefList/{query}' + url: '/orpa/api/helper-def-list/{query}' }, onChange: lDropdownOnChange }) ; + mGlobal.pyOpenRPA.RDPListTest= function() { + lResponseJSON={"HandlebarsList":[{"SessionKeyStr":"test"},{"SessionKeyStr":"test2"}]}; + /// !RDP List ! Сформировать HTML код новой таблицы - список RDP + lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-robotrdpactive-control-panel",lResponseJSON) + $(".openrpa-robotrdpactive-control-panel").html(lHTMLCode) + } }); \ No newline at end of file diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/orc.xhtml b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/orc.xhtml index 22b64a04..d25cd713 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/orc.xhtml +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Resources/Web/orpa/orc.xhtml @@ -22,16 +22,16 @@ Оркестратор pyOpenRPA - - + + - - - + + + @@ -234,27 +233,28 @@
{{#HandlebarsList}}
+
+
Session key: {{{SessionKeyStr}}}
+ {{{SessionHexStr}}} +
-
Переподключить
+
Переподключить
{{#if IsIgnoredBool}} -
Игнорировать
+
Игнорировать
{{else}} -
Игнорировать
+
Игнорировать
{{/if}}
{{#if IsFullScreenBool}} -
Полный экран
+
Полный экран
{{else}} -
Полный экран
+
Полный экран
{{/if}}
-
-
Session key: {{{SessionKeyStr}}}
- {{{SessionHexStr}}} -
+
{{/HandlebarsList}}
@@ -423,13 +423,13 @@

-
[документация]def UIOSelectorList(inUIOSelectorStr, inUIO=None) -> list: """L+,W+: Получить список UIO объектов по UIO селектору. @@ -386,7 +387,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - lUIOList = UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr) + lUIOList = UIWeb.UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr) UIWeb.BrowserClose() :param inUIOSelectorStr: XPATH или CSS селектор UI объекта на web странице. Подсказки по CSS: https://devhints.io/css Подсказки по XPath: https://devhints.io/xpath @@ -421,7 +422,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - lUIO = UIOSelectorFirst(inUIOSelectorStr = lUIOSelectorStr) + lUIO = UIWeb.UIOSelectorFirst(inUIOSelectorStr = lUIOSelectorStr) UIWeb.BrowserClose() :param inUIOSelectorStr: XPATH или CSS селектор UI объекта на web странице. Подсказки по CSS: https://devhints.io/css Подсказки по XPath: https://devhints.io/xpath @@ -446,7 +447,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - lUIO = UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] + lUIO = UIWeb.UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] lTextStr = UIWeb.UIOTextGet(inUIO=lUIO) UIWeb.BrowserClose() @@ -467,7 +468,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - lUIO = UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] + lUIO = UIWeb.UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] UIWeb.UIOAttributeGet(inUIO=lUIO, inAttributeStr = "href") UIWeb.BrowserClose() @@ -490,7 +491,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - lUIO = UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] + lUIO = UIWeb.UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] UIWeb.UIOAttributeStyleGet(inUIO=lUIO, inAttributeStr = "href") UIWeb.BrowserClose() @@ -513,7 +514,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - lUIO = UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] + lUIO = UIWeb.UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] UIWeb.UIOAttributeSet(inUIO=lUIO, inAttributeStr = "href", inValue = "https://mail.ru") UIWeb.BrowserClose() @@ -538,7 +539,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - lUIO = UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] + lUIO = UIWeb.UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] UIWeb.UIOAttributeRemove(lUIO, "href") UIWeb.BrowserClose() @@ -561,7 +562,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - lUIO = UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] + lUIO = UIWeb.UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] UIWeb.UIOAttributeStyleSet(inUIO=lUIO, inAttributeStr = "color", inValue = "grey") UIWeb.BrowserClose() @@ -586,7 +587,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - lUIO = UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] + lUIO = UIWeb.UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] UIWeb.UIOAttributeStyleRemove(lUIO, "color") UIWeb.BrowserClose() @@ -609,7 +610,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - lUIO = UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] + lUIO = UIWeb.UIOSelectorList(inUIOSelectorStr = lUIOSelectorStr)[0] UIOClick(inUIO = lUIO) UIWeb.BrowserClose() @@ -628,7 +629,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - UIOSelectorHighlight(inUIOSelectorStr = lUIOSelectorStr) + UIWeb.UIOSelectorHighlight(inUIOSelectorStr = lUIOSelectorStr) UIWeb.BrowserClose() :param inUIOSelectorStr: XPATH или CSS селектор UI элемента на web странице. Подсказки по CSS: https://devhints.io/css Подсказки по XPath: https://devhints.io/xpath @@ -684,7 +685,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - UIOSelectorClick(inUIOSelectorStr = lUIOSelectorStr) + UIWeb.UIOSelectorClick(inUIOSelectorStr = lUIOSelectorStr) UIWeb.BrowserClose() :param inUIOSelectorStr: XPATH или CSS селектор UI элемента на web странице. Подсказки по CSS: https://devhints.io/css Подсказки по XPath: https://devhints.io/xpath @@ -702,7 +703,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - lAppearUIOList = UIOSelectorWaitAppear(inUIOSelectorStr = lUIOSelectorStr) + lAppearUIOList = UIWeb.UIOSelectorWaitAppear(inUIOSelectorStr = lUIOSelectorStr) UIWeb.BrowserClose() :param inUIOSelectorStr: XPATH или CSS селектор UI элемента на web странице. Подсказки по CSS: https://devhints.io/css Подсказки по XPath: https://devhints.io/xpath @@ -734,7 +735,7 @@ UIWeb.BrowserChromeStart() UIWeb.PageOpen("https://mail.ru") lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - UIOSelectorWaitDisappear(inUIOSelectorStr = lUIOSelectorStr) + UIWeb.UIOSelectorWaitDisappear(inUIOSelectorStr = lUIOSelectorStr) UIWeb.BrowserClose() :param inUIOSelectorStr: XPATH или CSS селектор UI элемента на web странице. Подсказки по CSS: https://devhints.io/css Подсказки по XPath: https://devhints.io/xpath @@ -766,7 +767,7 @@ from pyOpenRPA.Robot import UIWeb lUIOSelectorStr = "#grid > div.grid-middle > div.grid__main-col.svelte-2y66pa > div.grid_newscol.grid_newscol__more-pulse.svelte-1yvqfic > div.grid__ccol.svelte-1yvqfic > ul > li:nth-child(5) > div > a" lUIOSelectorStr = "//*[@id=\"grid\"]/div[2]/div[2]/div[3]/div[1]/ul/li[5]/div/a" - lResultStr = UIOSelectorDetect(inUIOSelectorStr = lUIOSelectorStr) + lResultStr = UIWeb.UIOSelectorDetect(inUIOSelectorStr = lUIOSelectorStr) :param inUIOSelectorStr: XPATH или CSS селектор UI объекта на web странице. Подсказки по CSS: https://devhints.io/css Подсказки по XPath: https://devhints.io/xpath :type inUIOSelectorStr: str diff --git a/Wiki/RUS_Guide/html/_modules/pyOpenRPA/Tools/Debugger.html b/Wiki/RUS_Guide/html/_modules/pyOpenRPA/Tools/Debugger.html index abf585b5..25a417a7 100755 --- a/Wiki/RUS_Guide/html/_modules/pyOpenRPA/Tools/Debugger.html +++ b/Wiki/RUS_Guide/html/_modules/pyOpenRPA/Tools/Debugger.html @@ -26,7 +26,7 @@ - pyOpenRPA.Tools.Debugger — документация pyOpenRPA v1.3.0 v1.3.0 + pyOpenRPA.Tools.Debugger — документация pyOpenRPA v1.3.1 v1.3.1 @@ -73,7 +73,7 @@ - pyOpenRPA v1.3.0 + pyOpenRPA v1.3.1 @@ -119,7 +119,8 @@
  • 5. Функции Clipboard
  • 6. Функции Mouse
  • 7. Функции Screen
  • -
  • 8. Как использовать?
  • +
  • 8. Функции Audio
  • +
  • 9. Как использовать?
  • МОДУЛЬ СТУДИЯ

      @@ -156,7 +157,7 @@ @@ -229,6 +230,7 @@ global gKWARGS gKWARGS = inKWARGS lThread = threading.Thread(target=LiveDebugCheckLoop) + lThread.setName("DEBUG_LIVE") lThread.start()
    diff --git a/Wiki/RUS_Guide/html/_modules/pyOpenRPA/Tools/StopSafe.html b/Wiki/RUS_Guide/html/_modules/pyOpenRPA/Tools/StopSafe.html index 58e7cc07..f7511c06 100755 --- a/Wiki/RUS_Guide/html/_modules/pyOpenRPA/Tools/StopSafe.html +++ b/Wiki/RUS_Guide/html/_modules/pyOpenRPA/Tools/StopSafe.html @@ -26,7 +26,7 @@ - pyOpenRPA.Tools.StopSafe — документация pyOpenRPA v1.3.0 v1.3.0 + pyOpenRPA.Tools.StopSafe — документация pyOpenRPA v1.3.1 v1.3.1 @@ -73,7 +73,7 @@ - pyOpenRPA v1.3.0 + pyOpenRPA v1.3.1 @@ -119,7 +119,8 @@
  • 5. Функции Clipboard
  • 6. Функции Mouse
  • 7. Функции Screen
  • -
  • 8. Как использовать?
  • +
  • 8. Функции Audio
  • +
  • 9. Как использовать?
  • МОДУЛЬ СТУДИЯ

      @@ -156,7 +157,7 @@ diff --git a/Wiki/RUS_Guide/html/_sources/Orchestrator/01_Orchestrator.rst.txt b/Wiki/RUS_Guide/html/_sources/Orchestrator/01_Orchestrator.rst.txt index 09d195ee..5e99c531 100755 --- a/Wiki/RUS_Guide/html/_sources/Orchestrator/01_Orchestrator.rst.txt +++ b/Wiki/RUS_Guide/html/_sources/Orchestrator/01_Orchestrator.rst.txt @@ -21,6 +21,10 @@ - Ролевая модель разграничения доступа - Функциональность очередей для координации роботов +В качестве основы для web сервера используется один из самых прогрессивных и производительных фреймворков от FastAPI. + +Пример использования FastAPI см. в GIT/Orchestrator/config.py + ************************************************************************ Концепция единого глобального словаря настроек (GSettings) ************************************************************************ diff --git a/Wiki/RUS_Guide/html/_sources/Orchestrator/04_HowToUse.rst.txt b/Wiki/RUS_Guide/html/_sources/Orchestrator/04_HowToUse.rst.txt index c92f98b6..55d371a5 100755 --- a/Wiki/RUS_Guide/html/_sources/Orchestrator/04_HowToUse.rst.txt +++ b/Wiki/RUS_Guide/html/_sources/Orchestrator/04_HowToUse.rst.txt @@ -10,7 +10,7 @@ **Для этого достаточно (выбрать одно):** -- запустить .cmd файл, расположенный в папке pyOpenRPA по адресу: Orchestrator\pyOpenRPA.Orchestrator_x64.cmd +- запустить демо-стэнд: запустить .cmd файл, расположенный в папке pyOpenRPA по адресу: Orchestrator\start.cmd (для Windows) и start.sh (для Linux). Далее перейти в браузер по адресу: http://localhost:1024 - в свой .py скрипт добавить следующий код (см. ниже) .. code-block:: python @@ -23,12 +23,12 @@ ****************************** -Параметры настройки +Конфигурационный файл config.py ****************************** Также вы можете выполнить более тонкую настройку параметров Оркестратора. Ниже пример такой настройки: -.. include:: ../../../Orchestrator/OrchestratorSettings.py +.. include:: ../../../Orchestrator/config.py :literal: diff --git a/Wiki/RUS_Guide/html/_sources/Robot/01_Robot.rst.txt b/Wiki/RUS_Guide/html/_sources/Robot/01_Robot.rst.txt index dddf9006..0332b664 100755 --- a/Wiki/RUS_Guide/html/_sources/Robot/01_Robot.rst.txt +++ b/Wiki/RUS_Guide/html/_sources/Robot/01_Robot.rst.txt @@ -25,6 +25,10 @@ - Mouse: инструменты взаимодействия с мышью. Перейти к описанию функций: :ref:`module.robot.mouse` - Screen: инструменты взаимодействия с эраном рабочего стола. Перейти к описанию функций: :ref:`module.robot.screen` + +- **Уровень доступа к звуковым каналам передачи данных (микрофон, динамик)** + + - Audio: инструменты взаимодействия с аудио. Перейти к описанию функций: :ref:`module.robot.audio` Дорогие коллеги! diff --git a/Wiki/RUS_Guide/html/_sources/Robot/08_audio.rst.txt b/Wiki/RUS_Guide/html/_sources/Robot/08_audio.rst.txt new file mode 100644 index 00000000..2b12c79a --- /dev/null +++ b/Wiki/RUS_Guide/html/_sources/Robot/08_audio.rst.txt @@ -0,0 +1,55 @@ +.. _module.robot.audio: + +#################################### +8. Функции Audio +#################################### + +!ВНИМАНИЕ! ДЛЯ КОРРЕКТНОЙ РАБОТЫ МОДУЛЯ ТРЕБУЕТСЯ КОМПОНЕНТ ffmpeg.exe (Для Windows x64 можно найти в pyOpenRPA\Resources\WAudio). На него должен указывать один из путей в переменной окружения PATH. Или ffmpeg.exe должен быть расположен в рабочей директории (working directory) + +!ВНИМАНИЕ! ДЛЯ ВИРТУАЛЬНОЙ МАШИНЫ МОЖЕТ ПОТРЕБОВАТЬСЯ КОМПОНЕНТ ВИРТУАЛЬНОГО АУДИОДРАЙВЕРА (Для Windows x64 можно найти в pyOpenRPA\Resources\WAudio\VBCABLE_Driver_Pack43.zip) + +************************ +Общее +************************ + +Дорогие коллеги! + +Мы знаем, что с pyOpenRPA вы сможете существенно улучшить качество вашего бизнеса. Платформа роботизации pyOpenRPA - это разработка, которая дает возможность делать виртуальных сотрудников (программных роботов RPA) выгодными, начиная от эффекта всего в **10 тыс. руб.** И управлять ими будете только Вы! + +Если у вас останутся вопросы, то вы всегда можете обратиться в центр поддержки клиентов pyOpenRPA. Контакты: :ref:`3.-Copyrights-&-Contacts` + +pyOpenRPA - роботы помогут! + +************************ +Класс Recorder +************************ + +Экземпляр класса pyOpenRPA.Robot.Audio.Recorder, который обеспечивает захват звука (с микрофона или из приложений) и сохраняет в виде аудиофайла (множества аудиофайлов) + + +************************************************** +Описание функций +************************************************** + +Описание каждой функции начинается с обозначения L-,W+, что означает, что функция не поддерживается в ОС Linux (L) и поддерживается в Windows (W) + +.. automodule:: pyOpenRPA.Robot.Audio + :members: + :autosummary: + + +.. autoclass:: pyOpenRPA.Robot.Audio.Recorder + :members: + :autosummary: + + +****************************** +Быстрая навигация +****************************** + +- `Сообщество pyOpenRPA (telegram) `_ +- `Сообщество pyOpenRPA (tenchat) `_ +- `Сообщество pyOpenRPA (вконтакте) `_ +- `Презентация pyOpenRPA `_ +- `Портал pyOpenRPA `_ +- `Репозиторий pyOpenRPA `_ \ No newline at end of file diff --git a/Wiki/RUS_Guide/html/_sources/Robot/08_HowToUse.rst.txt b/Wiki/RUS_Guide/html/_sources/Robot/09_HowToUse.rst.txt old mode 100755 new mode 100644 similarity index 81% rename from Wiki/RUS_Guide/html/_sources/Robot/08_HowToUse.rst.txt rename to Wiki/RUS_Guide/html/_sources/Robot/09_HowToUse.rst.txt index 5c23544e..231d207d --- a/Wiki/RUS_Guide/html/_sources/Robot/08_HowToUse.rst.txt +++ b/Wiki/RUS_Guide/html/_sources/Robot/09_HowToUse.rst.txt @@ -1,9 +1,25 @@ #################################### -8. Как использовать? +9. Как использовать? #################################### Модуль РОБОТ - это ключевое звено, которое отвечает за продуктивную роботизацию процесса. Данный модуль не имеет графический или консольный интерфейс - он подключается в качестве библиотеки в проект робота, что позволяет выполнять операции максимально быстро. А также позволяет с легкостью интегрировать робота в другие проекты. + +************************************************** +Быстрый запуск (Quickstart) +************************************************** + +Платформа pyOpenRPA содержит инструменты быстрого прототипирования роботов. Вы можете провести серию экспериментов роботизации без развертывания полноценной инфраструктуры робота - в рамках одного уже преднастроенного файла. + +Для быстрого запуска робота необходимо: + +- Открыть Jupyter-notebooks: GIT\Tools\Jupyter-notebooks\start.cmd (для Windows) или GIT\Tools\Jupyter-notebooks\start.sh (для Linux). Откроется окно консоли, в которой будет отображен адрес для входа на веб страницу Jupyter-notebooks. +- В web окне Jupyter-notebooks открыть Quickstart\Robot.ipynb + +Быстрая инфраструктура для прототипирования робота готова! + +В файле Robot.ipynb содержится вся необходимая информация, которая позволит решить любую поставленную задачу. + ************************************************** Как запустить скрипт робота? ************************************************** @@ -12,6 +28,7 @@ - Скрипт Python (файл .py) - Скрипт в Студии pyOpenRPA +- Скрипт в Jupyter (см. раздел "Быстрый запуск") Скрипт Python (файл .py) diff --git a/Wiki/RUS_Guide/html/_sources/Studio/02_HowToUse.rst.txt b/Wiki/RUS_Guide/html/_sources/Studio/02_HowToUse.rst.txt index fb0c6678..39026dcf 100755 --- a/Wiki/RUS_Guide/html/_sources/Studio/02_HowToUse.rst.txt +++ b/Wiki/RUS_Guide/html/_sources/Studio/02_HowToUse.rst.txt @@ -22,7 +22,7 @@ Как запустить? ************************ -- Запустить файл Studio\pyOpenRPA.Studio_x64.cmd +- Запустить файл Studio\start.cmd - Ожидать текст в окне консоли: "running server". Браузер, установленный по умолчанию откроется автоматически - **!ВНИМАНИЕ!** Студия поддерживает все версии браузеров, кроме Internet Explorer. diff --git a/Wiki/RUS_Guide/html/_static/documentation_options.js b/Wiki/RUS_Guide/html/_static/documentation_options.js index 3925cade..a0c9447f 100755 --- a/Wiki/RUS_Guide/html/_static/documentation_options.js +++ b/Wiki/RUS_Guide/html/_static/documentation_options.js @@ -1,6 +1,6 @@ var DOCUMENTATION_OPTIONS = { URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: 'v1.3.0', + VERSION: 'v1.3.1', LANGUAGE: 'ru', COLLAPSE_INDEX: false, BUILDER: 'html', diff --git a/Wiki/RUS_Guide/html/genindex.html b/Wiki/RUS_Guide/html/genindex.html index c2dab04b..cbb6ec5f 100755 --- a/Wiki/RUS_Guide/html/genindex.html +++ b/Wiki/RUS_Guide/html/genindex.html @@ -26,7 +26,7 @@ - Алфавитный указатель — документация pyOpenRPA v1.3.0 v1.3.0 + Алфавитный указатель — документация pyOpenRPA v1.3.1 v1.3.1 @@ -73,7 +73,7 @@ - pyOpenRPA v1.3.0 + pyOpenRPA v1.3.1 @@ -119,7 +119,8 @@
    • 5. Функции Clipboard
    • 6. Функции Mouse
    • 7. Функции Screen
    • -
    • 8. Как использовать?
    • +
    • 8. Функции Audio
    • +
    • 9. Как использовать?

    МОДУЛЬ СТУДИЯ

    - + - +

    МОДУЛЬ СТУДИЯ

    Технические требования

    -

    ВЕРСИЯ v1.3.0

    +

    ВЕРСИЯ v1.3.1

    ! ВНИМАНИЕ ! Требуется пакет KB2999226 если используется windows Vista/7/8/8.1/Server 2008/Server 2012 https://support.microsoft.com/ru-ru/help/2999226 Использование компонента OpenCV: ОС Windows 7/8/8/10 (Windows Server только с 2016) В июле 2022 будет выпущен релиз pyOpenRPA, который будет работать на ОС семейства Linux (Ubuntu / Astra)

    @@ -455,9 +456,17 @@
  • Быстрая навигация
  • -
  • 8. Как использовать? @@ -507,8 +516,8 @@
  • 4. Как использовать?
  • 5. Права доступа пользователей UAC -

    .. v1.3.0 replace:: v1.3.0

    +

    .. v1.3.1 replace:: v1.3.1

  • diff --git a/Wiki/RUS_Guide/html/objects.inv b/Wiki/RUS_Guide/html/objects.inv index 1439d53095edda470597a3a1b9b5554f51d45edf..f47eeacc9c3af91ac64176acef0219c6ce132a9b 100755 GIT binary patch delta 2711 zcmV;I3TX9$7pfSLHvut`I9h+pONS!mh>2u!2-0evFc7d3QG-}!cOi*+@}<+8Jx!lF zop#zxXZitbkJZR>Y<~st8};l0AOUc}D;5uNM1cGI@8#?{XBSJ1#_bXEx}AEheu_L+ zGYs*6!_Y?KuZGz6U8LR6#I?_E+%%f#gw_UZ=zbL5tNu!>Rz`V@T3Z=!95y-W#P=-b zU{BkTv6eyZIWF3DJd=!@lPduq14HyRlT869e*vP5m<$t;NPf)BhUBdkCdEQr9i21}TUvb_+6(}bQyM^M{3CLv#tMp_Gh2?QfrSg~|T6S|w ze`=*(g7GX%ZBz=D(2WQ96rY@^Q&=P6Dn|8d9Wmy3r&PJXw`j~8^1yU`q|lK`^-66V z6czV7u20KT)fF{SU91B#K{gn@W4iPKBF@QJk&ePy+t#~ih#BfMx^UGbOqq&8dg7yU zftKg6Bhyjek`}GoL&qyYhc^k?%7ws+6i*RR<;s#DJ7XQ0@R>JExmXtw-;;*|9{~W9 zrvgKN%m(0gl-XUk*@;{mB)nbUQ!Ro$4_T_4(sZa*ijde};PJzKrlhIM&CojkqeGap=*sZ$Z6Q% zPax~IeT2|MSIt71&nNQ~b@4G~3U}<2GODtFlzzPtZH_bs$a<(sL-$9B^zcLEDGYp| zqnJ(+X*!m&!8k(4b>DW_AhA#TvM^xo_L<;-343&;a zDB8vLSUg-QOY9rHeZMR%oslx6c+yjbPRC>e#X4O?N7$q4o=JgJzk3j6*?>?lqH=V9 z5-QlW5mBhq@@#a`7?|Fvy4LW3gNLT$DRe$uq~)Dp)e>};1gO-3HHh-=f?Pmdx-`?+ zcM##*%j3=_XHMyl}}` z5H5avwJnYZjD&|O0(W3ejkpk;Qy31$l=*a1Si^Nj$JivcY_{JqtoZiQ89xQpa_9OS zZZSvSiUX_E+;-hI9!7VUHY>)|n)uw4S0_tbh}p*szTLpXW5+WEr!XcXZr$L2|27I` zJ}7|Jq6Kx|w|n0id-uOK8tsE{5dtexa|_mfyH^;i+t-cYZ_7bTA&Z10Y5gYk?T-q8 zNKPAUgdxt{ihm8xA@(Vf&GNg(kl$K5#RY)-ow@u>23kUBV*l7hTXFKI%8GzPe1>{> zD})Y-mh0|g;{1R;X1WEy9w5Sh9BWHdp4~1j4s}4`IwET(pBq%%TWTjEqPB}K>Yg>g zqzhk^W%W|-VxV-_YXeS`nCIJ5Ab@wU4awTLg?dcmD9+Bt_Ah4mFDa3fnBA`)8m9|jF+7m zSANs*9Xq_e)SFL1wO!MC2w9cRhyk9jherqK47q%TX7pQazK)bvc1~@v46u#1zUwfL zpH|BAu4_U&M|FLKEawCwD+low7;q70t{YuarvtrH2pl+jEu(=w@Xp2dIk0r(B1@dE zv#2q1YQ`?ct}>0Ot5YHaf5y*$u8pqm8T=7r(He#bOG>J5+{2bn_np&$3;z{gb1==u zz;W$(21|ZuScr&G@LbNp&p!ey24CRp&2nSwRMzu~d_L!$Ko}e}xh$Hew zbl9kP5pghHOx)eESnMgWP`OMGk`6^uQGeaXWN5n14?-^fiXut4QjT1IkBpn3V-ZFAU5YI6f zBhE22EBA5J1}y%Q!!uMP7)~#+YC0Rcg|<}yi*7Jy7SQSiyF05xM0C&nz1=pr@J$$# z7zZhTFJstb^7ml)Dg!5c03Id~C#m^__44z9INjvUX1ps#&@tQ|O>fAMJrMzw)QW5Op4<(p&7v=~jP zNWT$^-2}0J23M2c2baM+P`aA@2^ppZKr>!&loq@l4&IA)Jp~o`I41?R^%nknqXD22Il>)7{E?JP z-;>w~RewIm2_G+2(&yeJoaBi(?TdN0!f(cuFQrpt?q&wnced|qX^3YimuuvGP(Dn9-#q-NC- z!6SYc1<{pj_;(<`;tpr>hskpdy6+Wtx7;t zNF6S@a11BDw=ysq`DxApmAneaJc3cNvPtyP@wh4`Zgl`FM6$BbPtXxpBBz<_6ye1+ zFn<_6beFtE+@L3a(Slzl&mdG?Rc2!!*>Q!z%?90qkqQzMcG73G>dH8NIsIj9xFC!sWkTSbRPFH#d8U6mT*b zvE!LH)mZx0)@1prC_kTmNTtA|IwO(gE`Jb|BujGP8BON2WED82ai+3BKQH@{R$@k6 zGdGH=M?{t|iyhNCE%^O|C{qo~<)smxhN()fiAj^1SSKvJs+C1jQMj5j zfV_~D)=HFKB_B#eixt916r=wa*E|tU#7ZT6(MlzZv}s;=Z5HUl5L$s~ytHej`BbV0 Rc_fb3Qm;iY_&>7KOZWW!HM#%* delta 2523 zcmV<12_*Ka7=jm&Hvuq_I9h*9UOE&hTTCRALy%VUgaLt-h#JDOyGu#TlP{Ux>}mSc z>9o^kI@1qed#py5WBV%r->7F7011E#Ua@$HBNEu(e=ldxIlEYJG-;2J*X`76^%LZ= znqi3l8-_NTe0_@Tv5T}Dn)vRE8#j$6I;OQDJ9R$^uT_7gRV$-BMy(pHHx8SebUgMf z=3r0Tk+GIR?l~^nbv%tKCbxc~a+@a_kdVo#4G|m3VE~AP2$OYr$qGN`S9oH>Skz2bO zH9ldIl6BiIM`-T?+CLNBKUipgi4yr&oS=cQUzfM3dLs+FJTPQ4#V=9#=4AHWi zTYpk3^%9I{S!$zFu!L?rz$f_lSe?Qe30E-MSRm7v3$gly$PU=_tDh^TU9$&a0hj!gK>8>U>Wi^$lMg#sS| z2$Q7(Lw~}C;C7VRUANhZTpJ|3-La=y1bZH`R5zvRP^%OnvA@9Mj}5DE2PujTGCgIx z8Z$A4>xY@hA%<)V!mBF3H&aTw@YeAI%)r_`SWlKEtGt0=f@+PvhfYT>I68%{HO?TX zVS_(`tlRbxLXTWE3uQi^%oEhb1I!fe*e7LFWq&FCdL!B#X$+C|NR@^@9wE}hkC3M@ z@PUqEIz^=ESjqyN6OIYm~5z6r;F$adsN-iB9Q8L52E}R5b8x#j!r@a zyMHz!3UykZjV>BP(>qbu8VCg~?-(m|Jwk%cBBx3n2yXihB784%vU!t4rc!IT&S-#5 zVyDh3iECfnxMNuH%{NR)Ehb=!CpU0vF&7*lKFb5CBKENvlX zA2YbSflmjHX9`YXOh(+g!T)U(%6wP=t$#%e>b`IHzBBe7+&3ESgD~1cQeQs4fl0Epy)*G3rP%q5*`a1Qa9BH1jzYn<{+OQ*O1aKAIR zqLP7@5Sn;AaM4zr{Hd}c;1Hjo9^ML}TLioAJ|@oh*kh(!0PG3)h1Uk0CNa;qr$7MjV8>(IlMb;x zfBs=3PQFF2!)c!(;+or5sCCNM`}zK2J&<%yY9rDCw!n(&u3H3*J9qy4$dk_nFMo=XOPINC^p!dt=$%5~z}agV4eWt;F1F8sr6U(v z;(&)mjhRz3b}@F9X-r+65*he2et&#objO~-ce#t!Fhp2VQhnndw#IbdIT^a}U-2~u z(`*bK*N$hf^#GGo({;WVa`7#SB;lKK|O-Zb9jDG*}_| z2S9C?;B$(I^x2aPxB`jbQzSdgw;9gGbh~LnLWL?Z7!h;)8hf5x&Zjsg{H+L-HfD zd}*;otztw?GQroZMXg1X6iEksYPUr!K5-hIPw0iC=e)PhIDOB{zpEw?O4z{>$JA^yg#f-M9WV^vv`{ zYVEV&kICltJ0ukqA1}qAucXF3cQJ&0wSraaY-~H28&ddJ5}Uo2Z)NeFH>K5^zdEzBW%Wx1 zsU&nhdP%G{j(inxs)(3w+W+U&3!)%2@Kx|9n1+|Uq{BB0(naHMLt+1~Q1Ktc48MXI z{9eRCsK_;Z^>aL_gBO({KCd!dg`9^#K&g(Me<~jQ7Luy!h~N=FMuO=#!7Bw7 z0qh&Vz6*Y=gc)PajDGjejDDLkh0FhON^yJmZ*JZZDd1!pVaGFXsuhi{k*(IT8SBP&8#M>9ue_99oDAxT5_IQ zl&#LnE{b<4IY=%*yo30zhs?}$h!G%LF(v&+cE* - Содержание модулей Python — документация pyOpenRPA v1.3.0 v1.3.0 + Содержание модулей Python — документация pyOpenRPA v1.3.1 v1.3.1 @@ -76,7 +76,7 @@ - pyOpenRPA v1.3.0 + pyOpenRPA v1.3.1 @@ -122,7 +122,8 @@
  • 5. Функции Clipboard
  • 6. Функции Mouse
  • 7. Функции Screen
  • -
  • 8. Как использовать?
  • +
  • 8. Функции Audio
  • +
  • 9. Как использовать?
  • МОДУЛЬ СТУДИЯ

    МОДУЛЬ СТУДИЯ