diff --git a/.Dockerfile b/.Dockerfile new file mode 100644 index 0000000..1bdb2a5 --- /dev/null +++ b/.Dockerfile @@ -0,0 +1,27 @@ +FROM python:3.9-buster + +RUN apt-get update \ + # dependencies for building Python packages \ + && apt-get install -y libpq-dev python3-dev \ + && apt-get install -y build-essential \ + # psycopg2 dependencies + && apt-get install -y libpq-dev \ + # Translations dependencies + && apt-get install -y gettext \ + && apt-get install -y libcairo2 libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 libffi-dev shared-mime-info \ + # cleaning up unused files + && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ + && rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /usr/src/app +WORKDIR /usr/src/app + +COPY ./requirements.txt /requirements.txt +RUN pip install --no-cache-dir -r /requirements.txt \ + && rm -rf /requirements.txt + +COPY . /usr/src/app + +EXPOSE 9000 + +CMD [ "python3", "-m" , "server"] \ No newline at end of file diff --git a/.gitignore b/.gitignore index d3012c7..20deaca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ __pycache__ .vscode -models/diagram_1.bpmn +models/private/diagram_1.bpmn models/chatbot_model.bpmn models/test_podproces.bpmn models/test_call_activity.bpmn @@ -8,4 +8,5 @@ models/test_business_rule.bpmn models/test_dmn.dmn models/test_exe_dmn.dmn py-bpmn-env -database/ \ No newline at end of file +database/ +env.py diff --git a/Pipfile b/Pipfile index 179004f..5f74892 100644 --- a/Pipfile +++ b/Pipfile @@ -6,8 +6,24 @@ verify_ssl = true [dev-packages] [packages] -aiohttp = "==3.7.4.post0" -asyncio = "*" +pipenv = "2022.5.2" +aiohttp = "3.7.4.post0" +aiohttp-cors = "0.7.0" +async-timeout = "3.0.1" +asyncio = "3.4.3" +attrs = "21.2.0" +certifi = "2021.5.30" +chardet = "4.0.0" +charset-normalizer = "2.0.4" +idna = "3.2" +multidict = "5.1.0" +pony = "0.7.14" +requests = "2.26.0" +typing-extensions = "3.10.0.0" +urllib3 = "1.26.6" +yarl = "1.6.3" +psycopg2 = "2.9.1" +gunicorn = "20.1.0" [requires] -python_version = "3.9" +python_version = "3.8.10" diff --git a/Pipfile.lock b/Pipfile.lock index 8f43402..1a89772 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "f6b9b69e1a772fdc6e4bceccddb48dde2b41e0e3b1c8d9cd2c854a03389cd9c1" + "sha256": "703016ba8391505a78999495aa35d50ab0b700572ba6252f13eef14e62f6c11f" }, "pipfile-spec": 6, "requires": { - "python_version": "3.9" + "python_version": "3.8.10" }, "sources": [ { @@ -18,54 +18,105 @@ "default": { "aiohttp": { "hashes": [ - "sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe", - "sha256:0563c1b3826945eecd62186f3f5c7d31abb7391fedc893b7e2b26303b5a9f3fe", - "sha256:114b281e4d68302a324dd33abb04778e8557d88947875cbf4e842c2c01a030c5", - "sha256:14762875b22d0055f05d12abc7f7d61d5fd4fe4642ce1a249abdf8c700bf1fd8", - "sha256:15492a6368d985b76a2a5fdd2166cddfea5d24e69eefed4630cbaae5c81d89bd", - "sha256:17c073de315745a1510393a96e680d20af8e67e324f70b42accbd4cb3315c9fb", - "sha256:209b4a8ee987eccc91e2bd3ac36adee0e53a5970b8ac52c273f7f8fd4872c94c", - "sha256:230a8f7e24298dea47659251abc0fd8b3c4e38a664c59d4b89cca7f6c09c9e87", - "sha256:2e19413bf84934d651344783c9f5e22dee452e251cfd220ebadbed2d9931dbf0", - "sha256:393f389841e8f2dfc86f774ad22f00923fdee66d238af89b70ea314c4aefd290", - "sha256:3cf75f7cdc2397ed4442594b935a11ed5569961333d49b7539ea741be2cc79d5", - "sha256:3d78619672183be860b96ed96f533046ec97ca067fd46ac1f6a09cd9b7484287", - "sha256:40eced07f07a9e60e825554a31f923e8d3997cfc7fb31dbc1328c70826e04cde", - "sha256:493d3299ebe5f5a7c66b9819eacdcfbbaaf1a8e84911ddffcdc48888497afecf", - "sha256:4b302b45040890cea949ad092479e01ba25911a15e648429c7c5aae9650c67a8", - "sha256:515dfef7f869a0feb2afee66b957cc7bbe9ad0cdee45aec7fdc623f4ecd4fb16", - "sha256:547da6cacac20666422d4882cfcd51298d45f7ccb60a04ec27424d2f36ba3eaf", - "sha256:5df68496d19f849921f05f14f31bd6ef53ad4b00245da3195048c69934521809", - "sha256:64322071e046020e8797117b3658b9c2f80e3267daec409b350b6a7a05041213", - "sha256:7615dab56bb07bff74bc865307aeb89a8bfd9941d2ef9d817b9436da3a0ea54f", - "sha256:79ebfc238612123a713a457d92afb4096e2148be17df6c50fb9bf7a81c2f8013", - "sha256:7b18b97cf8ee5452fa5f4e3af95d01d84d86d32c5e2bfa260cf041749d66360b", - "sha256:932bb1ea39a54e9ea27fc9232163059a0b8855256f4052e776357ad9add6f1c9", - "sha256:a00bb73540af068ca7390e636c01cbc4f644961896fa9363154ff43fd37af2f5", - "sha256:a5ca29ee66f8343ed336816c553e82d6cade48a3ad702b9ffa6125d187e2dedb", - "sha256:af9aa9ef5ba1fd5b8c948bb11f44891968ab30356d65fd0cc6707d989cd521df", - "sha256:bb437315738aa441251214dad17428cafda9cdc9729499f1d6001748e1d432f4", - "sha256:bdb230b4943891321e06fc7def63c7aace16095be7d9cf3b1e01be2f10fba439", - "sha256:c6e9dcb4cb338d91a73f178d866d051efe7c62a7166653a91e7d9fb18274058f", - "sha256:cffe3ab27871bc3ea47df5d8f7013945712c46a3cc5a95b6bee15887f1675c22", - "sha256:d012ad7911653a906425d8473a1465caa9f8dea7fcf07b6d870397b774ea7c0f", - "sha256:d9e13b33afd39ddeb377eff2c1c4f00544e191e1d1dee5b6c51ddee8ea6f0cf5", - "sha256:e4b2b334e68b18ac9817d828ba44d8fcb391f6acb398bcc5062b14b2cbeac970", - "sha256:e54962802d4b8b18b6207d4a927032826af39395a3bd9196a5af43fc4e60b009", - "sha256:f705e12750171c0ab4ef2a3c76b9a4024a62c4103e3a55dd6f99265b9bc6fcfc", - "sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a", - "sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95" - ], - "index": "pypi", - "version": "==3.7.4.post0" + "sha256:01d7bdb774a9acc838e6b8f1d114f45303841b89b95984cbb7d80ea41172a9e3", + "sha256:03a6d5349c9ee8f79ab3ff3694d6ce1cfc3ced1c9d36200cb8f08ba06bd3b782", + "sha256:04d48b8ce6ab3cf2097b1855e1505181bdd05586ca275f2505514a6e274e8e75", + "sha256:0770e2806a30e744b4e21c9d73b7bee18a1cfa3c47991ee2e5a65b887c49d5cf", + "sha256:07b05cd3305e8a73112103c834e91cd27ce5b4bd07850c4b4dbd1877d3f45be7", + "sha256:086f92daf51a032d062ec5f58af5ca6a44d082c35299c96376a41cbb33034675", + "sha256:099ebd2c37ac74cce10a3527d2b49af80243e2a4fa39e7bce41617fbc35fa3c1", + "sha256:0c7ebbbde809ff4e970824b2b6cb7e4222be6b95a296e46c03cf050878fc1785", + "sha256:102e487eeb82afac440581e5d7f8f44560b36cf0bdd11abc51a46c1cd88914d4", + "sha256:11691cf4dc5b94236ccc609b70fec991234e7ef8d4c02dd0c9668d1e486f5abf", + "sha256:11a67c0d562e07067c4e86bffc1553f2cf5b664d6111c894671b2b8712f3aba5", + "sha256:12de6add4038df8f72fac606dff775791a60f113a725c960f2bab01d8b8e6b15", + "sha256:13487abd2f761d4be7c8ff9080de2671e53fff69711d46de703c310c4c9317ca", + "sha256:15b09b06dae900777833fe7fc4b4aa426556ce95847a3e8d7548e2d19e34edb8", + "sha256:1c182cb873bc91b411e184dab7a2b664d4fea2743df0e4d57402f7f3fa644bac", + "sha256:1ed0b6477896559f17b9eaeb6d38e07f7f9ffe40b9f0f9627ae8b9926ae260a8", + "sha256:28d490af82bc6b7ce53ff31337a18a10498303fe66f701ab65ef27e143c3b0ef", + "sha256:2e5d962cf7e1d426aa0e528a7e198658cdc8aa4fe87f781d039ad75dcd52c516", + "sha256:2ed076098b171573161eb146afcb9129b5ff63308960aeca4b676d9d3c35e700", + "sha256:2f2f69dca064926e79997f45b2f34e202b320fd3782f17a91941f7eb85502ee2", + "sha256:31560d268ff62143e92423ef183680b9829b1b482c011713ae941997921eebc8", + "sha256:31d1e1c0dbf19ebccbfd62eff461518dcb1e307b195e93bba60c965a4dcf1ba0", + "sha256:37951ad2f4a6df6506750a23f7cbabad24c73c65f23f72e95897bb2cecbae676", + "sha256:3af642b43ce56c24d063325dd2cf20ee012d2b9ba4c3c008755a301aaea720ad", + "sha256:44db35a9e15d6fe5c40d74952e803b1d96e964f683b5a78c3cc64eb177878155", + "sha256:473d93d4450880fe278696549f2e7aed8cd23708c3c1997981464475f32137db", + "sha256:477c3ea0ba410b2b56b7efb072c36fa91b1e6fc331761798fa3f28bb224830dd", + "sha256:4a4a4e30bf1edcad13fb0804300557aedd07a92cabc74382fdd0ba6ca2661091", + "sha256:4aed991a28ea3ce320dc8ce655875e1e00a11bdd29fe9444dd4f88c30d558602", + "sha256:51467000f3647d519272392f484126aa716f747859794ac9924a7aafa86cd411", + "sha256:55c3d1072704d27401c92339144d199d9de7b52627f724a949fc7d5fc56d8b93", + "sha256:589c72667a5febd36f1315aa6e5f56dd4aa4862df295cb51c769d16142ddd7cd", + "sha256:5bfde62d1d2641a1f5173b8c8c2d96ceb4854f54a44c23102e2ccc7e02f003ec", + "sha256:5c23b1ad869653bc818e972b7a3a79852d0e494e9ab7e1a701a3decc49c20d51", + "sha256:61bfc23df345d8c9716d03717c2ed5e27374e0fe6f659ea64edcd27b4b044cf7", + "sha256:6ae828d3a003f03ae31915c31fa684b9890ea44c9c989056fea96e3d12a9fa17", + "sha256:6c7cefb4b0640703eb1069835c02486669312bf2f12b48a748e0a7756d0de33d", + "sha256:6d69f36d445c45cda7b3b26afef2fc34ef5ac0cdc75584a87ef307ee3c8c6d00", + "sha256:6f0d5f33feb5f69ddd57a4a4bd3d56c719a141080b445cbf18f238973c5c9923", + "sha256:6f8b01295e26c68b3a1b90efb7a89029110d3a4139270b24fda961893216c440", + "sha256:713ac174a629d39b7c6a3aa757b337599798da4c1157114a314e4e391cd28e32", + "sha256:718626a174e7e467f0558954f94af117b7d4695d48eb980146016afa4b580b2e", + "sha256:7187a76598bdb895af0adbd2fb7474d7f6025d170bc0a1130242da817ce9e7d1", + "sha256:71927042ed6365a09a98a6377501af5c9f0a4d38083652bcd2281a06a5976724", + "sha256:7d08744e9bae2ca9c382581f7dce1273fe3c9bae94ff572c3626e8da5b193c6a", + "sha256:7dadf3c307b31e0e61689cbf9e06be7a867c563d5a63ce9dca578f956609abf8", + "sha256:81e3d8c34c623ca4e36c46524a3530e99c0bc95ed068fd6e9b55cb721d408fb2", + "sha256:844a9b460871ee0a0b0b68a64890dae9c415e513db0f4a7e3cab41a0f2fedf33", + "sha256:8b7ef7cbd4fec9a1e811a5de813311ed4f7ac7d93e0fda233c9b3e1428f7dd7b", + "sha256:97ef77eb6b044134c0b3a96e16abcb05ecce892965a2124c566af0fd60f717e2", + "sha256:99b5eeae8e019e7aad8af8bb314fb908dd2e028b3cdaad87ec05095394cce632", + "sha256:a25fa703a527158aaf10dafd956f7d42ac6d30ec80e9a70846253dd13e2f067b", + "sha256:a2f635ce61a89c5732537a7896b6319a8fcfa23ba09bec36e1b1ac0ab31270d2", + "sha256:a79004bb58748f31ae1cbe9fa891054baaa46fb106c2dc7af9f8e3304dc30316", + "sha256:a996d01ca39b8dfe77440f3cd600825d05841088fd6bc0144cc6c2ec14cc5f74", + "sha256:b0e20cddbd676ab8a64c774fefa0ad787cc506afd844de95da56060348021e96", + "sha256:b6613280ccedf24354406caf785db748bebbddcf31408b20c0b48cb86af76866", + "sha256:b9d00268fcb9f66fbcc7cd9fe423741d90c75ee029a1d15c09b22d23253c0a44", + "sha256:bb01ba6b0d3f6c68b89fce7305080145d4877ad3acaed424bae4d4ee75faa950", + "sha256:c2aef4703f1f2ddc6df17519885dbfa3514929149d3ff900b73f45998f2532fa", + "sha256:c34dc4958b232ef6188c4318cb7b2c2d80521c9a56c52449f8f93ab7bc2a8a1c", + "sha256:c3630c3ef435c0a7c549ba170a0633a56e92629aeed0e707fec832dee313fb7a", + "sha256:c3d6a4d0619e09dcd61021debf7059955c2004fa29f48788a3dfaf9c9901a7cd", + "sha256:d15367ce87c8e9e09b0f989bfd72dc641bcd04ba091c68cd305312d00962addd", + "sha256:d2f9b69293c33aaa53d923032fe227feac867f81682f002ce33ffae978f0a9a9", + "sha256:e999f2d0e12eea01caeecb17b653f3713d758f6dcc770417cf29ef08d3931421", + "sha256:ea302f34477fda3f85560a06d9ebdc7fa41e82420e892fc50b577e35fc6a50b2", + "sha256:eaba923151d9deea315be1f3e2b31cc39a6d1d2f682f942905951f4e40200922", + "sha256:ef9612483cb35171d51d9173647eed5d0069eaa2ee812793a75373447d487aa4", + "sha256:f5315a2eb0239185af1bddb1abf472d877fede3cc8d143c6cddad37678293237", + "sha256:fa0ffcace9b3aa34d205d8130f7873fcfefcb6a4dd3dd705b0dab69af6712642", + "sha256:fc5471e1a54de15ef71c1bc6ebe80d4dc681ea600e68bfd1cbce40427f0b7578" + ], + "index": "pypi", + "version": "==3.8.1" + }, + "aiohttp-cors": { + "hashes": [ + "sha256:0451ba59fdf6909d0e2cd21e4c0a43752bc0703d33fc78ae94d9d9321710193e", + "sha256:4d39c6d7100fd9764ed1caf8cebf0eb01bf5e3f24e2e073fda6234bc48b19f5d" + ], + "index": "pypi", + "version": "==0.7.0" + }, + "aiosignal": { + "hashes": [ + "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a", + "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2" + ], + "markers": "python_version >= '3.6'", + "version": "==1.2.0" }, "async-timeout": { "hashes": [ - "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", - "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" + "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15", + "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c" ], - "markers": "python_full_version >= '3.5.3'", - "version": "==3.0.1" + "index": "pypi", + "version": "==4.0.2" }, "asyncio": { "hashes": [ @@ -79,121 +130,379 @@ }, "attrs": { "hashes": [ - "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6", - "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700" + "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", + "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.3.0" + "index": "pypi", + "version": "==21.4.0" + }, + "certifi": { + "hashes": [ + "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", + "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" + ], + "index": "pypi", + "version": "==2021.10.8" }, "chardet": { "hashes": [ "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "index": "pypi", "version": "==4.0.0" }, + "charset-normalizer": { + "hashes": [ + "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", + "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" + ], + "index": "pypi", + "version": "==2.0.12" + }, + "distlib": { + "hashes": [ + "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b", + "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579" + ], + "version": "==0.3.4" + }, + "filelock": { + "hashes": [ + "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85", + "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0" + ], + "markers": "python_version >= '3.7'", + "version": "==3.6.0" + }, + "frozenlist": { + "hashes": [ + "sha256:006d3595e7d4108a12025ddf415ae0f6c9e736e726a5db0183326fd191b14c5e", + "sha256:01a73627448b1f2145bddb6e6c2259988bb8aee0fb361776ff8604b99616cd08", + "sha256:03a7dd1bfce30216a3f51a84e6dd0e4a573d23ca50f0346634916ff105ba6e6b", + "sha256:0437fe763fb5d4adad1756050cbf855bbb2bf0d9385c7bb13d7a10b0dd550486", + "sha256:04cb491c4b1c051734d41ea2552fde292f5f3a9c911363f74f39c23659c4af78", + "sha256:0c36e78b9509e97042ef869c0e1e6ef6429e55817c12d78245eb915e1cca7468", + "sha256:25af28b560e0c76fa41f550eacb389905633e7ac02d6eb3c09017fa1c8cdfde1", + "sha256:2fdc3cd845e5a1f71a0c3518528bfdbfe2efaf9886d6f49eacc5ee4fd9a10953", + "sha256:30530930410855c451bea83f7b272fb1c495ed9d5cc72895ac29e91279401db3", + "sha256:31977f84828b5bb856ca1eb07bf7e3a34f33a5cddce981d880240ba06639b94d", + "sha256:3c62964192a1c0c30b49f403495911298810bada64e4f03249ca35a33ca0417a", + "sha256:3f7c935c7b58b0d78c0beea0c7358e165f95f1fd8a7e98baa40d22a05b4a8141", + "sha256:40dff8962b8eba91fd3848d857203f0bd704b5f1fa2b3fc9af64901a190bba08", + "sha256:40ec383bc194accba825fbb7d0ef3dda5736ceab2375462f1d8672d9f6b68d07", + "sha256:436496321dad302b8b27ca955364a439ed1f0999311c393dccb243e451ff66aa", + "sha256:4406cfabef8f07b3b3af0f50f70938ec06d9f0fc26cbdeaab431cbc3ca3caeaa", + "sha256:45334234ec30fc4ea677f43171b18a27505bfb2dba9aca4398a62692c0ea8868", + "sha256:47be22dc27ed933d55ee55845d34a3e4e9f6fee93039e7f8ebadb0c2f60d403f", + "sha256:4a44ebbf601d7bac77976d429e9bdb5a4614f9f4027777f9e54fd765196e9d3b", + "sha256:4eda49bea3602812518765810af732229b4291d2695ed24a0a20e098c45a707b", + "sha256:57f4d3f03a18facacb2a6bcd21bccd011e3b75d463dc49f838fd699d074fabd1", + "sha256:603b9091bd70fae7be28bdb8aa5c9990f4241aa33abb673390a7f7329296695f", + "sha256:65bc6e2fece04e2145ab6e3c47428d1bbc05aede61ae365b2c1bddd94906e478", + "sha256:691ddf6dc50480ce49f68441f1d16a4c3325887453837036e0fb94736eae1e58", + "sha256:6983a31698490825171be44ffbafeaa930ddf590d3f051e397143a5045513b01", + "sha256:6a202458d1298ced3768f5a7d44301e7c86defac162ace0ab7434c2e961166e8", + "sha256:6eb275c6385dd72594758cbe96c07cdb9bd6becf84235f4a594bdf21e3596c9d", + "sha256:754728d65f1acc61e0f4df784456106e35afb7bf39cfe37227ab00436fb38676", + "sha256:768efd082074bb203c934e83a61654ed4931ef02412c2fbdecea0cff7ecd0274", + "sha256:772965f773757a6026dea111a15e6e2678fbd6216180f82a48a40b27de1ee2ab", + "sha256:871d42623ae15eb0b0e9df65baeee6976b2e161d0ba93155411d58ff27483ad8", + "sha256:88aafd445a233dbbf8a65a62bc3249a0acd0d81ab18f6feb461cc5a938610d24", + "sha256:8c905a5186d77111f02144fab5b849ab524f1e876a1e75205cd1386a9be4b00a", + "sha256:8cf829bd2e2956066dd4de43fd8ec881d87842a06708c035b37ef632930505a2", + "sha256:92e650bd09b5dda929523b9f8e7f99b24deac61240ecc1a32aeba487afcd970f", + "sha256:93641a51f89473837333b2f8100f3f89795295b858cd4c7d4a1f18e299dc0a4f", + "sha256:94c7a8a9fc9383b52c410a2ec952521906d355d18fccc927fca52ab575ee8b93", + "sha256:9f892d6a94ec5c7b785e548e42722e6f3a52f5f32a8461e82ac3e67a3bd073f1", + "sha256:acb267b09a509c1df5a4ca04140da96016f40d2ed183cdc356d237286c971b51", + "sha256:adac9700675cf99e3615eb6a0eb5e9f5a4143c7d42c05cea2e7f71c27a3d0846", + "sha256:aff388be97ef2677ae185e72dc500d19ecaf31b698986800d3fc4f399a5e30a5", + "sha256:b5009062d78a8c6890d50b4e53b0ddda31841b3935c1937e2ed8c1bda1c7fb9d", + "sha256:b684c68077b84522b5c7eafc1dc735bfa5b341fb011d5552ebe0968e22ed641c", + "sha256:b9e3e9e365991f8cc5f5edc1fd65b58b41d0514a6a7ad95ef5c7f34eb49b3d3e", + "sha256:bd89acd1b8bb4f31b47072615d72e7f53a948d302b7c1d1455e42622de180eae", + "sha256:bde99812f237f79eaf3f04ebffd74f6718bbd216101b35ac7955c2d47c17da02", + "sha256:c6c321dd013e8fc20735b92cb4892c115f5cdb82c817b1e5b07f6b95d952b2f0", + "sha256:ce6f2ba0edb7b0c1d8976565298ad2deba6f8064d2bebb6ffce2ca896eb35b0b", + "sha256:d2257aaba9660f78c7b1d8fea963b68f3feffb1a9d5d05a18401ca9eb3e8d0a3", + "sha256:d26b650b71fdc88065b7a21f8ace70175bcf3b5bdba5ea22df4bfd893e795a3b", + "sha256:d6d32ff213aef0fd0bcf803bffe15cfa2d4fde237d1d4838e62aec242a8362fa", + "sha256:e1e26ac0a253a2907d654a37e390904426d5ae5483150ce3adedb35c8c06614a", + "sha256:e30b2f9683812eb30cf3f0a8e9f79f8d590a7999f731cf39f9105a7c4a39489d", + "sha256:e84cb61b0ac40a0c3e0e8b79c575161c5300d1d89e13c0e02f76193982f066ed", + "sha256:e982878792c971cbd60ee510c4ee5bf089a8246226dea1f2138aa0bb67aff148", + "sha256:f20baa05eaa2bcd5404c445ec51aed1c268d62600362dc6cfe04fae34a424bd9", + "sha256:f7353ba3367473d1d616ee727945f439e027f0bb16ac1a750219a8344d1d5d3c", + "sha256:f96293d6f982c58ebebb428c50163d010c2f05de0cde99fd681bfdc18d4b2dc2", + "sha256:ff9310f05b9d9c5c4dd472983dc956901ee6cb2c3ec1ab116ecdde25f3ce4951" + ], + "markers": "python_version >= '3.7'", + "version": "==1.3.0" + }, + "gunicorn": { + "hashes": [ + "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", + "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8" + ], + "index": "pypi", + "version": "==20.1.0" + }, "idna": { "hashes": [ - "sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16", - "sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1" + "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", + "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" ], - "markers": "python_version >= '3.4'", - "version": "==3.1" + "index": "pypi", + "version": "==3.3" }, "multidict": { "hashes": [ - "sha256:018132dbd8688c7a69ad89c4a3f39ea2f9f33302ebe567a879da8f4ca73f0d0a", - "sha256:051012ccee979b2b06be928a6150d237aec75dd6bf2d1eeeb190baf2b05abc93", - "sha256:05c20b68e512166fddba59a918773ba002fdd77800cad9f55b59790030bab632", - "sha256:07b42215124aedecc6083f1ce6b7e5ec5b50047afa701f3442054373a6deb656", - "sha256:0e3c84e6c67eba89c2dbcee08504ba8644ab4284863452450520dad8f1e89b79", - "sha256:0e929169f9c090dae0646a011c8b058e5e5fb391466016b39d21745b48817fd7", - "sha256:1ab820665e67373de5802acae069a6a05567ae234ddb129f31d290fc3d1aa56d", - "sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5", - "sha256:2e68965192c4ea61fff1b81c14ff712fc7dc15d2bd120602e4a3494ea6584224", - "sha256:2f1a132f1c88724674271d636e6b7351477c27722f2ed789f719f9e3545a3d26", - "sha256:37e5438e1c78931df5d3c0c78ae049092877e5e9c02dd1ff5abb9cf27a5914ea", - "sha256:3a041b76d13706b7fff23b9fc83117c7b8fe8d5fe9e6be45eee72b9baa75f348", - "sha256:3a4f32116f8f72ecf2a29dabfb27b23ab7cdc0ba807e8459e59a93a9be9506f6", - "sha256:46c73e09ad374a6d876c599f2328161bcd95e280f84d2060cf57991dec5cfe76", - "sha256:46dd362c2f045095c920162e9307de5ffd0a1bfbba0a6e990b344366f55a30c1", - "sha256:4b186eb7d6ae7c06eb4392411189469e6a820da81447f46c0072a41c748ab73f", - "sha256:54fd1e83a184e19c598d5e70ba508196fd0bbdd676ce159feb412a4a6664f952", - "sha256:585fd452dd7782130d112f7ddf3473ffdd521414674c33876187e101b588738a", - "sha256:5cf3443199b83ed9e955f511b5b241fd3ae004e3cb81c58ec10f4fe47c7dce37", - "sha256:6a4d5ce640e37b0efcc8441caeea8f43a06addace2335bd11151bc02d2ee31f9", - "sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359", - "sha256:806068d4f86cb06af37cd65821554f98240a19ce646d3cd24e1c33587f313eb8", - "sha256:830f57206cc96ed0ccf68304141fec9481a096c4d2e2831f311bde1c404401da", - "sha256:929006d3c2d923788ba153ad0de8ed2e5ed39fdbe8e7be21e2f22ed06c6783d3", - "sha256:9436dc58c123f07b230383083855593550c4d301d2532045a17ccf6eca505f6d", - "sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf", - "sha256:ace010325c787c378afd7f7c1ac66b26313b3344628652eacd149bdd23c68841", - "sha256:b47a43177a5e65b771b80db71e7be76c0ba23cc8aa73eeeb089ed5219cdbe27d", - "sha256:b797515be8743b771aa868f83563f789bbd4b236659ba52243b735d80b29ed93", - "sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f", - "sha256:d5c65bdf4484872c4af3150aeebe101ba560dcfb34488d9a8ff8dbcd21079647", - "sha256:d81eddcb12d608cc08081fa88d046c78afb1bf8107e6feab5d43503fea74a635", - "sha256:dc862056f76443a0db4509116c5cd480fe1b6a2d45512a653f9a855cc0517456", - "sha256:ecc771ab628ea281517e24fd2c52e8f31c41e66652d07599ad8818abaad38cda", - "sha256:f200755768dc19c6f4e2b672421e0ebb3dd54c38d5a4f262b872d8cfcc9e93b5", - "sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281", - "sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80" + "sha256:0327292e745a880459ef71be14e709aaea2f783f3537588fb4ed09b6c01bca60", + "sha256:041b81a5f6b38244b34dc18c7b6aba91f9cdaf854d9a39e5ff0b58e2b5773b9c", + "sha256:0556a1d4ea2d949efe5fd76a09b4a82e3a4a30700553a6725535098d8d9fb672", + "sha256:05f6949d6169878a03e607a21e3b862eaf8e356590e8bdae4227eedadacf6e51", + "sha256:07a017cfa00c9890011628eab2503bee5872f27144936a52eaab449be5eaf032", + "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2", + "sha256:19adcfc2a7197cdc3987044e3f415168fc5dc1f720c932eb1ef4f71a2067e08b", + "sha256:19d9bad105dfb34eb539c97b132057a4e709919ec4dd883ece5838bcbf262b80", + "sha256:225383a6603c086e6cef0f2f05564acb4f4d5f019a4e3e983f572b8530f70c88", + "sha256:23b616fdc3c74c9fe01d76ce0d1ce872d2d396d8fa8e4899398ad64fb5aa214a", + "sha256:2957489cba47c2539a8eb7ab32ff49101439ccf78eab724c828c1a54ff3ff98d", + "sha256:2d36e929d7f6a16d4eb11b250719c39560dd70545356365b494249e2186bc389", + "sha256:2e4a0785b84fb59e43c18a015ffc575ba93f7d1dbd272b4cdad9f5134b8a006c", + "sha256:3368bf2398b0e0fcbf46d85795adc4c259299fec50c1416d0f77c0a843a3eed9", + "sha256:373ba9d1d061c76462d74e7de1c0c8e267e9791ee8cfefcf6b0b2495762c370c", + "sha256:4070613ea2227da2bfb2c35a6041e4371b0af6b0be57f424fe2318b42a748516", + "sha256:45183c96ddf61bf96d2684d9fbaf6f3564d86b34cb125761f9a0ef9e36c1d55b", + "sha256:4571f1beddff25f3e925eea34268422622963cd8dc395bb8778eb28418248e43", + "sha256:47e6a7e923e9cada7c139531feac59448f1f47727a79076c0b1ee80274cd8eee", + "sha256:47fbeedbf94bed6547d3aa632075d804867a352d86688c04e606971595460227", + "sha256:497988d6b6ec6ed6f87030ec03280b696ca47dbf0648045e4e1d28b80346560d", + "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae", + "sha256:50bd442726e288e884f7be9071016c15a8742eb689a593a0cac49ea093eef0a7", + "sha256:514fe2b8d750d6cdb4712346a2c5084a80220821a3e91f3f71eec11cf8d28fd4", + "sha256:5774d9218d77befa7b70d836004a768fb9aa4fdb53c97498f4d8d3f67bb9cfa9", + "sha256:5fdda29a3c7e76a064f2477c9aab1ba96fd94e02e386f1e665bca1807fc5386f", + "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013", + "sha256:626fe10ac87851f4cffecee161fc6f8f9853f0f6f1035b59337a51d29ff3b4f9", + "sha256:6701bf8a5d03a43375909ac91b6980aea74b0f5402fbe9428fc3f6edf5d9677e", + "sha256:684133b1e1fe91eda8fa7447f137c9490a064c6b7f392aa857bba83a28cfb693", + "sha256:6f3cdef8a247d1eafa649085812f8a310e728bdf3900ff6c434eafb2d443b23a", + "sha256:75bdf08716edde767b09e76829db8c1e5ca9d8bb0a8d4bd94ae1eafe3dac5e15", + "sha256:7c40b7bbece294ae3a87c1bc2abff0ff9beef41d14188cda94ada7bcea99b0fb", + "sha256:8004dca28e15b86d1b1372515f32eb6f814bdf6f00952699bdeb541691091f96", + "sha256:8064b7c6f0af936a741ea1efd18690bacfbae4078c0c385d7c3f611d11f0cf87", + "sha256:89171b2c769e03a953d5969b2f272efa931426355b6c0cb508022976a17fd376", + "sha256:8cbf0132f3de7cc6c6ce00147cc78e6439ea736cee6bca4f068bcf892b0fd658", + "sha256:9cc57c68cb9139c7cd6fc39f211b02198e69fb90ce4bc4a094cf5fe0d20fd8b0", + "sha256:a007b1638e148c3cfb6bf0bdc4f82776cef0ac487191d093cdc316905e504071", + "sha256:a2c34a93e1d2aa35fbf1485e5010337c72c6791407d03aa5f4eed920343dd360", + "sha256:a45e1135cb07086833ce969555df39149680e5471c04dfd6a915abd2fc3f6dbc", + "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3", + "sha256:aef9cc3d9c7d63d924adac329c33835e0243b5052a6dfcbf7732a921c6e918ba", + "sha256:b9d153e7f1f9ba0b23ad1568b3b9e17301e23b042c23870f9ee0522dc5cc79e8", + "sha256:bfba7c6d5d7c9099ba21f84662b037a0ffd4a5e6b26ac07d19e423e6fdf965a9", + "sha256:c207fff63adcdf5a485969131dc70e4b194327666b7e8a87a97fbc4fd80a53b2", + "sha256:d0509e469d48940147e1235d994cd849a8f8195e0bca65f8f5439c56e17872a3", + "sha256:d16cce709ebfadc91278a1c005e3c17dd5f71f5098bfae1035149785ea6e9c68", + "sha256:d48b8ee1d4068561ce8033d2c344cf5232cb29ee1a0206a7b828c79cbc5982b8", + "sha256:de989b195c3d636ba000ee4281cd03bb1234635b124bf4cd89eeee9ca8fcb09d", + "sha256:e07c8e79d6e6fd37b42f3250dba122053fddb319e84b55dd3a8d6446e1a7ee49", + "sha256:e2c2e459f7050aeb7c1b1276763364884595d47000c1cddb51764c0d8976e608", + "sha256:e5b20e9599ba74391ca0cfbd7b328fcc20976823ba19bc573983a25b32e92b57", + "sha256:e875b6086e325bab7e680e4316d667fc0e5e174bb5611eb16b3ea121c8951b86", + "sha256:f4f052ee022928d34fe1f4d2bc743f32609fb79ed9c49a1710a5ad6b2198db20", + "sha256:fcb91630817aa8b9bc4a74023e4198480587269c272c58b3279875ed7235c293", + "sha256:fd9fc9c4849a07f3635ccffa895d57abce554b467d611a5009ba4f39b78a8849", + "sha256:feba80698173761cddd814fa22e88b0661e98cb810f9f986c54aa34d281e4937", + "sha256:feea820722e69451743a3d56ad74948b68bf456984d63c1a92e8347b7b88452d" ], - "markers": "python_version >= '3.6'", - "version": "==5.1.0" + "index": "pypi", + "version": "==6.0.2" + }, + "pip": { + "hashes": [ + "sha256:b3a9de2c6ef801e9247d1527a4b16f92f2cc141cd1489f3fffaf6a9e96729764", + "sha256:c6aca0f2f081363f689f041d90dab2a07a9a07fb840284db2218117a52da800b" + ], + "markers": "python_version >= '3.7'", + "version": "==22.0.4" + }, + "pipenv": { + "hashes": [ + "sha256:06e19a3a2ae7db14a317bdedc61030cdcd132a012410de1e5bdb0e19d0620465", + "sha256:71d510c20f99ea5cd3c951f8203140197bcc79fc21a0d74924f97c726a0f2bd3" + ], + "index": "pypi", + "version": "==2022.5.2" + }, + "platformdirs": { + "hashes": [ + "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788", + "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19" + ], + "markers": "python_version >= '3.7'", + "version": "==2.5.2" + }, + "pony": { + "hashes": [ + "sha256:5f45fc67587f4520c560a57148cc573b097d42f82f5cb200d72c957b5708198d", + "sha256:608a1c1d662983bad2590e650f2bbc1cd6ed48558894ad8f50da4739ff98f614" + ], + "index": "pypi", + "version": "==0.7.16" + }, + "psycopg2": { + "hashes": [ + "sha256:06f32425949bd5fe8f625c49f17ebb9784e1e4fe928b7cce72edc36fb68e4c0c", + "sha256:0762c27d018edbcb2d34d51596e4346c983bd27c330218c56c4dc25ef7e819bf", + "sha256:083707a696e5e1c330af2508d8fab36f9700b26621ccbcb538abe22e15485362", + "sha256:34b33e0162cfcaad151f249c2649fd1030010c16f4bbc40a604c1cb77173dcf7", + "sha256:4295093a6ae3434d33ec6baab4ca5512a5082cc43c0505293087b8a46d108461", + "sha256:8cf3878353cc04b053822896bc4922b194792df9df2f1ad8da01fb3043602126", + "sha256:8e841d1bf3434da985cc5ef13e6f75c8981ced601fd70cc6bf33351b91562981", + "sha256:9572e08b50aed176ef6d66f15a21d823bb6f6d23152d35e8451d7d2d18fdac56", + "sha256:a81e3866f99382dfe8c15a151f1ca5fde5815fde879348fe5a9884a7c092a305", + "sha256:cb10d44e6694d763fa1078a26f7f6137d69f555a78ec85dc2ef716c37447e4b2", + "sha256:d3ca6421b942f60c008f81a3541e8faf6865a28d5a9b48544b0ee4f40cac7fca" + ], + "index": "pypi", + "version": "==2.9.3" + }, + "requests": { + "hashes": [ + "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61", + "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d" + ], + "index": "pypi", + "version": "==2.27.1" + }, + "setuptools": { + "hashes": [ + "sha256:26ead7d1f93efc0f8c804d9fafafbe4a44b179580a7105754b245155f9af05a8", + "sha256:47c7b0c0f8fc10eec4cf1e71c6fdadf8decaa74ffa087e68cd1c20db7ad6a592" + ], + "markers": "python_version >= '3.7'", + "version": "==62.1.0" + }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" }, "typing-extensions": { "hashes": [ - "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918", - "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c", - "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" + "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708", + "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376" + ], + "index": "pypi", + "version": "==4.2.0" + }, + "urllib3": { + "hashes": [ + "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", + "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" + ], + "index": "pypi", + "version": "==1.26.9" + }, + "virtualenv": { + "hashes": [ + "sha256:e617f16e25b42eb4f6e74096b9c9e37713cf10bf30168fb4a739f3fa8f898a3a", + "sha256:ef589a79795589aada0c1c5b319486797c03b67ac3984c48c669c0e4f50df3a5" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==20.14.1" + }, + "virtualenv-clone": { + "hashes": [ + "sha256:418ee935c36152f8f153c79824bb93eaf6f0f7984bae31d3f48f350b9183501a", + "sha256:44d5263bceed0bac3e1424d64f798095233b64def1c5689afa43dc3223caf5b0" ], - "version": "==3.7.4.3" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.5.7" }, "yarl": { "hashes": [ - "sha256:00d7ad91b6583602eb9c1d085a2cf281ada267e9a197e8b7cae487dadbfa293e", - "sha256:0355a701b3998dcd832d0dc47cc5dedf3874f966ac7f870e0f3a6788d802d434", - "sha256:15263c3b0b47968c1d90daa89f21fcc889bb4b1aac5555580d74565de6836366", - "sha256:2ce4c621d21326a4a5500c25031e102af589edb50c09b321049e388b3934eec3", - "sha256:31ede6e8c4329fb81c86706ba8f6bf661a924b53ba191b27aa5fcee5714d18ec", - "sha256:324ba3d3c6fee56e2e0b0d09bf5c73824b9f08234339d2b788af65e60040c959", - "sha256:329412812ecfc94a57cd37c9d547579510a9e83c516bc069470db5f75684629e", - "sha256:4736eaee5626db8d9cda9eb5282028cc834e2aeb194e0d8b50217d707e98bb5c", - "sha256:4953fb0b4fdb7e08b2f3b3be80a00d28c5c8a2056bb066169de00e6501b986b6", - "sha256:4c5bcfc3ed226bf6419f7a33982fb4b8ec2e45785a0561eb99274ebbf09fdd6a", - "sha256:547f7665ad50fa8563150ed079f8e805e63dd85def6674c97efd78eed6c224a6", - "sha256:5b883e458058f8d6099e4420f0cc2567989032b5f34b271c0827de9f1079a424", - "sha256:63f90b20ca654b3ecc7a8d62c03ffa46999595f0167d6450fa8383bab252987e", - "sha256:68dc568889b1c13f1e4745c96b931cc94fdd0defe92a72c2b8ce01091b22e35f", - "sha256:69ee97c71fee1f63d04c945f56d5d726483c4762845400a6795a3b75d56b6c50", - "sha256:6d6283d8e0631b617edf0fd726353cb76630b83a089a40933043894e7f6721e2", - "sha256:72a660bdd24497e3e84f5519e57a9ee9220b6f3ac4d45056961bf22838ce20cc", - "sha256:73494d5b71099ae8cb8754f1df131c11d433b387efab7b51849e7e1e851f07a4", - "sha256:7356644cbed76119d0b6bd32ffba704d30d747e0c217109d7979a7bc36c4d970", - "sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10", - "sha256:8aa3decd5e0e852dc68335abf5478a518b41bf2ab2f330fe44916399efedfae0", - "sha256:97b5bdc450d63c3ba30a127d018b866ea94e65655efaf889ebeabc20f7d12406", - "sha256:9ede61b0854e267fd565e7527e2f2eb3ef8858b301319be0604177690e1a3896", - "sha256:b2e9a456c121e26d13c29251f8267541bd75e6a1ccf9e859179701c36a078643", - "sha256:b5dfc9a40c198334f4f3f55880ecf910adebdcb2a0b9a9c23c9345faa9185721", - "sha256:bafb450deef6861815ed579c7a6113a879a6ef58aed4c3a4be54400ae8871478", - "sha256:c49ff66d479d38ab863c50f7bb27dee97c6627c5fe60697de15529da9c3de724", - "sha256:ce3beb46a72d9f2190f9e1027886bfc513702d748047b548b05dab7dfb584d2e", - "sha256:d26608cf178efb8faa5ff0f2d2e77c208f471c5a3709e577a7b3fd0445703ac8", - "sha256:d597767fcd2c3dc49d6eea360c458b65643d1e4dbed91361cf5e36e53c1f8c96", - "sha256:d5c32c82990e4ac4d8150fd7652b972216b204de4e83a122546dce571c1bdf25", - "sha256:d8d07d102f17b68966e2de0e07bfd6e139c7c02ef06d3a0f8d2f0f055e13bb76", - "sha256:e46fba844f4895b36f4c398c5af062a9808d1f26b2999c58909517384d5deda2", - "sha256:e6b5460dc5ad42ad2b36cca524491dfcaffbfd9c8df50508bddc354e787b8dc2", - "sha256:f040bcc6725c821a4c0665f3aa96a4d0805a7aaf2caf266d256b8ed71b9f041c", - "sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a", - "sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71" + "sha256:044daf3012e43d4b3538562da94a88fb12a6490652dbc29fb19adfa02cf72eac", + "sha256:0cba38120db72123db7c58322fa69e3c0efa933040ffb586c3a87c063ec7cae8", + "sha256:167ab7f64e409e9bdd99333fe8c67b5574a1f0495dcfd905bc7454e766729b9e", + "sha256:1be4bbb3d27a4e9aa5f3df2ab61e3701ce8fcbd3e9846dbce7c033a7e8136746", + "sha256:1ca56f002eaf7998b5fcf73b2421790da9d2586331805f38acd9997743114e98", + "sha256:1d3d5ad8ea96bd6d643d80c7b8d5977b4e2fb1bab6c9da7322616fd26203d125", + "sha256:1eb6480ef366d75b54c68164094a6a560c247370a68c02dddb11f20c4c6d3c9d", + "sha256:1edc172dcca3f11b38a9d5c7505c83c1913c0addc99cd28e993efeaafdfaa18d", + "sha256:211fcd65c58bf250fb994b53bc45a442ddc9f441f6fec53e65de8cba48ded986", + "sha256:29e0656d5497733dcddc21797da5a2ab990c0cb9719f1f969e58a4abac66234d", + "sha256:368bcf400247318382cc150aaa632582d0780b28ee6053cd80268c7e72796dec", + "sha256:39d5493c5ecd75c8093fa7700a2fb5c94fe28c839c8e40144b7ab7ccba6938c8", + "sha256:3abddf0b8e41445426d29f955b24aeecc83fa1072be1be4e0d194134a7d9baee", + "sha256:3bf8cfe8856708ede6a73907bf0501f2dc4e104085e070a41f5d88e7faf237f3", + "sha256:3ec1d9a0d7780416e657f1e405ba35ec1ba453a4f1511eb8b9fbab81cb8b3ce1", + "sha256:45399b46d60c253327a460e99856752009fcee5f5d3c80b2f7c0cae1c38d56dd", + "sha256:52690eb521d690ab041c3919666bea13ab9fbff80d615ec16fa81a297131276b", + "sha256:534b047277a9a19d858cde163aba93f3e1677d5acd92f7d10ace419d478540de", + "sha256:580c1f15500e137a8c37053e4cbf6058944d4c114701fa59944607505c2fe3a0", + "sha256:59218fef177296451b23214c91ea3aba7858b4ae3306dde120224cfe0f7a6ee8", + "sha256:5ba63585a89c9885f18331a55d25fe81dc2d82b71311ff8bd378fc8004202ff6", + "sha256:5bb7d54b8f61ba6eee541fba4b83d22b8a046b4ef4d8eb7f15a7e35db2e1e245", + "sha256:6152224d0a1eb254f97df3997d79dadd8bb2c1a02ef283dbb34b97d4f8492d23", + "sha256:67e94028817defe5e705079b10a8438b8cb56e7115fa01640e9c0bb3edf67332", + "sha256:695ba021a9e04418507fa930d5f0704edbce47076bdcfeeaba1c83683e5649d1", + "sha256:6a1a9fe17621af43e9b9fcea8bd088ba682c8192d744b386ee3c47b56eaabb2c", + "sha256:6ab0c3274d0a846840bf6c27d2c60ba771a12e4d7586bf550eefc2df0b56b3b4", + "sha256:6feca8b6bfb9eef6ee057628e71e1734caf520a907b6ec0d62839e8293e945c0", + "sha256:737e401cd0c493f7e3dd4db72aca11cfe069531c9761b8ea474926936b3c57c8", + "sha256:788713c2896f426a4e166b11f4ec538b5736294ebf7d5f654ae445fd44270832", + "sha256:797c2c412b04403d2da075fb93c123df35239cd7b4cc4e0cd9e5839b73f52c58", + "sha256:8300401dc88cad23f5b4e4c1226f44a5aa696436a4026e456fe0e5d2f7f486e6", + "sha256:87f6e082bce21464857ba58b569370e7b547d239ca22248be68ea5d6b51464a1", + "sha256:89ccbf58e6a0ab89d487c92a490cb5660d06c3a47ca08872859672f9c511fc52", + "sha256:8b0915ee85150963a9504c10de4e4729ae700af11df0dc5550e6587ed7891e92", + "sha256:8cce6f9fa3df25f55521fbb5c7e4a736683148bcc0c75b21863789e5185f9185", + "sha256:95a1873b6c0dd1c437fb3bb4a4aaa699a48c218ac7ca1e74b0bee0ab16c7d60d", + "sha256:9b4c77d92d56a4c5027572752aa35082e40c561eec776048330d2907aead891d", + "sha256:9bfcd43c65fbb339dc7086b5315750efa42a34eefad0256ba114cd8ad3896f4b", + "sha256:9c1f083e7e71b2dd01f7cd7434a5f88c15213194df38bc29b388ccdf1492b739", + "sha256:a1d0894f238763717bdcfea74558c94e3bc34aeacd3351d769460c1a586a8b05", + "sha256:a467a431a0817a292121c13cbe637348b546e6ef47ca14a790aa2fa8cc93df63", + "sha256:aa32aaa97d8b2ed4e54dc65d241a0da1c627454950f7d7b1f95b13985afd6c5d", + "sha256:ac10bbac36cd89eac19f4e51c032ba6b412b3892b685076f4acd2de18ca990aa", + "sha256:ac35ccde589ab6a1870a484ed136d49a26bcd06b6a1c6397b1967ca13ceb3913", + "sha256:bab827163113177aee910adb1f48ff7af31ee0289f434f7e22d10baf624a6dfe", + "sha256:baf81561f2972fb895e7844882898bda1eef4b07b5b385bcd308d2098f1a767b", + "sha256:bf19725fec28452474d9887a128e98dd67eee7b7d52e932e6949c532d820dc3b", + "sha256:c01a89a44bb672c38f42b49cdb0ad667b116d731b3f4c896f72302ff77d71656", + "sha256:c0910c6b6c31359d2f6184828888c983d54d09d581a4a23547a35f1d0b9484b1", + "sha256:c10ea1e80a697cf7d80d1ed414b5cb8f1eec07d618f54637067ae3c0334133c4", + "sha256:c1164a2eac148d85bbdd23e07dfcc930f2e633220f3eb3c3e2a25f6148c2819e", + "sha256:c145ab54702334c42237a6c6c4cc08703b6aa9b94e2f227ceb3d477d20c36c63", + "sha256:c17965ff3706beedafd458c452bf15bac693ecd146a60a06a214614dc097a271", + "sha256:c19324a1c5399b602f3b6e7db9478e5b1adf5cf58901996fc973fe4fccd73eed", + "sha256:c2a1ac41a6aa980db03d098a5531f13985edcb451bcd9d00670b03129922cd0d", + "sha256:c6ddcd80d79c96eb19c354d9dca95291589c5954099836b7c8d29278a7ec0bda", + "sha256:c9c6d927e098c2d360695f2e9d38870b2e92e0919be07dbe339aefa32a090265", + "sha256:cc8b7a7254c0fc3187d43d6cb54b5032d2365efd1df0cd1749c0c4df5f0ad45f", + "sha256:cff3ba513db55cc6a35076f32c4cdc27032bd075c9faef31fec749e64b45d26c", + "sha256:d260d4dc495c05d6600264a197d9d6f7fc9347f21d2594926202fd08cf89a8ba", + "sha256:d6f3d62e16c10e88d2168ba2d065aa374e3c538998ed04996cd373ff2036d64c", + "sha256:da6df107b9ccfe52d3a48165e48d72db0eca3e3029b5b8cb4fe6ee3cb870ba8b", + "sha256:dfe4b95b7e00c6635a72e2d00b478e8a28bfb122dc76349a06e20792eb53a523", + "sha256:e39378894ee6ae9f555ae2de332d513a5763276a9265f8e7cbaeb1b1ee74623a", + "sha256:ede3b46cdb719c794427dcce9d8beb4abe8b9aa1e97526cc20de9bd6583ad1ef", + "sha256:f2a8508f7350512434e41065684076f640ecce176d262a7d54f0da41d99c5a95", + "sha256:f44477ae29025d8ea87ec308539f95963ffdc31a82f42ca9deecf2d505242e72", + "sha256:f64394bd7ceef1237cc604b5a89bf748c95982a84bcd3c4bbeb40f685c810794", + "sha256:fc4dd8b01a8112809e6b636b00f487846956402834a7fd59d46d4f4267181c41", + "sha256:fce78593346c014d0d986b7ebc80d782b7f5e19843ca798ed62f8e3ba8728576", + "sha256:fd547ec596d90c8676e369dd8a581a21227fe9b4ad37d0dc7feb4ccf544c2d59" ], - "markers": "python_version >= '3.6'", - "version": "==1.6.3" + "index": "pypi", + "version": "==1.7.2" } }, "develop": {} diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..d5e2bb1 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: python server.py \ No newline at end of file diff --git a/bpmn_model.py b/bpmn_model.py index 6ebe0be..e223359 100644 --- a/bpmn_model.py +++ b/bpmn_model.py @@ -1,3 +1,5 @@ +from asyncio import get_running_loop +from concurrent.futures import ThreadPoolExecutor from types import SimpleNamespace import xml.etree.ElementTree as ET from bpmn_types import * @@ -11,12 +13,10 @@ import os from uuid import uuid4 import env +from bpmn_types import Task, ServiceTask -instance_models = {} - -def get_model_for_instance(iid): - return instance_models.get(iid, None) +# thread_pool = ThreadPoolExecutor(max_workers=100) class UserFormMessage: @@ -25,6 +25,12 @@ def __init__(self, task_id, form_data={}): self.form_data = form_data +class ReceiveMessage: + def __init__(self, task_id, data={}): + self.task_id = task_id + self.data = data or {} + + class BpmnModel: def __init__(self, model_path): self.pending = [] @@ -77,17 +83,24 @@ def __init__(self, model_path): break def to_json(self): + tasks = [x.to_json() for x in self.elements.values() if isinstance(x, UserTask) or isinstance(x, ReceiveTask)] return { "model_path": self.model_path, "main_process": self.main_process.__dict__, - "tasks": [ - x.to_json() for x in self.elements.values() if isinstance(x, UserTask) - ], + "tasks": tasks, "instances": [i._id for i in self.instances.values()], } - async def create_instance(self, _id, variables, process=None): + async def create_or_get_instance(self, _id, variables, process=None, initial=None): + if _id in self.instances: + return self.instances[_id] + instance = await self.create_instance(_id, variables, process=None, initial=None) + return instance + + async def create_instance(self, _id, variables, process=None, initial=None): queue = asyncio.Queue() + if initial: + queue.put_nowait(initial) if not process: if self.main_collaboration_process: # If Collaboration diagram @@ -95,10 +108,14 @@ async def create_instance(self, _id, variables, process=None): else: # If Process diagram process = list(self.process_elements)[0] + instance = await self.instance_obj(_id, process, queue, variables) + self.instances[_id] = instance + return instance + + async def instance_obj(self, _id, process, queue, variables): instance = BpmnInstance( _id, model=self, variables=variables, in_queue=queue, process=process ) - self.instances[_id] = instance return instance # Takes model_path needed for deployed subprocess @@ -122,7 +139,7 @@ def handle_deployment_subprocesses(self): class BpmnInstance: def __init__(self, _id, model, variables, in_queue, process): - instance_models[_id] = model + # instance_models[_id] = model self._id = _id self.model = model self.variables = deepcopy(variables) @@ -131,6 +148,7 @@ def __init__(self, _id, model, variables, in_queue, process): self.pending = deepcopy(self.model.process_pending[process]) self.process = process + def to_json(self): return { "id": self._id, @@ -148,12 +166,18 @@ def check_condition(cls, state, condition, log): if condition: key = condition.partition(":")[0] value = condition.partition(":")[2] - if key in state and state[key] == value: + + if key in state and str(state[key]).upper() == str(value).upper(): ok = True log("\t DONE: Result is", ok) return ok - async def run_from_log(self, log): + async def run_from_log(self, log,state): + if self.state == "running" or self.state == "finished": + return self + if state == "running" or state == "finished": + return self + for l in log: if l.get("activity_id") in self.model.elements: pending_elements_list = [] @@ -163,26 +187,19 @@ async def run_from_log(self, log): self.variables = {**l.get("activity_variables"), **self.variables} return self - async def run_subprocess(self, process_id): - new_subproces_instance_id = str(uuid4()) - if not self.model.subprocesses[process_id]: - new_subprocess_instance = await self.model.create_instance( - new_subproces_instance_id, {}, process_id - ) - finished_subprocess = await new_subprocess_instance.run() - else: - subprocess_model = BpmnModel(self.model.subprocesses[process_id]) - new_subproces_instance = await subprocess_model.create_instance( - new_subproces_instance_id, {}, process_id - ) - finished_subprocess = await new_subproces_instance.run() - return True - - async def run(self): + # async def run(self, is_subprocess=False): + # def task(): + # await self._run(is_subprocess=is_subprocess) + # + # vars = (get_running_loop().run_in_executor(thread_pool, lambda: task(), )) + # return vars + + async def run(self, is_subprocess=False): self.state = "running" _id = self._id prefix = f"\t[{_id}]" + log = partial(print, prefix) # if _id == "2" else lambda *x: x in_queue = self.in_queue @@ -220,7 +237,7 @@ async def run(self): } current_and_variables_dict[current._id] = new_variables # Create new running instance - db_connector.add_running_instance(instance_id=self._id) + db_connector.add_running_instance(instance_id=self._id, state=self.state, ran_as_subprocess=is_subprocess) if isinstance(current, EndEvent): exit = True @@ -232,15 +249,15 @@ async def run(self): activity_id=current._id, timestamp=datetime.now(), pending=[], - activity_variables={}, + activity_variables=self.variables, ) break if isinstance(current, UserTask): if ( - message - and isinstance(message, UserFormMessage) - and message.task_id == current._id + message + and isinstance(message, UserFormMessage) + and message.task_id == current._id ): user_action = message.form_data @@ -257,6 +274,7 @@ async def run(self): elif isinstance(current, ServiceTask): log("DOING:", current) + can_continue = await current.run(self.variables, _id) # Helper variables for DB insert new_variables = { @@ -274,11 +292,26 @@ async def run(self): for k in set(self.variables) - set(before_variables) } current_and_variables_dict[current._id] = new_variables + elif isinstance(current, ReceiveTask): + if ( + message + and isinstance(message, ReceiveMessage) + and message.task_id == current._id + ): + log("DOING:", current) + can_continue = current.run(self.variables, message.data) + # Helper variables for DB insert + new_variables = { + k: self.variables[k] + for k in set(self.variables) - set(before_variables) + } + current_and_variables_dict[current._id] = new_variables elif isinstance(current, CallActivity): - # TODO implement Variables tab CallActivity + log("DOING:", current) - can_continue = await self.run_subprocess(current.called_element) + can_continue = await current.run_subprocess(self.model, current.called_element, self.variables) + # log("SUBPROCESS DONE WITH VARIABLES\n" + "---> " + str(self.variables)) # Helper variables for DB insert new_variables = { k: self.variables[k] @@ -316,9 +349,10 @@ async def run(self): continue if sequence.condition: - if self.check_condition( + cond = self.check_condition( self.variables, sequence.condition, log - ): + ) + if cond: next_tasks.append(elements[sequence.target]) else: next_tasks.append(elements[sequence.target]) @@ -335,7 +369,9 @@ async def run(self): if isinstance(next_task, ParallelGateway): next_task.add_token() else: + log("Waiting for user...", self.pending) + queue.append(await in_queue.get()) # Insert finished events into DB @@ -349,10 +385,13 @@ async def run(self): pending=[pending._id for pending in self.pending], activity_variables=current_and_variables_dict[c], ) + if not is_subprocess: + log("WORKFLOW DONE WITH VARIABLES\n" + "---> ") - log("DONE") self.state = "finished" + db_connector.change_instance_state(self._id,state=self.state) self.pending = [] # Running instance finished db_connector.finish_running_instance(self._id) + return self.variables diff --git a/bpmn_types.py b/bpmn_types.py index 21f0cab..6944f01 100644 --- a/bpmn_types.py +++ b/bpmn_types.py @@ -1,7 +1,20 @@ +import asyncio +from copy import deepcopy +from uuid import uuid4 +from xml import etree + +import aiohttp import requests import os + +import xml.etree.ElementTree as ET + +from aiohttp import ContentTypeError, ClientSession, ClientTimeout + import env -from utils.common import parse_expression +from bpmn_model import * + +from utils.common import parse_expression, nested_dict_get, nested_dict_set NS = { "bpmn": "http://www.omg.org/spec/BPMN/20100524/MODEL", @@ -10,6 +23,8 @@ BPMN_MAPPINGS = {} +timeout = ClientTimeout(sock_connect=5) + def bpmn_tag(tag): def wrap(object): @@ -82,6 +97,30 @@ class Task(BpmnObject): def parse(self, element): super(Task, self).parse(element) + def _parse_input_output_variables(self, element, input_dict, output_dict): + for io in element.findall(".camunda:inputOutput", NS): + for inparam in io.findall(".camunda:inputParameter", NS): + self._parse_input_output_parameters(inparam, input_dict) + for outparam in io.findall(".camunda:outputParameter", NS): + self._parse_input_output_parameters(outparam, output_dict) + + def _parse_input_output_parameters(self, element, dictionary): + if element.findall(".camunda:list", NS): + helper_list = [] + for lv in element.find("camunda:list", NS): + helper_list.append(lv.text) if lv.text else "" + dictionary[element.attrib["name"]] = helper_list + elif element.findall(".camunda:map", NS): + helper_dict = {} + for mv in element.find("camunda:map", NS): + helper_dict[mv.attrib["key"]] = mv.text + dictionary[element.attrib["name"]] = helper_dict + elif element.findall(".camunda:script", NS): + # script not supported + pass + else: + dictionary[element.attrib["name"]] = element.text if element.text else "" + def get_info(self): return {"type": self.tag} @@ -178,30 +217,6 @@ def parse(self, element): self.connector_fields["connector_id"] = ds["type"] self.connector_fields["input_variables"]["base_url"] = ds["url"] - def _parse_input_output_variables(self, element, input_dict, output_dict): - for io in element.findall(".camunda:inputOutput", NS): - for inparam in io.findall(".camunda:inputParameter", NS): - self._parse_input_output_parameters(inparam, input_dict) - for outparam in io.findall(".camunda:outputParameter", NS): - self._parse_input_output_parameters(outparam, output_dict) - - def _parse_input_output_parameters(self, element, dictionary): - if element.findall(".camunda:list", NS): - helper_list = [] - for lv in element.find("camunda:list", NS): - helper_list.append(lv.text) if lv.text else "" - dictionary[element.attrib["name"]] = helper_list - elif element.findall(".camunda:map", NS): - helper_dict = {} - for mv in element.find("camunda:map", NS): - helper_dict[mv.attrib["key"]] = mv.text - dictionary[element.attrib["name"]] = helper_dict - elif element.findall(".camunda:script", NS): - # script not supported - pass - else: - dictionary[element.attrib["name"]] = element.text if element.text else "" - async def run_connector(self, variables, instance_id): # Check for URL parameters parameters = {} @@ -214,8 +229,9 @@ async def run_connector(self, variables, instance_id): # JSON data for API data = {} - for key, value in self.input_variables.items(): + for key, val in self.input_variables.items(): # Parse expression if it exists + value = val or key if isinstance(value, str): value = parse_expression(value, variables) elif isinstance(value, list): @@ -233,37 +249,59 @@ async def run_connector(self, variables, instance_id): url = os.path.join( self.connector_fields["input_variables"].get("base_url", ""), - self.connector_fields["input_variables"]["url"].lstrip("/"), + (self.connector_fields["input_variables"].get("url") or "").lstrip("/"), ) # Check method and make request - if method := self.connector_fields["input_variables"].get("method"): - if method == "POST": - call_function = requests.post - elif method == "PATCH": - call_function = requests.patch - else: - call_function = requests.get - - response = call_function( - url, - params=parameters, - json=data, - ) - - if response.status_code not in (200, 201): - raise Exception(response.text) - - # Check for output variables - if self.output_variables: - r = response.json() - for key in self.output_variables: - if key in r: - variables[key] = r[key] + async with aiohttp.ClientSession(timeout=timeout) as client_session: + if method := self.connector_fields["input_variables"].get("method") or "GET": + if method == "POST": + call_function = client_session.post + elif method == "PATCH": + call_function = client_session.patch + else: + call_function = client_session.get + if not isinstance(data, dict): + data = dict(data) + response = await call_function( + url, + params=parameters, + json=data, + headers={'content-type': 'application/json'} + ) + if response.status not in (200, 201): + raise Exception(response.text) + + r = {} + try: + r = await response.json() + except Exception as e: + print("error") + if not isinstance(e, ContentTypeError): + raise e + + # Check for output variables + + if self.output_variables: + for key in self.output_variables: + value = self.output_variables.get(key) + try: + if len(value) > 0: + variables[key] = parse_expression(expression=value, process_variables=r) + except Exception: + print("error") + if key in r: + variables[key] = r[key] + + # print(variables) + return r async def run(self, variables, instance_id): - if self.connector_fields["connector_id"] == "http-connector": + + if self.connector_fields["connector_id"] == "http-connector" and len(self.connector_fields["connector_id"]) > 0: await self.run_connector(variables, instance_id) + else: + return False return True @@ -273,23 +311,132 @@ def parse(self, element): super(SendTask, self).parse(element) +@bpmn_tag("bpmn:receiveTask") +class ReceiveTask(Task): + def __init__(self): + self.documentation = "" + self.input_variables = {} + self.output_variables = {} + + def parse(self, element): + + super(ReceiveTask, self).parse(element) + for ee in element.findall(".//bpmn:extensionElements", NS): + # Find direct children inputOutput, Input/Output tab in Camunda + self._parse_input_output_variables( + ee, self.input_variables, self.output_variables + ) + for d in element.findall(".//bpmn:documentation", NS): + self.documentation = d.text + + def run(self, state, user_input): + if isinstance(state, dict) and isinstance(user_input, dict): + for key in self.output_variables: + if key in user_input: + state[key] = user_input[key] + return True + + def get_info(self): + info = super(ReceiveTask, self).get_info() + return { + **info, + "documentation": self.documentation, + } + + @bpmn_tag("bpmn:callActivity") class CallActivity(Task): def __init__(self): + super().__init__() self.deployment = False self.called_element = "" + self.output_variables = {} + self.input_variables = {} + # + # {source:target} + self.in_mapping = {} + self.out_mapping = {} def parse(self, element): super(CallActivity, self).parse(element) if element.attrib.get("calledElement"): self.called_element = element.attrib["calledElement"] if ( - element.attrib.get(f"{{{NS['camunda']}}}calledElementBinding") - and element.attrib.get(f"{{{NS['camunda']}}}calledElementBinding") - == "deployment" + element.attrib.get(f"{{{NS['camunda']}}}calledElementBinding") + and element.attrib.get(f"{{{NS['camunda']}}}calledElementBinding") + == "deployment" ): self.deployment = True + for ee in element.findall(".//bpmn:extensionElements", NS): + # Find direct children inputOutput, Input/Output tab in Camunda + self._parse_mappings(ee, self.in_mapping, self.out_mapping) + + self._parse_input_output_variables( + ee, self.input_variables, self.output_variables + ) + + def transform_input_variables(self, dict_to_transform): + for source, target in self.in_mapping.items(): + if "." in str(source): + nested_value = nested_dict_get(dict_to_transform, str(source)) + dict_to_transform.pop(str(source).split(".")[0]) + dict_to_transform[target] = nested_value + if source in self.input_variables: + dict_to_transform[target] = dict_to_transform.pop(source) + + def transform_output_variables(self, dict_to_transform): + for source, target in self.out_mapping.items(): + if "." in str(source): + nested_value = nested_dict_get(dict_to_transform, str(source)) + dict_to_transform[target] = nested_value + if source in dict_to_transform: + dict_to_transform[target] = dict_to_transform.pop(source) + + def _parse_mappings(self, ee, in_dict, out_dict): + for io in ee.findall(".camunda:in", NS): + self._parse_in_out_mapping(io, in_dict) + for out in ee.findall(".camunda:out", NS): + self._parse_in_out_mapping(out, out_dict) + + def _parse_in_out_mapping(self, element, dictionary): + dictionary[element.attrib["source"]] = element.attrib["target"] + + async def run_subprocess(self, parent_model, process_id, parent_variables): + new_subproces_instance_id = str(uuid4()) + inital_variables = {} + copied = deepcopy(parent_variables) + self.transform_input_variables(copied) + for key in self.input_variables: + if key in copied: + inital_variables[key] = copied[key] + + if not parent_model.subprocesses[process_id]: + new_subprocess_instance: BpmnInstance = await parent_model.create_instance( + new_subproces_instance_id, inital_variables, process_id + ) + + finished_subprocess_variables = await new_subprocess_instance.run(is_subprocess=True) + else: + subprocess_model = BpmnModel(parent_model.subprocesses[process_id]) + new_subprocess_instance: BpmnInstance = await subprocess_model.create_instance( + new_subproces_instance_id, inital_variables, process_id + ) + finished_subprocess_variables = await new_subprocess_instance.run(is_subprocess=True) + + if finished_subprocess_variables is not None: + new_vars = dict(deepcopy(finished_subprocess_variables)) + # todo: check this + # if my process outputs "status" in new vars i need to transform it to "ticket_status" + # as im expecting "ticket_status" in output_variables + # lol this confused me + self.transform_output_variables(new_vars) + for key in self.output_variables: + if key in new_vars: + parent_variables[key] = new_vars[key] + + return finished_subprocess_variables is not None + @bpmn_tag("bpmn:businessRule") class BusinessRule(ServiceTask): @@ -332,6 +479,11 @@ def run(self): return self.incoming == 0 +@bpmn_tag("bpmn:inclusiveGateway") +class InclusiveGateway(Gateway): + pass + + @bpmn_tag("bpmn:exclusiveGateway") class ExclusiveGateway(Gateway): def __init__(self): diff --git a/db_connector.py b/db_connector.py index 716d5e7..14550f5 100644 --- a/db_connector.py +++ b/db_connector.py @@ -1,5 +1,10 @@ +from typing import Union, Any + from pony.orm import * from datetime import datetime + +from pony.orm.core import EntityMeta + import env import os @@ -16,8 +21,11 @@ class Event(DB.Entity): class RunningInstance(DB.Entity): - running = Required(bool) + state = Required(str) + ran_as_subprocess = Required(bool) instance_id = Required(str, unique=True) + # maybe need this + # initiator_instance_id = Optional(str) def setup_db(): @@ -26,13 +34,13 @@ def setup_db(): if env.DB["provider"] == "postgres": DB.bind(**env.DB) else: - DB.bind(provider="sqlite", filename="database/database.sqlite", create_db=True) + DB.bind(provider="sqlite", filename="database/database2.sqlite", create_db=True) DB.generate_mapping(create_tables=True) @db_session def add_event( - model_name, instance_id, activity_id, timestamp, pending, activity_variables + model_name, instance_id, activity_id, timestamp, pending, activity_variables ): Event( model_name=model_name, @@ -45,8 +53,13 @@ def add_event( @db_session -def add_running_instance(instance_id): - RunningInstance(instance_id=instance_id, running=True) +def add_running_instance(instance_id, ran_as_subprocess=False, state="initialized"): + RunningInstance(instance_id=instance_id, state=state, ran_as_subprocess=ran_as_subprocess) + + +@db_session +def change_instance_state(instance_id, state="initialized"): + RunningInstance[instance_id].state = state @db_session @@ -56,12 +69,21 @@ def finish_running_instance(instance): @db_session -def get_running_instances_log(): +def get_instances_log(state=None): log = [] - running_instances = RunningInstance.select(lambda ri: ri.running == True)[:] + running_instances = None + + if state is not None: + state_query = lambda ri: ri.state == state + running_instances = RunningInstance.select(state_query)[:] + else: + running_instances = RunningInstance.select()[:] + for instance in running_instances: instance_dict = {} instance_dict[instance.instance_id] = {} + instance_dict[instance.instance_id]["subprocess"] = instance.ran_as_subprocess + instance_dict[instance.instance_id]["state"] = instance.state events = Event.select(lambda e: e.instance_id == instance.instance_id).order_by( Event.timestamp )[:] @@ -79,3 +101,27 @@ def get_running_instances_log(): log.append(instance_dict) return log + + +@db_session +def get_instance(id): + instance_dict = {} + + db_instance: RunningInstance = RunningInstance.get(instance_id=id) + instance_dict["subprocess"] = db_instance.ran_as_subprocess + instance_dict["instance.state"] = db_instance.state + events = Event.select(lambda e: e.instance_id == id).order_by( + Event.timestamp + )[:] + events_list = [] + for event in events: + model_path = event.model_name + event_dict = {} + event_dict["activity_id"] = event.activity_id + event_dict["pending"] = event.pending + event_dict["activity_variables"] = event.activity_variables + events_list.append(event_dict) + instance_dict["model_path"] = model_path + instance_dict["events"] = events_list + instance_dict["running"] = db_instance.running + return instance_dict diff --git a/env.template.py b/env.template.py index af30f60..c5d8e2a 100644 --- a/env.template.py +++ b/env.template.py @@ -1,13 +1,20 @@ SYSTEM_VARS = {"_frontend_url": "http://localhost:9001"} DB = { - "provider": "postgres", - "user": "FILLME", - "password": "FILLME", + "provider": "sqlite", + "user": "postgres", + "password": "root", "host": "localhost", - "database": "bpmn_praksa", + "database": "a2", } DS = { "airtable": {"type": "http-connector", "url": "http://0.0.0.0:8082"}, "notification": {"type": "http-connector", "url": "http://0.0.0.0:8081"}, "pdf": {"type": "http-connector", "url": "http://0.0.0.0:8083"}, + "test": {"type": "http-connector", "url": "http://212.183.159.230/"}, + "scraper": {"type": "http-connector", "url": "http://172.17.0.1:60194"}, + "keyword_score_service": {"type": "http-connector", "url": "http://172.17.0.1:19770"}, + "dart_db": {"type": "http-connector", "url": "http://172.17.0.1:60194"}, + "db_connector_python": {"type": "http-connector", "url": "http://172.17.0.1:57881"}, + "meta_desc_gen_service": {"type": "http-connector", "url": "http://172.17.0.1:1307"}, } +# http://212.183.159.230/ diff --git a/example.py b/example.py index 95352cf..5972fe7 100644 --- a/example.py +++ b/example.py @@ -4,7 +4,7 @@ import sys -m = BpmnModel("models/model_01.bpmn") +m = BpmnModel("models/private/model_01.bpmn") NUM_INSTANCES = 2 diff --git a/models/meta_desc_generator.bpmn b/models/meta_desc_generator.bpmn new file mode 100644 index 0000000..c910eb2 --- /dev/null +++ b/models/meta_desc_generator.bpmn @@ -0,0 +1,223 @@ + + + + + + + + Flow_1fomewo + + + + + + + + + Flow_0015fxf + Flow_11e8ue1 + + + Flow_0vs55ro + Flow_1m468i0 + Flow_11e8ue1 + + + + + + POST + /checkGenerationExists + + db_connector_python + + + + + + + + + Flow_1ji1ax5 + Flow_0vs55ro + + + exists:true + + + + + + + POST + /getResult + + db_connector_python + + + + + + + + + Flow_1m468i0 + Flow_0dqcaro + + + + + + POST + /saveMetaDesc + + db_connector_python + + + + + + + Flow_0tp54c8 + Flow_0015fxf + + + + + + POST + /startDescSession + + db_connector_python + + + + + + ${data.doc_id} + + + Flow_0dqcaro + Flow_1y6vtsb + + + + + + POST + /generate + + meta_desc_gen_service + + + + ${data.summarized} + + + Flow_1y6vtsb + Flow_0tp54c8 + + + + + + + + + + + + + Flow_1fomewo + Flow_1ji1ax5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/models/private/diagram_1.bpmn b/models/private/diagram_1.bpmn new file mode 100644 index 0000000..7ea683e --- /dev/null +++ b/models/private/diagram_1.bpmn @@ -0,0 +1,291 @@ + + + + + + + + + option + Event_0wfjns7 + Gateway_1inkrgm + Event_1h94889 + middle + Activity_0vefuka + Activity_1x2zly5 + down + up + Gateway_0esshpu + up_a + Event_0525vgw + Activity_03l2pph + Gateway_0l9h8s3 + rt + manualt + + + + + + + + + Flow_0iettuo + Flow_002fsf6 + + + Flow_0iettuo + + + Flow_1i48xnl + Flow_1gulh84 + Flow_0xhtft0 + + + Flow_0jkrd5h + Flow_08y9i80 + Flow_1yop6yn + + + + + ${testinput} + + + Flow_0xhtft0 + Flow_0g741c8 + + + + + + GET + + + test + + + ${testinput} + + + Flow_0g741c8 + Flow_1rtwzf5 + + + + + + GET + + + test + + + Flow_1rtwzf5 + Flow_0jkrd5h + + + + + + + + Flow_1i48xnl + + + + + + + + Flow_08qrnf6 + Flow_08y9i80 + + + Flow_1gulh84 + Flow_08qrnf6 + Flow_1wdulu6 + + + + + + + + Flow_1wdulu6 + Flow_1yop6yn + + + + + + + + + + + + + + + + Flow_1g28ub4 + + + + + + GET + + + test + + + Flow_0g07yug + Flow_1g28ub4 + + + Flow_002fsf6 + Flow_0g07yug + Flow_05h6gge + + + + + + ${testinput} + + + + + + Flow_05h6gge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/models/private/meta_desc_gen.bpmn b/models/private/meta_desc_gen.bpmn new file mode 100644 index 0000000..0f0addb --- /dev/null +++ b/models/private/meta_desc_gen.bpmn @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + Flow_1fomewo + Flow_1ji1ax5 + + + Flow_1fomewo + + + + + + + + + + + + POST + /startSession + + dart_db + + + + + + + + Flow_1ji1ax5 + Flow_1y6vtsb + + + + + + ${data.results} + ${data.urls} + ${data.bulk} + + + + POST + /scrape + + scraper + + + Flow_1y6vtsb + Flow_1kn5m6k + + + bulk:false + + + Flow_1kn5m6k + Flow_1xl9jk8 + Flow_0e8t4n5 + + + bulk:true + + + + + + + + + + /test + POST + + keyword_score_service + + + Flow_1xl9jk8 + Flow_02lt03j + + + Flow_0015fxf + + + + + + POST + /saveResults + + dart_db + + + + + ${urls} + + + + + Flow_02lt03j + Flow_0e8t4n5 + Flow_0015fxf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/models/model_01.bpmn b/models/private/model_01.bpmn similarity index 100% rename from models/model_01.bpmn rename to models/private/model_01.bpmn diff --git a/models/private/spam_test.bpmn b/models/private/spam_test.bpmn new file mode 100644 index 0000000..e266690 --- /dev/null +++ b/models/private/spam_test.bpmn @@ -0,0 +1,79 @@ + + + + + + + + + + + Flow_0t55lv0 + + + + + + GET + 5MB.zip + + test + + + Flow_0t55lv0 + Flow_1jpuxxm + Flow_0c2r0ko + + + + + + GET + 20MB.zip + + test + + + Flow_0c2r0ko + Flow_1jpuxxm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/models/private/strucna_praksa.bpmn b/models/private/strucna_praksa.bpmn new file mode 100644 index 0000000..077d4fd --- /dev/null +++ b/models/private/strucna_praksa.bpmn @@ -0,0 +1,802 @@ + + + + + + + + + razgovor_za_praksu_poslodavac + evaluacija_poslodavac + student_prihvacen + obavijest_odbijanje + + + ispunjavanje_prijavnice_student + end_event_student + predavanje_dnevnika_student + start_event_student + odabiranje_zadatka_student + + + obavjestavanje_alociranje_student_slack + Gateway_1v1zql0 + obavjestavanje_studenta_slack_poslodavac + obavjestavanje_studenta_email_poslodavac + Gateway_022ukch + azuriranje_airtable_student + slanje_potvrde_slack_profesor + Gateway_0q2wy8q + Gateway_1b8kjb9 + slanje_potvrde_email_profesor + kreiranje_potvrde_profesor + azuriranje_podataka_profesor + obavjestavanje_alociranje_student + obavjestavanje_poslodavca_student + uzimanje_podataka_o_poslodavcu_student + potvrda_alociranja_profesor + alociranje_profesor + studentske_pref + + + + + + + + + + + + + + + + kandidat_odobren:true + + + + + kandidat_odobren:false + + + + + + + Flow_0ti6tpk + Flow_0lsghyt + + + Prvo trebate manualno alocirati studenta, te nakon toga potvrdite + + + + + + + + + + Flow_0lsghyt + Flow_07vs9rk + + + + + + + + ${student_id} + + + /allocation + GET + + airtable + + + + + + + + + Flow_07vs9rk + Flow_1vwqbxk + + + Dobro došli na stručnu studentsku praksu. U prvom koraku odabirete svoje preferencije prema listi ponuđenih zadataka i poslodavaca. + +Možete izraziti do tri preferencije. Na prvo mjesto stavite svoj prvi odabir. + +Dostupne prakse možete vidjeti na https://bit.ly/... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Flow_12zi41o + SequenceFlow_0v5m4rx + Flow_1duw845 + + + Flow_12zi41o + + + + + + /email + POST + + + ${poslodavac_email} + poslodavac_after_allocation + + + + notification + + + evaluacija_poslodavac + ${email_student} + ${ime_student} + ${godina_studija} + + + + Flow_1vwqbxk + Flow_0looqv9 + + + + + + /email + POST + + + ${email_student} + student_after_allocation + + + + notification + + + ${poslodavac_email} + ${kompanija} + ${opis_posla} + + + Flow_0looqv9 + Flow_177v773 + + + Flow_0eu1nfh + Flow_1rdv20r + Flow_1npalzz + + + + + + + + + + + + Flow_1cx42m5 + Flow_0eu1nfh + + + Template za dnevnik dostupan je na http://bit.ly/fipu-praksa-template +Dnevnik je potrebno predati prije prijave ispitnoga roka. + + + + + + + + + + + + + + + + + + + + + Flow_03i13r1 + Flow_1btfl5a + + + + + + /prijavnica + POST + + + ${student_id} + + + + airtable + + + ${potvrda_kontaktiranja} + ${dogovoreni_broj_sati} + ${detaljni_opis_zadatka} + ${poslodavac_id} + ${pocetak_prakse} + ${kraj_prakse} + ${mobitel} + ${oib} + ${mentor} + ${mentor_mail} + + + + Flow_1l8y47v + Flow_1bua3l7 + + + + + + /potvrda + POST + + pdf + + + ${email_student} + ${mobitel} + ${pocetak_prakse} + ${kraj_prakse} + ${oib} + ${mentor} + ${dogovoreni_broj_sati} + ${ime_student} + ${kompanija} + ${detaljni_opis_zadatka} + + + + + Flow_1bua3l7 + Flow_1g3f3ei + + + + + + + + ${email_student} + student_pdf + + + /email + POST + + notification + + + potvrda.pdf + + predavanje_dnevnika_student + ${attachment_url} + + + Flow_0rr5pyh + Flow_1jgq625 + + + Flow_1g3f3ei + Flow_0rr5pyh + + + Flow_1jgq625 + Flow_03i13r1 + + + + + + http://127.0.0.1:8090/notify/student/potvrda/pdf + POST + + + ${email_student} + + + + http-connector + + + + predavanje_dnevnika_student + ${attachment_url} + + + + + + + + /dnevnik + POST + + + ${prijavnica_id} + + + + airtable + + + ${nastavak_rada} + ${potvrda_attachment} + ${dnevnik_attachment} + + + Flow_1btfl5a + Flow_1cvohty + + + Flow_1cvohty + + + Flow_1rdv20r + Flow_10qrmyc + + + + + + /email + POST + + + ${email_student} + Approve + student_after_approval + + + + notification + + + ispunjavanje_prijavnice_student + + ${kompanija} + + + Flow_10qrmyc + Flow_0k988op + + + + + + POST + + + ${email_student} + + + http://127.0.0.1:8090/notify/student/after/approval + + http-connector + + + ispunjavanje_prijavnice_student + + + + + + Flow_0k988op + Flow_1ry7vwa + + + VAŽNO: Prijavnica se popunjava nakon (!) što nastavnik odobri kontakt određenom poduzeću i nakon što student s tim poduzećem dogovori praksu. Popunjenu prijavnicu šaljemo poduzeću na odobrenje i potpis. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Flow_1ry7vwa + Flow_1l8y47v + + + Flow_0kt3aem + Flow_177v773 + Flow_1cx42m5 + + + + + + http://127.0.0.1:8090//notify/student/after/allocation + POST + + + ${email_student} + + + + http-connector + + + ${poslodavac_email} + ${opis_posla} + ${kompanija} + + + Flow_0kt3aem + + + + + + /email + POST + + + ${email_student} + Reject + student_after_approval + + + + notification + + + ispunjavanje_prijavnice_student + + + + + Flow_1npalzz + SequenceFlow_0v5m4rx + + + + + + + + + POST + /student-preference + + airtable + + + ${napomena} + ${zeljeni_poslodavci} + ${godina_studija} + ${ime_student} + ${JMBAG} + ${email_student} + + + + + + Flow_1duw845 + Flow_0ti6tpk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/models/private/subprocess_test.bpmn b/models/private/subprocess_test.bpmn new file mode 100644 index 0000000..24b3815 --- /dev/null +++ b/models/private/subprocess_test.bpmn @@ -0,0 +1,158 @@ + + + + + + + + + Flow_0jd6o4s + + + + + + GET + + + test + + + Flow_0jd6o4s + Flow_0kv37am + + + + + ${time} + + + + + Flow_0kv37am + Flow_1s2pndl + + + Flow_0hgqpj8 + + + + + + + + + + GET + + + test + + + Flow_1s2pndl + Flow_0hgqpj8 + + + + + + + Flow_17poo2h + + + Flow_1mg4kow + + + + + + GET + + + test + + + Flow_1mg4kow + Flow_01x5waz + + + + + ${time} + + + Flow_01x5waz + Flow_17poo2h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/models/private/ticketing.bpmn b/models/private/ticketing.bpmn new file mode 100644 index 0000000..2d24186 --- /dev/null +++ b/models/private/ticketing.bpmn @@ -0,0 +1,931 @@ + + + + + + + + + Event_0f1jra8 + Gateway_1p2wrzn + Gateway_1ovp5w8 + Gateway_1de1jmk + zatvori_ticket_job + zatvori_ticket + provjera + Activity_1eq422r + Activity_115syfs + Activity_1uerjsf + Gateway_1564up3 + Activity_0130ec0 + potvrda_dodjele + Gateway_0odd9av + Gateway_0b5f9li + Activity_0fvafbe + Activity_0toh14w + Gateway_08rqdae + Activity_0xxjl2s + Activity_033gbhu + Activity_1643o90 + Activity_0vqcvof + Gateway_1fzwvkz + Activity_12v8dd6 + Activity_1ijx9ch + primi_mail + Activity_0typnak + Gateway_05wo417 + Activity_0w58ase + Activity_1qayqq0 + Activity_1vjleed + Activity_1yflf8w + Activity_0txq8tu + Activity_004j8gr + Activity_1ipxowd + radnik_odgovor_studentu + Activity_1sg89xe + + + zatvori_ticket_student + Activity_1qag9hu + Event_005tjuf + Gateway_0b8ppak + Activity_0evra9t + student_forma + Gateway_15ozh9b + + + + Flow_1gnsc9o + + + Flow_1nb14om + Flow_1gnsc9o + Flow_0ar1rwn + Flow_1n982kb + + + Flow_1po8wtg + Flow_1j6qcpl + Flow_0svyczs + Flow_0axa5ld + + + Flow_0qcxzcw + Flow_0gfpj4b + Flow_1po8wtg + + + Flow_0spb26m + Flow_119qqkd + + + Flow_0svyczs + Flow_1hehzz7 + + + + + test + + + ${nastavak_rada} + ${potvrda_attachment} + ${dnevnik_attachment} + + + Flow_119qqkd + Flow_0gfpj4b + Flow_061dipz + + + + + test + + + ${nastavak_rada} + ${potvrda_attachment} + ${dnevnik_attachment} + + + Flow_1hehzz7 + Flow_0qcxzcw + + + + + test + + + ${nastavak_rada} + ${potvrda_attachment} + ${dnevnik_attachment} + + + Flow_061dipz + Flow_1nb14om + + + + + test + + + ispunjavanje_prijavnice_student + + ${kompanija} + + + Flow_0ar1rwn + + + + + test + + + ispunjavanje_prijavnice_student + + ${kompanija} + + + Flow_1n982kb + + + Flow_008r62j + Flow_0lnhyj7 + Flow_06is9jd + Flow_046dtum + + + + + test + + + ispunjavanje_prijavnice_student + + ${kompanija} + + + Flow_06is9jd + + + Flow_0wl1dyh + Flow_008r62j + + + Flow_17c5f2k + Flow_05c0doy + Flow_104a55z + + + Flow_1hnzqzn + Flow_0hsk5mi + Flow_14n4m0f + Flow_1j6qcpl + + + + + test + + + ${nastavak_rada} + ${potvrda_attachment} + ${dnevnik_attachment} + + + Flow_05c0doy + Flow_0lnhyj7 + Flow_1my29ph + + + Ticket je napravljen te se čeka na managera da dodjeli radniku + + + test + + + ${napomena} + ${zeljeni_poslodavci} + ${godina_studija} + ${ime_student} + ${JMBAG} + ${email_student} + + + + + + Flow_104a55z + + + Flow_1my29ph + Flow_1yq1601 + Flow_0fli2yh + + + + + test + + + ispunjavanje_prijavnice_student + + ${kompanija} + + + Flow_0fli2yh + + + Flow_03kqyvr + Flow_0geba7o + + + Flow_03kqyvr + + + Ticket je napravljen te se čeka na managera da dodjeli radniku + + + test + + + ${napomena} + ${zeljeni_poslodavci} + ${godina_studija} + ${ime_student} + ${JMBAG} + ${email_student} + + + + + + Flow_1t3pfoq + Flow_1o4c6kj + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + test + + + ispunjavanje_prijavnice_student + + ${kompanija} + + + Flow_06tztz6 + + + Ticket je napravljen te se čeka na managera da dodjeli radniku + + + test + + + ${napomena} + ${zeljeni_poslodavci} + ${godina_studija} + ${ime_student} + ${JMBAG} + ${email_student} + + + + + + Flow_1o4c6kj + Flow_0kbkp3p + + + Flow_0kbkp3p + Flow_06tztz6 + Flow_1drzqj2 + Flow_06yemim + + + + + test + + + ispunjavanje_prijavnice_student + + ${kompanija} + + + Flow_06yemim + + + Flow_1drzqj2 + Flow_0wl1dyh + + + + + ${a} + + + Flow_0geba7o + Flow_1t3pfoq + + + + + test + + + ${nastavak_rada} + ${potvrda_attachment} + ${dnevnik_attachment} + + + Flow_1mcdjus + Flow_1o6mm97 + Flow_1hnzqzn + + + Flow_1yq1601 + Flow_1aqrxco + Flow_1iwp7nr + + + + + + + + Ticket je napravljen te se čeka na managera da dodjeli radniku + + + test + + + ${napomena} + ${zeljeni_poslodavci} + ${godina_studija} + ${ime_student} + ${JMBAG} + ${email_student} + + + + + + Flow_0n7qid1 + Flow_18bdozu + + + Ticket je napravljen te se čeka na managera da dodjeli radniku + + + test + + + ${napomena} + ${zeljeni_poslodavci} + ${godina_studija} + ${ime_student} + ${JMBAG} + ${email_student} + + + + + + Flow_0yhreyh + Flow_18bdozu + Flow_17c5f2k + + + Flow_0bsua64 + Flow_15ge8s8 + Flow_0l97pk5 + + + + + ${a} + + + Flow_0l97pk5 + Flow_0n7qid1 + + + Flow_15ge8s8 + Flow_0yhreyh + + + + + + test + + + ispunjavanje_prijavnice_student + + ${kompanija} + + + Flow_046dtum + + + + + ${a} + + + Flow_1iwp7nr + Flow_0z10y5v + + + + + Flow_0axa5ld + Flow_0bsua64 + Flow_0spb26m + + + + + + Ticket je napravljen te se čeka na managera da dodjeli radniku + + + test + + + ${napomena} + ${zeljeni_poslodavci} + ${godina_studija} + ${ime_student} + ${JMBAG} + ${email_student} + + + + + + Flow_0z10y5v + Flow_00x4tdz + + + Ticket je napravljen te se čeka na managera da dodjeli radniku + + + test + + + ${napomena} + ${zeljeni_poslodavci} + ${godina_studija} + ${ime_student} + ${JMBAG} + ${email_student} + + + + + + Flow_00x4tdz + Flow_1o6mm97 + + + Ticket je napravljen te se čeka na managera da dodjeli radniku + + + test + + + ${napomena} + ${zeljeni_poslodavci} + ${godina_studija} + ${ime_student} + ${JMBAG} + ${email_student} + + + + + + Flow_14n4m0f + + + Flow_1aqrxco + Flow_1mcdjus + + + + + test + + + ispunjavanje_prijavnice_student + + ${kompanija} + + + Flow_0hsk5mi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/models/scraper.bpmn b/models/scraper.bpmn new file mode 100644 index 0000000..6e6b645 --- /dev/null +++ b/models/scraper.bpmn @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + Flow_1fomewo + Flow_1ji1ax5 + + + Flow_1fomewo + + + + + + + + + + + + POST + /startSession + + dart_db + + + + + + + + Flow_1ji1ax5 + Flow_1y6vtsb + + + + + + ${data.results} + ${data.urls} + ${data.bulk} + + + + POST + /scrape + + scraper + + + Flow_1y6vtsb + Flow_1kn5m6k + + + bulk:false + + + Flow_1kn5m6k + Flow_1xl9jk8 + Flow_0e8t4n5 + + + bulk:true + + + + + + + + + + /test + POST + + keyword_score_service + + + Flow_1xl9jk8 + Flow_02lt03j + + + Flow_0015fxf + + + + + + POST + /saveResults + + dart_db + + + + + ${urls} + + + + + Flow_02lt03j + Flow_0e8t4n5 + Flow_0015fxf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/models/scraper2.bpmn b/models/scraper2.bpmn new file mode 100644 index 0000000..3e2c640 --- /dev/null +++ b/models/scraper2.bpmn @@ -0,0 +1,330 @@ + + + + + + + + + + + + + + Flow_1fomewo + Flow_1ji1ax5 + + + Flow_1qz11fk + Flow_0bf8ugz + Flow_0rwpnlo + + + + + + POST + /startSession + + dart_db + + + + + + + + Flow_1ji1ax5 + Flow_1qz11fk + + + + + + POST + /startSession + + dart_db + + + + + + + + Flow_0bf8ugz + Flow_1gsfb1d + + + Flow_1kn5m6k + Flow_1xl9jk8 + Flow_0e8t4n5 + + + + + + + + + + /test + POST + + keyword_score_service + + + Flow_1xl9jk8 + Flow_02lt03j + + + Flow_0015fxf + Flow_0rwpnlo + + + + + + POST + /saveResults + + dart_db + + + + + ${urls} + + + + + Flow_02lt03j + Flow_0e8t4n5 + Flow_0015fxf + + + + + + ${data.results} + ${data.urls} + ${data.bulk} + + + + POST + /scrape + + scraper + + + Flow_1y6vtsb + Flow_1kn5m6k + + + + + + POST + /startSession + + dart_db + + + + + + + Flow_1o5ey4z + Flow_1i3mrr7 + Flow_1y6vtsb + + + Flow_1gsfb1d + Flow_1o5ey4z + Flow_0enjvxq + + + + + + + + + Flow_0enjvxq + Flow_1i3mrr7 + + + Flow_1fomewo + + + + + + + + + bulk:false + + + bulk:true + + + good:true + + + + good:no + + + + premium:true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/requirements.txt b/requirements.txt index af2337c..5138f33 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +pipenv==2022.5.2 aiohttp==3.7.4.post0 aiohttp-cors==0.7.0 async-timeout==3.0.1 @@ -14,4 +15,5 @@ typing-extensions==3.10.0.0 urllib3==1.26.6 yarl==1.6.3 psycopg2==2.9.1 -gunicorn==20.1.0 \ No newline at end of file +gunicorn==20.1.0 +redis-om==0.0.26 \ No newline at end of file diff --git a/runtime.txt b/runtime.txt new file mode 100644 index 0000000..f96c0fa --- /dev/null +++ b/runtime.txt @@ -0,0 +1 @@ +python-3.8.10 \ No newline at end of file diff --git a/server.py b/server.py index f745831..824da37 100644 --- a/server.py +++ b/server.py @@ -1,9 +1,18 @@ +import json +import time +import uuid +from asyncio import sleep +from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor + import aiohttp import os -from aiohttp import web from uuid import uuid4 import asyncio -from bpmn_model import BpmnModel, UserFormMessage, get_model_for_instance +from aiohttp import web, ClientSession, ClientTimeout + +from aiohttp.web_ws import WebSocketResponse + +from bpmn_model import BpmnModel, UserFormMessage, ReceiveMessage import aiohttp_cors import db_connector from functools import reduce @@ -15,25 +24,66 @@ # uuid4 = lambda: 2 # hardcoded for easy testing models = {} -for file in os.listdir("models"): - if file.endswith(".bpmn"): - m = BpmnModel(file) - models[file] = m + +ignored_files = ["scraper2.bpmn", "fipu_ticketing.bpmn"] + + +def create_models(): + global models + for file in os.listdir("models"): + if file.endswith(".bpmn") and file not in ignored_files: + try: + m = BpmnModel(file) + models[file] = m + except Exception as e: + print("Failed creating BPMN model from " + str(file)) + raise e + + return models + + +async def get_model_for_instance(iid): + instance_dict = db_connector.get_instance(id=iid) + + # creates a new empty instance or gets an existing one + instance = await models[instance_dict["model_path"]].create_or_get_instance( + iid, {} + ) + + instance = await instance.run_from_log(instance_dict["events"],instance_dict["state"]) + + return instance async def run_as_server(app): - app["bpmn_models"] = models - log = db_connector.get_running_instances_log() - for l in log: + app["bpmn_models"] = create_models() + # db_connector.DB.drop_all_tables(with_all_data=True) + start_time = time.time() + logs = db_connector.get_instances_log(state="running") + print("Running: " + str(len(logs))) + completed = db_connector.get_instances_log(state=None) + print("Completed: " + str(len(completed))) + print("--- %s seconds ---" % (time.time() - start_time)) + + # return + for l in logs: for key, data in l.items(): if data["model_path"] in app["bpmn_models"]: instance = await app["bpmn_models"][data["model_path"]].create_instance( key, {} ) - instance = await instance.run_from_log(data["events"]) + instance = await instance.run_from_log(data["events"],data["state"]) asyncio.create_task(instance.run()) +# Placeholder for a service task +@routes.get("/test") +async def test_call(request): + print("Called test") + import sys + return web.json_response({"status": "ok", "size": sys.getsizeof(models)}) + + @routes.get("/model") async def get_models(request): data = [m.to_json() for m in models.values()] @@ -57,17 +107,52 @@ async def handle_new_instance(request): return web.json_response({"id": _id}) +@routes.get("/model/{model_name}/instance") +async def handle_new_instance(request): + _id = str(uuid4()) + str(uuid.uuid1()) + + model = request.match_info.get("model_name") + instance = await app["bpmn_models"][model].create_instance(_id, {}) + asyncio.create_task(instance.run()) + return web.json_response({"id": _id}) + + @routes.post("/instance/{instance_id}/task/{task_id}/form") async def handle_form(request): post = await request.json() instance_id = request.match_info.get("instance_id") task_id = request.match_info.get("task_id") - m = get_model_for_instance(instance_id) + m = await get_model_for_instance(instance_id) m.instances[instance_id].in_queue.put_nowait(UserFormMessage(task_id, post)) + return web.json_response({"status": "OK"}) + +@routes.post("/instance/{instance_id}/task/{task_id}/receive") +async def handle_receive_task(request): + data = await request.json() + instance_id = request.match_info.get("instance_id") + task_id = request.match_info.get("task_id") + m = await get_model_for_instance(instance_id) + m.instances[instance_id].in_queue.put_nowait(ReceiveMessage(task_id, data)) return web.json_response({"status": "OK"}) +@routes.post("/model/{model}/task/{task_id}/receive") +async def handle_auto_receive(request): + _id = str(uuid4()) + str(uuid.uuid1()) + + model = request.match_info.get("model") + instance = await app["bpmn_models"][model].create_instance(_id, {}) + asyncio.create_task(instance.run()) + await asyncio.sleep(0.0000000000000000001) + data = await request.json() + instance_id = instance._id + task_id = request.match_info.get("task_id") + m = await get_model_for_instance(instance_id) + m.instances[instance_id].in_queue.put_nowait(ReceiveMessage(task_id, data)) + return web.json_response({"status": "OK", "id_instance": _id}) + + @routes.get("/instance") async def search_instance(request): params = request.rel_url.query @@ -114,7 +199,7 @@ async def search_instance(request): data = [] for _id in ids: - data.append(get_model_for_instance(_id).instances[_id].to_json()) + data.append((await get_model_for_instance(_id)).instances[_id].to_json()) return web.json_response({"status": "ok", "results": data}) @@ -123,7 +208,7 @@ async def search_instance(request): async def handle_task_info(request): instance_id = request.match_info.get("instance_id") task_id = request.match_info.get("task_id") - m = get_model_for_instance(instance_id) + m: BpmnModel = get_model_for_instance(instance_id) if not m: raise aiohttp.web.HTTPNotFound instance = m.instances[instance_id] @@ -135,7 +220,7 @@ async def handle_task_info(request): @routes.get("/instance/{instance_id}") async def handle_instance_info(request): instance_id = request.match_info.get("instance_id") - m = get_model_for_instance(instance_id) + m = await get_model_for_instance(instance_id) if not m: raise aiohttp.web.HTTPNotFound instance = m.instances[instance_id].to_json() @@ -143,10 +228,53 @@ async def handle_instance_info(request): return web.json_response(instance) +@routes.get("/instance/{instance_id}/statews") +async def handle_instance_state_ws(request): + ws: WebSocketResponse = web.WebSocketResponse() + + await ws.prepare(request) + state = "running" + async for msg in ws: + if msg.type == aiohttp.WSMsgType.TEXT: + if msg.data == 'close': + await ws.close() + else: + instance_id = request.match_info.get("instance_id") + + while state != "finished" and not ws.closed: + + m = await get_model_for_instance(instance_id) + if not m: + await ws.close() + instance = m.instances[instance_id].to_json() + + await ws.send_json(({"state": instance["state"]})) + await asyncio.sleep(3) + + elif msg.type == aiohttp.WSMsgType.ERROR: + print('ws connection closed with exception %s' % + ws.exception()) + + print('websocket connection closed') + + return ws + + +@routes.get("/instance/{instance_id}/state") +async def handle_instance_state(request): + instance_id = request.match_info.get("instance_id") + m = await get_model_for_instance(instance_id) + if not m: + raise aiohttp.web.HTTPNotFound + instance = m.instances[instance_id].to_json() + + return web.json_response({"state": instance["state"]}) + + app = None -def run(): +async def run(): global app app = web.Application() app.on_startup.append(run_as_server) @@ -176,4 +304,4 @@ async def serve(): if __name__ == "__main__": app = run() - web.run_app(app, port=9000) + web.run_app(app, port=os.environ.get('PORT', 9000)) diff --git a/utils/common.py b/utils/common.py index ff01d73..cdb47bf 100644 --- a/utils/common.py +++ b/utils/common.py @@ -1,15 +1,41 @@ +import functools +from copy import deepcopy + + class SafeDict(dict): def __missing__(self, key): return "${" + key + "}" def parse_expression(expression, process_variables): - if (key := expression.replace("${", "").replace("}", "")) in process_variables: + key = expression.replace("${", "").replace("}", "") + if key in process_variables: return process_variables[key] + if "." in key: + value = nested_dict_get(process_variables, key) + if value is not None: + return value return expression.replace("${", "{").format_map(SafeDict(process_variables)) +def nested_dict_get(dictionary, dotted_key): + keys = dotted_key.split('.') + return functools.reduce(lambda d, key: d.get(key) if d else None, keys, dictionary) + + +def nested_dict_set(dictionary, dotted_key, value): + # not sure if we need this + keys = dotted_key.split('.') + last = keys.pop() + for k in keys: + dictionary.setdefault(k, {}) + dictionary[last] = value + + if __name__ == "__main__": test = "___${a[nice]}___" + dic = {} + nested_dict_set(dic, "source.payment.status", "failed") + print(dic) print(parse_expression(test, {"a": {"nice": ["OK"]}}))