Merge branch 'dev' into feature/delete-variable-script-584
# Conflicts: # Pipfile.lock
This commit is contained in:
commit
f2c97f80d5
2
Pipfile
2
Pipfile
|
@ -12,7 +12,7 @@ coverage = "*"
|
|||
alembic = "*"
|
||||
coverage = "*"
|
||||
docxtpl = "*"
|
||||
flask = "<2"
|
||||
flask = "*"
|
||||
celery = "<5"
|
||||
flask-admin = "*"
|
||||
flask-bcrypt = "*"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "bf333e0e7aaaff0988808dab8191f9711f1100f3af3dc35123672086c290667c"
|
||||
"sha256": "eb924ba10433552dcde585064a905bb8b78e96b28fc23391eee486ca34e22aad"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
@ -48,11 +48,11 @@
|
|||
},
|
||||
"apscheduler": {
|
||||
"hashes": [
|
||||
"sha256:5cf344ebcfbdaa48ae178c029c055cec7bc7a4a47c21e315e4d1f08bd35f2355",
|
||||
"sha256:c22cb14b411a31435eb2c530dfbbec948ac63015b517087c7978adb61b574865"
|
||||
"sha256:236dbf7244200ffc79c6c0b9ff7d2ed10e7e985f37f48d4a23f4142f4967dcb5",
|
||||
"sha256:f8a3e6e4d178de40fdbd5a3eefcc217588fc7f42f443e2335bb2dc29daf99357"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.8.1"
|
||||
"version": "==3.9.0.post1"
|
||||
},
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
|
@ -209,11 +209,11 @@
|
|||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||
"sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1",
|
||||
"sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==7.1.2"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==8.0.4"
|
||||
},
|
||||
"clickclick": {
|
||||
"hashes": [
|
||||
|
@ -242,58 +242,58 @@
|
|||
"swagger-ui"
|
||||
],
|
||||
"hashes": [
|
||||
"sha256:66620b10b2c03eab6af981f8489d0ff7ada19f66710274effc71258fb8221419",
|
||||
"sha256:b5e5ba236894a02b8da4d10face412f471abb6ff77de10dad32fa88cb894acf7"
|
||||
"sha256:2d163976fbc8766038d71f4232ace07826be7dd0a8fe7a539ce5fc8a80f1ab35",
|
||||
"sha256:c08b530418a1c448d34cd142713ddd1b245e7694f45cd80533fe8538b64aa7eb"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.11.1"
|
||||
"version": "==2.12.0"
|
||||
},
|
||||
"coverage": {
|
||||
"hashes": [
|
||||
"sha256:1245ab82e8554fa88c4b2ab1e098ae051faac5af829efdcf2ce6b34dccd5567c",
|
||||
"sha256:1bc6d709939ff262fd1432f03f080c5042dc6508b6e0d3d20e61dd045456a1a0",
|
||||
"sha256:25e73d4c81efa8ea3785274a2f7f3bfbbeccb6fcba2a0bdd3be9223371c37554",
|
||||
"sha256:276b13cc085474e482566c477c25ed66a097b44c6e77132f3304ac0b039f83eb",
|
||||
"sha256:2aed4761809640f02e44e16b8b32c1a5dee5e80ea30a0ff0912158bde9c501f2",
|
||||
"sha256:2dd70a167843b4b4b2630c0c56f1b586fe965b4f8ac5da05b6690344fd065c6b",
|
||||
"sha256:352c68e233409c31048a3725c446a9e48bbff36e39db92774d4f2380d630d8f8",
|
||||
"sha256:3f2b05757c92ad96b33dbf8e8ec8d4ccb9af6ae3c9e9bd141c7cc44d20c6bcba",
|
||||
"sha256:448d7bde7ceb6c69e08474c2ddbc5b4cd13c9e4aa4a717467f716b5fc938a734",
|
||||
"sha256:463e52616ea687fd323888e86bf25e864a3cc6335a043fad6bbb037dbf49bbe2",
|
||||
"sha256:482fb42eea6164894ff82abbcf33d526362de5d1a7ed25af7ecbdddd28fc124f",
|
||||
"sha256:56c4a409381ddd7bbff134e9756077860d4e8a583d310a6f38a2315b9ce301d0",
|
||||
"sha256:56d296cbc8254a7dffdd7bcc2eb70be5a233aae7c01856d2d936f5ac4e8ac1f1",
|
||||
"sha256:5e15d424b8153756b7c903bde6d4610be0c3daca3986173c18dd5c1a1625e4cd",
|
||||
"sha256:618eeba986cea7f621d8607ee378ecc8c2504b98b3fdc4952b30fe3578304687",
|
||||
"sha256:61d47a897c1e91f33f177c21de897267b38fbb45f2cd8e22a710bcef1df09ac1",
|
||||
"sha256:621f6ea7260ea2ffdaec64fe5cb521669984f567b66f62f81445221d4754df4c",
|
||||
"sha256:6a5cdc3adb4f8bb8d8f5e64c2e9e282bc12980ef055ec6da59db562ee9bdfefa",
|
||||
"sha256:6c3f6158b02ac403868eea390930ae64e9a9a2a5bbfafefbb920d29258d9f2f8",
|
||||
"sha256:704f89b87c4f4737da2860695a18c852b78ec7279b24eedacab10b29067d3a38",
|
||||
"sha256:72128176fea72012063200b7b395ed8a57849282b207321124d7ff14e26988e8",
|
||||
"sha256:78fbb2be068a13a5d99dce9e1e7d168db880870f7bc73f876152130575bd6167",
|
||||
"sha256:7bff3a98f63b47464480de1b5bdd80c8fade0ba2832c9381253c9b74c4153c27",
|
||||
"sha256:84f2436d6742c01136dd940ee158bfc7cf5ced3da7e4c949662b8703b5cd8145",
|
||||
"sha256:9976fb0a5709988778ac9bc44f3d50fccd989987876dfd7716dee28beed0a9fa",
|
||||
"sha256:9ad0a117b8dc2061ce9461ea4c1b4799e55edceb236522c5b8f958ce9ed8fa9a",
|
||||
"sha256:9e3dd806f34de38d4c01416344e98eab2437ac450b3ae39c62a0ede2f8b5e4ed",
|
||||
"sha256:9eb494070aa060ceba6e4bbf44c1bc5fa97bfb883a0d9b0c9049415f9e944793",
|
||||
"sha256:9fde6b90889522c220dd56a670102ceef24955d994ff7af2cb786b4ba8fe11e4",
|
||||
"sha256:9fff3ff052922cb99f9e52f63f985d4f7a54f6b94287463bc66b7cdf3eb41217",
|
||||
"sha256:a06c358f4aed05fa1099c39decc8022261bb07dfadc127c08cfbd1391b09689e",
|
||||
"sha256:a4f923b9ab265136e57cc14794a15b9dcea07a9c578609cd5dbbfff28a0d15e6",
|
||||
"sha256:c5b81fb37db76ebea79aa963b76d96ff854e7662921ce742293463635a87a78d",
|
||||
"sha256:d5ed164af5c9078596cfc40b078c3b337911190d3faeac830c3f1274f26b8320",
|
||||
"sha256:d651fde74a4d3122e5562705824507e2f5b2d3d57557f1916c4b27635f8fbe3f",
|
||||
"sha256:de73fca6fb403dd72d4da517cfc49fcf791f74eee697d3219f6be29adf5af6ce",
|
||||
"sha256:e647a0be741edbb529a72644e999acb09f2ad60465f80757da183528941ff975",
|
||||
"sha256:e92c7a5f7d62edff50f60a045dc9542bf939758c95b2fcd686175dd10ce0ed10",
|
||||
"sha256:eeffd96882d8c06d31b65dddcf51db7c612547babc1c4c5db6a011abe9798525",
|
||||
"sha256:f5a4551dfd09c3bd12fca8144d47fe7745275adf3229b7223c2f9e29a975ebda",
|
||||
"sha256:fac0bcc5b7e8169bffa87f0dcc24435446d329cbc2b5486d155c2e0f3b493ae1"
|
||||
"sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9",
|
||||
"sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d",
|
||||
"sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf",
|
||||
"sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7",
|
||||
"sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6",
|
||||
"sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4",
|
||||
"sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059",
|
||||
"sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39",
|
||||
"sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536",
|
||||
"sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac",
|
||||
"sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c",
|
||||
"sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903",
|
||||
"sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d",
|
||||
"sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05",
|
||||
"sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684",
|
||||
"sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1",
|
||||
"sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f",
|
||||
"sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7",
|
||||
"sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca",
|
||||
"sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad",
|
||||
"sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca",
|
||||
"sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d",
|
||||
"sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92",
|
||||
"sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4",
|
||||
"sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf",
|
||||
"sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6",
|
||||
"sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1",
|
||||
"sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4",
|
||||
"sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359",
|
||||
"sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3",
|
||||
"sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620",
|
||||
"sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512",
|
||||
"sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69",
|
||||
"sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2",
|
||||
"sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518",
|
||||
"sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0",
|
||||
"sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa",
|
||||
"sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4",
|
||||
"sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e",
|
||||
"sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1",
|
||||
"sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==6.3.1"
|
||||
"version": "==6.3.2"
|
||||
},
|
||||
"dateparser": {
|
||||
"hashes": [
|
||||
|
@ -343,11 +343,11 @@
|
|||
},
|
||||
"flask": {
|
||||
"hashes": [
|
||||
"sha256:0fbeb6180d383a9186d0d6ed954e0042ad9f18e0e8de088b2b419d526927d196",
|
||||
"sha256:c34f04500f2cbbea882b1acb02002ad6fe6b7ffa64a6164577995657f50aed22"
|
||||
"sha256:59da8a3170004800a2837844bfa84d49b022550616070f7cb1a659682b2e7c9f",
|
||||
"sha256:e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.1.4"
|
||||
"version": "==2.0.3"
|
||||
},
|
||||
"flask-admin": {
|
||||
"hashes": [
|
||||
|
@ -427,11 +427,11 @@
|
|||
},
|
||||
"gitpython": {
|
||||
"hashes": [
|
||||
"sha256:26ac35c212d1f7b16036361ca5cff3ec66e11753a0d677fb6c48fa4e1a9dd8d6",
|
||||
"sha256:fc8868f63a2e6d268fb25f481995ba185a85a66fcad126f039323ff6635669ee"
|
||||
"sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704",
|
||||
"sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.1.26"
|
||||
"version": "==3.1.27"
|
||||
},
|
||||
"greenlet": {
|
||||
"hashes": [
|
||||
|
@ -549,35 +549,29 @@
|
|||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"isodate": {
|
||||
"hashes": [
|
||||
"sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96",
|
||||
"sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"
|
||||
],
|
||||
"version": "==0.6.1"
|
||||
},
|
||||
"itsdangerous": {
|
||||
"hashes": [
|
||||
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
|
||||
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
|
||||
"sha256:29285842166554469a56d427addc0843914172343784cb909695fdbe90a3e129",
|
||||
"sha256:d848fcb8bc7d507c4546b448574e8a44fc4ea2ba84ebf8d783290d53e81992f5"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.1.0"
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419",
|
||||
"sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"
|
||||
"sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8",
|
||||
"sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.11.3"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.0.3"
|
||||
},
|
||||
"jsonschema": {
|
||||
"hashes": [
|
||||
"sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163",
|
||||
"sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"
|
||||
"sha256:636694eb41b3535ed608fe04129f26542b59ed99808b4f688aa32dcf55317a83",
|
||||
"sha256:77281a1f71684953ee8b3d488371b162419767973789272434bbc3f29d9c8823"
|
||||
],
|
||||
"version": "==3.2.0"
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==4.4.0"
|
||||
},
|
||||
"kombu": {
|
||||
"hashes": [
|
||||
|
@ -600,69 +594,70 @@
|
|||
},
|
||||
"lxml": {
|
||||
"hashes": [
|
||||
"sha256:0607ff0988ad7e173e5ddf7bf55ee65534bd18a5461183c33e8e41a59e89edf4",
|
||||
"sha256:09b738360af8cb2da275998a8bf79517a71225b0de41ab47339c2beebfff025f",
|
||||
"sha256:0a5f0e4747f31cff87d1eb32a6000bde1e603107f632ef4666be0dc065889c7a",
|
||||
"sha256:0b5e96e25e70917b28a5391c2ed3ffc6156513d3db0e1476c5253fcd50f7a944",
|
||||
"sha256:1104a8d47967a414a436007c52f533e933e5d52574cab407b1e49a4e9b5ddbd1",
|
||||
"sha256:13dbb5c7e8f3b6a2cf6e10b0948cacb2f4c9eb05029fe31c60592d08ac63180d",
|
||||
"sha256:2a906c3890da6a63224d551c2967413b8790a6357a80bf6b257c9a7978c2c42d",
|
||||
"sha256:317bd63870b4d875af3c1be1b19202de34c32623609ec803b81c99193a788c1e",
|
||||
"sha256:34c22eb8c819d59cec4444d9eebe2e38b95d3dcdafe08965853f8799fd71161d",
|
||||
"sha256:36b16fecb10246e599f178dd74f313cbdc9f41c56e77d52100d1361eed24f51a",
|
||||
"sha256:38d9759733aa04fb1697d717bfabbedb21398046bd07734be7cccc3d19ea8675",
|
||||
"sha256:3e26ad9bc48d610bf6cc76c506b9e5ad9360ed7a945d9be3b5b2c8535a0145e3",
|
||||
"sha256:41358bfd24425c1673f184d7c26c6ae91943fe51dfecc3603b5e08187b4bcc55",
|
||||
"sha256:447d5009d6b5447b2f237395d0018901dcc673f7d9f82ba26c1b9f9c3b444b60",
|
||||
"sha256:44f552e0da3c8ee3c28e2eb82b0b784200631687fc6a71277ea8ab0828780e7d",
|
||||
"sha256:490712b91c65988012e866c411a40cc65b595929ececf75eeb4c79fcc3bc80a6",
|
||||
"sha256:4c093c571bc3da9ebcd484e001ba18b8452903cd428c0bc926d9b0141bcb710e",
|
||||
"sha256:50d3dba341f1e583265c1a808e897b4159208d814ab07530202b6036a4d86da5",
|
||||
"sha256:534e946bce61fd162af02bad7bfd2daec1521b71d27238869c23a672146c34a5",
|
||||
"sha256:585ea241ee4961dc18a95e2f5581dbc26285fcf330e007459688096f76be8c42",
|
||||
"sha256:59e7da839a1238807226f7143c68a479dee09244d1b3cf8c134f2fce777d12d0",
|
||||
"sha256:5b0f782f0e03555c55e37d93d7a57454efe7495dab33ba0ccd2dbe25fc50f05d",
|
||||
"sha256:5bee1b0cbfdb87686a7fb0e46f1d8bd34d52d6932c0723a86de1cc532b1aa489",
|
||||
"sha256:610807cea990fd545b1559466971649e69302c8a9472cefe1d6d48a1dee97440",
|
||||
"sha256:6308062534323f0d3edb4e702a0e26a76ca9e0e23ff99be5d82750772df32a9e",
|
||||
"sha256:67fa5f028e8a01e1d7944a9fb616d1d0510d5d38b0c41708310bd1bc45ae89f6",
|
||||
"sha256:6a2ab9d089324d77bb81745b01f4aeffe4094306d939e92ba5e71e9a6b99b71e",
|
||||
"sha256:6c198bfc169419c09b85ab10cb0f572744e686f40d1e7f4ed09061284fc1303f",
|
||||
"sha256:6e56521538f19c4a6690f439fefed551f0b296bd785adc67c1777c348beb943d",
|
||||
"sha256:6ec829058785d028f467be70cd195cd0aaf1a763e4d09822584ede8c9eaa4b03",
|
||||
"sha256:718d7208b9c2d86aaf0294d9381a6acb0158b5ff0f3515902751404e318e02c9",
|
||||
"sha256:735e3b4ce9c0616e85f302f109bdc6e425ba1670a73f962c9f6b98a6d51b77c9",
|
||||
"sha256:772057fba283c095db8c8ecde4634717a35c47061d24f889468dc67190327bcd",
|
||||
"sha256:7b5e2acefd33c259c4a2e157119c4373c8773cf6793e225006a1649672ab47a6",
|
||||
"sha256:82d16a64236970cb93c8d63ad18c5b9f138a704331e4b916b2737ddfad14e0c4",
|
||||
"sha256:87c1b0496e8c87ec9db5383e30042357b4839b46c2d556abd49ec770ce2ad868",
|
||||
"sha256:8e54945dd2eeb50925500957c7c579df3cd07c29db7810b83cf30495d79af267",
|
||||
"sha256:9393a05b126a7e187f3e38758255e0edf948a65b22c377414002d488221fdaa2",
|
||||
"sha256:9fbc0dee7ff5f15c4428775e6fa3ed20003140560ffa22b88326669d53b3c0f4",
|
||||
"sha256:a1613838aa6b89af4ba10a0f3a972836128801ed008078f8c1244e65958f1b24",
|
||||
"sha256:a1bbc4efa99ed1310b5009ce7f3a1784698082ed2c1ef3895332f5df9b3b92c2",
|
||||
"sha256:a555e06566c6dc167fbcd0ad507ff05fd9328502aefc963cb0a0547cfe7f00db",
|
||||
"sha256:a58d78653ae422df6837dd4ca0036610b8cb4962b5cfdbd337b7b24de9e5f98a",
|
||||
"sha256:a5edc58d631170de90e50adc2cc0248083541affef82f8cd93bea458e4d96db8",
|
||||
"sha256:a5f623aeaa24f71fce3177d7fee875371345eb9102b355b882243e33e04b7175",
|
||||
"sha256:adaab25be351fff0d8a691c4f09153647804d09a87a4e4ea2c3f9fe9e8651851",
|
||||
"sha256:ade74f5e3a0fd17df5782896ddca7ddb998845a5f7cd4b0be771e1ffc3b9aa5b",
|
||||
"sha256:b1d381f58fcc3e63fcc0ea4f0a38335163883267f77e4c6e22d7a30877218a0e",
|
||||
"sha256:bf6005708fc2e2c89a083f258b97709559a95f9a7a03e59f805dd23c93bc3986",
|
||||
"sha256:d546431636edb1d6a608b348dd58cc9841b81f4116745857b6cb9f8dadb2725f",
|
||||
"sha256:d5618d49de6ba63fe4510bdada62d06a8acfca0b4b5c904956c777d28382b419",
|
||||
"sha256:dfd0d464f3d86a1460683cd742306d1138b4e99b79094f4e07e1ca85ee267fe7",
|
||||
"sha256:e18281a7d80d76b66a9f9e68a98cf7e1d153182772400d9a9ce855264d7d0ce7",
|
||||
"sha256:e410cf3a2272d0a85526d700782a2fa92c1e304fdcc519ba74ac80b8297adf36",
|
||||
"sha256:e662c6266e3a275bdcb6bb049edc7cd77d0b0f7e119a53101d367c841afc66dc",
|
||||
"sha256:ec9027d0beb785a35aa9951d14e06d48cfbf876d8ff67519403a2522b181943b",
|
||||
"sha256:eed394099a7792834f0cb4a8f615319152b9d801444c1c9e1b1a2c36d2239f9e",
|
||||
"sha256:f76dbe44e31abf516114f6347a46fa4e7c2e8bceaa4b6f7ee3a0a03c8eba3c17",
|
||||
"sha256:fc15874816b9320581133ddc2096b644582ab870cf6a6ed63684433e7af4b0d3",
|
||||
"sha256:fc9fb11b65e7bc49f7f75aaba1b700f7181d95d4e151cf2f24d51bfd14410b77"
|
||||
"sha256:078306d19a33920004addeb5f4630781aaeabb6a8d01398045fcde085091a169",
|
||||
"sha256:0c1978ff1fd81ed9dcbba4f91cf09faf1f8082c9d72eb122e92294716c605428",
|
||||
"sha256:1010042bfcac2b2dc6098260a2ed022968dbdfaf285fc65a3acf8e4eb1ffd1bc",
|
||||
"sha256:1d650812b52d98679ed6c6b3b55cbb8fe5a5460a0aef29aeb08dc0b44577df85",
|
||||
"sha256:20b8a746a026017acf07da39fdb10aa80ad9877046c9182442bf80c84a1c4696",
|
||||
"sha256:2403a6d6fb61c285969b71f4a3527873fe93fd0abe0832d858a17fe68c8fa507",
|
||||
"sha256:24f5c5ae618395ed871b3d8ebfcbb36e3f1091fd847bf54c4de623f9107942f3",
|
||||
"sha256:28d1af847786f68bec57961f31221125c29d6f52d9187c01cd34dc14e2b29430",
|
||||
"sha256:31499847fc5f73ee17dbe1b8e24c6dafc4e8d5b48803d17d22988976b0171f03",
|
||||
"sha256:31ba2cbc64516dcdd6c24418daa7abff989ddf3ba6d3ea6f6ce6f2ed6e754ec9",
|
||||
"sha256:330bff92c26d4aee79c5bc4d9967858bdbe73fdbdbacb5daf623a03a914fe05b",
|
||||
"sha256:5045ee1ccd45a89c4daec1160217d363fcd23811e26734688007c26f28c9e9e7",
|
||||
"sha256:52cbf2ff155b19dc4d4100f7442f6a697938bf4493f8d3b0c51d45568d5666b5",
|
||||
"sha256:530f278849031b0eb12f46cca0e5db01cfe5177ab13bd6878c6e739319bae654",
|
||||
"sha256:545bd39c9481f2e3f2727c78c169425efbfb3fbba6e7db4f46a80ebb249819ca",
|
||||
"sha256:5804e04feb4e61babf3911c2a974a5b86f66ee227cc5006230b00ac6d285b3a9",
|
||||
"sha256:5a58d0b12f5053e270510bf12f753a76aaf3d74c453c00942ed7d2c804ca845c",
|
||||
"sha256:5f148b0c6133fb928503cfcdfdba395010f997aa44bcf6474fcdd0c5398d9b63",
|
||||
"sha256:5f7d7d9afc7b293147e2d506a4596641d60181a35279ef3aa5778d0d9d9123fe",
|
||||
"sha256:60d2f60bd5a2a979df28ab309352cdcf8181bda0cca4529769a945f09aba06f9",
|
||||
"sha256:6259b511b0f2527e6d55ad87acc1c07b3cbffc3d5e050d7e7bcfa151b8202df9",
|
||||
"sha256:6268e27873a3d191849204d00d03f65c0e343b3bcb518a6eaae05677c95621d1",
|
||||
"sha256:627e79894770783c129cc5e89b947e52aa26e8e0557c7e205368a809da4b7939",
|
||||
"sha256:62f93eac69ec0f4be98d1b96f4d6b964855b8255c345c17ff12c20b93f247b68",
|
||||
"sha256:6d6483b1229470e1d8835e52e0ff3c6973b9b97b24cd1c116dca90b57a2cc613",
|
||||
"sha256:6f7b82934c08e28a2d537d870293236b1000d94d0b4583825ab9649aef7ddf63",
|
||||
"sha256:6fe4ef4402df0250b75ba876c3795510d782def5c1e63890bde02d622570d39e",
|
||||
"sha256:719544565c2937c21a6f76d520e6e52b726d132815adb3447ccffbe9f44203c4",
|
||||
"sha256:730766072fd5dcb219dd2b95c4c49752a54f00157f322bc6d71f7d2a31fecd79",
|
||||
"sha256:74eb65ec61e3c7c019d7169387d1b6ffcfea1b9ec5894d116a9a903636e4a0b1",
|
||||
"sha256:7993232bd4044392c47779a3c7e8889fea6883be46281d45a81451acfd704d7e",
|
||||
"sha256:80bbaddf2baab7e6de4bc47405e34948e694a9efe0861c61cdc23aa774fcb141",
|
||||
"sha256:86545e351e879d0b72b620db6a3b96346921fa87b3d366d6c074e5a9a0b8dadb",
|
||||
"sha256:891dc8f522d7059ff0024cd3ae79fd224752676447f9c678f2a5c14b84d9a939",
|
||||
"sha256:8a31f24e2a0b6317f33aafbb2f0895c0bce772980ae60c2c640d82caac49628a",
|
||||
"sha256:8b99ec73073b37f9ebe8caf399001848fced9c08064effdbfc4da2b5a8d07b93",
|
||||
"sha256:986b7a96228c9b4942ec420eff37556c5777bfba6758edcb95421e4a614b57f9",
|
||||
"sha256:a1547ff4b8a833511eeaceacbcd17b043214fcdb385148f9c1bc5556ca9623e2",
|
||||
"sha256:a2bfc7e2a0601b475477c954bf167dee6d0f55cb167e3f3e7cefad906e7759f6",
|
||||
"sha256:a3c5f1a719aa11866ffc530d54ad965063a8cbbecae6515acbd5f0fae8f48eaa",
|
||||
"sha256:a9f1c3489736ff8e1c7652e9dc39f80cff820f23624f23d9eab6e122ac99b150",
|
||||
"sha256:aa0cf4922da7a3c905d000b35065df6184c0dc1d866dd3b86fd961905bbad2ea",
|
||||
"sha256:ad4332a532e2d5acb231a2e5d33f943750091ee435daffca3fec0a53224e7e33",
|
||||
"sha256:b2582b238e1658c4061ebe1b4df53c435190d22457642377fd0cb30685cdfb76",
|
||||
"sha256:b6fc2e2fb6f532cf48b5fed57567ef286addcef38c28874458a41b7837a57807",
|
||||
"sha256:b92d40121dcbd74831b690a75533da703750f7041b4bf951befc657c37e5695a",
|
||||
"sha256:bbab6faf6568484707acc052f4dfc3802bdb0cafe079383fbaa23f1cdae9ecd4",
|
||||
"sha256:c0b88ed1ae66777a798dc54f627e32d3b81c8009967c63993c450ee4cbcbec15",
|
||||
"sha256:ce13d6291a5f47c1c8dbd375baa78551053bc6b5e5c0e9bb8e39c0a8359fd52f",
|
||||
"sha256:db3535733f59e5605a88a706824dfcb9bd06725e709ecb017e165fc1d6e7d429",
|
||||
"sha256:dd10383f1d6b7edf247d0960a3db274c07e96cf3a3fc7c41c8448f93eac3fb1c",
|
||||
"sha256:e01f9531ba5420838c801c21c1b0f45dbc9607cb22ea2cf132844453bec863a5",
|
||||
"sha256:e11527dc23d5ef44d76fef11213215c34f36af1608074561fcc561d983aeb870",
|
||||
"sha256:e1ab2fac607842ac36864e358c42feb0960ae62c34aa4caaf12ada0a1fb5d99b",
|
||||
"sha256:e1fd7d2fe11f1cb63d3336d147c852f6d07de0d0020d704c6031b46a30b02ca8",
|
||||
"sha256:e9f84ed9f4d50b74fbc77298ee5c870f67cb7e91dcdc1a6915cb1ff6a317476c",
|
||||
"sha256:ec4b4e75fc68da9dc0ed73dcdb431c25c57775383fec325d23a770a64e7ebc87",
|
||||
"sha256:f10ce66fcdeb3543df51d423ede7e238be98412232fca5daec3e54bcd16b8da0",
|
||||
"sha256:f63f62fc60e6228a4ca9abae28228f35e1bd3ce675013d1dfb828688d50c6e23",
|
||||
"sha256:fa56bb08b3dd8eac3a8c5b7d075c94e74f755fd9d8a04543ae8d37b1612dd170",
|
||||
"sha256:fa9b7c450be85bfc6cd39f6df8c5b8cbd76b5d6fc1f69efec80203f9894b885f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.7.1"
|
||||
"version": "==4.8.0"
|
||||
},
|
||||
"mako": {
|
||||
"hashes": [
|
||||
|
@ -682,78 +677,49 @@
|
|||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298",
|
||||
"sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64",
|
||||
"sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b",
|
||||
"sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194",
|
||||
"sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567",
|
||||
"sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff",
|
||||
"sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724",
|
||||
"sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74",
|
||||
"sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646",
|
||||
"sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35",
|
||||
"sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6",
|
||||
"sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a",
|
||||
"sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6",
|
||||
"sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad",
|
||||
"sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26",
|
||||
"sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38",
|
||||
"sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac",
|
||||
"sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7",
|
||||
"sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6",
|
||||
"sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047",
|
||||
"sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75",
|
||||
"sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f",
|
||||
"sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b",
|
||||
"sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135",
|
||||
"sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8",
|
||||
"sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a",
|
||||
"sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a",
|
||||
"sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1",
|
||||
"sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9",
|
||||
"sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864",
|
||||
"sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914",
|
||||
"sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee",
|
||||
"sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f",
|
||||
"sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18",
|
||||
"sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8",
|
||||
"sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2",
|
||||
"sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d",
|
||||
"sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b",
|
||||
"sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b",
|
||||
"sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86",
|
||||
"sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6",
|
||||
"sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f",
|
||||
"sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb",
|
||||
"sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833",
|
||||
"sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28",
|
||||
"sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e",
|
||||
"sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415",
|
||||
"sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902",
|
||||
"sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f",
|
||||
"sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d",
|
||||
"sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9",
|
||||
"sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d",
|
||||
"sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145",
|
||||
"sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066",
|
||||
"sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c",
|
||||
"sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1",
|
||||
"sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a",
|
||||
"sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207",
|
||||
"sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f",
|
||||
"sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53",
|
||||
"sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd",
|
||||
"sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134",
|
||||
"sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85",
|
||||
"sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9",
|
||||
"sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5",
|
||||
"sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94",
|
||||
"sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509",
|
||||
"sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51",
|
||||
"sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"
|
||||
"sha256:023af8c54fe63530545f70dd2a2a7eed18d07a9a77b94e8bf1e2ff7f252db9a3",
|
||||
"sha256:09c86c9643cceb1d87ca08cdc30160d1b7ab49a8a21564868921959bd16441b8",
|
||||
"sha256:142119fb14a1ef6d758912b25c4e803c3ff66920635c44078666fe7cc3f8f759",
|
||||
"sha256:1d1fb9b2eec3c9714dd936860850300b51dbaa37404209c8d4cb66547884b7ed",
|
||||
"sha256:204730fd5fe2fe3b1e9ccadb2bd18ba8712b111dcabce185af0b3b5285a7c989",
|
||||
"sha256:24c3be29abb6b34052fd26fc7a8e0a49b1ee9d282e3665e8ad09a0a68faee5b3",
|
||||
"sha256:290b02bab3c9e216da57c1d11d2ba73a9f73a614bbdcc027d299a60cdfabb11a",
|
||||
"sha256:3028252424c72b2602a323f70fbf50aa80a5d3aa616ea6add4ba21ae9cc9da4c",
|
||||
"sha256:30c653fde75a6e5eb814d2a0a89378f83d1d3f502ab710904ee585c38888816c",
|
||||
"sha256:3cace1837bc84e63b3fd2dfce37f08f8c18aeb81ef5cf6bb9b51f625cb4e6cd8",
|
||||
"sha256:4056f752015dfa9828dce3140dbadd543b555afb3252507348c493def166d454",
|
||||
"sha256:454ffc1cbb75227d15667c09f164a0099159da0c1f3d2636aa648f12675491ad",
|
||||
"sha256:598b65d74615c021423bd45c2bc5e9b59539c875a9bdb7e5f2a6b92dfcfc268d",
|
||||
"sha256:599941da468f2cf22bf90a84f6e2a65524e87be2fce844f96f2dd9a6c9d1e635",
|
||||
"sha256:5ddea4c352a488b5e1069069f2f501006b1a4362cb906bee9a193ef1245a7a61",
|
||||
"sha256:62c0285e91414f5c8f621a17b69fc0088394ccdaa961ef469e833dbff64bd5ea",
|
||||
"sha256:679cbb78914ab212c49c67ba2c7396dc599a8479de51b9a87b174700abd9ea49",
|
||||
"sha256:6e104c0c2b4cd765b4e83909cde7ec61a1e313f8a75775897db321450e928cce",
|
||||
"sha256:736895a020e31b428b3382a7887bfea96102c529530299f426bf2e636aacec9e",
|
||||
"sha256:75bb36f134883fdbe13d8e63b8675f5f12b80bb6627f7714c7d6c5becf22719f",
|
||||
"sha256:7d2f5d97fcbd004c03df8d8fe2b973fe2b14e7bfeb2cfa012eaa8759ce9a762f",
|
||||
"sha256:80beaf63ddfbc64a0452b841d8036ca0611e049650e20afcb882f5d3c266d65f",
|
||||
"sha256:84ad5e29bf8bab3ad70fd707d3c05524862bddc54dc040982b0dbcff36481de7",
|
||||
"sha256:8da5924cb1f9064589767b0f3fc39d03e3d0fb5aa29e0cb21d43106519bd624a",
|
||||
"sha256:961eb86e5be7d0973789f30ebcf6caab60b844203f4396ece27310295a6082c7",
|
||||
"sha256:96de1932237abe0a13ba68b63e94113678c379dca45afa040a17b6e1ad7ed076",
|
||||
"sha256:a0a0abef2ca47b33fb615b491ce31b055ef2430de52c5b3fb19a4042dbc5cadb",
|
||||
"sha256:b2a5a856019d2833c56a3dcac1b80fe795c95f401818ea963594b345929dffa7",
|
||||
"sha256:b8811d48078d1cf2a6863dafb896e68406c5f513048451cd2ded0473133473c7",
|
||||
"sha256:c532d5ab79be0199fa2658e24a02fce8542df196e60665dd322409a03db6a52c",
|
||||
"sha256:d3b64c65328cb4cd252c94f83e66e3d7acf8891e60ebf588d7b493a55a1dbf26",
|
||||
"sha256:d4e702eea4a2903441f2735799d217f4ac1b55f7d8ad96ab7d4e25417cb0827c",
|
||||
"sha256:d5653619b3eb5cbd35bfba3c12d575db2a74d15e0e1c08bf1db788069d410ce8",
|
||||
"sha256:d66624f04de4af8bbf1c7f21cc06649c1c69a7f84109179add573ce35e46d448",
|
||||
"sha256:e67ec74fada3841b8c5f4c4f197bea916025cb9aa3fe5abf7d52b655d042f956",
|
||||
"sha256:e6f7f3f41faffaea6596da86ecc2389672fa949bd035251eab26dc6697451d05",
|
||||
"sha256:f02cf7221d5cd915d7fa58ab64f7ee6dd0f6cddbb48683debf5d04ae9b1c2cc1",
|
||||
"sha256:f0eddfcabd6936558ec020130f932d479930581171368fd728efcfb6ef0dd357",
|
||||
"sha256:fabbe18087c3d33c5824cb145ffca52eccd053061df1d79d4b66dafa5ad2a5ea",
|
||||
"sha256:fc3150f85e2dbcf99e65238c842d1cfe69d3e7649b19864c1cc043213d9cd730"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.1"
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"marshmallow": {
|
||||
"hashes": [
|
||||
|
@ -804,23 +770,6 @@
|
|||
"markers": "python_version < '3.10' and platform_machine != 'aarch64' and platform_machine != 'arm64'",
|
||||
"version": "==1.22.2"
|
||||
},
|
||||
"openapi-schema-validator": {
|
||||
"hashes": [
|
||||
"sha256:230db361c71a5b08b25ec926797ac8b59a8f499bbd7316bd15b6cd0fc9aea5df",
|
||||
"sha256:8ef097b78c191c89d9a12cdf3d311b2ecf9d3b80bbe8610dbc67a812205a6a8d",
|
||||
"sha256:af023ae0d16372cf8dd0d128c9f3eaa080dc3cd5dfc69e6a247579f25bd10503"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==0.1.6"
|
||||
},
|
||||
"openapi-spec-validator": {
|
||||
"hashes": [
|
||||
"sha256:43d606c5910ed66e1641807993bd0a981de2fc5da44f03e1c4ca2bb65b94b68e",
|
||||
"sha256:49d7da81996714445116f6105c9c5955c0e197ef8636da4f368c913f64753443"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==0.3.3"
|
||||
},
|
||||
"openpyxl": {
|
||||
"hashes": [
|
||||
"sha256:40f568b9829bf9e446acfffce30250ac1fa39035124d55fc024025c41481c90f",
|
||||
|
@ -1002,10 +951,30 @@
|
|||
},
|
||||
"pyrsistent": {
|
||||
"hashes": [
|
||||
"sha256:aa2ae1c2e496f4d6777f869ea5de7166a8ccb9c2e06ebcf6c7ff1b670c98c5ef"
|
||||
"sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c",
|
||||
"sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc",
|
||||
"sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e",
|
||||
"sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26",
|
||||
"sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec",
|
||||
"sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286",
|
||||
"sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045",
|
||||
"sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec",
|
||||
"sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8",
|
||||
"sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c",
|
||||
"sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca",
|
||||
"sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22",
|
||||
"sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a",
|
||||
"sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96",
|
||||
"sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc",
|
||||
"sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1",
|
||||
"sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07",
|
||||
"sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6",
|
||||
"sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b",
|
||||
"sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5",
|
||||
"sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6"
|
||||
],
|
||||
"markers": "python_version >= '2.7'",
|
||||
"version": "==0.16.1"
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==0.18.1"
|
||||
},
|
||||
"python-dateutil": {
|
||||
"hashes": [
|
||||
|
@ -1266,7 +1235,7 @@
|
|||
},
|
||||
"spiffworkflow": {
|
||||
"git": "https://github.com/sartography/SpiffWorkflow",
|
||||
"ref": "5c9301a3f47bd3dbeae72ffefd9d25cfee35fd0e"
|
||||
"ref": "3904fdbc90f7fabddfe1e6a4f802963a2364ae7e"
|
||||
},
|
||||
"sqlalchemy": {
|
||||
"hashes": [
|
||||
|
@ -1376,11 +1345,11 @@
|
|||
},
|
||||
"werkzeug": {
|
||||
"hashes": [
|
||||
"sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43",
|
||||
"sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"
|
||||
"sha256:1421ebfc7648a39a5c58c601b154165d05cf47a3cd0ccb70857cbdacf6c8f2b8",
|
||||
"sha256:b863f8ff057c522164b6067c9e28b041161b4be5ba4d0daceeaa50a163822d3c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.0.1"
|
||||
"version": "==2.0.3"
|
||||
},
|
||||
"wrapt": {
|
||||
"hashes": [
|
||||
|
@ -1483,50 +1452,50 @@
|
|||
},
|
||||
"coverage": {
|
||||
"hashes": [
|
||||
"sha256:1245ab82e8554fa88c4b2ab1e098ae051faac5af829efdcf2ce6b34dccd5567c",
|
||||
"sha256:1bc6d709939ff262fd1432f03f080c5042dc6508b6e0d3d20e61dd045456a1a0",
|
||||
"sha256:25e73d4c81efa8ea3785274a2f7f3bfbbeccb6fcba2a0bdd3be9223371c37554",
|
||||
"sha256:276b13cc085474e482566c477c25ed66a097b44c6e77132f3304ac0b039f83eb",
|
||||
"sha256:2aed4761809640f02e44e16b8b32c1a5dee5e80ea30a0ff0912158bde9c501f2",
|
||||
"sha256:2dd70a167843b4b4b2630c0c56f1b586fe965b4f8ac5da05b6690344fd065c6b",
|
||||
"sha256:352c68e233409c31048a3725c446a9e48bbff36e39db92774d4f2380d630d8f8",
|
||||
"sha256:3f2b05757c92ad96b33dbf8e8ec8d4ccb9af6ae3c9e9bd141c7cc44d20c6bcba",
|
||||
"sha256:448d7bde7ceb6c69e08474c2ddbc5b4cd13c9e4aa4a717467f716b5fc938a734",
|
||||
"sha256:463e52616ea687fd323888e86bf25e864a3cc6335a043fad6bbb037dbf49bbe2",
|
||||
"sha256:482fb42eea6164894ff82abbcf33d526362de5d1a7ed25af7ecbdddd28fc124f",
|
||||
"sha256:56c4a409381ddd7bbff134e9756077860d4e8a583d310a6f38a2315b9ce301d0",
|
||||
"sha256:56d296cbc8254a7dffdd7bcc2eb70be5a233aae7c01856d2d936f5ac4e8ac1f1",
|
||||
"sha256:5e15d424b8153756b7c903bde6d4610be0c3daca3986173c18dd5c1a1625e4cd",
|
||||
"sha256:618eeba986cea7f621d8607ee378ecc8c2504b98b3fdc4952b30fe3578304687",
|
||||
"sha256:61d47a897c1e91f33f177c21de897267b38fbb45f2cd8e22a710bcef1df09ac1",
|
||||
"sha256:621f6ea7260ea2ffdaec64fe5cb521669984f567b66f62f81445221d4754df4c",
|
||||
"sha256:6a5cdc3adb4f8bb8d8f5e64c2e9e282bc12980ef055ec6da59db562ee9bdfefa",
|
||||
"sha256:6c3f6158b02ac403868eea390930ae64e9a9a2a5bbfafefbb920d29258d9f2f8",
|
||||
"sha256:704f89b87c4f4737da2860695a18c852b78ec7279b24eedacab10b29067d3a38",
|
||||
"sha256:72128176fea72012063200b7b395ed8a57849282b207321124d7ff14e26988e8",
|
||||
"sha256:78fbb2be068a13a5d99dce9e1e7d168db880870f7bc73f876152130575bd6167",
|
||||
"sha256:7bff3a98f63b47464480de1b5bdd80c8fade0ba2832c9381253c9b74c4153c27",
|
||||
"sha256:84f2436d6742c01136dd940ee158bfc7cf5ced3da7e4c949662b8703b5cd8145",
|
||||
"sha256:9976fb0a5709988778ac9bc44f3d50fccd989987876dfd7716dee28beed0a9fa",
|
||||
"sha256:9ad0a117b8dc2061ce9461ea4c1b4799e55edceb236522c5b8f958ce9ed8fa9a",
|
||||
"sha256:9e3dd806f34de38d4c01416344e98eab2437ac450b3ae39c62a0ede2f8b5e4ed",
|
||||
"sha256:9eb494070aa060ceba6e4bbf44c1bc5fa97bfb883a0d9b0c9049415f9e944793",
|
||||
"sha256:9fde6b90889522c220dd56a670102ceef24955d994ff7af2cb786b4ba8fe11e4",
|
||||
"sha256:9fff3ff052922cb99f9e52f63f985d4f7a54f6b94287463bc66b7cdf3eb41217",
|
||||
"sha256:a06c358f4aed05fa1099c39decc8022261bb07dfadc127c08cfbd1391b09689e",
|
||||
"sha256:a4f923b9ab265136e57cc14794a15b9dcea07a9c578609cd5dbbfff28a0d15e6",
|
||||
"sha256:c5b81fb37db76ebea79aa963b76d96ff854e7662921ce742293463635a87a78d",
|
||||
"sha256:d5ed164af5c9078596cfc40b078c3b337911190d3faeac830c3f1274f26b8320",
|
||||
"sha256:d651fde74a4d3122e5562705824507e2f5b2d3d57557f1916c4b27635f8fbe3f",
|
||||
"sha256:de73fca6fb403dd72d4da517cfc49fcf791f74eee697d3219f6be29adf5af6ce",
|
||||
"sha256:e647a0be741edbb529a72644e999acb09f2ad60465f80757da183528941ff975",
|
||||
"sha256:e92c7a5f7d62edff50f60a045dc9542bf939758c95b2fcd686175dd10ce0ed10",
|
||||
"sha256:eeffd96882d8c06d31b65dddcf51db7c612547babc1c4c5db6a011abe9798525",
|
||||
"sha256:f5a4551dfd09c3bd12fca8144d47fe7745275adf3229b7223c2f9e29a975ebda",
|
||||
"sha256:fac0bcc5b7e8169bffa87f0dcc24435446d329cbc2b5486d155c2e0f3b493ae1"
|
||||
"sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9",
|
||||
"sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d",
|
||||
"sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf",
|
||||
"sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7",
|
||||
"sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6",
|
||||
"sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4",
|
||||
"sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059",
|
||||
"sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39",
|
||||
"sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536",
|
||||
"sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac",
|
||||
"sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c",
|
||||
"sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903",
|
||||
"sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d",
|
||||
"sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05",
|
||||
"sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684",
|
||||
"sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1",
|
||||
"sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f",
|
||||
"sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7",
|
||||
"sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca",
|
||||
"sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad",
|
||||
"sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca",
|
||||
"sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d",
|
||||
"sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92",
|
||||
"sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4",
|
||||
"sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf",
|
||||
"sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6",
|
||||
"sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1",
|
||||
"sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4",
|
||||
"sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359",
|
||||
"sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3",
|
||||
"sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620",
|
||||
"sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512",
|
||||
"sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69",
|
||||
"sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2",
|
||||
"sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518",
|
||||
"sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0",
|
||||
"sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa",
|
||||
"sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4",
|
||||
"sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e",
|
||||
"sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1",
|
||||
"sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==6.3.1"
|
||||
"version": "==6.3.2"
|
||||
},
|
||||
"iniconfig": {
|
||||
"hashes": [
|
||||
|
|
|
@ -86,7 +86,7 @@ GIT_BRANCH = environ.get('GIT_BRANCH', None) # example: 'main'
|
|||
GIT_MERGE_BRANCH = environ.get('GIT_MERGE_BRANCH', None) # Example: 'staging'
|
||||
|
||||
# Email configuration
|
||||
DEFAULT_SENDER = 'uvacrconnect@virginia.edu'
|
||||
DEFAULT_SENDER = 'crconnect2@virginia.edu'
|
||||
FALLBACK_EMAILS = ['askresearch@virginia.edu', 'sartographysupport@googlegroups.com']
|
||||
MAIL_DEBUG = environ.get('MAIL_DEBUG', default=True)
|
||||
MAIL_SERVER = environ.get('MAIL_SERVER', default='smtp.mailtrap.io')
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import time
|
||||
import uuid
|
||||
|
||||
from SpiffWorkflow.util.metrics import firsttime, timeit, sincetime
|
||||
from flask import g
|
||||
|
||||
from crc import session
|
||||
|
@ -209,7 +210,6 @@ def get_workflow(workflow_id, do_engine_steps=True):
|
|||
workflow_api_model = WorkflowService.processor_to_workflow_api(processor)
|
||||
return WorkflowApiSchema().dump(workflow_api_model)
|
||||
|
||||
|
||||
def restart_workflow(workflow_id, clear_data=False, delete_files=False):
|
||||
"""Restart a workflow with the latest spec.
|
||||
Clear data allows user to restart the workflow without previous data."""
|
||||
|
@ -219,7 +219,8 @@ def restart_workflow(workflow_id, clear_data=False, delete_files=False):
|
|||
processor.save()
|
||||
WorkflowService.update_task_assignments(processor)
|
||||
workflow_api_model = WorkflowService.processor_to_workflow_api(processor)
|
||||
return WorkflowApiSchema().dump(workflow_api_model)
|
||||
api_model = WorkflowApiSchema().dump(workflow_api_model)
|
||||
return api_model
|
||||
|
||||
|
||||
def get_task_events(action = None, workflow = None, study = None):
|
||||
|
|
|
@ -3,6 +3,7 @@ import enum
|
|||
import marshmallow
|
||||
from marshmallow import EXCLUDE, post_load, fields, INCLUDE
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import deferred
|
||||
|
||||
from crc import db, ma
|
||||
|
||||
|
@ -104,10 +105,10 @@ class WorkflowStatus(enum.Enum):
|
|||
class WorkflowModel(db.Model):
|
||||
__tablename__ = 'workflow'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
bpmn_workflow_json = db.Column(db.JSON)
|
||||
bpmn_workflow_json = deferred(db.Column(db.JSON))
|
||||
status = db.Column(db.Enum(WorkflowStatus))
|
||||
study_id = db.Column(db.Integer, db.ForeignKey('study.id'))
|
||||
study = db.relationship("StudyModel", backref='workflow')
|
||||
study = db.relationship("StudyModel", backref='workflow', lazy='select')
|
||||
workflow_spec_id = db.Column(db.String)
|
||||
total_tasks = db.Column(db.Integer, default=0)
|
||||
completed_tasks = db.Column(db.Integer, default=0)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from SpiffWorkflow.util.metrics import timeit
|
||||
|
||||
from crc.scripts.script import Script
|
||||
from crc.services.user_file_service import UserFileService
|
||||
|
||||
|
@ -14,10 +16,6 @@ class IsFileUploaded(Script):
|
|||
|
||||
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
|
||||
files = UserFileService.get_files_for_study(study_id)
|
||||
if len(files) > 0:
|
||||
doc_code = args[0]
|
||||
for file in files:
|
||||
if doc_code == file.irb_doc_code:
|
||||
return True
|
||||
return False
|
||||
doc_code = args[0]
|
||||
files = UserFileService.get_files_for_study(study_id, irb_doc_code=doc_code)
|
||||
return len(files) > 0
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
from crc import session
|
||||
from crc.api.common import ApiError
|
||||
from crc.models.file import FileModel, FileDataModel
|
||||
from crc.scripts.script import Script
|
||||
|
||||
from io import BytesIO
|
||||
from openpyxl import load_workbook
|
||||
from openpyxl.writer.excel import save_virtual_workbook
|
||||
|
||||
|
||||
class ModifySpreadsheet(Script):
|
||||
|
||||
@staticmethod
|
||||
def get_parameters(args, kwargs):
|
||||
parameters = {}
|
||||
if len(args) == 3 or ('irb_doc_code' in kwargs and 'cell' in kwargs and 'text' in kwargs):
|
||||
if 'irb_doc_code' in kwargs and 'cell' in kwargs and 'text' in kwargs:
|
||||
parameters['irb_doc_code'] = (kwargs['irb_doc_code'])
|
||||
parameters['cell'] = (kwargs['cell'])
|
||||
parameters['text'] = (kwargs['text'])
|
||||
else:
|
||||
parameters['irb_doc_code'] = (args[0])
|
||||
parameters['cell'] = (args[1])
|
||||
parameters['text'] = (args[2])
|
||||
return parameters
|
||||
|
||||
def get_description(self):
|
||||
return """Script to modify an existing spreadsheet.
|
||||
It inserts text into a spreadsheet in the cell indicated.
|
||||
Requires 'irb_doc_code', 'cell', and 'text' parameters.
|
||||
Example: modify_spreadsheet('Finance_BCA', 'C4', 'This is my inserted text')
|
||||
Example: modify_spreadsheet(irb_doc_code='Finance_BCA', cell='C4', text='This is my inserted text')
|
||||
"""
|
||||
|
||||
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
parameters = self.get_parameters(args, kwargs)
|
||||
if len(parameters) == 3:
|
||||
return True
|
||||
else:
|
||||
raise ApiError(code='missing_parameters',
|
||||
message='The modify_spreadsheet script requires 3 parameters: irb_doc_code, cell, and text')
|
||||
|
||||
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
parameters = self.get_parameters(args, kwargs)
|
||||
if len(parameters) == 3:
|
||||
|
||||
spreadsheet = session.query(FileModel). \
|
||||
filter(FileModel.workflow_id == workflow_id). \
|
||||
filter(FileModel.irb_doc_code == parameters['irb_doc_code']).\
|
||||
first()
|
||||
if spreadsheet:
|
||||
spreadsheet_data = session.query(FileDataModel).\
|
||||
filter(FileDataModel.file_model_id==spreadsheet.id).\
|
||||
first()
|
||||
workbook = load_workbook(BytesIO(spreadsheet_data.data))
|
||||
sheet = workbook.active
|
||||
sheet[parameters['cell']] = parameters['text']
|
||||
data_string = save_virtual_workbook(workbook)
|
||||
spreadsheet_data.data = data_string
|
||||
session.commit()
|
||||
else:
|
||||
raise ApiError(code='missing_spreadsheet',
|
||||
message=f"The spreadshhet you want to modify does not exist. Workflow ID is {workflow_id}, and IRB Doc Code is {parameters['irb_doc_code']}")
|
||||
else:
|
||||
raise ApiError(code='missing_parameters',
|
||||
message='The modify_spreadsheet script requires 3 parameters: irb_doc_code, cell, and text')
|
|
@ -2,14 +2,20 @@ import importlib
|
|||
import os
|
||||
import pkgutil
|
||||
|
||||
from SpiffWorkflow.util.metrics import timeit
|
||||
|
||||
from crc.api.common import ApiError
|
||||
|
||||
|
||||
# Generally speaking, having some global in a flask app is TERRIBLE.
|
||||
# This is here, because after loading the application this will never change under
|
||||
# any known condition, and it is expensive to calculate it everytime.
|
||||
SCRIPT_SUB_CLASSES = None
|
||||
|
||||
class Script(object):
|
||||
""" Provides an abstract class that defines how scripts should work, this
|
||||
must be extended in all Script Tasks."""
|
||||
|
||||
SUB_CLASSES = []
|
||||
|
||||
def get_description(self):
|
||||
raise ApiError("invalid_script",
|
||||
|
@ -82,10 +88,11 @@ class Script(object):
|
|||
|
||||
@classmethod
|
||||
def get_all_subclasses(cls):
|
||||
# This is expensive to generate, so reuse it if possible.
|
||||
if not cls.SUB_CLASSES:
|
||||
cls.SUB_CLASSES = Script._get_all_subclasses(Script)
|
||||
return cls.SUB_CLASSES
|
||||
# This is expensive to generate, never changes after we load up.
|
||||
global SCRIPT_SUB_CLASSES
|
||||
if not SCRIPT_SUB_CLASSES:
|
||||
SCRIPT_SUB_CLASSES = Script._get_all_subclasses(Script)
|
||||
return SCRIPT_SUB_CLASSES
|
||||
|
||||
@staticmethod
|
||||
def _get_all_subclasses(cls):
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
from crc import session
|
||||
from crc.api.common import ApiError
|
||||
from crc.models.api_models import WorkflowApi, WorkflowApiSchema
|
||||
from crc.models.workflow import WorkflowModel, WorkflowStatus
|
||||
from crc.scripts.script import Script
|
||||
from crc.services.workflow_processor import WorkflowProcessor
|
||||
from crc.services.workflow_service import WorkflowService
|
||||
|
||||
|
||||
class StartWorkflow(Script):
|
||||
|
||||
@staticmethod
|
||||
def get_workflow(workflow_id):
|
||||
workflow_model: WorkflowModel = session.query(WorkflowModel).filter_by(id=workflow_id).first()
|
||||
processor = WorkflowProcessor(workflow_model)
|
||||
|
||||
processor.do_engine_steps()
|
||||
processor.save()
|
||||
WorkflowService.update_task_assignments(processor)
|
||||
|
||||
workflow_api_model = WorkflowService.processor_to_workflow_api(processor)
|
||||
return WorkflowApiSchema().dump(workflow_api_model)
|
||||
|
||||
def get_description(self):
|
||||
return """Script to start a workflow programmatically.
|
||||
It requires a workflow_spec_id.
|
||||
It accepts the workflow_spec_id as a positional argument
|
||||
or with the keyword 'workflow_spec_id'"""
|
||||
|
||||
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
if len(args) == 1 or 'workflow_spec_id' in kwargs:
|
||||
if 'workflow_spec_id' in kwargs:
|
||||
workflow_spec_id = kwargs['workflow_spec_id']
|
||||
else:
|
||||
workflow_spec_id = args[0]
|
||||
|
||||
workflow_api = WorkflowApi(1234,
|
||||
WorkflowStatus('user_input_required'),
|
||||
'next_task',
|
||||
'navigation',
|
||||
workflow_spec_id,
|
||||
'total_tasks',
|
||||
'completed_tasks',
|
||||
'last_updated',
|
||||
'is_review',
|
||||
'title',
|
||||
study_id)
|
||||
return WorkflowApiSchema().dump(workflow_api)
|
||||
|
||||
else:
|
||||
raise ApiError(code='missing_parameter',
|
||||
message=f'The start_workflow script requires a workflow id')
|
||||
|
||||
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
if len(args) == 1 or 'workflow_spec_id' in kwargs:
|
||||
if 'workflow_spec_id' in kwargs:
|
||||
workflow_spec_id = kwargs['workflow_spec_id']
|
||||
else:
|
||||
workflow_spec_id = args[0]
|
||||
|
||||
workflow = session.query(WorkflowModel).\
|
||||
filter(WorkflowModel.study_id==study_id).\
|
||||
filter(WorkflowModel.workflow_spec_id==workflow_spec_id).\
|
||||
first()
|
||||
|
||||
if workflow:
|
||||
workflow_api = self.get_workflow(workflow.id)
|
||||
return workflow_api
|
||||
else:
|
||||
raise ApiError(code='unknown_workflow',
|
||||
message=f"We could not find a workflow with workflow_spec_id '{workflow_spec_id}'.")
|
||||
|
||||
else:
|
||||
raise ApiError(code='missing_parameter',
|
||||
message=f'The start_workflow script requires a workflow id')
|
|
@ -166,7 +166,6 @@ Please note this is just a few examples, ALL known document types are returned i
|
|||
# in order to test multiple paths thru the workflow
|
||||
return self.do_task(task, study_id, workflow_id, *args, **kwargs)
|
||||
|
||||
@timeit
|
||||
def do_task(self, task, study_id, workflow_id, *args, **kwargs):
|
||||
self.check_args(args, 2)
|
||||
prefix = None
|
||||
|
|
|
@ -3,6 +3,7 @@ from json import JSONDecodeError
|
|||
from typing import List, Optional
|
||||
|
||||
import requests
|
||||
from SpiffWorkflow.util.metrics import timeit
|
||||
|
||||
from crc import app
|
||||
from crc.api.common import ApiError
|
||||
|
|
|
@ -113,6 +113,13 @@ class SpecFileService(FileSystemService):
|
|||
|
||||
except etree.XMLSyntaxError as xse:
|
||||
raise ApiError("invalid_xml", "Failed to parse xml: " + str(xse), file_name=file_name)
|
||||
except ValidationException as ve:
|
||||
if ve.args[0].find('No executable process tag found') >= 0:
|
||||
raise ApiError(code='missing_executable_option',
|
||||
message='No executable process tag found. Please make sure the Executable option is set in the workflow.')
|
||||
else:
|
||||
raise ApiError(code='validation_error',
|
||||
message=f'There was an error validating your workflow. Original message is: {ve}')
|
||||
else:
|
||||
raise ApiError("invalid_xml", "Only a BPMN can be the primary file.", file_name=file_name)
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ import requests
|
|||
from SpiffWorkflow import WorkflowException
|
||||
from SpiffWorkflow.bpmn.PythonScriptEngine import Box
|
||||
from SpiffWorkflow.exceptions import WorkflowTaskExecException
|
||||
from SpiffWorkflow.util.metrics import timeit, firsttime, sincetime, LOG
|
||||
from flask import g
|
||||
from ldap3.core.exceptions import LDAPSocketOpenError
|
||||
|
||||
from crc import db, session, app
|
||||
|
@ -251,8 +253,20 @@ class StudyService(object):
|
|||
session.delete(workflow)
|
||||
session.commit()
|
||||
|
||||
@classmethod
|
||||
def get_documents_status(cls, study_id, force=False):
|
||||
"""Returns a list of documents related to the study, and any file information
|
||||
that is available. This is a fairly expensive operation. So we cache the results
|
||||
in Flask's g. Each fresh api request will get an up to date list, but we won't
|
||||
re-create it sevearl times."""
|
||||
if 'doc_statuses' not in g:
|
||||
g.doc_statuses = {}
|
||||
if study_id not in g.doc_statuses or force:
|
||||
g.doc_statuses[study_id] = StudyService.__get_documents_status(study_id)
|
||||
return g.doc_statuses[study_id]
|
||||
|
||||
@staticmethod
|
||||
def get_documents_status(study_id):
|
||||
def __get_documents_status(study_id):
|
||||
"""Returns a list of documents related to the study, and any file information
|
||||
that is available.."""
|
||||
|
||||
|
@ -265,12 +279,13 @@ class StudyService(object):
|
|||
pb_docs = []
|
||||
else:
|
||||
pb_docs = []
|
||||
|
||||
# Loop through all known document types, get the counts for those files,
|
||||
# and use pb_docs to mark those as required.
|
||||
doc_dictionary = DocumentService.get_dictionary()
|
||||
|
||||
documents = {}
|
||||
study_files = UserFileService.get_files_for_study(study_id=study_id)
|
||||
|
||||
for code, doc in doc_dictionary.items():
|
||||
|
||||
doc['required'] = False
|
||||
|
@ -284,6 +299,7 @@ class StudyService(object):
|
|||
doc['study_id'] = study_id
|
||||
doc['code'] = code
|
||||
|
||||
|
||||
# Make a display name out of categories
|
||||
name_list = []
|
||||
for cat_key in ['category1', 'category2', 'category3']:
|
||||
|
@ -291,11 +307,14 @@ class StudyService(object):
|
|||
name_list.append(doc[cat_key])
|
||||
doc['display_name'] = ' / '.join(name_list)
|
||||
|
||||
|
||||
# For each file, get associated workflow status
|
||||
doc_files = UserFileService.get_files_for_study(study_id=study_id, irb_doc_code=code)
|
||||
doc_files = list(filter(lambda f: f.irb_doc_code == code, study_files))
|
||||
# doc_files = UserFileService.get_files_for_study(study_id=study_id, irb_doc_code=code)
|
||||
doc['count'] = len(doc_files)
|
||||
doc['files'] = []
|
||||
|
||||
|
||||
for file_model in doc_files:
|
||||
file = File.from_models(file_model, UserFileService.get_file_data(file_model.id), [])
|
||||
file_data = FileSchema().dump(file)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import json
|
||||
from typing import List
|
||||
|
||||
from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine
|
||||
|
@ -59,7 +60,6 @@ class CustomBpmnScriptEngine(PythonScriptEngine):
|
|||
"Error evaluating expression "
|
||||
"'%s', %s" % (expression, str(e)))
|
||||
|
||||
@timeit
|
||||
def execute(self, task: SpiffTask, script, data):
|
||||
study_id = task.workflow.data[WorkflowProcessor.STUDY_ID_KEY]
|
||||
if WorkflowProcessor.WORKFLOW_ID_KEY in task.workflow.data:
|
||||
|
@ -70,6 +70,7 @@ class CustomBpmnScriptEngine(PythonScriptEngine):
|
|||
if task.workflow.data[WorkflowProcessor.VALIDATION_PROCESS_KEY]:
|
||||
augment_methods = Script.generate_augmented_validate_list(task, study_id, workflow_id)
|
||||
else:
|
||||
# Costs 0.25 seconds the first time it is executed.
|
||||
augment_methods = Script.generate_augmented_list(task, study_id, workflow_id)
|
||||
super().execute(task, script, data, external_methods=augment_methods)
|
||||
except WorkflowException as e:
|
||||
|
@ -78,10 +79,6 @@ class CustomBpmnScriptEngine(PythonScriptEngine):
|
|||
raise WorkflowTaskExecException(task, f' {script}, {e}', e)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class MyCustomParser(BpmnDmnParser):
|
||||
"""
|
||||
A BPMN and DMN parser that can also parse Camunda forms.
|
||||
|
@ -110,7 +107,27 @@ class WorkflowProcessor(object):
|
|||
raise (ApiError("missing_spec", "The spec this workflow references does not currently exist."))
|
||||
self.spec_files = SpecFileService.get_files(spec_info, include_libraries=True)
|
||||
spec = self.get_spec(self.spec_files, spec_info)
|
||||
|
||||
else:
|
||||
B = len(workflow_model.bpmn_workflow_json.encode('utf-8'))
|
||||
MB = float(1024 ** 2)
|
||||
json_size = B/MB
|
||||
if json_size > 1:
|
||||
wf_json = json.loads(workflow_model.bpmn_workflow_json)
|
||||
task_tree = wf_json['task_tree']
|
||||
test_spec = wf_json['wf_spec']
|
||||
task_size = "{:.2f}".format(len(json.dumps(task_tree).encode('utf-8'))/MB)
|
||||
spec_size = "{:.2f}".format(len(test_spec.encode('utf-8'))/MB)
|
||||
task_specs = json.loads(test_spec)['task_specs']
|
||||
sub_workflows = json.loads(test_spec)['sub_workflows']
|
||||
message = 'Workflow ' + workflow_model.workflow_spec_id + ' JSON Size is over 1MB:{0:.2f} MB'.format(json_size)
|
||||
message += f"\n Task Size: {task_size}"
|
||||
message += f"\n Spec Size: {spec_size}"
|
||||
message += f"\n Largest Sub-Process Sizes:"
|
||||
for sw_name, sw_data in sub_workflows.items():
|
||||
size = len(json.dumps(sw_data).encode('utf-8')) / MB
|
||||
if size > 0.1:
|
||||
message += "\n " + sw_name + " {:.2f}".format(size)
|
||||
app.logger.warning(message)
|
||||
self.workflow_spec_id = workflow_model.workflow_spec_id
|
||||
|
||||
try:
|
||||
|
@ -127,7 +144,6 @@ class WorkflowProcessor(object):
|
|||
if self.WORKFLOW_ID_KEY not in self.bpmn_workflow.data:
|
||||
if not workflow_model.id:
|
||||
session.add(workflow_model)
|
||||
session.commit()
|
||||
# If the model is new, and has no id, save it, write it into the workflow model
|
||||
# and save it again. In this way, the workflow process is always aware of the
|
||||
# database model to which it is associated, and scripts running within the model
|
||||
|
@ -135,6 +151,7 @@ class WorkflowProcessor(object):
|
|||
self.bpmn_workflow.data[WorkflowProcessor.WORKFLOW_ID_KEY] = workflow_model.id
|
||||
workflow_model.bpmn_workflow_json = WorkflowProcessor._serializer.serialize_workflow(
|
||||
self.bpmn_workflow, include_spec=True)
|
||||
|
||||
self.save()
|
||||
|
||||
except MissingSpecError as ke:
|
||||
|
@ -145,11 +162,10 @@ class WorkflowProcessor(object):
|
|||
|
||||
@staticmethod
|
||||
def reset(workflow_model, clear_data=False, delete_files=False):
|
||||
|
||||
# Try to execute a cancel notify
|
||||
try:
|
||||
wp = WorkflowProcessor(workflow_model)
|
||||
wp.cancel_notify() # The executes a notification to all endpoints that
|
||||
bpmn_workflow = WorkflowProcessor.__get_bpmn_workflow(workflow_model)
|
||||
WorkflowProcessor.__cancel_notify(bpmn_workflow)
|
||||
except Exception as e:
|
||||
app.logger.error(f"Unable to send a cancel notify for workflow %s during a reset."
|
||||
f" Continuing with the reset anyway so we don't get in an unresolvable"
|
||||
|
@ -170,12 +186,14 @@ class WorkflowProcessor(object):
|
|||
session.commit()
|
||||
return WorkflowProcessor(workflow_model)
|
||||
|
||||
def __get_bpmn_workflow(self, workflow_model: WorkflowModel, spec: WorkflowSpec, validate_only=False):
|
||||
@staticmethod
|
||||
def __get_bpmn_workflow(workflow_model: WorkflowModel, spec: WorkflowSpec = None, validate_only=False):
|
||||
if workflow_model.bpmn_workflow_json:
|
||||
bpmn_workflow = self._serializer.deserialize_workflow(workflow_model.bpmn_workflow_json,
|
||||
bpmn_workflow = WorkflowProcessor._serializer.deserialize_workflow(workflow_model.bpmn_workflow_json,
|
||||
workflow_spec=spec)
|
||||
bpmn_workflow.script_engine = WorkflowProcessor._script_engine
|
||||
else:
|
||||
bpmn_workflow = BpmnWorkflow(spec, script_engine=self._script_engine)
|
||||
bpmn_workflow = BpmnWorkflow(spec, script_engine=WorkflowProcessor._script_engine)
|
||||
bpmn_workflow.data[WorkflowProcessor.STUDY_ID_KEY] = workflow_model.study_id
|
||||
bpmn_workflow.data[WorkflowProcessor.VALIDATION_PROCESS_KEY] = validate_only
|
||||
return bpmn_workflow
|
||||
|
@ -193,22 +211,16 @@ class WorkflowProcessor(object):
|
|||
session.commit()
|
||||
|
||||
@staticmethod
|
||||
@timeit
|
||||
def run_master_spec(spec_model, study):
|
||||
"""Executes a BPMN specification for the given study, without recording any information to the database
|
||||
Useful for running the master specification, which should not persist. """
|
||||
lasttime = firsttime()
|
||||
spec_files = SpecFileService().get_files(spec_model, include_libraries=True)
|
||||
lasttime = sincetime('load Files', lasttime)
|
||||
spec = WorkflowProcessor.get_spec(spec_files, spec_model)
|
||||
lasttime = sincetime('get spec', lasttime)
|
||||
try:
|
||||
bpmn_workflow = BpmnWorkflow(spec, script_engine=WorkflowProcessor._script_engine)
|
||||
bpmn_workflow.data[WorkflowProcessor.STUDY_ID_KEY] = study.id
|
||||
bpmn_workflow.data[WorkflowProcessor.VALIDATION_PROCESS_KEY] = False
|
||||
lasttime = sincetime('get_workflow', lasttime)
|
||||
bpmn_workflow.do_engine_steps()
|
||||
lasttime = sincetime('run steps', lasttime)
|
||||
except WorkflowException as we:
|
||||
raise ApiError.from_task_spec("error_running_master_spec", str(we), we.sender)
|
||||
|
||||
|
@ -275,14 +287,19 @@ class WorkflowProcessor(object):
|
|||
raise ApiError.from_workflow_exception("task_error", str(we), we)
|
||||
|
||||
def cancel_notify(self):
|
||||
self.__cancel_notify(self.bpmn_workflow)
|
||||
|
||||
@staticmethod
|
||||
def __cancel_notify(bpmn_workflow):
|
||||
try:
|
||||
# A little hackly, but make the bpmn_workflow catch a cancel event.
|
||||
self.bpmn_workflow.signal('cancel') # generate a cancel signal.
|
||||
self.bpmn_workflow.catch(CancelEventDefinition())
|
||||
self.bpmn_workflow.do_engine_steps()
|
||||
bpmn_workflow.signal('cancel') # generate a cancel signal.
|
||||
bpmn_workflow.catch(CancelEventDefinition())
|
||||
bpmn_workflow.do_engine_steps()
|
||||
except WorkflowTaskExecException as we:
|
||||
raise ApiError.from_workflow_exception("task_error", str(we), we)
|
||||
|
||||
|
||||
def serialize(self):
|
||||
return self._serializer.serialize_workflow(self.bpmn_workflow,include_spec=True)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ from SpiffWorkflow.dmn.specs.BusinessRuleTask import BusinessRuleTask
|
|||
from SpiffWorkflow.exceptions import WorkflowTaskExecException
|
||||
from SpiffWorkflow.specs import CancelTask, StartTask
|
||||
from SpiffWorkflow.util.deep_merge import DeepMerge
|
||||
from SpiffWorkflow.util.metrics import timeit
|
||||
from SpiffWorkflow.util.metrics import timeit, firsttime, sincetime
|
||||
from sqlalchemy.exc import InvalidRequestError
|
||||
|
||||
from crc import db, app, session
|
||||
|
@ -177,7 +177,6 @@ class WorkflowService(object):
|
|||
raise ApiError(code='disabled_workflow', message=f"This workflow is disabled. {status[spec_id]['message']}")
|
||||
|
||||
@staticmethod
|
||||
@timeit
|
||||
def test_spec(spec_id, validate_study_id=None, test_until=None, required_only=False):
|
||||
"""Runs a spec through it's paces to see if it results in any errors.
|
||||
Not fool-proof, but a good sanity check. Returns the final data
|
||||
|
@ -256,6 +255,9 @@ class WorkflowService(object):
|
|||
|
||||
hide_groups = []
|
||||
|
||||
for field in task_api.form.fields:
|
||||
form_data[field.id] = None
|
||||
|
||||
for field in task_api.form.fields:
|
||||
# Assure we have a field type
|
||||
if field.type is None:
|
||||
|
@ -627,7 +629,6 @@ class WorkflowService(object):
|
|||
def processor_to_workflow_api(processor: WorkflowProcessor, next_task=None):
|
||||
"""Returns an API model representing the state of the current workflow, if requested, and
|
||||
possible, next_task is set to the current_task."""
|
||||
|
||||
navigation = processor.bpmn_workflow.get_deep_nav_list()
|
||||
WorkflowService.update_navigation(navigation, processor)
|
||||
spec_service = WorkflowSpecService()
|
||||
|
@ -658,6 +659,7 @@ class WorkflowService(object):
|
|||
user_uids = WorkflowService.get_users_assigned_to_task(processor, next_task)
|
||||
if not UserService.in_list(user_uids, allow_admin_impersonate=True):
|
||||
workflow_api.next_task.state = WorkflowService.TASK_STATE_LOCKED
|
||||
|
||||
return workflow_api
|
||||
|
||||
@staticmethod
|
||||
|
@ -666,9 +668,7 @@ class WorkflowService(object):
|
|||
for nav_item in navigation:
|
||||
spiff_task = processor.bpmn_workflow.get_task(nav_item.task_id)
|
||||
if spiff_task:
|
||||
# Use existing logic to set the description, and alter the state based on permissions.
|
||||
api_task = WorkflowService.spiff_task_to_api_task(spiff_task, add_docs_and_forms=False)
|
||||
nav_item.description = api_task.title
|
||||
nav_item.description = WorkflowService.__calculate_title(spiff_task)
|
||||
user_uids = WorkflowService.get_users_assigned_to_task(processor, spiff_task)
|
||||
if (isinstance(spiff_task.task_spec, UserTask) or isinstance(spiff_task.task_spec, ManualTask)) \
|
||||
and not UserService.in_list(user_uids, allow_admin_impersonate=True):
|
||||
|
@ -777,13 +777,23 @@ class WorkflowService(object):
|
|||
if spiff_task.state == SpiffTask.READY:
|
||||
task.properties = WorkflowService._process_properties(spiff_task, props)
|
||||
|
||||
# Replace the title with the display name if it is set in the task properties,
|
||||
# otherwise strip off the first word of the task, as that should be following
|
||||
# a BPMN standard, and should not be included in the display.
|
||||
if task.properties and "display_name" in task.properties:
|
||||
task.title = WorkflowService.__calculate_title(spiff_task)
|
||||
|
||||
if task.properties and "clear_data" in task.properties:
|
||||
if task.form and task.properties['clear_data'] == 'True':
|
||||
for i in range(len(task.form.fields)):
|
||||
task.data.pop(task.form.fields[i].id, None)
|
||||
|
||||
return task
|
||||
|
||||
@staticmethod
|
||||
def __calculate_title(spiff_task):
|
||||
title = spiff_task.task_spec.description or None
|
||||
if hasattr(spiff_task.task_spec, 'extensions') and "display_name" in spiff_task.task_spec.extensions:
|
||||
title = spiff_task.task_spec.extensions["display_name"]
|
||||
try:
|
||||
task.title = spiff_task.workflow.script_engine.evaluate(spiff_task,
|
||||
task.properties[Task.PROP_EXTENSIONS_TITLE])
|
||||
title = JinjaService.get_content(title, spiff_task.data)
|
||||
title = spiff_task.workflow.script_engine.evaluate(spiff_task, title)
|
||||
except Exception as e:
|
||||
# if the task is ready, we should raise an error, but if it is in the future or the past, we may not
|
||||
# have the information we need to properly set the title, so don't error out, and just use what is
|
||||
|
@ -793,16 +803,10 @@ class WorkflowService(object):
|
|||
message="Could not set task title on task %s with '%s' property because %s" %
|
||||
(spiff_task.task_spec.name, Task.PROP_EXTENSIONS_TITLE, str(e)),
|
||||
task=spiff_task)
|
||||
# Otherwise, just use the curreent title.
|
||||
elif task.title and ' ' in task.title:
|
||||
task.title = task.title.partition(' ')[2]
|
||||
elif title and ' ' in title:
|
||||
title = title.partition(' ')[2]
|
||||
return title
|
||||
|
||||
if task.properties and "clear_data" in task.properties:
|
||||
if task.form and task.properties['clear_data'] == 'True':
|
||||
for i in range(len(task.form.fields)):
|
||||
task.data.pop(task.form.fields[i].id, None)
|
||||
|
||||
return task
|
||||
|
||||
@staticmethod
|
||||
def _process_properties(spiff_task, props):
|
||||
|
@ -839,7 +843,10 @@ class WorkflowService(object):
|
|||
try:
|
||||
return JinjaService.get_content(raw_doc, spiff_task.data)
|
||||
except jinja2.exceptions.TemplateSyntaxError as tse:
|
||||
error_line = documentation.splitlines()[tse.lineno - 1]
|
||||
lines = tse.source.splitlines()
|
||||
error_line = ""
|
||||
if len(lines) >= tse.lineno - 1:
|
||||
error_line = tse.source.splitlines()[tse.lineno - 1]
|
||||
raise ApiError.from_task(code="template_error", message="Jinja Template Error: %s" % str(tse),
|
||||
task=spiff_task, line_number=tse.lineno, error_line=error_line)
|
||||
except jinja2.exceptions.TemplateError as te:
|
||||
|
@ -926,9 +933,8 @@ class WorkflowService(object):
|
|||
db.session.query(TaskEventModel). \
|
||||
filter(TaskEventModel.workflow_id == processor.workflow_model.id). \
|
||||
filter(TaskEventModel.action == WorkflowService.TASK_ACTION_ASSIGNMENT).delete()
|
||||
db.session.commit()
|
||||
|
||||
for task in processor.get_current_user_tasks():
|
||||
tasks = processor.get_current_user_tasks()
|
||||
for task in tasks:
|
||||
user_ids = WorkflowService.get_users_assigned_to_task(processor, task)
|
||||
for user_id in user_ids:
|
||||
WorkflowService.log_task_action(user_id, processor, task, WorkflowService.TASK_ACTION_ASSIGNMENT)
|
||||
|
@ -996,7 +1002,6 @@ class WorkflowService(object):
|
|||
# date=datetime.utcnow(), <=== For future reference, NEVER do this. Let the database set the time.
|
||||
)
|
||||
db.session.add(task_event)
|
||||
db.session.commit()
|
||||
|
||||
@staticmethod
|
||||
def extract_form_data(latest_data, task):
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_0g5rfar" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
|
||||
<bpmn:process id="Process_05y6lb7">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_0djwo51</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0djwo51" sourceRef="StartEvent_1" targetRef="Activity_1gst0w5" />
|
||||
<bpmn:endEvent id="Event_1fetqlx">
|
||||
<bpmn:incoming>Flow_19hnovy</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_19hnovy" sourceRef="Activity_1gst0w5" targetRef="Event_1fetqlx" />
|
||||
<bpmn:manualTask id="Activity_1gst0w5" name="Hello World">
|
||||
<bpmn:documentation>## Hello World</bpmn:documentation>
|
||||
<bpmn:incoming>Flow_0djwo51</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_19hnovy</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_05y6lb7">
|
||||
<bpmndi:BPMNEdge id="Flow_0djwo51_di" bpmnElement="Flow_0djwo51">
|
||||
<di:waypoint x="215" y="117" />
|
||||
<di:waypoint x="270" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_19hnovy_di" bpmnElement="Flow_19hnovy">
|
||||
<di:waypoint x="370" y="117" />
|
||||
<di:waypoint x="432" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="179" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1fetqlx_di" bpmnElement="Event_1fetqlx">
|
||||
<dc:Bounds x="432" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_07hce4z_di" bpmnElement="Activity_1gst0w5">
|
||||
<dc:Bounds x="270" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1wrf54p" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
|
||||
<bpmn:process id="Process_ModifySpreadsheet" name="Modify Spreadsheet" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_03wyga3</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_03wyga3" sourceRef="StartEvent_1" targetRef="Activity_FileUpload" />
|
||||
<bpmn:sequenceFlow id="Flow_0msewj5" sourceRef="Activity_FileUpload" targetRef="Activity_GetModifyData" />
|
||||
<bpmn:sequenceFlow id="Flow_0fpc32g" sourceRef="Activity_GetModifyData" targetRef="Activity_ModifySpreadsheet" />
|
||||
<bpmn:sequenceFlow id="Flow_10ulj3l" sourceRef="Activity_ModifySpreadsheet" targetRef="Event_1d07dls" />
|
||||
<bpmn:endEvent id="Event_1d07dls">
|
||||
<bpmn:incoming>Flow_10ulj3l</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:userTask id="Activity_FileUpload" name="Upload Spreadsheet" camunda:formKey="FileUpload">
|
||||
<bpmn:extensionElements>
|
||||
<camunda:formData>
|
||||
<camunda:formField id="Finance_BCA" label="'File Upload'" type="file">
|
||||
<camunda:validation>
|
||||
<camunda:constraint name="required" config="True" />
|
||||
</camunda:validation>
|
||||
</camunda:formField>
|
||||
</camunda:formData>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_03wyga3</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0msewj5</bpmn:outgoing>
|
||||
</bpmn:userTask>
|
||||
<bpmn:scriptTask id="Activity_ModifySpreadsheet" name="Modify Spreadsheet">
|
||||
<bpmn:incoming>Flow_0fpc32g</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_10ulj3l</bpmn:outgoing>
|
||||
<bpmn:script>modify_spreadsheet(irb_doc_code='Finance_BCA', cell=cell_indicator, text=input_text)</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:userTask id="Activity_GetModifyData" name="Get Modify Data" camunda:formKey="ModifyData">
|
||||
<bpmn:documentation>## File Upload
|
||||
{{ Finance_BCA }}</bpmn:documentation>
|
||||
<bpmn:extensionElements>
|
||||
<camunda:formData>
|
||||
<camunda:formField id="cell_indicator" label="Cell Indicator" type="string">
|
||||
<camunda:validation>
|
||||
<camunda:constraint name="required" config="True" />
|
||||
</camunda:validation>
|
||||
</camunda:formField>
|
||||
<camunda:formField id="input_text" label="Input Text" type="string">
|
||||
<camunda:validation>
|
||||
<camunda:constraint name="required" config="True" />
|
||||
</camunda:validation>
|
||||
</camunda:formField>
|
||||
</camunda:formData>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_0msewj5</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0fpc32g</bpmn:outgoing>
|
||||
</bpmn:userTask>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_ModifySpreadsheet">
|
||||
<bpmndi:BPMNEdge id="Flow_10ulj3l_di" bpmnElement="Flow_10ulj3l">
|
||||
<di:waypoint x="691" y="117" />
|
||||
<di:waypoint x="912" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0fpc32g_di" bpmnElement="Flow_0fpc32g">
|
||||
<di:waypoint x="530" y="117" />
|
||||
<di:waypoint x="591" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0msewj5_di" bpmnElement="Flow_0msewj5">
|
||||
<di:waypoint x="370" y="117" />
|
||||
<di:waypoint x="430" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_03wyga3_di" bpmnElement="Flow_03wyga3">
|
||||
<di:waypoint x="215" y="117" />
|
||||
<di:waypoint x="270" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="179" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1d07dls_di" bpmnElement="Event_1d07dls">
|
||||
<dc:Bounds x="912" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0jut75d_di" bpmnElement="Activity_FileUpload">
|
||||
<dc:Bounds x="270" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0uk32ds_di" bpmnElement="Activity_ModifySpreadsheet">
|
||||
<dc:Bounds x="591" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0hn4ju2_di" bpmnElement="Activity_GetModifyData">
|
||||
<dc:Bounds x="430" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
Binary file not shown.
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_00dbd41" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.0.0">
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_00dbd41" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.10.0">
|
||||
<bpmn:process id="Process_SetStudyStatus" name="Set Study Status" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_0c77bdh</bpmn:outgoing>
|
||||
|
@ -7,7 +7,10 @@
|
|||
<bpmn:userTask id="Activity_GetSelectedStatus" name="Get Selected Status" camunda:formKey="SelectStudyStatus">
|
||||
<bpmn:extensionElements>
|
||||
<camunda:formData>
|
||||
<camunda:formField id="selected_status" label="'Select Study Status'" type="enum">
|
||||
<camunda:formField id="selected_status" label="'Select Study Status'" type="enum">
|
||||
<camunda:validation>
|
||||
<camunda:constraint name="required" config="True" />
|
||||
</camunda:validation>
|
||||
<camunda:value id="approved" name="Approved" />
|
||||
<camunda:value id="disapproved" name="Disapproved" />
|
||||
</camunda:formField>
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_0a7bvlf" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
|
||||
<bpmn:process id="Process_0inkg2m" name="Start Workflow Programmatically" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_0ac3s7d</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0ac3s7d" sourceRef="StartEvent_1" targetRef="Activity_0n0md5g" />
|
||||
<bpmn:sequenceFlow id="Flow_03vp8ep" sourceRef="Activity_0n0md5g" targetRef="Activity_0qxilu1" />
|
||||
<bpmn:sequenceFlow id="Flow_0etvuwr" sourceRef="Activity_0qxilu1" targetRef="Activity_1thn0qo" />
|
||||
<bpmn:endEvent id="Event_1hlx8d1">
|
||||
<bpmn:incoming>Flow_1ppd3wf</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1ppd3wf" sourceRef="Activity_1thn0qo" targetRef="Event_1hlx8d1" />
|
||||
<bpmn:userTask id="Activity_0n0md5g" name="Get Required Data" camunda:formKey="DataForm">
|
||||
<bpmn:extensionElements>
|
||||
<camunda:formData>
|
||||
<camunda:formField id="workflow_spec_to_start" label="'Workflow Spec'" type="string">
|
||||
<camunda:validation>
|
||||
<camunda:constraint name="required" config="True" />
|
||||
</camunda:validation>
|
||||
</camunda:formField>
|
||||
</camunda:formData>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_0ac3s7d</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_03vp8ep</bpmn:outgoing>
|
||||
</bpmn:userTask>
|
||||
<bpmn:scriptTask id="Activity_0qxilu1" name="Start Workflow ">
|
||||
<bpmn:incoming>Flow_03vp8ep</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0etvuwr</bpmn:outgoing>
|
||||
<bpmn:script>workflow_api = start_workflow(workflow_spec_id=workflow_spec_to_start)</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:manualTask id="Activity_1thn0qo" name="Display Result">
|
||||
<bpmn:documentation>## Result
|
||||
|
||||
|
||||
{{ workflow_api }}</bpmn:documentation>
|
||||
<bpmn:incoming>Flow_0etvuwr</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1ppd3wf</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_0inkg2m">
|
||||
<bpmndi:BPMNEdge id="Flow_1ppd3wf_di" bpmnElement="Flow_1ppd3wf">
|
||||
<di:waypoint x="690" y="117" />
|
||||
<di:waypoint x="752" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0etvuwr_di" bpmnElement="Flow_0etvuwr">
|
||||
<di:waypoint x="530" y="117" />
|
||||
<di:waypoint x="590" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_03vp8ep_di" bpmnElement="Flow_03vp8ep">
|
||||
<di:waypoint x="370" y="117" />
|
||||
<di:waypoint x="430" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0ac3s7d_di" bpmnElement="Flow_0ac3s7d">
|
||||
<di:waypoint x="215" y="117" />
|
||||
<di:waypoint x="270" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="179" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1hlx8d1_di" bpmnElement="Event_1hlx8d1">
|
||||
<dc:Bounds x="752" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0gf4hes_di" bpmnElement="Activity_0n0md5g">
|
||||
<dc:Bounds x="270" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_11ydp76_di" bpmnElement="Activity_0qxilu1">
|
||||
<dc:Bounds x="430" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_1sy9ble_di" bpmnElement="Activity_1thn0qo">
|
||||
<dc:Bounds x="590" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -35,7 +35,7 @@ class TestEmailScript(BaseTest):
|
|||
self.assertIn('<strong>Test Some Formatting</strong><br />', outbox[0].html)
|
||||
|
||||
# Correct From field
|
||||
self.assertEqual('uvacrconnect@virginia.edu', outbox[0].sender)
|
||||
self.assertEqual('crconnect2@virginia.edu', outbox[0].sender)
|
||||
|
||||
# Make sure we log the email
|
||||
# Grab model for comparison below
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
from tests.base_test import BaseTest
|
||||
|
||||
from crc import app, session
|
||||
from crc.models.file import FileModel, FileDataModel
|
||||
from crc.services.user_file_service import UserFileService
|
||||
|
||||
from io import BytesIO
|
||||
from openpyxl import load_workbook
|
||||
|
||||
import os
|
||||
|
||||
|
||||
class TestModifySpreadsheet(BaseTest):
|
||||
|
||||
def upload_spreadsheet(self, workflow, task, irb_doc_code):
|
||||
filepath = os.path.join(app.root_path, '..', 'tests', 'data',
|
||||
'modify_spreadsheet', 'test_spreadsheet.xlsx')
|
||||
with open(filepath, 'br') as f_open:
|
||||
ss_data = f_open.read()
|
||||
|
||||
file_model = UserFileService.add_workflow_file(workflow_id=workflow.id,
|
||||
task_spec_name=task.name,
|
||||
name="test_spreadsheet.xlsx", content_type="text",
|
||||
binary_data=ss_data, irb_doc_code=irb_doc_code)
|
||||
workflow_api = self.complete_form(workflow, task, {irb_doc_code: {'id': file_model.id}})
|
||||
return workflow_api
|
||||
|
||||
@staticmethod
|
||||
def get_sheet(workflow_id, irb_doc_code):
|
||||
spreadsheet = session.query(FileModel). \
|
||||
filter(FileModel.workflow_id == workflow_id). \
|
||||
filter(FileModel.irb_doc_code == irb_doc_code). \
|
||||
first()
|
||||
spreadsheet_data = session.query(FileDataModel). \
|
||||
filter(FileDataModel.file_model_id == spreadsheet.id). \
|
||||
first()
|
||||
workbook = load_workbook(BytesIO(spreadsheet_data.data))
|
||||
sheet = workbook.active
|
||||
return sheet
|
||||
|
||||
def test_modify_spreadsheet(self):
|
||||
irb_doc_code = 'Finance_BCA'
|
||||
cell_indicator = 'C4'
|
||||
input_text = 'This is my input text.'
|
||||
|
||||
workflow = self.create_workflow('modify_spreadsheet')
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
task = workflow_api.next_task
|
||||
|
||||
workflow_api = self.upload_spreadsheet(workflow, task, irb_doc_code)
|
||||
|
||||
sheet = self.get_sheet(workflow.id, irb_doc_code)
|
||||
self.assertEqual(None, sheet[cell_indicator].value)
|
||||
|
||||
task = workflow_api.next_task
|
||||
self.complete_form(workflow, task, {'cell_indicator': cell_indicator,
|
||||
'input_text': input_text})
|
||||
|
||||
sheet = self.get_sheet(workflow.id, irb_doc_code)
|
||||
self.assertEqual(input_text, sheet[cell_indicator].value)
|
||||
|
||||
def test_missing_spreadsheet(self):
|
||||
"""The modify_spreadsheet has Finance_BCA hard-coded as the spreadsheet to modify.
|
||||
In this test we upload a spreadsheet with a different doc code,
|
||||
and assert that we raise an error when the Finance_BCA spreadsheet does not exist"""
|
||||
irb_doc_code = 'Finance_GPRF'
|
||||
cell_indicator = 'C4'
|
||||
input_text = 'This is my input text.'
|
||||
|
||||
workflow = self.create_workflow('modify_spreadsheet')
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
task = workflow_api.next_task
|
||||
|
||||
workflow_api = self.upload_spreadsheet(workflow, task, irb_doc_code)
|
||||
task = workflow_api.next_task
|
||||
with self.assertRaises(AssertionError):
|
||||
self.complete_form(workflow, task, {'cell_indicator': cell_indicator,
|
||||
'input_text': input_text})
|
|
@ -0,0 +1,47 @@
|
|||
from tests.base_test import BaseTest
|
||||
|
||||
from crc import session
|
||||
from crc.models.study import StudyModel
|
||||
from crc.models.workflow import WorkflowModel
|
||||
from crc.services.study_service import StudyService
|
||||
from crc.services.workflow_spec_service import WorkflowSpecService
|
||||
|
||||
|
||||
class TestStartWorkflow(BaseTest):
|
||||
|
||||
def setup_test_start_workflow(self):
|
||||
self.add_users()
|
||||
self.create_workflow('hello_world')
|
||||
workflow_spec_to_start = WorkflowSpecService().get_spec('hello_world')
|
||||
|
||||
workflow = self.create_workflow('start_workflow')
|
||||
study_id = workflow.study_id
|
||||
study = session.query(StudyModel).filter(StudyModel.id==study_id).first()
|
||||
StudyService.add_all_workflow_specs_to_study(study, [workflow_spec_to_start])
|
||||
|
||||
return workflow
|
||||
|
||||
def test_start_workflow_validation(self):
|
||||
spec_model = self.load_test_spec('start_workflow')
|
||||
rv = self.app.get('/v1.0/workflow-specification/%s/validate' % spec_model.id, headers=self.logged_in_headers())
|
||||
self.assertEqual([], rv.json)
|
||||
|
||||
def test_start_workflow(self):
|
||||
workflow = self.setup_test_start_workflow()
|
||||
|
||||
workflow_before = session.query(WorkflowModel).filter(WorkflowModel.workflow_spec_id=='hello_world').first()
|
||||
self.assertEqual('not_started', workflow_before.status.value)
|
||||
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
task = workflow_api.next_task
|
||||
self.complete_form(workflow, task, {'workflow_spec_to_start': 'hello_world'})
|
||||
|
||||
workflow_after = session.query(WorkflowModel).filter(WorkflowModel.workflow_spec_id=='hello_world').first()
|
||||
self.assertEqual('user_input_required', workflow_after.status.value)
|
||||
|
||||
def test_bad_workflow_spec_id(self):
|
||||
workflow = self.setup_test_start_workflow()
|
||||
workflow_api = self.get_workflow_api(workflow)
|
||||
task = workflow_api.next_task
|
||||
with self.assertRaises(AssertionError) as e:
|
||||
self.complete_form(workflow, task, {'workflow_spec_to_start': 'bad_spec_id'})
|
|
@ -107,6 +107,7 @@ class TestStudyDetailsDocumentsScript(BaseTest):
|
|||
FileDataSet().do_task(task, study.id, workflow_model.id, key="ginger", value="doodle", file_id=file.id)
|
||||
docs = StudyInfo().do_task(task, study.id, workflow_model.id, "documents")
|
||||
self.assertTrue(isinstance(docs, Box))
|
||||
docs = StudyService.get_documents_status(study.id, force=True)
|
||||
self.assertEqual(1, len(docs.UVACompl_PRCAppr.files))
|
||||
self.assertEqual("doodle", docs.UVACompl_PRCAppr.files[0].data_store.ginger)
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ class TestStudyService(BaseTest):
|
|||
|
||||
|
||||
study_service = StudyService()
|
||||
documents = study_service.get_documents_status(study_id=study.id) # Mocked out, any random study id works.
|
||||
documents = study_service.get_documents_status(study_id=study.id, force=True) # Mocked out, any random study id works.
|
||||
self.assertIsNotNone(documents)
|
||||
self.assertTrue("UVACompl_PRCAppr" in documents.keys())
|
||||
self.assertEqual("UVACompl_PRCAppr", documents["UVACompl_PRCAppr"]['code'])
|
||||
|
|
|
@ -6,6 +6,7 @@ from crc.scripts.study_info import StudyInfo
|
|||
from crc import app
|
||||
from unittest.mock import patch
|
||||
from crc.services.protocol_builder import ProtocolBuilderService
|
||||
from crc.services.study_service import StudyService
|
||||
|
||||
|
||||
class TestStudyInfoScript(BaseTest):
|
||||
|
@ -100,6 +101,8 @@ class TestStudyInfoScript(BaseTest):
|
|||
content_type='multipart/form-data', headers=self.logged_in_headers())
|
||||
self.assert_success(rv)
|
||||
file_data = json.loads(rv.get_data(as_text=True))
|
||||
study_info = StudyService.get_documents_status(self.workflow.study_id, force=True)
|
||||
self.assertEqual(1, len(study_info['Grant_App']['files']), "Grant_App has exactly one file.")
|
||||
|
||||
# Now get the study info again.
|
||||
study_info = StudyInfo().do_task(self.workflow_api.study_id, self.workflow.study.id, self.workflow.id,
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
from tests.base_test import BaseTest
|
||||
|
||||
from crc.api.common import ApiError
|
||||
|
||||
|
||||
class TestMissingExecutable(BaseTest):
|
||||
|
||||
def test_missing_executable(self):
|
||||
with self.assertRaises(ApiError) as ae:
|
||||
self.create_workflow('missing_executable_tag')
|
||||
self.assertEqual('No executable process tag found. Please make sure the Executable option is set in the workflow.',
|
||||
ae.exception.message)
|
Loading…
Reference in New Issue