exception decorator and mail send for errors and changes to rec state checker

This commit is contained in:
2019-11-14 14:15:36 +01:00
parent 6081486a35
commit e19ce060d8
12 changed files with 305 additions and 136 deletions

View File

@@ -27,6 +27,8 @@ html5lib = "*"
beautifulsoup4 = "*" beautifulsoup4 = "*"
flask-socketio = "*" flask-socketio = "*"
eventlet = "*" eventlet = "*"
ics = "*"
coloredlogs = "*"
[dev-packages] [dev-packages]

244
Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "1eb275e98d59f5fec7c926d01669aafaa57050844b8a5f35aebf396bcbdaeaa5" "sha256": "f202c24683975df8c5539037b48a09753cfdfcab4669da6c6d35ffef97a4eb63"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@@ -25,9 +25,9 @@
}, },
"alembic": { "alembic": {
"hashes": [ "hashes": [
"sha256:9f907d7e8b286a1cfb22db9084f9ce4fde7ad7956bb496dc7c952e10ac90e36a" "sha256:e6c6a4243e89c8d3e2342a1562b2388f3b524c9cac2fccc4d2c461a1320cc1c1"
], ],
"version": "==1.2.1" "version": "==1.3.0"
}, },
"aniso8601": { "aniso8601": {
"hashes": [ "hashes": [
@@ -38,10 +38,17 @@
}, },
"apispec": { "apispec": {
"hashes": [ "hashes": [
"sha256:5fdaa1173b32515cc83f9d413a49a6c37fafc2b87f6b40e95923d3e85f0942c5", "sha256:cf8e1f3b56949710f8cf23797b7f40215e9dae8bac583789a3f2c13dc56349fa",
"sha256:9e88c51517a6515612e818459f61c1bc06c00f2313e5187828bdbabaa7461473" "sha256:fe5cf5fc89b1c4a73acd5af3a10ede02b31ec116f215ed02271cb905d3172367"
], ],
"version": "==3.0.0" "version": "==3.1.0"
},
"arrow": {
"hashes": [
"sha256:4bfacea734ead51495dc47df00421ecfd4ca1f2c0fbe58b9a26eaeddedc31caf",
"sha256:67f8be7c0cf420424bc62d8d7dc40b44e4bb2f7b515f9cc2954fb36e35797656"
],
"version": "==0.14.7"
}, },
"attrs": { "attrs": {
"hashes": [ "hashes": [
@@ -74,38 +81,41 @@
}, },
"cffi": { "cffi": {
"hashes": [ "hashes": [
"sha256:00d890313797d9fe4420506613384b43099ad7d2b905c0752dbcc3a6f14d80fa", "sha256:0b49274afc941c626b605fb59b59c3485c17dc776dc3cc7cc14aca74cc19cc42",
"sha256:0cf9e550ac6c5e57b713437e2f4ac2d7fd0cd10336525a27224f5fc1ec2ee59a", "sha256:0e3ea92942cb1168e38c05c1d56b0527ce31f1a370f6117f1d490b8dcd6b3a04",
"sha256:0ea23c9c0cdd6778146a50d867d6405693ac3b80a68829966c98dd5e1bbae400", "sha256:135f69aecbf4517d5b3d6429207b2dff49c876be724ac0c8bf8e1ea99df3d7e5",
"sha256:193697c2918ecdb3865acf6557cddf5076bb39f1f654975e087b67efdff83365", "sha256:19db0cdd6e516f13329cba4903368bff9bb5a9331d3410b1b448daaadc495e54",
"sha256:1ae14b542bf3b35e5229439c35653d2ef7d8316c1fffb980f9b7647e544baa98", "sha256:2781e9ad0e9d47173c0093321bb5435a9dfae0ed6a762aabafa13108f5f7b2ba",
"sha256:1e389e069450609c6ffa37f21f40cce36f9be7643bbe5051ab1de99d5a779526", "sha256:291f7c42e21d72144bb1c1b2e825ec60f46d0a7468f5346841860454c7aa8f57",
"sha256:263242b6ace7f9cd4ea401428d2d45066b49a700852334fd55311bde36dcda14", "sha256:2c5e309ec482556397cb21ede0350c5e82f0eb2621de04b2633588d118da4396",
"sha256:33142ae9807665fa6511cfa9857132b2c3ee6ddffb012b3f0933fc11e1e830d5", "sha256:2e9c80a8c3344a92cb04661115898a9129c074f7ab82011ef4b612f645939f12",
"sha256:364f8404034ae1b232335d8c7f7b57deac566f148f7222cef78cf8ae28ef764e", "sha256:32a262e2b90ffcfdd97c7a5e24a6012a43c61f1f5a57789ad80af1d26c6acd97",
"sha256:47368f69fe6529f8f49a5d146ddee713fc9057e31d61e8b6dc86a6a5e38cecc1", "sha256:3c9fff570f13480b201e9ab69453108f6d98244a7f495e91b6c654a47486ba43",
"sha256:4895640844f17bec32943995dc8c96989226974dfeb9dd121cc45d36e0d0c434", "sha256:415bdc7ca8c1c634a6d7163d43fb0ea885a07e9618a64bda407e04b04333b7db",
"sha256:558b3afef987cf4b17abd849e7bedf64ee12b28175d564d05b628a0f9355599b", "sha256:42194f54c11abc8583417a7cf4eaff544ce0de8187abaf5d29029c91b1725ad3",
"sha256:5ba86e1d80d458b338bda676fd9f9d68cb4e7a03819632969cf6d46b01a26730", "sha256:4424e42199e86b21fc4db83bd76909a6fc2a2aefb352cb5414833c030f6ed71b",
"sha256:63424daa6955e6b4c70dc2755897f5be1d719eabe71b2625948b222775ed5c43", "sha256:4a43c91840bda5f55249413037b7a9b79c90b1184ed504883b72c4df70778579",
"sha256:6381a7d8b1ebd0bc27c3bc85bc1bfadbb6e6f756b4d4db0aa1425c3719ba26b4", "sha256:599a1e8ff057ac530c9ad1778293c665cb81a791421f46922d80a86473c13346",
"sha256:6381ab708158c4e1639da1f2a7679a9bbe3e5a776fc6d1fd808076f0e3145331", "sha256:5c4fae4e9cdd18c82ba3a134be256e98dc0596af1e7285a3d2602c97dcfa5159",
"sha256:6fd58366747debfa5e6163ada468a90788411f10c92597d3b0a912d07e580c36", "sha256:5ecfa867dea6fabe2a58f03ac9186ea64da1386af2159196da51c4904e11d652",
"sha256:728ec653964655d65408949b07f9b2219df78badd601d6c49e28d604efe40599", "sha256:62f2578358d3a92e4ab2d830cd1c2049c9c0d0e6d3c58322993cc341bdeac22e",
"sha256:7cfcfda59ef1f95b9f729c56fe8a4041899f96b72685d36ef16a3440a0f85da8", "sha256:6471a82d5abea994e38d2c2abc77164b4f7fbaaf80261cb98394d5793f11b12a",
"sha256:819f8d5197c2684524637f940445c06e003c4a541f9983fd30d6deaa2a5487d8", "sha256:6d4f18483d040e18546108eb13b1dfa1000a089bcf8529e30346116ea6240506",
"sha256:825ecffd9574557590e3225560a8a9d751f6ffe4a49e3c40918c9969b93395fa", "sha256:71a608532ab3bd26223c8d841dde43f3516aa5d2bf37b50ac410bb5e99053e8f",
"sha256:9009e917d8f5ef780c2626e29b6bc126f4cb2a4d43ca67aa2b40f2a5d6385e78", "sha256:74a1d8c85fb6ff0b30fbfa8ad0ac23cd601a138f7509dc617ebc65ef305bb98d",
"sha256:9c77564a51d4d914ed5af096cd9843d90c45b784b511723bd46a8a9d09cf16fc", "sha256:7b93a885bb13073afb0aa73ad82059a4c41f4b7d8eb8368980448b52d4c7dc2c",
"sha256:a19089fa74ed19c4fe96502a291cfdb89223a9705b1d73b3005df4256976142e", "sha256:7d4751da932caaec419d514eaa4215eaf14b612cff66398dd51129ac22680b20",
"sha256:a40ed527bffa2b7ebe07acc5a3f782da072e262ca994b4f2085100b5a444bbb2", "sha256:7f627141a26b551bdebbc4855c1157feeef18241b4b8366ed22a5c7d672ef858",
"sha256:bb75ba21d5716abc41af16eac1145ab2e471deedde1f22c6f99bd9f995504df0", "sha256:8169cf44dd8f9071b2b9248c35fc35e8677451c52f795daa2bb4643f32a540bc",
"sha256:e22a00c0c81ffcecaf07c2bfb3672fa372c50e2bd1024ffee0da191c1b27fc71", "sha256:aa00d66c0fab27373ae44ae26a66a9e43ff2a678bf63a9c7c1a9a4d61172827a",
"sha256:e55b5a746fb77f10c83e8af081979351722f6ea48facea79d470b3731c7b2891", "sha256:ccb032fda0873254380aa2bfad2582aedc2959186cce61e3a17abc1a55ff89c3",
"sha256:ec2fa3ee81707a5232bf2dfbd6623fdb278e070d596effc7e2d788f2ada71a05", "sha256:d754f39e0d1603b5b24a7f8484b22d2904fa551fe865fd0d4c3332f078d20d4e",
"sha256:fd82eb4694be712fcae03c717ca2e0fc720657ac226b80bbb597e971fc6928c2" "sha256:d75c461e20e29afc0aee7172a0950157c704ff0dd51613506bd7d82b718e7410",
"sha256:dcd65317dd15bc0451f3e01c80da2216a31916bdcffd6221ca1202d96584aa25",
"sha256:e570d3ab32e2c2861c4ebe6ffcad6a8abf9347432a37608fe1fbd157b3f0036b",
"sha256:fd43a88e045cf992ed09fa724b5315b790525f2676883a6ea64e3263bae6549d"
], ],
"version": "==1.13.1" "version": "==1.13.2"
}, },
"chardet": { "chardet": {
"hashes": [ "hashes": [
@@ -121,6 +131,22 @@
], ],
"version": "==7.0" "version": "==7.0"
}, },
"colorama": {
"hashes": [
"sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d",
"sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"
],
"markers": "sys_platform == 'win32'",
"version": "==0.4.1"
},
"coloredlogs": {
"hashes": [
"sha256:34fad2e342d5a559c31b6c889e8d14f97cb62c47d9a2ae7b5ed14ea10a79eff8",
"sha256:b869a2dda3fa88154b9dd850e27828d8755bfab5a838a1c97fbc850c6e377c36"
],
"index": "pypi",
"version": "==10.0"
},
"coverage": { "coverage": {
"hashes": [ "hashes": [
"sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6", "sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6",
@@ -187,10 +213,10 @@
}, },
"decorator": { "decorator": {
"hashes": [ "hashes": [
"sha256:86156361c50488b84a3f148056ea716ca587df2f0de1d34750d35c21312725de", "sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce",
"sha256:f069f3a01830ca754ba5258fde2278454a0b5b79e0d7f5c13b3b97e57d4acff6" "sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d"
], ],
"version": "==4.4.0" "version": "==4.4.1"
}, },
"dnspython": { "dnspython": {
"hashes": [ "hashes": [
@@ -201,10 +227,10 @@
}, },
"ecdsa": { "ecdsa": {
"hashes": [ "hashes": [
"sha256:163c80b064a763ea733870feb96f9dd9b92216cfcacd374837af18e4e8ec3d4d", "sha256:64c613005f13efec6541bb0a33290d0d03c27abab5f15fbab20fb0ee162bdd8e",
"sha256:9814e700890991abeceeb2242586024d4758c8fc18445b194a49bd62d85861db" "sha256:e108a5fe92c67639abae3260e43561af914e7fd0d27bae6d2ec1312ae7934dfe"
], ],
"version": "==0.13.3" "version": "==0.14.1"
}, },
"eventlet": { "eventlet": {
"hashes": [ "hashes": [
@@ -320,9 +346,9 @@
}, },
"future": { "future": {
"hashes": [ "hashes": [
"sha256:858e38522e8fd0d3ce8f0c1feaf0603358e366d5403209674c7b617fa0c24093" "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
], ],
"version": "==0.18.1" "version": "==0.18.2"
}, },
"greenlet": { "greenlet": {
"hashes": [ "hashes": [
@@ -356,6 +382,20 @@
"index": "pypi", "index": "pypi",
"version": "==1.0.1" "version": "==1.0.1"
}, },
"humanfriendly": {
"hashes": [
"sha256:23057b10ad6f782e7bc3a20e3cb6768ab919f619bbdc0dd75691121bbde5591d",
"sha256:33ee8ceb63f1db61cce8b5c800c531e1a61023ac5488ccde2ba574a85be00a85"
],
"version": "==4.18"
},
"ics": {
"hashes": [
"sha256:12cf34aed0dafa1bf99d79ca58e99949d6721511b856386e118015fe5f5d6e3a"
],
"index": "pypi",
"version": "==0.6"
},
"idna": { "idna": {
"hashes": [ "hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
@@ -432,10 +472,10 @@
}, },
"marshmallow": { "marshmallow": {
"hashes": [ "hashes": [
"sha256:077b4612f5d3b9333b736fdc6b963d2b46d409070f44ff3e6c4109645c673e83", "sha256:1a358beb89c2b4d5555272065a9533591a3eb02f1b854f3c4002d88d8f2a1ddb",
"sha256:9a2f3e8ea5f530a9664e882d7d04b58650f46190178b2264c72b7d20399d28f0" "sha256:eb97c42c5928b5720812c9268865fe863d4807bc1a8b48ddd7d5c9e1779a6af0"
], ],
"version": "==3.2.1" "version": "==3.2.2"
}, },
"monotonic": { "monotonic": {
"hashes": [ "hashes": [
@@ -487,36 +527,40 @@
}, },
"pycryptodomex": { "pycryptodomex": {
"hashes": [ "hashes": [
"sha256:020928b2831b2047288c9143f41c6690eb669d60761c7ca8c5ca743a2c51517c", "sha256:0ab2251a386c065331115c408c23274e8aea7ddf5452f2e92120b88fa09aba23",
"sha256:0ce1950ba6544eca4d6fd7386e2502d4bd871fcbd5e5b977604f48ea37b29fc6", "sha256:0da48ccd0944a952cbaac623bf0e1139969078551a213c019ca885ed66771539",
"sha256:0d5b1159a24a56fd3359b7b1aa1e4331c394033eababb2972bb923d6767968db", "sha256:1d98214b7bc6f9ceb68eb5cdbd4237f23485b4b746e7e582990be492b6c4797b",
"sha256:11453e8628cdccbcb08e04405298d659c0c0458cf9bf23eaaa3c201f8d635389", "sha256:275e8f0f7fd03ec4b9f7fecfeac3dad8e5a1fe389369efda1e365e8c5795c1ac",
"sha256:22e050089f60e70b97909fe62612ee9589f0be1c928c2aa637f2534eddf61632", "sha256:30975ac3ee7c632eb34a05d2aa0e9933cab9a0746b77d44612a3b61c56ecfa3c",
"sha256:27317f1e8e496a2f208b1c40da425d5fe760b494f95c847bb7c3074c95a8edcb", "sha256:37f84bef86e935e10a2ccb22f6cd2cebac274dff8867f16f7c2d5da9aa27665d",
"sha256:32e2fe1d0c5fada45b22b647f88367b210dfea40a5cc849b142b4e9fa497c488", "sha256:3b80f06556552a515ff9f1052ea41895e34745558a5ddbab46e300ba43384a35",
"sha256:3a998b390a80fd0d22c7d9fbaf49a9a11772ef90495a8baecdea2e6d09929937", "sha256:3b9f81fd0c897c493ff8367cca41b9b93f6c9277990c8c4c2756538ed1aa4a99",
"sha256:46dda35fbed5426794ab64d483d6257dc43f52e78ba934563492df7cb89f7de6", "sha256:6d58f13c8ca6bac3bf0d64e7474725ff55c2d6db60ed03d5b98b81c757bf1f4c",
"sha256:4846ca0f2363bdb934c556667b056331d4aabd48f20924b0c5583a49d764d3fc", "sha256:6f86a6d668d4f918b21452fcf8bb24dc9c135b6564cbd4ff7b954b1d35fe7527",
"sha256:550f5e6f07b091f986023f871fa8a2bde9875ccae51d4bd07b31fa9855fe994f", "sha256:7c462632ff441203fc30f11cab9cf12e2eb00417b4a1ea3c5208e875d81cb160",
"sha256:561905b459de41c3ad19912cdcd88c8e24295d01e97b7b2a63d4188c8e4e0dbc", "sha256:87d278909c7fabd303d87268eeda7350641f094792ecd023965f960ae6d2d3da",
"sha256:5745ca86a4e88a775b7cace28b947a86661d5cc09ecc1c8d97293a7d20c1bb79", "sha256:87d3f7357789171a0f05e3b1bac782989619043693e4200518c678245856ca7c",
"sha256:5c2a3bb28dde992f97d856937e973dda0462bf3acb7d0009308a81159a35323b", "sha256:8913f185eccb2f270030a0347161d2cd47ef691f12a4b9af9772319e5a6a717b",
"sha256:73a8acc8ff7f09d482e481757d92a250f803e66e0f248019df90a69e61840180", "sha256:8ac49b6ad1e57a0914d8d5e0267e4df5fbdf4e62abdf982bd5493d634cd3a686",
"sha256:8601613ebc329b853e466f581ad1156638989926e0dcdf52952542a89883836c", "sha256:8d8b071a159e9b46734cbb802282719a0d0d0e40523c8648fab0b6739f98a882",
"sha256:8b604f4fa1de456d6d19771b01c2823675a75a2c60e51a6b738f71fdfe865370", "sha256:a06a1f927d02c1fea1f7656e32bf36149d0f6cab750313a03a085e43632163e8",
"sha256:96f8622cb8061f4aca95e52cc835659f024bc2e237ee6a9d01117873b7490b98", "sha256:adb6ca0aee7fd2807628d1cb77fc9be8a82f493240e2349da06419221b1f6b19",
"sha256:a01c99532c5f7ab96274b5c9f3e135315b79b55ba5c8233fc4d029e0369e94df", "sha256:b3503841cb5185b210876d7ff8f541e2c2ea0915c83f6330be6d7026a34828ca",
"sha256:c63040e0313e27b62b0f4295f41adecf96cde7ff4d49f653b81b1958cb1180bf", "sha256:b90ecc35567d77e7dc9f70817826f077c9dbb37abdd16e2c2d57887c21053e53",
"sha256:c812cb9f3af63da8eaa251e7e48f8b38c4e40974d2bdae2f0ca7a7a12549727a", "sha256:ba18a7dfef6d89605ca76f077d033143fab8f2d6948620d09337567402f1c0c4",
"sha256:cb9e8ef672b7a961f90e0a497718e0f052f76324f216840a4ec30248e4d19f20", "sha256:be635b1f9ee9615243dc706c11047015d22312e7425c9009dd6447c229370e1a",
"sha256:ce8edda46374c344de87089f9887ad4dd317bb4a22f91f1844202eaf14b08de0", "sha256:d1db857b0ac6bac6d4d4758250d548d7146d63cb36c6c50b7481837f02d38ef7",
"sha256:de58de0d5f2fb9253707ee718e1378f2194fdd394cdbed1b6464ab44642f5217", "sha256:d9537841af488a4b83977aeebfd4aebe011b7d1d19e9d45ad32a1f8dfca7eec8",
"sha256:e0100f9b93d0119d846a33e6cb5001ee208519b81c6acf76da614b71de75885b", "sha256:e413457859d3c3e4a4263ef24ccaefe4107b3e3e219c4fb87215cfc34ff8dba0",
"sha256:e530b77bdff5c2bf3065e6a088e1602ad193b43e285bac196d4b8820308ec6bb", "sha256:e87c272263559d657ab3b990be8174c0d492cbc2f4f8d0bddfaef82dfe05d54c",
"sha256:f048069aa7b530f1c5e84d55c2b28ca7a7272bb3b8d28829d454a94bec6529a8", "sha256:eb5aef32e65d7802e04c78074af1ba8e7a5b4c0482d3a110f236082fadac6859",
"sha256:f6a9271c842e93c349b6007676a62d03dca712c9f4dff66c3270d50504ca9014" "sha256:ee03dc6124287e27738e5f1d1150031d706f7fb96f1770859cb3cebe64c191ea",
"sha256:f792b5deca98bee676912d27bc1aba96b614986a9a89df7cf15e95d7bd480768",
"sha256:f84e6e66af8805703b5f4d1243747accf519cba0223d598b58e85edbec8583d7",
"sha256:fbd9e3ba9437b087b16481d1e34ec4f495ffabb4bee7e2c150b50d28ebe00e44",
"sha256:fbfaf65e610089f37c46e2cb2ff2dbf9a04bbcecd3a2beaa85494094e9987aff"
], ],
"version": "==3.9.0" "version": "==3.9.3"
}, },
"pyjwkest": { "pyjwkest": {
"hashes": [ "hashes": [
@@ -539,18 +583,25 @@
], ],
"version": "==19.0.0" "version": "==19.0.0"
}, },
"pyreadline": {
"hashes": [
"sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1"
],
"markers": "sys_platform == 'win32'",
"version": "==2.1"
},
"pyrsistent": { "pyrsistent": {
"hashes": [ "hashes": [
"sha256:34b47fa169d6006b32e99d4b3c4031f155e6e68ebcc107d6454852e8e0ee6533" "sha256:eb6545dbeb1aa69ab1fb4809bfbf5a8705e44d92ef8fc7c2361682a47c46c778"
], ],
"version": "==0.15.4" "version": "==0.15.5"
}, },
"python-dateutil": { "python-dateutil": {
"hashes": [ "hashes": [
"sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
"sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e" "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
], ],
"version": "==2.8.0" "version": "==2.8.1"
}, },
"python-editor": { "python-editor": {
"hashes": [ "hashes": [
@@ -605,24 +656,24 @@
}, },
"six": { "six": {
"hashes": [ "hashes": [
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
], ],
"version": "==1.12.0" "version": "==1.13.0"
}, },
"soupsieve": { "soupsieve": {
"hashes": [ "hashes": [
"sha256:605f89ad5fdbfefe30cdc293303665eff2d188865d4dbe4eb510bba1edfbfce3", "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5",
"sha256:b91d676b330a0ebd5b21719cb6e9b57c57d433671f65b9c28dd3461d9a1ed0b6" "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"
], ],
"version": "==1.9.4" "version": "==1.9.5"
}, },
"sqlalchemy": { "sqlalchemy": {
"hashes": [ "hashes": [
"sha256:0f0768b5db594517e1f5e1572c73d14cf295140756431270d89496dc13d5e46c" "sha256:afa5541e9dea8ad0014251bc9d56171ca3d8b130c9627c6cb3681cff30be3f8a"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.3.10" "version": "==1.3.11"
}, },
"sqlalchemy-migrate": { "sqlalchemy-migrate": {
"hashes": [ "hashes": [
@@ -672,6 +723,13 @@
], ],
"version": "==1.1.0" "version": "==1.1.0"
}, },
"tatsu": {
"hashes": [
"sha256:80713413473a009f2081148d0f494884cabaf9d6866b71f2a68a92b6442f343d",
"sha256:c9211eeee9a2d4c90f69879ec0b518b1aa0d9450249cb0dd181f5f5b18be0a92"
],
"version": "==4.4.0"
},
"tempita": { "tempita": {
"hashes": [ "hashes": [
"sha256:cacecf0baa674d356641f1d406b8bff1d756d739c46b869a54de515d08e6fc9c" "sha256:cacecf0baa674d356641f1d406b8bff1d756d739c46b869a54de515d08e6fc9c"
@@ -687,10 +745,10 @@
}, },
"urllib3": { "urllib3": {
"hashes": [ "hashes": [
"sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398", "sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293",
"sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86" "sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745"
], ],
"version": "==1.25.6" "version": "==1.25.7"
}, },
"webargs": { "webargs": {
"hashes": [ "hashes": [

View File

@@ -3,7 +3,10 @@
Backend base module Backend base module
""" """
import logging import logging
from io import StringIO
from logging.config import dictConfig from logging.config import dictConfig
from typing import Union
import coloredlogs as coloredlogs import coloredlogs as coloredlogs
import jwt import jwt
import requests import requests
@@ -25,7 +28,6 @@ __email__ = "it@t-kurze.de"
# __status__ = "Production" # __status__ = "Production"
__status__ = "Development" __status__ = "Development"
dictConfig({ dictConfig({
'version': 1, 'version': 1,
'formatters': { 'formatters': {
@@ -66,7 +68,7 @@ dictConfig({
}, },
}, },
'loggers': { 'loggers': {
'mal': { 'lrc': {
'level': Config.LOG_LEVEL, 'level': Config.LOG_LEVEL,
'handlers': ['wsgi', 'file', 'errors_file'] 'handlers': ['wsgi', 'file', 'errors_file']
} }
@@ -78,18 +80,34 @@ dictConfig({
}) })
main_logger = logging.getLogger("lrc") main_logger = logging.getLogger("lrc")
# following might be dangerous, as buffer might be filled without a mechanism to empty it
# error_log_stream = StringIO()
# error_log_stream_handler = logging.StreamHandler(stream=error_log_stream)
# error_log_stream_handler.setLevel(logging.ERROR)
# main_logger.addHandler(error_log_stream_handler)
coloredlogs.install(level='DEBUG', logger=main_logger) coloredlogs.install(level='DEBUG', logger=main_logger)
class LrcException(Exception): class LrcException(Exception):
def __init__(self, message: str, html_code: int = None): def __init__(self, message_or_exception: Union[str, Exception], html_code: int = None):
super().__init__(message) if isinstance(message_or_exception, str):
super().__init__(message_or_exception)
self.type = None
else:
super().__init__(str(message_or_exception))
self.type = type(message_or_exception)
self.html_code = html_code self.html_code = html_code
def __repr__(self): def __repr__(self):
if self.type is None:
msg = "LRC Exception: \"{}\"".format(', '.join(super().args))
else:
msg = "LRC Exception: (original Exception: {}) \"{}\"".format(self.type, ', '.join(super().args))
if self.html_code is not None: if self.html_code is not None:
return "LRC Exception: \"{}\" (HTML Code: {})".format(', '.join(super().args), self.html_code) msg += " (HTML Code: {})".format(self.html_code)
return ', '.join(super().args) return msg
def __str__(self): def __str__(self):
return self.__repr__() return self.__repr__()

Binary file not shown.

View File

@@ -104,6 +104,9 @@ class RecorderAdapter:
def is_recording(self) -> bool: def is_recording(self) -> bool:
pass pass
def get_recording_status(self) -> str:
pass
def get_defined_recorder_adapters(): def get_defined_recorder_adapters():
models = [] models = []

View File

@@ -6,11 +6,14 @@ from pprint import pprint
import requests import requests
from requests.auth import HTTPBasicAuth from requests.auth import HTTPBasicAuth
from requests.exceptions import ConnectionError
from backend import LrcException from backend import LrcException
from backend.recorder_adapters import RecorderAdapter from backend.recorder_adapters import RecorderAdapter
# HOST = "localhost" # HOST = "localhost"
from backend.tools.exception_decorator import exception_decorator
BASE_URL = "http://172.23.8.102" # Audimax SMP 351 BASE_URL = "http://172.23.8.102" # Audimax SMP 351
USER = "admin" USER = "admin"
@@ -34,12 +37,14 @@ class EpiphanV1(RecorderAdapter):
def _get_version(self): def _get_version(self):
pass pass
def get_status(self) -> dict: @exception_decorator(ConnectionError)
def get_recording_status(self) -> dict:
res = self.session.get(self.url + "/admin/ajax/recorder_status.cgi") res = self.session.get(self.url + "/admin/ajax/recorder_status.cgi")
if res.ok: if res.ok:
return res.json() return res.json()
raise LrcException(res.text, res.status_code) raise LrcException(res.text, res.status_code)
@exception_decorator(ConnectionError)
def get_sysinfo(self) -> dict: def get_sysinfo(self) -> dict:
res = self.session.get(self.url + "/ajax/sysinfo.cgi") res = self.session.get(self.url + "/ajax/sysinfo.cgi")
if res.ok: if res.ok:
@@ -47,7 +52,7 @@ class EpiphanV1(RecorderAdapter):
raise LrcException(res.text, res.status_code) raise LrcException(res.text, res.status_code)
def is_recording(self) -> bool: def is_recording(self) -> bool:
state = self.get_status().get('state', None) state = self.get_recording_status().get('state', None)
return state == "up" return state == "up"
def get_recording_time(self): def get_recording_time(self):
@@ -55,7 +60,7 @@ class EpiphanV1(RecorderAdapter):
Returns recording time in seconds. Also returns 0 if not recording. Returns recording time in seconds. Also returns 0 if not recording.
:return: :return:
""" """
return self.get_status().get('seconds', None) return self.get_recording_status().get('seconds', None)
def start_recording(self): def start_recording(self):
res = self.session.get(self.url + "/admin/ajax/start_recorder.cgi") res = self.session.get(self.url + "/admin/ajax/start_recorder.cgi")

View File

@@ -2,8 +2,9 @@ import logging
from backend import LrcException from backend import LrcException
from backend.recorder_adapters import telnetlib, TelnetAdapter, RecorderAdapter from backend.recorder_adapters import telnetlib, TelnetAdapter, RecorderAdapter
from backend.tools.exception_decorator import exception_decorator
logger = logging.getLogger() logger = logging.getLogger("lrc.recorder_adapters.extron_smp")
RECORDER_MODEL_NAME = "SMP 351 / 352" RECORDER_MODEL_NAME = "SMP 351 / 352"
VERSION = "0.9.0" VERSION = "0.9.0"
@@ -28,11 +29,13 @@ class SMP(TelnetAdapter, RecorderAdapter):
self._login() self._login()
def _login(self): def _login(self):
print("Connecting to {} ...".format(self.address)) logger.info("Connecting to {} ...".format(self.address))
try: try:
self.tn = telnetlib.Telnet(self.address) self.tn = telnetlib.Telnet(self.address)
except TimeoutError as e: except TimeoutError as e:
raise LrcException(str(e)) raise LrcException(str(e))
except ConnectionRefusedError as e:
raise LrcException(str(e))
self.tn.read_until("\r\nPassword:") self.tn.read_until("\r\nPassword:")
# password = getpass.getpass() # password = getpass.getpass()
password = self.admin_pw password = self.admin_pw
@@ -371,6 +374,7 @@ class SMP(TelnetAdapter, RecorderAdapter):
self.tn.write("{}Y2RCDR\n".format(self.esc_char)) self.tn.write("{}Y2RCDR\n".format(self.esc_char))
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line()) return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
@exception_decorator(ConnectionError)
def get_recording_status(self): def get_recording_status(self):
""" """
Status may be one of: Status may be one of:

View File

@@ -16,6 +16,7 @@ if not os.path.exists(fe_path) or not os.path.exists(os.path.join(fe_path, "inde
app.logger.critical( app.logger.critical(
"Frontend path and/or index.html does not exist! Please build frontend before continuing! " "Frontend path and/or index.html does not exist! Please build frontend before continuing! "
"You might want to go to ../frontend and continue from there.") "You might want to go to ../frontend and continue from there.")
print("FATAL: Frontend path wrong or index.html missing -> EXITING!")
exit() exit()
fe_bp = Blueprint('frontend', __name__, url_prefix='/', template_folder=os.path.join(fe_path, "")) fe_bp = Blueprint('frontend', __name__, url_prefix='/', template_folder=os.path.join(fe_path, ""))

View File

@@ -0,0 +1,13 @@
from backend import LrcException
def exception_decorator(*exceptions):
def decorator(func):
def new_func(*args, **kwargs):
try:
ret = func(*args, **kwargs)
return ret
except exceptions as e:
raise LrcException(e)
return new_func
return decorator

View File

@@ -0,0 +1,45 @@
import smtplib
import traceback
from email.message import EmailMessage
from typing import List, Union
from backend import main_logger, Config
def send_mail(subject: str, msg_body: str, to_mail: List, from_mail: str = Config.FROM_MAIL):
subject = subject.strip().replace("\r", "").split("\n")[0] # remove breaks resp. cut after line break
try:
msg = EmailMessage()
msg.set_content(msg_body)
msg["Subject"] = subject
msg["From"] = from_mail
msg["To"] = to_mail
s = smtplib.SMTP(Config.SMTP_SERVER)
s.send_message(msg)
s.quit()
except Exception as e:
main_logger.error(
"Could not send E-Mail (Exception: {})".format(str(e)))
def send_error_mail(message_or_exception: Union[str, Exception], subject: str = None,
subject_prefix: str = "[LRC] Error: ",
receiver_mail_addresses=Config.ERROR_E_MAIL_TO):
if isinstance(message_or_exception, Exception):
if subject is None:
subject = subject_prefix + str(type(message_or_exception))
else:
subject = subject_prefix + subject
msg_body = str(type(message_or_exception)) + ": " + str(message_or_exception) + "\n\n" + traceback.format_exc()
else:
if subject is None:
subject = str(message_or_exception)
else:
subject = subject_prefix + subject
msg_body = str(message_or_exception)
send_mail(subject, msg_body, receiver_mail_addresses)
def send_warning_mail():
pass

View File

@@ -1,23 +1,31 @@
import json import json
import os import os
import logging import logging
from io import StringIO
import requests
from requests.auth import HTTPBasicAuth
from multiprocessing.pool import ThreadPool from multiprocessing.pool import ThreadPool
from pprint import pprint from pprint import pprint
import requests
from requests.auth import HTTPBasicAuth
from ics import Calendar from ics import Calendar
from backend import LrcException
from backend.config import Config from backend.config import Config
from backend.recorder_adapters import RecorderAdapter
from backend.recorder_adapters.epiphan_base import EpiphanV1 from backend.recorder_adapters.epiphan_base import EpiphanV1
from backend.recorder_adapters.extron_smp import SMP from backend.recorder_adapters.extron_smp import SMP
from backend.tools.send_mail import send_error_mail
logger = logging.getLogger(__name__) logger = logging.getLogger("lrc.tools.simple_state_checker")
logger.setLevel(logging.DEBUG)
stream_handler = logging.StreamHandler() rec_err_state_log_stream = StringIO()
stream_handler.setLevel(logging.DEBUG) rec_err_state_log_stream_handler = logging.StreamHandler(stream=rec_err_state_log_stream)
logger.addHandler(stream_handler) rec_err_state_log_stream_handler.setLevel(logging.ERROR)
logger.addHandler(rec_err_state_log_stream_handler)
base_url = "https://opencast.bibliothek.kit.edu" base_url = "https://opencast.bibliothek.kit.edu"
@@ -46,7 +54,6 @@ def get_service_url(service_type: str):
def get_calender(rec_id): def get_calender(rec_id):
params = {'agentid': rec_id} params = {'agentid': rec_id}
url = get_service_url('org.opencastproject.scheduler') + "/calendars" url = get_service_url('org.opencastproject.scheduler') + "/calendars"
print(url)
res = session.get(url, params=params) res = session.get(url, params=params)
if res.ok: if res.ok:
return Calendar(res.text) return Calendar(res.text)
@@ -80,41 +87,49 @@ def notify_users_of_problem(msg: str):
pass pass
def get_recorder_adapter(recorder_info:dict) -> RecorderAdapter:
if "SMP" in recorder_info["type"]:
rec = SMP(recorder_info['ip'], recorder_info['password'])
else:
rec = EpiphanV1(recorder_info['ip'], recorder_info["username"], recorder_info["password"])
return rec
def check_capture_agent_state(a: dict): def check_capture_agent_state(a: dict):
logger.debug("Checking Agent {}".format(a['name'])) logger.debug("Checking Agent {}".format(a['name']))
c = get_calender(a['name']) c = get_calender(a['name'])
is_recording_in_calendar = len(list(c.timeline.now())) >= 1 is_recording_in_calendar = len(list(c.timeline.now())) >= 1
if is_recording_in_calendar: if is_recording_in_calendar:
logger.info("{} has entry in Calender and should therfor be recording... checking now!".format(a['name']))
if a['state'] == "capturing": if a['state'] == "capturing":
print( logger.info(
"{} is in capturing state, so there should be an entry in the calendar of the recorder, right? -> {}".format( "{} is in capturing state, so there should be an entry in the calendar of the recorder, right? -> {}".format(
a['name'], is_recording_in_calendar a['name'], is_recording_in_calendar
)) ))
rec = get_recorder_by_name(a['name']) recorder_info = get_recorder_by_name(a['name'])
print(rec) try:
if "SMP" in rec["type"]: rec = get_recorder_adapter(recorder_info)
print("using SMP adapter") if rec.is_recording():
rec = SMP(rec['ip'], rec['password']) logger.info("OK recorder {} is recording :)".format(a['name']))
else: else:
rec = EpiphanV1(rec['ip'], rec["username"], rec["password"]) logger.info(rec.get_recording_status())
if rec.is_recording(): logger.error("FATAL - recorder {} must be recording but is not!!!!".format(a['name']))
print("OK recorder is recording :)") except LrcException as e:
else: logger.fatal("Exception occurred: {}".format(str(e)))
logger.info(rec.get_recording_status()) logger.error("Could not check state of recorder {}, Address: {}".format(a['name'], recorder_info['ip']))
logger.error("FATAL - recorder {} must be recording!!!!".format(a['name']))
else: else:
print("FATAL: {} is not in capturing state...but should be!!".format(a['name'])) logger.error("FATAL: {} is not in capturing state...but should be!!".format(a['name']))
else: else:
rec = get_recorder_by_name(a['name']) recorder_info = get_recorder_by_name(a['name'])
if "SMP" in rec["type"]: try:
logger.debug("using SMP adapter") rec = get_recorder_adapter(recorder_info)
rec = SMP(rec['ip'], rec['password']) if rec.is_recording():
else: logger.error("FATAL - recorder must not be recording!!!!")
rec = EpiphanV1(rec['ip'], rec["username"], rec["password"]) else:
if rec.is_recording(): logger.info("OK recorder is not recording :)")
logger.error("FATAL - recorder must not be recording!!!!") except LrcException as e:
else: logger.fatal("Exception occurred: {}".format(str(e)))
logger.info("OK recorder is not recording :)") logger.error("Could not check state of recorder {}, Address: {}".format(a['name'], recorder_info['ip']))
agents = get_capture_agents() agents = get_capture_agents()
@@ -123,6 +138,11 @@ logger.info("Got {} capture agents that will be checked...".format(len(agents)))
pool = ThreadPool(5) pool = ThreadPool(5)
pool.map(check_capture_agent_state, agents) pool.map(check_capture_agent_state, agents)
pool.close()
pool.join()
logged_events = rec_err_state_log_stream.getvalue()
if len(logged_events) > 0:
send_error_mail(logged_events, "Errors have been detected while checking recorder states!")
exit() exit()
c = get_calender('CS 30.46 Chemie Neuer Hoersaal') c = get_calender('CS 30.46 Chemie Neuer Hoersaal')

0
logs/app.log.2019-11-13 Normal file
View File