From a48322ef6ac0af59da3c0ce8725d23ccd623c36b Mon Sep 17 00:00:00 2001 From: Dan Funk Date: Tue, 14 Jul 2020 10:29:25 -0400 Subject: [PATCH] Partial work on CR Connect Roles. Adding checks in the API to assure the correct person is completeing a task based on the task's lane. Adding lane to the Navigation item. Adding a check to assure that unique user ids can be identified using task.data Added some additional ldap entries to make testing and development easier. Removed a big chunk of duplicate code from task_tests_api Modified some of the helper functions to make it easier to test as specific users. Added some additional bpmn models to the tests for testing lanes and roles. --- Pipfile.lock | 130 +++------ crc/api/workflow.py | 50 +++- crc/models/api_models.py | 4 +- crc/services/workflow_service.py | 14 +- tests/base_test.py | 5 +- tests/data/invalid_roles/invalid_roles.bpmn | 177 +++++++++++++ tests/data/ldap_response.json | 275 +++++++++----------- tests/data/roles/roles.bpmn | 155 +++++++++++ tests/test_tasks_api.py | 72 +---- tests/workflow/test_workflow_processor.py | 17 +- 10 files changed, 560 insertions(+), 339 deletions(-) create mode 100644 tests/data/invalid_roles/invalid_roles.bpmn create mode 100644 tests/data/roles/roles.bpmn diff --git a/Pipfile.lock b/Pipfile.lock index cd2c1370..37672182 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -35,7 +35,6 @@ "sha256:24dbaff8ce4f30566bb88976b398e8c4e77637171af3af6f1b9650f48890e60b", "sha256:bb68f8d2bced8f93ccfd07d96c689b716b3227720add971be980accfc2952139" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==2.6.0" }, "aniso8601": { @@ -50,7 +49,6 @@ "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==19.3.0" }, "babel": { @@ -58,7 +56,6 @@ "sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38", "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.8.0" }, "bcrypt": { @@ -82,7 +79,6 @@ "sha256:d7bdc26475679dd073ba0ed2766445bb5b20ca4793ca0db32b399dccc6bc84b7", "sha256:ff032765bb8716d9387fd5376d987a937254b0619eff0972779515b5c98820bc" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==3.1.7" }, "beautifulsoup4": { @@ -111,7 +107,6 @@ "sha256:ef17d7dffde7fc73ecab3a3b6389d93d3213bac53fa7f28e68e33647ad50b916", "sha256:fd77e4248bb1b7af5f7922dd8e81156f540306e3a5c4b1c24167c1f5f06025da" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==4.4.6" }, "certifi": { @@ -166,7 +161,6 @@ "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==7.1.2" }, "clickclick": { @@ -188,7 +182,6 @@ "sha256:2ca44140ee259b5e3d8aaf47c79c36a7ab0d5e94d70bd4105c03ede7a20ea5a1", "sha256:cffc044844040c7ce04e9acd1838b5f2e5fa3170182f6fda4d2ea8b0099dbadd" ], - "markers": "python_version >= '3.6'", "version": "==5.0.0" }, "connexion": { @@ -247,7 +240,6 @@ "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af", "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==0.16" }, "docxtpl": { @@ -330,14 +322,12 @@ "sha256:0b656fbf87c5f24109d859bafa791d29751fabbda2302b606881ae5485b557a5", "sha256:fcfe6df52cd2ed8a63008ca36b86a51fa7a4b70cef1c39e5625f722fca32308e" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.4.3" }, "future": { "hashes": [ "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.18.2" }, "gunicorn": { @@ -360,7 +350,6 @@ "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.10" }, "imagesize": { @@ -368,7 +357,6 @@ "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1", "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.2.0" }, "importlib-metadata": { @@ -384,7 +372,6 @@ "sha256:88b101b2668a1d81d6d72d4c2018e53bc6c7fc544c987849da1c7f77545c3bc9", "sha256:f576e85132d34f5bf7df5183c2c6f94cfb32e528f53065345cf71329ba0b8924" ], - "markers": "python_version >= '3.5'", "version": "==0.5.0" }, "itsdangerous": { @@ -392,7 +379,6 @@ "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.1.0" }, "jdcal": { @@ -407,7 +393,6 @@ "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0", "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==2.11.2" }, "jsonschema": { @@ -422,16 +407,11 @@ "sha256:be48cdffb54a2194d93ad6533d73f69408486483d189fe9f5990ee24255b0e0a", "sha256:ca1b45faac8c0b18493d02a8571792f3c40291cf2bcf1f55afed3d8f3aa7ba74" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==4.6.11" }, "ldap3": { "hashes": [ "sha256:17f04298b70bf7ecaa5db8a7d8622b5a962ef7fc2b245b2eea705ac1c24338c0", - "sha256:298769ab0232b3a3efa1e84881096c24526fe37911c83a11285f222fe4975efd", - "sha256:4fd2db72d0412cc16ee86be01332095e86e361329c3579b314231eb2e56c7871", - "sha256:52ab557b3c4908db4a90bea16731aa714b1b54e039b54fd4c4b83994c6c48c0c", - "sha256:53aaae5bf14f3827c69600ddf4d61b88f49c055bb93060e9702c5bafd206c744", "sha256:81df4ac8b6df10fb1f05b17c18d0cb8c4c344d5a03083c382824960ed959cf5b" ], "index": "pypi", @@ -439,43 +419,42 @@ }, "lxml": { "hashes": [ - "sha256:06748c7192eab0f48e3d35a7adae609a329c6257495d5e53878003660dc0fec6", - "sha256:0790ddca3f825dd914978c94c2545dbea5f56f008b050e835403714babe62a5f", - "sha256:1aa7a6197c1cdd65d974f3e4953764eee3d9c7b67e3966616b41fab7f8f516b7", - "sha256:22c6d34fdb0e65d5f782a4d1a1edb52e0a8365858dafb1c08cb1d16546cf0786", - "sha256:2754d4406438c83144f9ffd3628bbe2dcc6d62b20dbc5c1ec4bc4385e5d44b42", - "sha256:27ee0faf8077c7c1a589573b1450743011117f1aa1a91d5ae776bbc5ca6070f2", - "sha256:2b02c106709466a93ed424454ce4c970791c486d5fcdf52b0d822a7e29789626", - "sha256:2d1ddce96cf15f1254a68dba6935e6e0f1fe39247de631c115e84dd404a6f031", - "sha256:4f282737d187ae723b2633856085c31ae5d4d432968b7f3f478a48a54835f5c4", - "sha256:51bb4edeb36d24ec97eb3e6a6007be128b720114f9a875d6b370317d62ac80b9", - "sha256:7eee37c1b9815e6505847aa5e68f192e8a1b730c5c7ead39ff317fde9ce29448", - "sha256:7fd88cb91a470b383aafad554c3fe1ccf6dfb2456ff0e84b95335d582a799804", - "sha256:9144ce36ca0824b29ebc2e02ca186e54040ebb224292072250467190fb613b96", - "sha256:925baf6ff1ef2c45169f548cc85204433e061360bfa7d01e1be7ae38bef73194", - "sha256:a636346c6c0e1092ffc202d97ec1843a75937d8c98aaf6771348ad6422e44bb0", - "sha256:a87dbee7ad9dce3aaefada2081843caf08a44a8f52e03e0a4cc5819f8398f2f4", - "sha256:a9e3b8011388e7e373565daa5e92f6c9cb844790dc18e43073212bb3e76f7007", - "sha256:afb53edf1046599991fb4a7d03e601ab5f5422a5435c47ee6ba91ec3b61416a6", - "sha256:b26719890c79a1dae7d53acac5f089d66fd8cc68a81f4e4bd355e45470dc25e1", - "sha256:b7462cdab6fffcda853338e1741ce99706cdf880d921b5a769202ea7b94e8528", - "sha256:b77975465234ff49fdad871c08aa747aae06f5e5be62866595057c43f8d2f62c", - "sha256:c47a8a5d00060122ca5908909478abce7bbf62d812e3fc35c6c802df8fb01fe7", - "sha256:c79e5debbe092e3c93ca4aee44c9a7631bdd407b2871cb541b979fd350bbbc29", - "sha256:d8d40e0121ca1606aa9e78c28a3a7d88a05c06b3ca61630242cded87d8ce55fa", - "sha256:ee2be8b8f72a2772e72ab926a3bccebf47bb727bda41ae070dc91d1fb759b726", - "sha256:f95d28193c3863132b1f55c1056036bf580b5a488d908f7d22a04ace8935a3a9", - "sha256:fadd2a63a2bfd7fb604508e553d1cf68eca250b2fbdbd81213b5f6f2fbf23529" + "sha256:05a444b207901a68a6526948c7cc8f9fe6d6f24c70781488e32fd74ff5996e3f", + "sha256:08fc93257dcfe9542c0a6883a25ba4971d78297f63d7a5a26ffa34861ca78730", + "sha256:107781b213cf7201ec3806555657ccda67b1fccc4261fb889ef7fc56976db81f", + "sha256:121b665b04083a1e85ff1f5243d4a93aa1aaba281bc12ea334d5a187278ceaf1", + "sha256:2b30aa2bcff8e958cd85d907d5109820b01ac511eae5b460803430a7404e34d7", + "sha256:4b4a111bcf4b9c948e020fd207f915c24a6de3f1adc7682a2d92660eb4e84f1a", + "sha256:5591c4164755778e29e69b86e425880f852464a21c7bb53c7ea453bbe2633bbe", + "sha256:59daa84aef650b11bccd18f99f64bfe44b9f14a08a28259959d33676554065a1", + "sha256:5a9c8d11aa2c8f8b6043d845927a51eb9102eb558e3f936df494e96393f5fd3e", + "sha256:5dd20538a60c4cc9a077d3b715bb42307239fcd25ef1ca7286775f95e9e9a46d", + "sha256:74f48ec98430e06c1fa8949b49ebdd8d27ceb9df8d3d1c92e1fdc2773f003f20", + "sha256:786aad2aa20de3dbff21aab86b2fb6a7be68064cbbc0219bde414d3a30aa47ae", + "sha256:7ad7906e098ccd30d8f7068030a0b16668ab8aa5cda6fcd5146d8d20cbaa71b5", + "sha256:80a38b188d20c0524fe8959c8ce770a8fdf0e617c6912d23fc97c68301bb9aba", + "sha256:92282c83547a9add85ad658143c76a64a8d339028926d7dc1998ca029c88ea6a", + "sha256:94150231f1e90c9595ccc80d7d2006c61f90a5995db82bccbca7944fd457f0f6", + "sha256:9dc9006dcc47e00a8a6a029eb035c8f696ad38e40a27d073a003d7d1443f5d88", + "sha256:a76979f728dd845655026ab991df25d26379a1a8fc1e9e68e25c7eda43004bed", + "sha256:aa8eba3db3d8761db161003e2d0586608092e217151d7458206e243be5a43843", + "sha256:bea760a63ce9bba566c23f726d72b3c0250e2fa2569909e2d83cda1534c79443", + "sha256:c3f511a3c58676147c277eff0224c061dd5a6a8e1373572ac817ac6324f1b1e0", + "sha256:cc411ad324a4486b142c41d9b2b6a722c534096963688d879ea6fa8a35028258", + "sha256:cdc13a1682b2a6241080745b1953719e7fe0850b40a5c71ca574f090a1391df6", + "sha256:e1cacf4796b20865789083252186ce9dc6cc59eca0c2e79cca332bdff24ac481", + "sha256:e70d4e467e243455492f5de463b72151cc400710ac03a0678206a5f27e79ddef", + "sha256:ecc930ae559ea8a43377e8b60ca6f8d61ac532fc57efb915d899de4a67928efd", + "sha256:f161af26f596131b63b236372e4ce40f3167c1b5b5d459b29d2514bd8c9dc9ee" ], "index": "pypi", - "version": "==4.5.1" + "version": "==4.5.2" }, "mako": { "hashes": [ "sha256:8195c8c1400ceb53496064314c6736719c6f25e7479cd24c77be3d9361cddc27", "sha256:93729a258e4ff0747c876bd9e20df1b9758028946e976324ccd2d68245c7b6a9" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.1.3" }, "markdown": { @@ -522,16 +501,15 @@ "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.1.1" }, "marshmallow": { "hashes": [ - "sha256:35ee2fb188f0bd9fc1cf9ac35e45fd394bd1c153cee430745a465ea435514bd5", - "sha256:9aa20f9b71c992b4782dad07c51d92884fd0f7c5cb9d3c737bea17ec1bad765f" + "sha256:0f3a630f6a2fd124929f1bdcb5df65bd14cc8f49f52a18d0bdcfa0c42414e4a7", + "sha256:ba949379cb6ef73655f72075e82b31cf57012a5557ede642fc8614ab0354f869" ], "index": "pypi", - "version": "==3.6.1" + "version": "==3.7.0" }, "marshmallow-enum": { "hashes": [ @@ -578,7 +556,6 @@ "sha256:df1889701e2dfd8ba4dc9b1a010f0a60950077fb5242bb92c8b5c7f1a6f2668a", "sha256:fa1fe75b4a9e18b66ae7f0b122543c42debcf800aaafa0212aaff3ad273c2596" ], - "markers": "python_version >= '3.6'", "version": "==1.19.0" }, "openapi-spec-validator": { @@ -602,7 +579,6 @@ "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8", "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==20.4" }, "pandas": { @@ -665,19 +641,8 @@ }, "pyasn1": { "hashes": [ - "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359", - "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576", - "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf", - "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7", "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", - "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00", - "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8", - "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86", - "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12", - "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776", - "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", - "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2", - "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3" + "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba" ], "version": "==0.4.8" }, @@ -686,7 +651,6 @@ "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.20" }, "pygments": { @@ -694,7 +658,6 @@ "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44", "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324" ], - "markers": "python_version >= '3.5'", "version": "==2.6.1" }, "pyjwt": { @@ -710,7 +673,6 @@ "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.4.7" }, "pyrsistent": { @@ -737,9 +699,7 @@ "hashes": [ "sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d", "sha256:51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b", - "sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8", - "sha256:c3da2053dbab6b29c94e43c486ff67206eafbe7eb52dbec7390b5e2fb05aac77", - "sha256:ea87e17f6ec459e780e4221f295411462e0d0810858e055fc514684350a2f522" + "sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8" ], "version": "==1.0.4" }, @@ -853,7 +813,6 @@ "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.15.0" }, "snowballstemmer": { @@ -868,7 +827,6 @@ "sha256:1634eea42ab371d3d346309b93df7870a88610f0725d47528be902a0d95ecc55", "sha256:a59dc181727e95d25f781f0eb4fd1825ff45590ec8ff49eadfd7f1a537cc0232" ], - "markers": "python_version >= '3.5'", "version": "==2.0.1" }, "sphinx": { @@ -884,7 +842,6 @@ "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" ], - "markers": "python_version >= '3.5'", "version": "==1.0.2" }, "sphinxcontrib-devhelp": { @@ -892,7 +849,6 @@ "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e", "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4" ], - "markers": "python_version >= '3.5'", "version": "==1.0.2" }, "sphinxcontrib-htmlhelp": { @@ -900,7 +856,6 @@ "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f", "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b" ], - "markers": "python_version >= '3.5'", "version": "==1.0.3" }, "sphinxcontrib-jsmath": { @@ -908,7 +863,6 @@ "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" ], - "markers": "python_version >= '3.5'", "version": "==1.0.1" }, "sphinxcontrib-qthelp": { @@ -916,7 +870,6 @@ "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72", "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6" ], - "markers": "python_version >= '3.5'", "version": "==1.0.3" }, "sphinxcontrib-serializinghtml": { @@ -924,13 +877,12 @@ "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc", "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a" ], - "markers": "python_version >= '3.5'", "version": "==1.1.4" }, "spiffworkflow": { "editable": true, "git": "https://github.com/sartography/SpiffWorkflow.git", - "ref": "e47dbce4147f2475f50ef705eab32a1426540613" + "ref": "bf9fdcd51846126e0acc8eeccad1a16c8b8330ce" }, "sqlalchemy": { "hashes": [ @@ -963,7 +915,6 @@ "sha256:f57be5673e12763dd400fea568608700a63ce1c6bd5bdbc3cc3a2c5fdb045274", "sha256:fc728ece3d5c772c196fd338a99798e7efac7a04f9cb6416299a3638ee9a94cd" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.3.18" }, "swagger-ui-bundle": { @@ -980,7 +931,6 @@ "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527", "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", "version": "==1.25.9" }, "vine": { @@ -988,7 +938,6 @@ "sha256:133ee6d7a9016f177ddeaf191c1f58421a1dcc6ee9a42c58b34bed40e1d2cd87", "sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.3.0" }, "waitress": { @@ -996,7 +945,6 @@ "sha256:1bb436508a7487ac6cb097ae7a7fe5413aefca610550baf58f0940e51ecfb261", "sha256:3d633e78149eb83b60a07dfabb35579c29aac2d24bb803c18b26fb2ab1a584db" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==1.4.4" }, "webob": { @@ -1004,7 +952,6 @@ "sha256:a3c89a8e9ba0aeb17382836cdb73c516d0ecf6630ec40ec28288f3ed459ce87b", "sha256:aa3a917ed752ba3e0b242234b2a373f9c4e2a75d35291dcbe977649bd21fd108" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.8.6" }, "webtest": { @@ -1051,7 +998,6 @@ "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b", "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96" ], - "markers": "python_version >= '3.6'", "version": "==3.1.0" } }, @@ -1061,7 +1007,6 @@ "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==19.3.0" }, "coverage": { @@ -1117,7 +1062,6 @@ "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5", "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2" ], - "markers": "python_version >= '3.5'", "version": "==8.4.0" }, "packaging": { @@ -1125,7 +1069,6 @@ "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8", "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==20.4" }, "pbr": { @@ -1141,7 +1084,6 @@ "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.13.1" }, "py": { @@ -1149,7 +1091,6 @@ "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2", "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.9.0" }, "pyparsing": { @@ -1157,7 +1098,6 @@ "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.4.7" }, "pytest": { @@ -1173,7 +1113,6 @@ "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.15.0" }, "wcwidth": { @@ -1188,7 +1127,6 @@ "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b", "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96" ], - "markers": "python_version >= '3.6'", "version": "==3.1.0" } } diff --git a/crc/api/workflow.py b/crc/api/workflow.py index dc86ac9e..82a4b27f 100644 --- a/crc/api/workflow.py +++ b/crc/api/workflow.py @@ -107,10 +107,11 @@ def delete_workflow(workflow_id): def set_current_task(workflow_id, task_id): workflow_model = session.query(WorkflowModel).filter_by(id=workflow_id).first() - user_uid = __get_user_uid(workflow_model.study.user_uid) processor = WorkflowProcessor(workflow_model) task_id = uuid.UUID(task_id) spiff_task = processor.bpmn_workflow.get_task(task_id) + _verify_user_and_role(workflow_model, spiff_task) + user_uid = g.user.uid if spiff_task.state != spiff_task.COMPLETED and spiff_task.state != spiff_task.READY: raise ApiError("invalid_state", "You may not move the token to a task who's state is not " "currently set to COMPLETE or READY.") @@ -136,15 +137,17 @@ def update_task(workflow_id, task_id, body, terminate_loop=None): elif workflow_model.study is None: raise ApiError("invalid_study", "There is no study associated with the given workflow.", status_code=404) - user_uid = __get_user_uid(workflow_model.study.user_uid) processor = WorkflowProcessor(workflow_model) task_id = uuid.UUID(task_id) spiff_task = processor.bpmn_workflow.get_task(task_id) + _verify_user_and_role(workflow_model, spiff_task) + user_uid = g.user.uid if not spiff_task: raise ApiError("empty_task", "Processor failed to obtain task.", status_code=404) if spiff_task.state != spiff_task.READY: raise ApiError("invalid_state", "You may not update a task unless it is in the READY state. " "Consider calling a token reset to make this task Ready.") + if terminate_loop: spiff_task.terminate_loop() @@ -156,6 +159,9 @@ def update_task(workflow_id, task_id, body, terminate_loop=None): WorkflowService.log_task_action(user_uid, workflow_model, spiff_task, WorkflowService.TASK_ACTION_COMPLETE, version=processor.get_version_string()) workflow_api_model = WorkflowService.processor_to_workflow_api(processor) + + # If the next task + return WorkflowApiSchema().dump(workflow_api_model) @@ -210,13 +216,37 @@ def lookup(workflow_id, field_id, query=None, value=None, limit=10): return LookupDataSchema(many=True).dump(lookup_data) -def __get_user_uid(user_uid): - if 'user' in g: - if g.user.uid not in app.config['ADMIN_UIDS'] and user_uid != g.user.uid: - raise ApiError("permission_denied", "You are not authorized to edit the task data for this workflow.", - status_code=403) - else: - return g.user.uid +def _verify_user_and_role(workflow_model, spiff_task): + """Assures the currently logged in user can access the given workflow and task, or + raises an error. + Allow administrators to modify tasks, otherwise assure that the current user + is allowed to edit or update the task. Will raise the appropriate error if user + is not authorized. """ - else: + if 'user' not in g: raise ApiError("logged_out", "You are no longer logged in.", status_code=401) + + if g.user.uid in app.config['ADMIN_UIDS']: + return g.user.uid + + # If the task is in a lane, determine the user from that value. + if spiff_task.task_spec.lane is not None: + if spiff_task.task_spec.lane not in spiff_task.data: + raise ApiError.from_task("invalid_role", + f"This task is in a lane called '{spiff_task.task_spec.lane}', The " + f" current task data must have information mapping this role to " + f" a unique user id.", spiff_task) + user_id = spiff_task.data[spiff_task.task_spec.lane] + if g.user.uid != user_id: + raise ApiError.from_task("role_permission", + f"This task is in a lane called '{spiff_task.task_spec.lane}' which" + f" must be completed by '{user_id}', but you are {g.user.uid}", spiff_task) + return + elif g.user.uid == workflow_model.study.user_uid: + return + + # todo: If other users as associated with the study, and were granted access, allow them to modify tasks as well + + raise ApiError("permission_denied", "You are not authorized to edit the task data for this workflow.", + status_code=403, task_id=spiff_task.id, task_name=spiff_task.name, task_data=spiff_task.data) + diff --git a/crc/models/api_models.py b/crc/models/api_models.py index bb99eebb..e4d8425b 100644 --- a/crc/models/api_models.py +++ b/crc/models/api_models.py @@ -29,6 +29,7 @@ class NavigationItem(object): self.state = state self.is_decision = is_decision self.task = task + self.lane = lane class Task(object): @@ -107,10 +108,11 @@ class TaskSchema(ma.Schema): class NavigationItemSchema(ma.Schema): class Meta: fields = ["id", "task_id", "name", "title", "backtracks", "level", "indent", "child_count", "state", - "is_decision", "task"] + "is_decision", "task", "lane"] unknown = INCLUDE task = marshmallow.fields.Nested(TaskSchema, dump_only=True, required=False, allow_none=True) backtracks = marshmallow.fields.String(required=False, allow_none=True) + lane = marshmallow.fields.String(required=False, allow_none=True) title = marshmallow.fields.String(required=False, allow_none=True) task_id = marshmallow.fields.String(required=False, allow_none=True) diff --git a/crc/services/workflow_service.py b/crc/services/workflow_service.py index 157c4c13..18f88f4c 100644 --- a/crc/services/workflow_service.py +++ b/crc/services/workflow_service.py @@ -92,11 +92,16 @@ class WorkflowService(object): processor.bpmn_workflow.do_engine_steps() tasks = processor.bpmn_workflow.get_tasks(SpiffTask.READY) for task in tasks: + if task.task_spec.lane is not None and task.task_spec.lane not in task.data: + raise ApiError.from_task("invalid_role", + f"This task is in a lane called '{task.task_spec.lane}', The " + f" current task data must have information mapping this role to " + f" a unique user id.", task) task_api = WorkflowService.spiff_task_to_api_task( task, add_docs_and_forms=True) # Assure we try to process the documenation, and raise those errors. WorkflowService.populate_form_with_random_data(task, task_api, required_only) - task.complete() + processor.complete_task(task) except WorkflowException as we: WorkflowService.delete_test_data() raise ApiError.from_workflow_exception("workflow_validation_exception", str(we), we) @@ -195,25 +200,24 @@ class WorkflowService(object): possible, next_task is set to the current_task.""" nav_dict = processor.bpmn_workflow.get_nav_list() + + # Some basic cleanup of the title for the for the navigation. navigation = [] for nav_item in nav_dict: spiff_task = processor.bpmn_workflow.get_task(nav_item['task_id']) if 'description' in nav_item: nav_item['title'] = nav_item.pop('description') # fixme: duplicate code from the workflow_service. Should only do this in one place. - if ' ' in nav_item['title']: + if nav_item['title'] is not None and ' ' in nav_item['title']: nav_item['title'] = nav_item['title'].partition(' ')[2] else: nav_item['title'] = "" if spiff_task: nav_item['task'] = WorkflowService.spiff_task_to_api_task(spiff_task, add_docs_and_forms=False) nav_item['title'] = nav_item['task'].title # Prefer the task title. - else: nav_item['task'] = None - if not 'is_decision' in nav_item: - nav_item['is_decision'] = False navigation.append(NavigationItem(**nav_item)) NavigationItemSchema().dump(nav_item) diff --git a/tests/base_test.py b/tests/base_test.py index 116df5a2..2ead9e43 100644 --- a/tests/base_test.py +++ b/tests/base_test.py @@ -263,13 +263,13 @@ class BaseTest(unittest.TestCase): return full_study - def create_workflow(self, workflow_name, study=None, category_id=None): + def create_workflow(self, workflow_name, study=None, category_id=None, as_user="dhf8r"): db.session.flush() spec = db.session.query(WorkflowSpecModel).filter(WorkflowSpecModel.name == workflow_name).first() if spec is None: spec = self.load_test_spec(workflow_name, category_id=category_id) if study is None: - study = self.create_study() + study = self.create_study(uid=as_user) workflow_model = StudyService._create_workflow_model(study, spec) return workflow_model @@ -313,6 +313,7 @@ class BaseTest(unittest.TestCase): self.assertEqual(workflow.workflow_spec_id, workflow_api.workflow_spec_id) return workflow_api + def complete_form(self, workflow_in, task_in, dict_data, error_code=None, terminate_loop=None, user_uid="dhf8r"): prev_completed_task_count = workflow_in.completed_tasks if isinstance(task_in, dict): diff --git a/tests/data/invalid_roles/invalid_roles.bpmn b/tests/data/invalid_roles/invalid_roles.bpmn new file mode 100644 index 00000000..de10f712 --- /dev/null +++ b/tests/data/invalid_roles/invalid_roles.bpmn @@ -0,0 +1,177 @@ + + + + + + + + + StartEvent_1 + Activity_1hljoeq + Event_0lscajc + Activity_19ccxoj + + + Gateway_1fkgc4u + Activity_14eor1x + + + + Flow_0a7090c + + + # Answer me these questions 3, ere the other side you see! + + + + + + + + Flow_0a7090c + Flow_070gq5r + Flow_1hcpt7c + + + Flow_1gp4zfd + Flow_0vnghsi + Flow_1g38q6b + + + # Your responses were approved! + + +Gosh! you must really know a lot about colors and swallows and stuff! +Your supervisor provided the following feedback: + + +{{feedback}} + + +You are all done! WARNING: If you go back and reanswer the questions it will create a new approval request. + + + + + + + Flow_1g38q6b + + + # Your Request was rejected + + +Perhaps you don't know the right answer to one of the questions. +Your Supervisor provided the following feedback: + + +{{feedback}} + + +Please press save to re-try the questions, and submit your responses again. + + + + + + + Flow_0vnghsi + Flow_070gq5r + + + + + + + + + Flow_1hcpt7c + Flow_1gp4zfd + + + + + approval==True + + + approval==True + + + + + Removed a field that would set the supervisor, making this not validate. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/ldap_response.json b/tests/data/ldap_response.json index f42fee94..cab99457 100644 --- a/tests/data/ldap_response.json +++ b/tests/data/ldap_response.json @@ -1,155 +1,124 @@ { - "entries": [ - { - "attributes": { - "cn": [ - "Laura Barnes (lb3dp)" - ], - "displayName": "Laura Barnes", - "givenName": [ - "Laura" - ], - "mail": [ - "lb3dp@virginia.edu" - ], - "objectClass": [ - "top", - "person", - "organizationalPerson", - "inetOrgPerson", - "uvaPerson", - "uidObject" - ], - "telephoneNumber": [ - "+1 (434) 924-1723" - ], - "title": [ - "E0:Associate Professor of Systems and Information Engineering" - ], - "uvaDisplayDepartment": [ - "E0:EN-Eng Sys and Environment" - ], - "uvaPersonIAMAffiliation": [ - "faculty" - ], - "uvaPersonSponsoredType": [ - "Staff" - ] - }, - "dn": "uid=lb3dp,ou=People,o=University of Virginia,c=US", - "raw": { - "cn": [ - "Laura Barnes (lb3dp)" - ], - "displayName": [ - "Laura Barnes" - ], - "givenName": [ - "Laura" - ], - "mail": [ - "lb3dp@virginia.edu" - ], - "objectClass": [ - "top", - "person", - "organizationalPerson", - "inetOrgPerson", - "uvaPerson", - "uidObject" - ], - "telephoneNumber": [ - "+1 (434) 924-1723" - ], - "title": [ - "E0:Associate Professor of Systems and Information Engineering" - ], - "uvaDisplayDepartment": [ - "E0:EN-Eng Sys and Environment" - ], - "uvaPersonIAMAffiliation": [ - "faculty" - ], - "uvaPersonSponsoredType": [ - "Staff" - ] - } - }, - { - "attributes": { - "cn": [ - "Dan Funk (dhf8r)" - ], - "displayName": "Dan Funk", - "givenName": [ - "Dan" - ], - "mail": [ - "dhf8r@virginia.edu" - ], - "objectClass": [ - "top", - "person", - "organizationalPerson", - "inetOrgPerson", - "uvaPerson", - "uidObject" - ], - "telephoneNumber": [ - "+1 (434) 924-1723" - ], - "title": [ - "E42:He's a hoopy frood" - ], - "uvaDisplayDepartment": [ - "E0:EN-Eng Study of Parallel Universes" - ], - "uvaPersonIAMAffiliation": [ - "faculty" - ], - "uvaPersonSponsoredType": [ - "Staff" - ] - }, - "dn": "uid=dhf8r,ou=People,o=University of Virginia,c=US", - "raw": { - "cn": [ - "Dan Funk (dhf84)" - ], - "displayName": [ - "Dan Funk" - ], - "givenName": [ - "Dan" - ], - "mail": [ - "dhf8r@virginia.edu" - ], - "objectClass": [ - "top", - "person", - "organizationalPerson", - "inetOrgPerson", - "uvaPerson", - "uidObject" - ], - "telephoneNumber": [ - "+1 (434) 924-1723" - ], - "title": [ - "E42:He's a hoopy frood" - ], - "uvaDisplayDepartment": [ - "E0:EN-Eng Study of Parallel Universes" - ], - "uvaPersonIAMAffiliation": [ - "faculty" - ], - "uvaPersonSponsoredType": [ - "Staff" - ] - } - } - - ] + "entries": [ + { + "dn": "uid=lb3dp,ou=People,o=University of Virginia,c=US", + "raw": { + "cn": [ + "Laura Barnes (lb3dp)" + ], + "displayName": [ + "Laura Barnes" + ], + "givenName": [ + "Laura" + ], + "mail": [ + "lb3dp@virginia.edu" + ], + "objectClass": [ + "top", + "person", + "organizationalPerson", + "inetOrgPerson", + "uvaPerson", + "uidObject" + ], + "telephoneNumber": [ + "+1 (434) 924-1723" + ], + "title": [ + "E0:Associate Professor of Systems and Information Engineering" + ], + "uvaDisplayDepartment": [ + "E0:EN-Eng Sys and Environment" + ], + "uvaPersonIAMAffiliation": [ + "faculty" + ], + "uvaPersonSponsoredType": [ + "Staff" + ] + } + }, + { + "dn": "uid=dhf8r,ou=People,o=University of Virginia,c=US", + "raw": { + "cn": [ + "Dan Funk (dhf84)" + ], + "displayName": [ + "Dan Funk" + ], + "givenName": [ + "Dan" + ], + "mail": [ + "dhf8r@virginia.edu" + ], + "objectClass": [ + "top", + "person", + "organizationalPerson", + "inetOrgPerson", + "uvaPerson", + "uidObject" + ], + "telephoneNumber": [ + "+1 (434) 924-1723" + ], + "title": [ + "E42:He's a hoopy frood" + ], + "uvaDisplayDepartment": [ + "E0:EN-Eng Study of Parallel Universes" + ], + "uvaPersonIAMAffiliation": [ + "faculty" + ], + "uvaPersonSponsoredType": [ + "Staff" + ] + } + }, + { + "dn": "uid=lje5u,ou=People,o=University of Virginia,c=US", + "raw": { + "cn": [ + "Elder, Lori J (lje5u)" + ], + "displayName": [ + "Lori Elder" + ], + "givenName": [ + "Lori" + ], + "mail": [ + "lje5u@virginia.edu" + ], + "objectClass": [ + "top", + "person", + "organizationalPerson", + "inetOrgPerson", + "uvaPerson", + "uidObject" + ], + "telephoneNumber": [ + "+1 (434) 924-1723" + ], + "title": [ + "E42:The vision" + ], + "uvaDisplayDepartment": [ + "E0:EN-Phy Anything could go here." + ], + "uvaPersonIAMAffiliation": [ + "faculty" + ], + "uvaPersonSponsoredType": [ + "Staff" + ] + } + } + ] } \ No newline at end of file diff --git a/tests/data/roles/roles.bpmn b/tests/data/roles/roles.bpmn new file mode 100644 index 00000000..291f3bdd --- /dev/null +++ b/tests/data/roles/roles.bpmn @@ -0,0 +1,155 @@ + + + + + + + + + StartEvent_1 + Activity_1hljoeq + Event_0lscajc + Activity_19ccxoj + + + Gateway_1fkgc4u + Activity_14eor1x + + + + Flow_0a7090c + + + # Answer me these questions 3, ere the other side you see! + + + + + + + + + Flow_0a7090c + Flow_070gq5r + Flow_1hcpt7c + + + Flow_1gp4zfd + Flow_0vnghsi + Flow_1g38q6b + + + # Your responses were approved! + + +Gosh! you must really know a lot about colors and swallows and stuff! +Your supervisor provided the following feedback: + + +{{feedback}} + + +You are all done! WARNING: If you go back and reanswer the questions it will create a new approval request. + Flow_1g38q6b + + + # Your Request was rejected + + +Perhaps you don't know the right answer to one of the questions. +Your Supervisor provided the following feedback: + + +{{feedback}} + + +Please press save to re-try the questions, and submit your responses again. + Flow_0vnghsi + Flow_070gq5r + + + + + approval==True + + + approval==True + + + + + + + + + + + Flow_1hcpt7c + Flow_1gp4zfd + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_tasks_api.py b/tests/test_tasks_api.py index ebe99d93..702e8a89 100644 --- a/tests/test_tasks_api.py +++ b/tests/test_tasks_api.py @@ -9,80 +9,10 @@ from crc import session, app from crc.models.api_models import WorkflowApiSchema, MultiInstanceType, TaskSchema from crc.models.file import FileModelSchema from crc.models.workflow import WorkflowStatus -from crc.services.workflow_service import WorkflowService -from crc.models.stats import TaskEventModel + class TestTasksApi(BaseTest): - def get_workflow_api(self, workflow, soft_reset=False, hard_reset=False): - rv = self.app.get('/v1.0/workflow/%i?soft_reset=%s&hard_reset=%s' % - (workflow.id, str(soft_reset), str(hard_reset)), - headers=self.logged_in_headers(), - content_type="application/json") - self.assert_success(rv) - json_data = json.loads(rv.get_data(as_text=True)) - workflow_api = WorkflowApiSchema().load(json_data) - self.assertEqual(workflow.workflow_spec_id, workflow_api.workflow_spec_id) - return workflow_api - - def complete_form(self, workflow_in, task_in, dict_data, error_code = None): - prev_completed_task_count = workflow_in.completed_tasks - if isinstance(task_in, dict): - task_id = task_in["id"] - else: - task_id = task_in.id - rv = self.app.put('/v1.0/workflow/%i/task/%s/data' % (workflow_in.id, task_id), - headers=self.logged_in_headers(), - content_type="application/json", - data=json.dumps(dict_data)) - if error_code: - self.assert_failure(rv, error_code=error_code) - return - - self.assert_success(rv) - json_data = json.loads(rv.get_data(as_text=True)) - - # Assure stats are updated on the model - workflow = WorkflowApiSchema().load(json_data) - # The total number of tasks may change over time, as users move through gateways - # branches may be pruned. As we hit parallel Multi-Instance new tasks may be created... - self.assertIsNotNone(workflow.total_tasks) - self.assertEqual(prev_completed_task_count + 1, workflow.completed_tasks) - # Assure a record exists in the Task Events - task_events = session.query(TaskEventModel) \ - .filter_by(workflow_id=workflow.id) \ - .filter_by(task_id=task_id) \ - .order_by(TaskEventModel.date.desc()).all() - self.assertGreater(len(task_events), 0) - event = task_events[0] - self.assertIsNotNone(event.study_id) - self.assertEqual("dhf8r", event.user_uid) - self.assertEqual(workflow.id, event.workflow_id) - self.assertEqual(workflow.workflow_spec_id, event.workflow_spec_id) - self.assertEqual(workflow.spec_version, event.spec_version) - self.assertEqual(WorkflowService.TASK_ACTION_COMPLETE, event.action) - self.assertEqual(task_in.id, task_id) - self.assertEqual(task_in.name, event.task_name) - self.assertEqual(task_in.title, event.task_title) - self.assertEqual(task_in.type, event.task_type) - self.assertEqual("COMPLETED", event.task_state) - # Not sure what vodoo is happening inside of marshmallow to get me in this state. - if isinstance(task_in.multi_instance_type, MultiInstanceType): - self.assertEqual(task_in.multi_instance_type.value, event.mi_type) - else: - self.assertEqual(task_in.multi_instance_type, event.mi_type) - - self.assertEqual(task_in.multi_instance_count, event.mi_count) - self.assertEqual(task_in.multi_instance_index, event.mi_index) - self.assertEqual(task_in.process_name, event.process_name) - self.assertIsNotNone(event.date) - - # Assure that there is data in the form_data - self.assertIsNotNone(event.form_data) - - workflow = WorkflowApiSchema().load(json_data) - return workflow - def assert_options_populated(self, results, lookup_data_keys): option_keys = ['value', 'label', 'data'] self.assertIsInstance(results, list) diff --git a/tests/workflow/test_workflow_processor.py b/tests/workflow/test_workflow_processor.py index 44d90cf3..a51f029d 100644 --- a/tests/workflow/test_workflow_processor.py +++ b/tests/workflow/test_workflow_processor.py @@ -368,4 +368,19 @@ class TestWorkflowProcessor(BaseTest): task.task_spec.form.fields.append(field) with self.assertRaises(ApiError): - self._populate_form_with_random_data(task) \ No newline at end of file + self._populate_form_with_random_data(task) + + + def test_get_role_by_name(self): + self.load_example_data() + workflow_spec_model = self.load_test_spec("roles") + study = session.query(StudyModel).first() + processor = self.get_processor(study, workflow_spec_model) + processor.do_engine_steps() + tasks = processor.next_user_tasks() + task = tasks[0] + self._populate_form_with_random_data(task) + processor.complete_task(task) + supervisor_task = processor.next_user_tasks()[0] + self.assertEquals("supervisor", supervisor_task.task_spec.lane) +