11 Commits

Author SHA1 Message Date
9e6d6d273c added comfort functions for audio channel mute control 2023-10-26 13:07:11 +02:00
b91cc55341 added a lot of documentation and Enums for most function parameters 2023-10-26 11:51:07 +02:00
2d0a5c2974 added a lot of enums for SMP parameters 2023-10-25 16:24:03 +02:00
b60d89ce0a linted code of extron smp adapter 2023-10-25 15:05:47 +02:00
Tobias K.
6936d8d02c reformated some code 2023-10-24 16:57:28 +02:00
Tobias K.
e5eb9ceeb6 updated initial recorders.json 2023-10-24 16:30:50 +02:00
Tobias K.
1d563cd8b7 handling some exceptions in simple state checker 2023-10-24 16:25:03 +02:00
Tobias K.
40ddd4bbeb updated urls 2023-10-24 16:16:57 +02:00
884ae00574 readded fe 2023-10-13 16:09:34 +02:00
52664b7adb migrated to poetry; updated all packages 2023-10-13 12:05:23 +02:00
6e2fa6c101 migrated to poetry; updated all packages 2023-10-13 12:01:01 +02:00
31 changed files with 3886 additions and 1375 deletions

762
Pipfile.lock generated
View File

@@ -1,762 +0,0 @@
{
"_meta": {
"hash": {
"sha256": "76bfb08c216b99c72b4d6f0e7379173e2dcbc59c351b15d0695f60c2ddf46f5c"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.8"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"alabaster": {
"hashes": [
"sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359",
"sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"
],
"version": "==0.7.12"
},
"alembic": {
"hashes": [
"sha256:49277bb7242192bbb9eac58fed4fe02ec6c3a2a4b4345d2171197459266482b2"
],
"version": "==1.3.1"
},
"aniso8601": {
"hashes": [
"sha256:529dcb1f5f26ee0df6c0a1ee84b7b27197c3c50fc3a6321d66c544689237d072",
"sha256:c033f63d028b9a58e3ab0c2c7d0532ab4bfa7452bfc788fbfe3ddabd327b181a"
],
"version": "==8.0.0"
},
"apispec": {
"hashes": [
"sha256:cf8e1f3b56949710f8cf23797b7f40215e9dae8bac583789a3f2c13dc56349fa",
"sha256:fe5cf5fc89b1c4a73acd5af3a10ede02b31ec116f215ed02271cb905d3172367"
],
"version": "==3.1.0"
},
"arrow": {
"hashes": [
"sha256:4bfacea734ead51495dc47df00421ecfd4ca1f2c0fbe58b9a26eaeddedc31caf",
"sha256:67f8be7c0cf420424bc62d8d7dc40b44e4bb2f7b515f9cc2954fb36e35797656"
],
"version": "==0.14.7"
},
"attrs": {
"hashes": [
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
"sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
],
"version": "==19.3.0"
},
"beaker": {
"hashes": [
"sha256:ad5d1c05027ee3be3a482ea39f8cb70339b41e5d6ace0cb861382754076d187e"
],
"version": "==1.11.0"
},
"beautifulsoup4": {
"hashes": [
"sha256:5279c36b4b2ec2cb4298d723791467e3000e5384a43ea0cdf5d45207c7e97169",
"sha256:6135db2ba678168c07950f9a16c4031822c6f4aec75a65e0a97bc5ca09789931",
"sha256:dcdef580e18a76d54002088602eba453eec38ebbcafafeaabd8cab12b6155d57"
],
"index": "pypi",
"version": "==4.8.1"
},
"certifi": {
"hashes": [
"sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50",
"sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef"
],
"version": "==2019.9.11"
},
"cffi": {
"hashes": [
"sha256:0b49274afc941c626b605fb59b59c3485c17dc776dc3cc7cc14aca74cc19cc42",
"sha256:0e3ea92942cb1168e38c05c1d56b0527ce31f1a370f6117f1d490b8dcd6b3a04",
"sha256:135f69aecbf4517d5b3d6429207b2dff49c876be724ac0c8bf8e1ea99df3d7e5",
"sha256:19db0cdd6e516f13329cba4903368bff9bb5a9331d3410b1b448daaadc495e54",
"sha256:2781e9ad0e9d47173c0093321bb5435a9dfae0ed6a762aabafa13108f5f7b2ba",
"sha256:291f7c42e21d72144bb1c1b2e825ec60f46d0a7468f5346841860454c7aa8f57",
"sha256:2c5e309ec482556397cb21ede0350c5e82f0eb2621de04b2633588d118da4396",
"sha256:2e9c80a8c3344a92cb04661115898a9129c074f7ab82011ef4b612f645939f12",
"sha256:32a262e2b90ffcfdd97c7a5e24a6012a43c61f1f5a57789ad80af1d26c6acd97",
"sha256:3c9fff570f13480b201e9ab69453108f6d98244a7f495e91b6c654a47486ba43",
"sha256:415bdc7ca8c1c634a6d7163d43fb0ea885a07e9618a64bda407e04b04333b7db",
"sha256:42194f54c11abc8583417a7cf4eaff544ce0de8187abaf5d29029c91b1725ad3",
"sha256:4424e42199e86b21fc4db83bd76909a6fc2a2aefb352cb5414833c030f6ed71b",
"sha256:4a43c91840bda5f55249413037b7a9b79c90b1184ed504883b72c4df70778579",
"sha256:599a1e8ff057ac530c9ad1778293c665cb81a791421f46922d80a86473c13346",
"sha256:5c4fae4e9cdd18c82ba3a134be256e98dc0596af1e7285a3d2602c97dcfa5159",
"sha256:5ecfa867dea6fabe2a58f03ac9186ea64da1386af2159196da51c4904e11d652",
"sha256:62f2578358d3a92e4ab2d830cd1c2049c9c0d0e6d3c58322993cc341bdeac22e",
"sha256:6471a82d5abea994e38d2c2abc77164b4f7fbaaf80261cb98394d5793f11b12a",
"sha256:6d4f18483d040e18546108eb13b1dfa1000a089bcf8529e30346116ea6240506",
"sha256:71a608532ab3bd26223c8d841dde43f3516aa5d2bf37b50ac410bb5e99053e8f",
"sha256:74a1d8c85fb6ff0b30fbfa8ad0ac23cd601a138f7509dc617ebc65ef305bb98d",
"sha256:7b93a885bb13073afb0aa73ad82059a4c41f4b7d8eb8368980448b52d4c7dc2c",
"sha256:7d4751da932caaec419d514eaa4215eaf14b612cff66398dd51129ac22680b20",
"sha256:7f627141a26b551bdebbc4855c1157feeef18241b4b8366ed22a5c7d672ef858",
"sha256:8169cf44dd8f9071b2b9248c35fc35e8677451c52f795daa2bb4643f32a540bc",
"sha256:aa00d66c0fab27373ae44ae26a66a9e43ff2a678bf63a9c7c1a9a4d61172827a",
"sha256:ccb032fda0873254380aa2bfad2582aedc2959186cce61e3a17abc1a55ff89c3",
"sha256:d754f39e0d1603b5b24a7f8484b22d2904fa551fe865fd0d4c3332f078d20d4e",
"sha256:d75c461e20e29afc0aee7172a0950157c704ff0dd51613506bd7d82b718e7410",
"sha256:dcd65317dd15bc0451f3e01c80da2216a31916bdcffd6221ca1202d96584aa25",
"sha256:e570d3ab32e2c2861c4ebe6ffcad6a8abf9347432a37608fe1fbd157b3f0036b",
"sha256:fd43a88e045cf992ed09fa724b5315b790525f2676883a6ea64e3263bae6549d"
],
"version": "==1.13.2"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"click": {
"hashes": [
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
],
"version": "==7.0"
},
"coloredlogs": {
"hashes": [
"sha256:34fad2e342d5a559c31b6c889e8d14f97cb62c47d9a2ae7b5ed14ea10a79eff8",
"sha256:b869a2dda3fa88154b9dd850e27828d8755bfab5a838a1c97fbc850c6e377c36"
],
"index": "pypi",
"version": "==10.0"
},
"coverage": {
"hashes": [
"sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6",
"sha256:0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650",
"sha256:141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5",
"sha256:19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d",
"sha256:23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351",
"sha256:245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755",
"sha256:331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef",
"sha256:386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca",
"sha256:3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca",
"sha256:60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9",
"sha256:63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc",
"sha256:6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5",
"sha256:6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f",
"sha256:7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe",
"sha256:826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888",
"sha256:93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5",
"sha256:9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce",
"sha256:af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5",
"sha256:bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e",
"sha256:bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e",
"sha256:c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9",
"sha256:dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437",
"sha256:df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1",
"sha256:e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c",
"sha256:e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24",
"sha256:e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47",
"sha256:eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2",
"sha256:eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28",
"sha256:ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c",
"sha256:efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7",
"sha256:fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0",
"sha256:ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025"
],
"index": "pypi",
"version": "==4.5.4"
},
"cryptography": {
"hashes": [
"sha256:02079a6addc7b5140ba0825f542c0869ff4df9a69c360e339ecead5baefa843c",
"sha256:1df22371fbf2004c6f64e927668734070a8953362cd8370ddd336774d6743595",
"sha256:369d2346db5934345787451504853ad9d342d7f721ae82d098083e1f49a582ad",
"sha256:3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651",
"sha256:44ff04138935882fef7c686878e1c8fd80a723161ad6a98da31e14b7553170c2",
"sha256:4b1030728872c59687badcca1e225a9103440e467c17d6d1730ab3d2d64bfeff",
"sha256:58363dbd966afb4f89b3b11dfb8ff200058fbc3b947507675c19ceb46104b48d",
"sha256:6ec280fb24d27e3d97aa731e16207d58bd8ae94ef6eab97249a2afe4ba643d42",
"sha256:7270a6c29199adc1297776937a05b59720e8a782531f1f122f2eb8467f9aab4d",
"sha256:73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e",
"sha256:7f09806ed4fbea8f51585231ba742b58cbcfbfe823ea197d8c89a5e433c7e912",
"sha256:90df0cc93e1f8d2fba8365fb59a858f51a11a394d64dbf3ef844f783844cc793",
"sha256:971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13",
"sha256:a518c153a2b5ed6b8cc03f7ae79d5ffad7315ad4569b2d5333a13c38d64bd8d7",
"sha256:b0de590a8b0979649ebeef8bb9f54394d3a41f66c5584fff4220901739b6b2f0",
"sha256:b43f53f29816ba1db8525f006fa6f49292e9b029554b3eb56a189a70f2a40879",
"sha256:d31402aad60ed889c7e57934a03477b572a03af7794fa8fb1780f21ea8f6551f",
"sha256:de96157ec73458a7f14e3d26f17f8128c959084931e8997b9e655a39c8fde9f9",
"sha256:df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2",
"sha256:ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf",
"sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8"
],
"version": "==2.8"
},
"decorator": {
"hashes": [
"sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce",
"sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d"
],
"version": "==4.4.1"
},
"dnspython": {
"hashes": [
"sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01",
"sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"
],
"version": "==1.16.0"
},
"ecdsa": {
"hashes": [
"sha256:64c613005f13efec6541bb0a33290d0d03c27abab5f15fbab20fb0ee162bdd8e",
"sha256:e108a5fe92c67639abae3260e43561af914e7fd0d27bae6d2ec1312ae7934dfe"
],
"version": "==0.14.1"
},
"eventlet": {
"hashes": [
"sha256:658b1cd80937adc1a4860de2841e0528f64e2ca672885c4e00fc0e2217bde6b1",
"sha256:6c9c625af48424c4680d89314dbe45a76cc990cf002489f9469ff214b044ffc1"
],
"index": "pypi",
"version": "==0.25.1"
},
"flask": {
"hashes": [
"sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52",
"sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6"
],
"index": "pypi",
"version": "==1.1.1"
},
"flask-cors": {
"hashes": [
"sha256:72170423eb4612f0847318afff8c247b38bd516b7737adfc10d1c2cdbb382d16",
"sha256:f4d97201660e6bbcff2d89d082b5b6d31abee04b1b3003ee073a6fd25ad1d69a"
],
"index": "pypi",
"version": "==3.0.8"
},
"flask-httpauth": {
"hashes": [
"sha256:0149953720489407e51ec24bc2f86273597b7973d71cd51f9443bd0e2a89bd72",
"sha256:6ef8b761332e780f9ff74d5f9056c2616f52babc1998b01d9f361a1e439e61b9"
],
"index": "pypi",
"version": "==3.3.0"
},
"flask-jwt-extended": {
"hashes": [
"sha256:0aa8ee6fa7eb3be9314e39dd199ac8e19389a95371f9d54e155c7aa635e319dd"
],
"index": "pypi",
"version": "==3.24.1"
},
"flask-login": {
"hashes": [
"sha256:c815c1ac7b3e35e2081685e389a665f2c74d7e077cb93cecabaea352da4752ec"
],
"index": "pypi",
"version": "==0.4.1"
},
"flask-marshmallow": {
"hashes": [
"sha256:4f507f883838b397638a3a36c7d36ee146b255a49db952f5d9de3f6f4522e8a8",
"sha256:69e99e3a123393894884a032ae2d11e6bdf4519a505819b66cec7eda32057741"
],
"version": "==0.10.1"
},
"flask-migrate": {
"hashes": [
"sha256:6fb038be63d4c60727d5dfa5f581a6189af5b4e2925bc378697b4f0a40cfb4e1",
"sha256:a96ff1875a49a40bd3e8ac04fce73fdb0870b9211e6168608cbafa4eb839d502"
],
"index": "pypi",
"version": "==2.5.2"
},
"flask-pyoidc": {
"hashes": [
"sha256:c5556e82eb45c6314f4dc4c357c9909830e99cd2e4237ba56f34ca9e699aae42"
],
"index": "pypi",
"version": "==3.0.0"
},
"flask-restplus": {
"hashes": [
"sha256:a15d251923a8feb09a5d805c2f4d188555910a42c64d58f7dd281b8cac095f1b",
"sha256:a66e442d0bca08f389fc3d07b4d808fc89961285d12fb8013f7cf15516fa9f5c"
],
"version": "==0.13.0"
},
"flask-restplus-patched": {
"hashes": [
"sha256:36342775f9e0990dfc000dbe61133dfe56f9ef32c9b4c6293ba7f2c128d16efc"
],
"index": "pypi",
"version": "==0.1.10"
},
"flask-script": {
"hashes": [
"sha256:6425963d91054cfcc185807141c7314a9c5ad46325911bd24dcb489bd0161c65"
],
"index": "pypi",
"version": "==2.0.6"
},
"flask-socketio": {
"hashes": [
"sha256:2172dff1e42415ba480cee02c30c2fc833671ff326f1598ee3d69aa02cf768ec",
"sha256:7ff5b2f5edde23e875a8b0abf868584e5706e11741557449bc5147df2cd78268"
],
"index": "pypi",
"version": "==4.2.1"
},
"flask-sqlalchemy": {
"hashes": [
"sha256:0078d8663330dc05a74bc72b3b6ddc441b9a744e2f56fe60af1a5bfc81334327",
"sha256:6974785d913666587949f7c2946f7001e4fa2cb2d19f4e69ead02e4b8f50b33d"
],
"index": "pypi",
"version": "==2.4.1"
},
"flask-testing": {
"hashes": [
"sha256:dc076623d7d850653a018cb64f500948334c8aeb6b10a5a842bf1bcfb98122bc"
],
"index": "pypi",
"version": "==0.7.1"
},
"future": {
"hashes": [
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
],
"version": "==0.18.2"
},
"greenlet": {
"hashes": [
"sha256:000546ad01e6389e98626c1367be58efa613fa82a1be98b0c6fc24b563acc6d0",
"sha256:0d48200bc50cbf498716712129eef819b1729339e34c3ae71656964dac907c28",
"sha256:23d12eacffa9d0f290c0fe0c4e81ba6d5f3a5b7ac3c30a5eaf0126bf4deda5c8",
"sha256:37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304",
"sha256:51503524dd6f152ab4ad1fbd168fc6c30b5795e8c70be4410a64940b3abb55c0",
"sha256:8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214",
"sha256:81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043",
"sha256:853da4f9563d982e4121fed8c92eea1a4594a2299037b3034c3c898cb8e933d6",
"sha256:8b4572c334593d449113f9dc8d19b93b7b271bdbe90ba7509eb178923327b625",
"sha256:9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc",
"sha256:9854f612e1b59ec66804931df5add3b2d5ef0067748ea29dc60f0efdcda9a638",
"sha256:99a26afdb82ea83a265137a398f570402aa1f2b5dfb4ac3300c026931817b163",
"sha256:a19bf883b3384957e4a4a13e6bd1ae3d85ae87f4beb5957e35b0be287f12f4e4",
"sha256:a9f145660588187ff835c55a7d2ddf6abfc570c2651c276d3d4be8a2766db490",
"sha256:ac57fcdcfb0b73bb3203b58a14501abb7e5ff9ea5e2edfa06bb03035f0cff248",
"sha256:bcb530089ff24f6458a81ac3fa699e8c00194208a724b644ecc68422e1111939",
"sha256:beeabe25c3b704f7d56b573f7d2ff88fc99f0138e43480cecdfcaa3b87fe4f87",
"sha256:d634a7ea1fc3380ff96f9e44d8d22f38418c1c381d5fac680b272d7d90883720",
"sha256:d97b0661e1aead761f0ded3b769044bb00ed5d33e1ec865e891a8b128bf7c656"
],
"version": "==0.4.15"
},
"html5lib": {
"hashes": [
"sha256:20b159aa3badc9d5ee8f5c647e5efd02ed2a66ab8d354930bd9ff139fc1dc0a3",
"sha256:66cb0dcfdbbc4f9c3ba1a63fdb511ffdbd4f513b2b6d81b80cd26ce6b3fb3736"
],
"index": "pypi",
"version": "==1.0.1"
},
"humanfriendly": {
"hashes": [
"sha256:23057b10ad6f782e7bc3a20e3cb6768ab919f619bbdc0dd75691121bbde5591d",
"sha256:33ee8ceb63f1db61cce8b5c800c531e1a61023ac5488ccde2ba574a85be00a85"
],
"version": "==4.18"
},
"ics": {
"hashes": [
"sha256:12cf34aed0dafa1bf99d79ca58e99949d6721511b856386e118015fe5f5d6e3a"
],
"index": "pypi",
"version": "==0.6"
},
"idna": {
"hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
],
"version": "==2.8"
},
"itsdangerous": {
"hashes": [
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
],
"version": "==1.1.0"
},
"jinja2": {
"hashes": [
"sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f",
"sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de"
],
"version": "==2.10.3"
},
"jsonschema": {
"hashes": [
"sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163",
"sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"
],
"version": "==3.2.0"
},
"mako": {
"hashes": [
"sha256:a36919599a9b7dc5d86a7a8988f23a9a3a3d083070023bab23d64f7f1d1e0a4b"
],
"version": "==1.1.0"
},
"markupsafe": {
"hashes": [
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"
],
"version": "==1.1.1"
},
"marshmallow": {
"hashes": [
"sha256:1a358beb89c2b4d5555272065a9533591a3eb02f1b854f3c4002d88d8f2a1ddb",
"sha256:eb97c42c5928b5720812c9268865fe863d4807bc1a8b48ddd7d5c9e1779a6af0"
],
"version": "==3.2.2"
},
"monotonic": {
"hashes": [
"sha256:23953d55076df038541e648a53676fb24980f7a1be290cdda21300b3bc21dfb0",
"sha256:552a91f381532e33cbd07c6a2655a21908088962bb8fa7239ecbcc6ad1140cc7"
],
"version": "==1.5"
},
"oic": {
"hashes": [
"sha256:34da42f4f9b4a36a02b28d72a42a3197a91e7efc5356c1c41d7f1a0bdf3ad1d2"
],
"version": "==0.12"
},
"passlib": {
"hashes": [
"sha256:3d948f64138c25633613f303bcc471126eae67c04d5e3f6b7b8ce6242f8653e0",
"sha256:43526aea08fa32c6b6dbbbe9963c4c767285b78147b7437597f992812f69d280"
],
"index": "pypi",
"version": "==1.7.1"
},
"pbr": {
"hashes": [
"sha256:2c8e420cd4ed4cec4e7999ee47409e876af575d4c35a45840d59e8b5f3155ab8",
"sha256:b32c8ccaac7b1a20c0ce00ce317642e6cf231cf038f9875e0280e28af5bf7ac9"
],
"version": "==5.4.3"
},
"pyasn1": {
"hashes": [
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"
],
"version": "==0.4.8"
},
"pycparser": {
"hashes": [
"sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"
],
"version": "==2.19"
},
"pycryptodomex": {
"hashes": [
"sha256:0943b65fb41b7403a9def6214061fdd9ab9afd0bbc581e553c72eebe60bded36",
"sha256:0a1dbb5c4d975a4ea568fb7686550aa225d94023191fb0cca8747dc5b5d77857",
"sha256:0f43f1608518347fdcb9c8f443fa5cabedd33f94188b13e4196a3a7ba90d169c",
"sha256:11ce5fec5990e34e3981ed14897ba601c83957b577d77d395f1f8f878a179f98",
"sha256:17a09e38fdc91e4857cf5a7ce82f3c0b229c3977490f2146513e366923fc256b",
"sha256:22d970cee5c096b9123415e183ae03702b2cd4d3ba3f0ced25c4e1aba3967167",
"sha256:2a1793efcbae3a2264c5e0e492a2629eb10d895d6e5f17dbbd00eb8b489c6bda",
"sha256:30a8a148a0fe482cec1aaf942bbd0ade56ec197c14fe058b2a94318c57e1f991",
"sha256:32fbbaf964c5184d3f3e349085b0536dd28184b02e2b014fc900f58bbc126339",
"sha256:347d67faee36d449dc9632da411cc318df52959079062627f1243001b10dc227",
"sha256:45f4b4e5461a041518baabc52340c249b60833aa84cea6377dc8016a2b33c666",
"sha256:4717daec0035034b002d31c42e55431c970e3e38a78211f43990e1b7eaf19e28",
"sha256:51a1ac9e7dda81da444fed8be558a60ec88dfc73b2aa4b0efa310e87acb75838",
"sha256:53e9dcc8f14783f6300b70da325a50ac1b0a3dbaee323bd9dc3f71d409c197a1",
"sha256:5519a2ed776e193688b7ddb61ab709303f6eb7d1237081e298283c72acc44271",
"sha256:583450e8e80a0885c453211ed2bd69ceea634d8c904f23ff8687f677fe810e95",
"sha256:60f862bd2a07133585a4fc2ce2b1a8ec24746b07ac44307d22ef2b767cb03435",
"sha256:612091f1d3c84e723bec7cb855cf77576e646045744794c9a3f75ba80737762f",
"sha256:629a87b87c8203b8789ccefc7f2f2faecd2daaeb56bdd0b4e44cd89565f2db07",
"sha256:6e56ec4c8938fb388b6f250ddd5e21c15e8f25a76e0ad0e2abae9afee09e67b4",
"sha256:8e8092651844a11ec7fa534395f3dfe99256ce4edca06f128efc9d770d6e1dc1",
"sha256:8f5f260629876603e08f3ce95c8ccd9b6b83bf9a921c41409046796267f7adc5",
"sha256:9a6b74f38613f54c56bd759b411a352258f47489bbefd1d57c930a291498b35b",
"sha256:a5a13ebb52c4cd065fb673d8c94f39f30823428a4de19e1f3f828b63a8882d1e",
"sha256:a77ca778a476829876a3a70ae880073379160e4a465d057e3c4e1c79acdf1b8a",
"sha256:a9f7be3d19f79429c2118fd61bc2ec4fa095e93b56fb3a5f3009822402c4380f",
"sha256:dc15a467c4f9e4b43748ba2f97aea66f67812bfd581818284c47cadc81d4caec",
"sha256:e13cdeea23059f7577c230fd580d2c8178e67ebe10e360041abe86c33c316f1c",
"sha256:e45b85c8521bca6bdfaf57e4987743ade53e9f03529dd3adbc9524094c6d55c4",
"sha256:e87f17867b260f57c88487f943eb4d46c90532652bb37046e764842c3b66cbb1",
"sha256:ee40a5b156f6c1192bc3082e9d73d0479904433cdda83110546cd67f5a15a5be",
"sha256:ef63ffde3b267043579af8830fc97fc3b9b8a526a24e3ba23af9989d4e9e689a"
],
"version": "==3.9.4"
},
"pyjwkest": {
"hashes": [
"sha256:5560fd5ba08655f29ff6ad1df1e15dc05abc9d976fcbcec8d2b5167f49b70222"
],
"version": "==1.4.2"
},
"pyjwt": {
"hashes": [
"sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e",
"sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"
],
"index": "pypi",
"version": "==1.7.1"
},
"pyopenssl": {
"hashes": [
"sha256:621880965a720b8ece2f1b2f54ea2071966ab00e2970ad2ce11d596102063504",
"sha256:9a24494b2602aaf402be5c9e30a0b82d4a5c67528fe8fb475e3f3bc00dd69507"
],
"version": "==19.1.0"
},
"pyrsistent": {
"hashes": [
"sha256:eb6545dbeb1aa69ab1fb4809bfbf5a8705e44d92ef8fc7c2361682a47c46c778"
],
"version": "==0.15.5"
},
"python-dateutil": {
"hashes": [
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
],
"version": "==2.8.1"
},
"python-editor": {
"hashes": [
"sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d",
"sha256:51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b",
"sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8"
],
"version": "==1.0.4"
},
"python-engineio": {
"hashes": [
"sha256:4a13fb87c819b855c55a731fdf82559adb8311c04cfdfebd6b9ecd1c2afbb575",
"sha256:9c9a6035b4b5e5a225f426f846afa14cf627f7571d1ae02167cb703fefd134b7"
],
"version": "==3.10.0"
},
"python-jose": {
"hashes": [
"sha256:29701d998fe560e52f17246c3213a882a4a39da7e42c7015bcc1f7823ceaff1c",
"sha256:ed7387f0f9af2ea0ddc441d83a6eb47a5909bd0c8a72ac3250e75afec2cc1371"
],
"index": "pypi",
"version": "==3.0.1"
},
"python-socketio": {
"hashes": [
"sha256:506b2cf7a520b40ea0b3f25e1272eff8de134dce6f471c1f6bc0de8c90fe8c57",
"sha256:d4e2c23241afa0aae2a5bcc107523b2fcc71f5020df89a093f3634eb48955967"
],
"version": "==4.3.1"
},
"pythonping": {
"hashes": [
"sha256:c754c2bd8617943988a0a1b47d7392a57efea51fb7a30c7e938e246e90ea91eb"
],
"index": "pypi",
"version": "==1.0.7"
},
"pytz": {
"hashes": [
"sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d",
"sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"
],
"version": "==2019.3"
},
"requests": {
"hashes": [
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
],
"version": "==2.22.0"
},
"rsa": {
"hashes": [
"sha256:14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66",
"sha256:1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487"
],
"version": "==4.0"
},
"scapy": {
"hashes": [
"sha256:e2f8d11f6a941c14a789ae8b236b27bd634681f1b29b5e893861e284d234f6b0"
],
"index": "pypi",
"version": "==2.4.3"
},
"six": {
"hashes": [
"sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
"sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
],
"version": "==1.13.0"
},
"soupsieve": {
"hashes": [
"sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5",
"sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"
],
"version": "==1.9.5"
},
"sqlalchemy": {
"hashes": [
"sha256:afa5541e9dea8ad0014251bc9d56171ca3d8b130c9627c6cb3681cff30be3f8a"
],
"index": "pypi",
"version": "==1.3.11"
},
"sqlalchemy-migrate": {
"hashes": [
"sha256:0bc02e292a040ade5e35a01d3ea744119e1309cdddb704fdb99bac13236614f8",
"sha256:e5d2348db19a5062132d93e3b4d9e7644af552fffbec4c78cc5358f848d2f6c1"
],
"index": "pypi",
"version": "==0.13.0"
},
"sqlparse": {
"hashes": [
"sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177",
"sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873"
],
"version": "==0.3.0"
},
"ssh2-python": {
"hashes": [
"sha256:054f2cab611ddca34095eb78d1ae1f6e29521678c82f0de17f696072a0b924fe",
"sha256:097d74684172f163d5025aef316987c1c7acf852d9fb75e4735720c8690adf87",
"sha256:0f4555b79e19ca6fdd84a74e85152d375a921d167ed9dc680d05f1f9f5dfc463",
"sha256:0fb3d9eca454b2874748c69e7e836ea5c6544f1b7acd87d8a876f99f618c806c",
"sha256:180c2728796f777a5856b23e5e1656a15a3e8602b4270348f892599ae5426f45",
"sha256:49aaa9d48cf52798d89f466a5e774e9dab8b76dc380b90645fd8d5c6622df177",
"sha256:4b5ba1390ff5e8faa6b2409df750e4650de3934c3b76ad707d7b54b477600226",
"sha256:57a4452dfc5c7f414de14e32f29e21f680fb8d7bdf94306e5f6bc8c2a235fa7a",
"sha256:584f753f0401217a55e70d2ae97a7e5220f4d37993a1bba275c4c5e110d87193",
"sha256:692cf27ddc5583da9b07b0f0348f0577579f8d798a0b8e4bf495b8d7f19fc854",
"sha256:6dc75bacc37de63aa9c86f9982642982c3a8103297fbbb73543a76e3db9abc6a",
"sha256:7a029275e62a1e31333ee7f2f151f661dedfac0345f1108e1a8d0b62e08ddf9b",
"sha256:7a3d761c669392e778c24a0eabcf6f1ba48ad68bb3b82a2d98235f56500bc8b0",
"sha256:8632684aae2f523e603381cf51a1da134fd5937cf0ae9650b1b9e7b4f328c133",
"sha256:8acab66dd73554d2c68abaccf96cdddfc10449ad6c7c273ac4b7a91779d414b2",
"sha256:9410b63c2361b2b65a55b5e8dc8187270de0f81e11864a427ad52b82b926bcc9",
"sha256:abe29ad01ed2ac4465e61c8de42b6850fca9c87d8792686a2de7c7d06c6eb72d",
"sha256:de151500a2a027a29bca3d7196c76008b41bb97db29378f29c4651ba1bcb00e8",
"sha256:debc56711643b82ab60a9c8b8cbf2978b65c0293aa7e53557a3c0d1fc57799cf",
"sha256:f508144d684b3c3c0f264ce67058f05ae3729ae77cc3a8f2051b442e01594849"
],
"index": "pypi",
"version": "==0.18.0.post1"
},
"style": {
"hashes": [
"sha256:6485a4bcb84629341a5fd1587fe3ac4887daa4741f0c8a1d01b9c3c8a263afe7",
"sha256:8eb365fc15039b19b728bd4e6e85fb7daf24e7aeeec6a15a666f97484c564005"
],
"version": "==1.1.0"
},
"tatsu": {
"hashes": [
"sha256:80713413473a009f2081148d0f494884cabaf9d6866b71f2a68a92b6442f343d",
"sha256:c9211eeee9a2d4c90f69879ec0b518b1aa0d9450249cb0dd181f5f5b18be0a92"
],
"version": "==4.4.0"
},
"tempita": {
"hashes": [
"sha256:cacecf0baa674d356641f1d406b8bff1d756d739c46b869a54de515d08e6fc9c"
],
"version": "==0.5.2"
},
"update": {
"hashes": [
"sha256:a25522b4bf60e3e3c1a3ff3ca3a4f5a328ac4b8ff400fdc9614483147e313323"
],
"index": "pypi",
"version": "==0.0.1"
},
"urllib3": {
"hashes": [
"sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293",
"sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745"
],
"version": "==1.25.7"
},
"webargs": {
"hashes": [
"sha256:3beca296598067cec24a0b6f91c0afcc19b6e3c4d84ab026b931669628bb47b4",
"sha256:3f9dc15de183d356c9a0acc159c100ea0506c0c240c1e6f1d8b308c5fed4dbbd",
"sha256:fa4ad3ad9b38bedd26c619264fdc50d7ae014b49186736bca851e5b5228f2a1b"
],
"version": "==5.5.2"
},
"webencodings": {
"hashes": [
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
],
"version": "==0.5.1"
},
"werkzeug": {
"hashes": [
"sha256:7280924747b5733b246fe23972186c6b348f9ae29724135a6dfc1e53cea433e7",
"sha256:e5f4a1f98b52b18a93da705a7458e55afb26f32bff83ff5d19189f92462d65c4"
],
"version": "==0.16.0"
}
},
"develop": {}
}

View File

@@ -3,19 +3,18 @@
Backend base module
"""
import logging
from io import StringIO
from logging.config import dictConfig
from logging.handlers import MemoryHandler
from typing import Union
import coloredlogs as coloredlogs
import coloredlogs
import jwt
import requests
from flask import Flask, jsonify
from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth, MultiAuth
from flask_jwt_extended import JWTManager, decode_token
from flask_login import LoginManager
from flask_restplus import abort
from flask_restx import abort
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
from backend.config import Config
@@ -109,11 +108,11 @@ class LrcException(Exception):
def __repr__(self):
if self.type is None:
msg = "LRC Exception: \"{}\"".format(', '.join(super().args))
msg = f"LRC Exception: \"{', '.join(super().args)}\""
else:
msg = "LRC Exception: (original Exception: {}) \"{}\"".format(self.type, ', '.join(super().args))
msg = f"LRC Exception: (original Exception: {self.type}) \"{', '.join(super().args)}\""
if self.html_code is not None:
msg += " (HTML Code: {})".format(self.html_code)
msg += f" (HTML Code: {self.html_code})"
return msg
def __str__(self):
@@ -135,7 +134,7 @@ jwt_auth = HTTPTokenAuth('Bearer')
@jwt_extended.invalid_token_loader
def unauthorized_jwt(token):
main_logger.info("Unauthorized access; invalid token provided: {}".format(token))
main_logger.info("Unauthorized access; invalid token provided: %s", token)
abort(401)
@@ -147,10 +146,10 @@ def verify_token(token):
try:
decoded = decode_token(token)
except jwt.exceptions.DecodeError as e:
app.logger.warn("Could not verify token: {}".format(str(e)))
app.logger.warning("Could not verify token: %s", str(e))
return False
except jwt.exceptions.ExpiredSignatureError as e:
app.logger.warn("Could not verify token: {}".format(str(e)))
app.logger.warning("Could not verify token: %s", str(e))
return False
app.logger.info(decoded)
return True
@@ -164,20 +163,22 @@ from backend.auth import oidc_auth, auth_bp
try:
oidc_auth.init_app(app)
except requests.exceptions.ConnectionError as err:
app.logger.error("Could not connect to OIDC!!", err)
app.logger.exception("Could not connect to OIDC!!", exc_info=err)
# oidc_multi_auth = MultiAuth(oidc_auth, jwt_auth) <- can't work as OIDCAuthentication not implementing HTTPAuth
from .serve_frontend import fe_bp
from .api import auth_api_bp, api_v1, api_bp
CORS(app)
CORS(api_bp)
app.register_blueprint(auth_bp)
app.register_blueprint(auth_api_bp)
app.register_blueprint(api_bp)
app.register_blueprint(fe_bp)
CORS(app)
CORS(api_bp)
# Fix flask-restplus by duck typing error handlers
jwt_extended._set_error_handler_callbacks(api_v1)

View File

@@ -12,16 +12,25 @@ from backend.models import room_model, recorder_model, RecorderCommand
from backend.recorder_adapters import get_defined_recorder_adapters
from backend.tools.model_updater import update_recorder_models_database, create_default_recorders
def setup_database(app):
with app.app_context():
#db.drop_all()
db.create_all()
room_model.pre_fill_table()
update_recorder_models_database(drop=False)
create_default_recorders()
def get_app():
setup_database(app)
#app.register_blueprint(api_blueprint)
return app
def main():
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
#db.drop_all()
#db.create_all()
room_model.pre_fill_table()
update_recorder_models_database(drop=False)
create_default_recorders()
app = get_app()
print(app.config.get("SERVER_NAME", None))
server_name = app.config.get("SERVER_NAME", None)
if server_name is not None and "ubkaps154.ubka.uni-karlsruhe.de" in server_name:

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from flask import Blueprint, abort
from flask_restplus import Api, Namespace
from flask_restx import Api, Namespace
api_authorizations = {
'apikey': {

View File

@@ -10,21 +10,16 @@ import json
from pprint import pprint
import flask
from datetime import datetime, timedelta
import jwt
from flask import request, jsonify, current_app, url_for, Response, session, redirect, make_response
from flask_jwt_extended import create_access_token, create_refresh_token, jwt_refresh_token_required, get_jwt_identity, \
get_raw_jwt, jwt_required
from functools import wraps
from random import randint
from flask import request, jsonify, current_app, url_for, redirect, make_response
from flask_jwt_extended import create_access_token, create_refresh_token, get_jwt, get_jwt_identity, jwt_required
from flask_login import logout_user, login_user
from typing import Iterable
from flask_restplus import Resource, fields
from flask_restx import Resource, fields
from werkzeug.routing import BuildError
from backend import db, app, jwt_extended
from backend import db, app
from backend.api import auth_api_bp, auth_api_providers_ns, auth_api_register_ns
from backend.auth import AUTH_PROVIDERS, oidc_auth
from backend.models.user_model import User, Group, BlacklistToken
@@ -58,19 +53,19 @@ def register():
return jsonify(user.to_dict()), 201
@auth_api_register_ns.route('/')
@auth_api_register_ns.expect(auth_api_register_ns.model('RegisterModel', {
'nickname': fields.String(required=False, description='The user\'s nickname'),
'first_name': fields.String(required=False, description='The user\'s first name'),
'last_name': fields.String(required=False, description='The user\'s last name'),
'lang': fields.String(required=False, description='The user\'s preferred language'),
'timezone': fields.String(required=False, description='The user\'s preferred timezone'),
'email': fields.String(required=True, description='The user\'s e-mail address'),
'password': fields.String(required=False, description='The group\'s name')
}))
class AuthProviders(Resource):
def get(self):
return register()
# @auth_api_register_ns.route('/')
# @auth_api_register_ns.expect(auth_api_register_ns.model('RegisterModel', {
# 'nickname': fields.String(required=False, description='The user\'s nickname'),
# 'first_name': fields.String(required=False, description='The user\'s first name'),
# 'last_name': fields.String(required=False, description='The user\'s last name'),
# 'lang': fields.String(required=False, description='The user\'s preferred language'),
# 'timezone': fields.String(required=False, description='The user\'s preferred timezone'),
# 'email': fields.String(required=True, description='The user\'s e-mail address'),
# 'password': fields.String(required=False, description='The group\'s name')
# }))
# class AuthProviders(Resource):
# def get(self):
# return register()
@auth_api_bp.route('/login', methods=('GET', 'POST',))
@@ -96,7 +91,7 @@ def login():
@auth_api_bp.route('/logout', methods=['GET', 'DELETE'])
@jwt_required
def logout():
jti = get_raw_jwt()['jti']
jti = get_jwt()['jti']
db.session.add(BlacklistToken(token=jti))
db.session.commit()
return jsonify({"msg": "Successfully logged out"}), 200
@@ -104,9 +99,9 @@ def logout():
# Endpoint for revoking the current users refresh token
@auth_api_bp.route('/logout2', methods=['GET', 'DELETE'])
@jwt_refresh_token_required
@jwt_required(refresh=True)
def logout2():
jti = get_raw_jwt()['jti']
jti = get_jwt()['jti']
db.session.add(BlacklistToken(token=jti))
db.session.commit()
return jsonify({"msg": "Successfully logged out"}), 200
@@ -182,7 +177,7 @@ def oidc(redirect_url=None):
@auth_api_bp.route('/refresh', methods=['GET'])
@jwt_refresh_token_required
@jwt_required(refresh=True)
def refresh():
"""Refresh token endpoint. This will generate a new access token from
the refresh token, but will mark that access token as non-fresh,

View File

@@ -8,8 +8,8 @@ Login through API does not start a new session, but instead returns JWT.
import json
from datetime import datetime
from flask_jwt_extended import jwt_required, get_current_user, get_jwt_claims
from flask_restplus import fields, Resource
from flask_jwt_extended import jwt_required, get_current_user, get_jwt
from flask_restx import fields, Resource
from backend import db
from backend.api import api_control, get_jwt_identity
@@ -37,6 +37,6 @@ class ControlCommand(Resource):
def post(self):
print(get_current_user())
print(get_jwt_identity())
current_user = {'user': get_current_user(), 'claims': get_jwt_claims()}
current_user = {'user': get_current_user(), 'claims': get_jwt()}
args = self.control_command_parser.parse_args()
return {'time': datetime.utcnow(), 'output': args, 'state': current_user}

View File

@@ -5,7 +5,7 @@ import json
import logging
from random import *
from flask import jsonify, Blueprint, request
from flask_restplus import Resource, reqparse
from flask_restx import Resource, reqparse
from backend import basic_auth, multi_auth, db, jwt_auth
from backend.api import api_v1, api_bp

View File

@@ -6,7 +6,7 @@ For example: listing of available auth providers or registration of users.
Login through API does not start a new session, but instead returns JWT.
"""
from flask_jwt_extended import jwt_required
from flask_restplus import fields, Resource
from flask_restx import fields, Resource
from backend import db
from backend.api import api_group

View File

@@ -1,4 +1,4 @@
from flask_restplus import fields
from flask_restx import fields
from backend.api import api_user, api_recorder, api_v1
generic_id_parser = api_v1.parser()

View File

@@ -9,7 +9,7 @@ from datetime import datetime
from pprint import pprint
from flask_jwt_extended import jwt_required
from flask_restplus import fields, Resource, inputs
from flask_restx import fields, Resource, inputs
from backend import db, app
from backend.api import api_recorder

View File

@@ -6,7 +6,7 @@ For example: listing of available auth providers or registration of users.
Login through API does not start a new session, but instead returns JWT.
"""
from flask_jwt_extended import jwt_required
from flask_restplus import fields, Resource
from flask_restx import fields, Resource
from sqlalchemy import exc
from backend import db, app

View File

@@ -8,14 +8,14 @@ Login through API does not start a new session, but instead returns JWT.
from datetime import datetime
from pprint import pprint
from flask_jwt_extended import get_jwt_identity, jwt_required, current_user
from flask_restplus import Resource, fields, inputs, abort
from flask_jwt_extended import get_jwt_identity, jwt_required, current_user, verify_jwt_in_request
from flask_restx import Resource, inputs, abort
from backend import db, app, jwt_auth
from backend.api import api_user
from backend.api.models import user_model, recorder_model, generic_id_parser
from backend.models import Recorder
from backend.models.user_model import User, Group
from backend.models.recorder_model import Recorder
from backend.models.user_model import User
user_update_parser = api_user.parser()
@@ -27,10 +27,11 @@ user_update_parser.add_argument('last_name', type=str, required=False, store_mis
@api_user.route('/profile')
class Profile(Resource):
@jwt_required
@jwt_required()
@api_user.marshal_with(user_model)
def get(self):
"""Get infos about logged in user."""
print("hey!")
current_user_id = get_jwt_identity()
app.logger.info(current_user_id)
return User.get_by_identifier(current_user_id)
@@ -102,7 +103,7 @@ class UserList(Resource):
return User.get_all()
@jwt_required
@api_user.doc('create_group')
@api_user.doc('create_user')
@api_user.expect(user_model)
@api_user.marshal_with(user_model, code=201)
def post(self):

View File

@@ -10,7 +10,7 @@ import pkgutil
from pprint import pprint
from flask_jwt_extended import jwt_required
from flask_restplus import fields, Resource
from flask_restx import fields, Resource
from backend import db, app
from backend.api import api_virtual_command

View File

@@ -54,7 +54,7 @@ def logout():
logout_user()
@jwt_extended.user_claims_loader
@jwt_extended.additional_claims_loader
def add_claims_to_access_token(user):
if isinstance(user, str):
return {}
@@ -66,13 +66,13 @@ def user_identity_loader(user):
return user.email
@jwt_extended.user_loader_callback_loader
@jwt_extended.user_lookup_loader
def user_loader_callback(identity):
print("### user_loader_callback_loader")
return User.get_by_identifier(identity)
@jwt_extended.token_in_blacklist_loader
@jwt_extended.token_in_blocklist_loader
def check_if_token_in_blacklist(decrypted_token):
jti = decrypted_token['jti']
return BlacklistToken.get_by_token(jti) is not None

Binary file not shown.

View File

@@ -21,14 +21,13 @@ class AccessControlEntry(db.Model):
name = db.Column(db.Unicode(127), unique=False, nullable=False)
url = db.Column(db.Unicode(2047), unique=False, nullable=True, default="")
required_permission_id = db.Column(db.Integer, db.ForeignKey('permission.id'))
required_permission = db.relationship('Permission', back_populates='access_control_entry')
__table_args__ = (
CheckConstraint('length(name) > 2',
name='name_min_length'),
required_permission_id = db.Column(db.Integer, db.ForeignKey("permission.id"))
required_permission = db.relationship(
"Permission", back_populates="access_control_entry"
)
__table_args__ = (CheckConstraint("length(name) > 2", name="name_min_length"),)
def __init__(self, **kwargs):
super(AccessControlEntry, self).__init__(**kwargs)
@@ -56,15 +55,24 @@ class AccessControlEntry(db.Model):
return dict(id=self.id, name=self.name)
def toJSON(self):
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
sort_keys=True, indent=4)
return json.dumps(
self.to_dict(), default=lambda o: o.__dict__, sort_keys=True, indent=4
)
def pre_fill_table():
a_es = {"url": "", }
access_entries = [AccessControlEntry(name=room['name'], number=room['room_number'],
building_name=room['building_name'], building_number=room['building_number']) for room in
a_es]
a_es = {
"url": "",
}
access_entries = [
AccessControlEntry(
name=room["name"],
number=room["room_number"],
building_name=room["building_name"],
building_number=room["building_number"],
)
for room in a_es
]
try:
db.session.bulk_save_objects(access_entries)

View File

@@ -7,9 +7,18 @@ class ExampleDataItem(db.Model):
"""
just an example class...
"""
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
mac = db.Column(db.String(32), nullable=False, unique=True, index=True)
uuid = db.Column(db.String(36), nullable=False, unique=True, index=True, default=str(uuid.uuid4()))
uuid = db.Column(
db.String(36),
nullable=False,
unique=True,
index=True,
default=str(uuid.uuid4()),
)
some_string_value = db.Column(db.String, nullable=True, index=True)
name = db.Column(db.String(128), default="<not set>", nullable=False, index=True, unique=False)
name = db.Column(
db.String(128), default="<not set>", nullable=False, index=True, unique=False
)
description = db.Column(db.String(4096), nullable=True, unique=False)

View File

@@ -10,10 +10,11 @@ class Post(db.Model):
"""
A post example class
"""
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
def __repr__(self):
return '<Post %r>' % self.body
return "<Post %r>" % self.body

View File

@@ -18,26 +18,32 @@ from backend import db, app, login_manager, LrcException
from sqlalchemy import or_
from datetime import datetime, timedelta
from backend.models.virtual_command_model import virtual_command_recorder_command_table, virtual_command_recorder_table
from backend.models.virtual_command_model import (
virtual_command_recorder_command_table,
virtual_command_recorder_table,
)
metadata = MetaData()
class RecorderModel(db.Model):
__table_args__ = {'extend_existing': True}
__table_args__ = {"extend_existing": True}
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
last_time_modified = db.Column(db.DateTime, nullable=True, default=None)
record_adapter_id = db.Column(db.Unicode(63), unique=True, nullable=False)
model_name = db.Column(db.Unicode(63), unique=True, nullable=False)
notes = db.Column(db.Unicode(255), unique=False, nullable=True, default=None)
recorder_commands = db.relationship('RecorderCommand', back_populates='recorder_model')
recorders = db.relationship('Recorder', back_populates='recorder_model')
checksum = db.Column(db.String(63), unique=True,
nullable=False) # checksum of the recorder commands! (see: model_updater.py)
recorder_commands = db.relationship(
"RecorderCommand", back_populates="recorder_model"
)
recorders = db.relationship("Recorder", back_populates="recorder_model")
checksum = db.Column(
db.String(63), unique=True, nullable=False
) # checksum of the recorder commands! (see: model_updater.py)
last_checksum_change = db.Column(db.DateTime, nullable=True, default=None)
_requires_user = db.Column(db.Integer, default=False, name='requires_user')
_requires_password = db.Column(db.Integer, default=True, name='requires_password')
_requires_user = db.Column(db.Integer, default=False, name="requires_user")
_requires_password = db.Column(db.Integer, default=True, name="requires_password")
@staticmethod
def get_all():
@@ -49,11 +55,15 @@ class RecorderModel(db.Model):
@staticmethod
def get_by_adapter_id(name):
return RecorderModel.query.filter(RecorderModel.record_adapter_id == name).first()
return RecorderModel.query.filter(
RecorderModel.record_adapter_id == name
).first()
@staticmethod
def get_where_adapter_id_contains(adapter_id):
return RecorderModel.query.filter(RecorderModel.record_adapter_id.contains(adapter_id)).first()
return RecorderModel.query.filter(
RecorderModel.record_adapter_id.contains(adapter_id)
).first()
@staticmethod
def get_by_checksum(md5_sum):
@@ -80,10 +90,12 @@ class RecorderModel(db.Model):
class Recorder(db.Model):
__table_args__ = {'extend_existing': True}
__table_args__ = {"extend_existing": True}
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
last_time_modified = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
last_time_modified = db.Column(
db.DateTime, nullable=False, default=datetime.utcnow()
)
name = db.Column(db.Unicode(63), unique=True, nullable=False)
model_name = db.Column(db.Unicode(63), unique=False, nullable=False)
serial_number = db.Column(db.Unicode(63), unique=True, nullable=True)
@@ -99,16 +111,21 @@ class Recorder(db.Model):
ssh_port = db.Column(db.Integer, unique=False, nullable=False, default=22)
username = db.Column(db.String, nullable=True, default=None)
password = db.Column(db.String, nullable=True, default=None)
_configured_options_json_string = db.Column(db.UnicodeText, default='')
_additional_notes_json_string = db.Column(db.UnicodeText, default='')
_configured_options_json_string = db.Column(db.UnicodeText, default="")
_additional_notes_json_string = db.Column(db.UnicodeText, default="")
additional_camera_connected = db.Column(db.Boolean, default=False)
firmware_version = db.Column(db.String, nullable=True, default=None)
room_id = db.Column(db.Integer, db.ForeignKey('room.id'))
room = db.relationship('Room', uselist=False, back_populates='recorder') # one-to-one relation (uselist=False)
recorder_model_id = db.Column(db.Integer, db.ForeignKey('recorder_model.id'))
recorder_model = db.relationship('RecorderModel', back_populates='recorders')
virtual_commands = db.relationship('VirtualCommand', secondary=virtual_command_recorder_table,
back_populates='recorders')
room_id = db.Column(db.Integer, db.ForeignKey("room.id"))
room = db.relationship(
"Room", uselist=False, back_populates="recorder"
) # one-to-one relation (uselist=False)
recorder_model_id = db.Column(db.Integer, db.ForeignKey("recorder_model.id"))
recorder_model = db.relationship("RecorderModel", back_populates="recorders")
virtual_commands = db.relationship(
"VirtualCommand",
secondary=virtual_command_recorder_table,
back_populates="recorders",
)
def __init__(self, **kwargs):
super(Recorder, self).__init__(**kwargs)
@@ -123,16 +140,16 @@ class Recorder(db.Model):
@staticmethod
def get_by_mac(mac: str):
if mac is None or mac == '':
if mac is None or mac == "":
return None
mac = mac.replace('-', ':').lower()
mac = mac.replace("-", ":").lower()
return Recorder.query.filter(Recorder._mac == mac).first()
@staticmethod
def get_all():
return Recorder.query.all()
@validates('name')
@validates("name")
def validate_name(self, key, value):
assert len(value) > 2
return value
@@ -146,7 +163,9 @@ class Recorder(db.Model):
self._configured_options_json_string = json.dumps(value)
def add_configured_option(self, value: str):
self._configured_options_json_string = json.dumps(self.configured_options.append(value))
self._configured_options_json_string = json.dumps(
self.configured_options.append(value)
)
@hybrid_property
def additional_notes(self) -> list:
@@ -157,7 +176,9 @@ class Recorder(db.Model):
self._additional_notes_json_string = json.dumps(value)
def add_additional_notes(self, value: str):
self._additional_notes_json_string = json.dumps(self._additional_notes_json_string.append(value))
self._additional_notes_json_string = json.dumps(
self._additional_notes_json_string.append(value)
)
@hybrid_property
def mac(self) -> str:
@@ -165,10 +186,10 @@ class Recorder(db.Model):
@mac.setter
def mac(self, value: str):
if value is None or value == '':
if value is None or value == "":
return
if re.match("[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", value.lower()):
self._mac = value.replace('-', ':').lower()
self._mac = value.replace("-", ":").lower()
else:
raise LrcException("'{}' is not a valid MAC Address!".format(value))
@@ -205,25 +226,35 @@ class Recorder(db.Model):
return dict(id=self.id, name=self.name)
def toJSON(self):
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
sort_keys=True, indent=4)
return json.dumps(
self.to_dict(), default=lambda o: o.__dict__, sort_keys=True, indent=4
)
class RecorderCommand(db.Model):
__table_args__ = {'extend_existing': True}
__table_args__ = {"extend_existing": True}
"""Table containing permissions associated with groups."""
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
last_time_modified = db.Column(db.DateTime, nullable=True, default=datetime.utcnow())
last_time_modified = db.Column(
db.DateTime, nullable=True, default=datetime.utcnow()
)
name = db.Column(db.Unicode(63), unique=True, nullable=False)
alternative_name = db.Column(db.Unicode(63), unique=True, nullable=True, default=None)
alternative_name = db.Column(
db.Unicode(63), unique=True, nullable=True, default=None
)
disabled = db.Column(db.Boolean, default=False)
description = db.Column(db.Unicode(511), nullable=True, default=None)
parameters_string = db.Column(db.String(2047), nullable=True)
recorder_model = db.relationship('RecorderModel', back_populates='recorder_commands')
recorder_model_id = db.Column(db.Integer, db.ForeignKey('recorder_model.id'))
virtual_commands = db.relationship('VirtualCommand', secondary=virtual_command_recorder_command_table,
back_populates='recorder_commands')
recorder_model = db.relationship(
"RecorderModel", back_populates="recorder_commands"
)
recorder_model_id = db.Column(db.Integer, db.ForeignKey("recorder_model.id"))
virtual_commands = db.relationship(
"VirtualCommand",
secondary=virtual_command_recorder_command_table,
back_populates="recorder_commands",
)
@staticmethod
def get_all():

View File

@@ -8,12 +8,13 @@ import logging
from sqlalchemy import MetaData, CheckConstraint
from sqlalchemy.exc import IntegrityError
from datetime import datetime, timedelta
from datetime import datetime
from backend import db, app, login_manager
from backend import db
from backend.models.recorder_model import Recorder
from backend.tools.scrape_rooms import scrape_rooms
logger = logging.getLogger("lrc."+__name__)
logger = logging.getLogger("lrc." + __name__)
metadata = MetaData()
@@ -22,21 +23,22 @@ class Room(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
name = db.Column(db.Unicode(127), unique=False, nullable=False)
alternate_name = db.Column(db.Unicode(127), unique=False, nullable=True, default=None)
alternate_name = db.Column(
db.Unicode(127), unique=False, nullable=True, default=None
)
comment = db.Column(db.Unicode(2047), unique=False, nullable=True, default="")
number = db.Column(db.Unicode(63), unique=False, nullable=True)
building_name = db.Column(db.Unicode(63), unique=False, nullable=True)
building_number = db.Column(db.Unicode(63), unique=False, nullable=True)
recorder = db.relationship('Recorder', uselist=False, back_populates='room') # one-to-one relation (uselist=False)
recorder = db.relationship(
Recorder, uselist=False, back_populates="room"
) # one-to-one relation (uselist=False)
__table_args__ = (
CheckConstraint('length(name) > 2',
name='name_min_length'),
)
__table_args__ = (CheckConstraint("length(name) > 2", name="name_min_length"),)
def __init__(self, **kwargs):
super(Room, self).__init__(**kwargs)
db.Model.__init__(self, **kwargs)
@staticmethod
def get_by_name(name):
@@ -71,17 +73,24 @@ class Room(db.Model):
return dict(id=self.id, name=self.name)
def toJSON(self):
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
sort_keys=True, indent=4)
return json.dumps(
self.to_dict(), default=lambda o: o.__dict__, sort_keys=True, indent=4
)
def pre_fill_table():
rooms = scrape_rooms()
logger.debug("tada")
logger.debug("got {} rooms".format(len(rooms)))
db_rooms = [Room(name=room['name'], number=room['room_number'],
building_name=room['building_name'], building_number=room['building_number']) for room in
rooms]
db_rooms = [
Room(
name=room["name"],
number=room["room_number"],
building_name=room["building_name"],
building_number=room["building_number"],
)
for room in rooms
]
try:
db.session.bulk_save_objects(db_rooms)

View File

@@ -4,10 +4,10 @@ Example user model and related models
"""
import json
from sqlalchemy.orm import relation
from sqlalchemy import MetaData
from backend import db, app, login_manager
from backend.models.recorder_model import Recorder
from backend.config import Config
from backend.models.post_model import Post
from backend.models.example_model import ExampleDataItem
@@ -21,61 +21,76 @@ from hashlib import md5
metadata = MetaData()
followers = db.Table('followers',
db.Column('follower_id', db.Integer, db.ForeignKey('user.id')),
db.Column('followed_id', db.Integer, db.ForeignKey('user.id'))
)
followers = db.Table(
"followers",
db.Column("follower_id", db.Integer, db.ForeignKey("user.id")),
db.Column("followed_id", db.Integer, db.ForeignKey("user.id")),
)
acquaintances = db.Table('acquaintances',
db.Column('me_id', db.Integer, db.ForeignKey('user.id')),
db.Column('acquaintance_id', db.Integer, db.ForeignKey('user.id'))
)
acquaintances = db.Table(
"acquaintances",
db.Column("me_id", db.Integer, db.ForeignKey("user.id")),
db.Column("acquaintance_id", db.Integer, db.ForeignKey("user.id")),
)
user_favorite_recorders_table = db.Table('user_favorite_recorders',
db.Column('user_id', db.Integer,
db.ForeignKey('user.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True),
db.Column('recorder_id', db.Integer,
db.ForeignKey('recorder.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True))
user_favorite_recorders_table = db.Table(
"user_favorite_recorders",
db.Column(
"user_id",
db.Integer,
db.ForeignKey("user.id", onupdate="CASCADE", ondelete="CASCADE"),
primary_key=True,
),
db.Column(
"recorder_id",
db.Integer,
db.ForeignKey("recorder.id", onupdate="CASCADE", ondelete="CASCADE"),
primary_key=True,
),
)
# This is the association table for the many-to-many relationship between
# groups and members - this is, the memberships.
user_group_table = db.Table('user_group',
db.Column('user_id', db.Integer,
db.ForeignKey('user.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True),
db.Column('group_id', db.Integer,
db.ForeignKey('group.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True))
user_group_table = db.Table(
"user_group",
db.Column(
"user_id",
db.Integer,
db.ForeignKey("user.id", onupdate="CASCADE", ondelete="CASCADE"),
primary_key=True,
),
db.Column(
"group_id",
db.Integer,
db.ForeignKey("group.id", onupdate="CASCADE", ondelete="CASCADE"),
primary_key=True,
),
)
# This is the association table for the many-to-many relationship between
# groups and permissions.
group_permission_table = db.Table('group_permission',
db.Column('group_id', db.Integer,
db.ForeignKey('group.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True),
db.Column('permission_id', db.Integer,
db.ForeignKey('permission.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True))
group_permission_table = db.Table(
"group_permission",
db.Column(
"group_id",
db.Integer,
db.ForeignKey("group.id", onupdate="CASCADE", ondelete="CASCADE"),
primary_key=True,
),
db.Column(
"permission_id",
db.Integer,
db.ForeignKey("permission.id", onupdate="CASCADE", ondelete="CASCADE"),
primary_key=True,
),
)
class User(UserMixin, db.Model):
"""
Example user model representation.
"""
id = db.Column(db.Integer, primary_key=True)
social_id = db.Column(db.Unicode(63), nullable=True, unique=True)
nickname = db.Column(db.Unicode(63), index=True, unique=True)
@@ -84,32 +99,40 @@ class User(UserMixin, db.Model):
email = db.Column(db.String(120), nullable=False, index=True, unique=True)
lang = db.Column(db.Unicode(32), index=False, unique=False)
timezone = db.Column(db.Unicode(63), index=False, unique=False)
posts = db.relationship('Post', backref='author', lazy='dynamic')
example_data_item = db.relationship('ExampleDataItem', backref='owner')
posts = db.relationship(Post, backref="author", lazy="dynamic")
example_data_item = db.relationship(ExampleDataItem, backref="owner")
example_data_item_id = db.Column(db.ForeignKey(ExampleDataItem.id))
about_me = db.Column(db.Unicode(255))
role = db.Column(db.Unicode(63))
groups = db.relationship('Group', secondary=user_group_table, back_populates='users')
groups = db.relationship(
"Group", secondary=user_group_table, back_populates="users"
)
password = db.Column(db.String(255), nullable=True)
registered_on = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
external_user = db.Column(db.Boolean, default=False)
last_seen = db.Column(db.DateTime, default=datetime.utcnow())
last_time_modified = db.Column(db.DateTime, default=datetime.utcnow())
jwt_exp_delta_seconds = db.Column(db.Integer, nullable=True)
acquainted = db.relationship('User',
secondary=acquaintances,
primaryjoin=(acquaintances.c.me_id == id),
secondaryjoin=(acquaintances.c.acquaintance_id == id),
backref=db.backref('acquaintances', lazy='dynamic'),
lazy='dynamic')
followed = db.relationship('User',
secondary=followers,
primaryjoin=(followers.c.follower_id == id),
secondaryjoin=(followers.c.followed_id == id),
backref=db.backref('followers', lazy='dynamic'),
lazy='dynamic')
acquainted = db.relationship(
"User",
secondary=acquaintances,
primaryjoin=(acquaintances.c.me_id == id),
secondaryjoin=(acquaintances.c.acquaintance_id == id),
backref=db.backref("acquaintances", lazy="dynamic"),
lazy="dynamic",
)
followed = db.relationship(
"User",
secondary=followers,
primaryjoin=(followers.c.follower_id == id),
secondaryjoin=(followers.c.followed_id == id),
backref=db.backref("followers", lazy="dynamic"),
lazy="dynamic",
)
favorite_recorders = db.relationship('Recorder', secondary=user_favorite_recorders_table)
favorite_recorders = db.relationship(
Recorder, secondary=user_favorite_recorders_table
)
def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
@@ -128,9 +151,13 @@ class User(UserMixin, db.Model):
:param identifier:
:return:
"""
return User.query.filter(or_(User.nickname == identifier,
User.email == identifier,
User.id == identifier)).first()
return User.query.filter(
or_(
User.nickname == identifier,
User.email == identifier,
User.id == identifier,
)
).first()
@staticmethod
@login_manager.user_loader
@@ -174,12 +201,12 @@ class User(UserMixin, db.Model):
:param nickname:
:return:
"""
return re.sub('[^a-zA-Z0-9_.]', '', nickname)
return re.sub("[^a-zA-Z0-9_.]", "", nickname)
@classmethod
def authenticate(cls, **kwargs):
email = kwargs.get('email')
password = kwargs.get('password')
email = kwargs.get("email")
password = kwargs.get("password")
if not email or not password:
return None
@@ -244,16 +271,16 @@ class User(UserMixin, db.Model):
:return: integer|string
"""
try:
payload = jwt.decode(auth_token, app.config.get('SECRET_KEY'))
payload = jwt.decode(auth_token, app.config.get("SECRET_KEY"))
is_blacklisted_token = BlacklistToken.check_blacklist(auth_token)
if is_blacklisted_token:
return 'Token blacklisted. Please log in again.'
return "Token blacklisted. Please log in again."
else:
return payload['sub']
return payload["sub"]
except jwt.ExpiredSignatureError:
return 'Signature expired. Please log in again.'
return "Signature expired. Please log in again."
except jwt.InvalidTokenError:
return 'Invalid token. Please log in again.'
return "Invalid token. Please log in again."
def encode_auth_token(self):
"""
@@ -262,15 +289,11 @@ class User(UserMixin, db.Model):
"""
try:
payload = {
'exp': datetime.utcnow() + timedelta(days=0, hours=3, seconds=5),
'iat': datetime.utcnow(),
'sub': self.id
"exp": datetime.utcnow() + timedelta(days=0, hours=3, seconds=5),
"iat": datetime.utcnow(),
"sub": self.id,
}
return jwt.encode(
payload,
app.config.get('SECRET_KEY'),
algorithm='HS256'
)
return jwt.encode(payload, app.config.get("SECRET_KEY"), algorithm="HS256")
except Exception as e:
return e
@@ -309,7 +332,10 @@ class User(UserMixin, db.Model):
:param size:
:return:
"""
return 'https://s.gravatar.com/avatar/%s?d=mm&s=%d' % (md5(self.email.encode('utf-8')).hexdigest(), size)
return "https://s.gravatar.com/avatar/%s?d=mm&s=%d" % (
md5(self.email.encode("utf-8")).hexdigest(),
size,
)
def acquaint(self, user):
"""
@@ -337,24 +363,35 @@ class User(UserMixin, db.Model):
:param user:
:return:
"""
return self.acquainted.filter(acquaintances.c.acquaintance_id == user.id).count() > 0
return (
self.acquainted.filter(acquaintances.c.acquaintance_id == user.id).count()
> 0
)
def get_acquaintances(self):
"""
Returns the list of acquaintances.
:return:
"""
return User.query.join(acquaintances, (acquaintances.c.acquaintance_id == User.id)).filter(
acquaintances.c.me_id == self.id).order_by(User.nickname.desc())
return (
User.query.join(acquaintances, (acquaintances.c.acquaintance_id == User.id))
.filter(acquaintances.c.me_id == self.id)
.order_by(User.nickname.desc())
)
def shared_example_data_items(self):
"""
Returns a list of the shared data items.
:return:
"""
return ExampleDataItem.query.join(acquaintances,
(acquaintances.c.acquaintance_id == ExampleDataItem.user_id)).filter(
acquaintances.c.me_id == self.id).order_by(ExampleDataItem.timestamp.desc())
return (
ExampleDataItem.query.join(
acquaintances,
(acquaintances.c.acquaintance_id == ExampleDataItem.user_id),
)
.filter(acquaintances.c.me_id == self.id)
.order_by(ExampleDataItem.timestamp.desc())
)
def follow(self, user):
"""
@@ -389,26 +426,33 @@ class User(UserMixin, db.Model):
Returns list of followed posts.
:return:
"""
return Post.query.join(followers, (followers.c.followed_id == Post.user_id)).filter(
followers.c.follower_id == self.id).order_by(Post.timestamp.desc())
return (
Post.query.join(followers, (followers.c.followed_id == Post.user_id))
.filter(followers.c.follower_id == self.id)
.order_by(Post.timestamp.desc())
)
def to_dict(self):
# return self.__dict__
return dict(id=self.id, email=self.email, groups=[g.to_dict() for g in self.groups])
return dict(
id=self.id, email=self.email, groups=[g.to_dict() for g in self.groups]
)
def toJSON(self):
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
sort_keys=True, indent=4)
return json.dumps(
self.to_dict(), default=lambda o: o.__dict__, sort_keys=True, indent=4
)
def __repr__(self):
return '<User %r>' % self.email
return "<User %r>" % self.email
class BlacklistToken(db.Model):
"""
Token Model for storing JWT tokens
"""
__tablename__ = 'blacklist_tokens'
__tablename__ = "blacklist_tokens"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
token = db.Column(db.String(500), unique=True, nullable=False)
@@ -419,7 +463,7 @@ class BlacklistToken(db.Model):
self.blacklisted_on = datetime.now()
def __repr__(self):
return '<id: token: {}'.format(self.token)
return "<id: token: {}".format(self.token)
@staticmethod
def get_by_token(jwt_id):
@@ -443,10 +487,19 @@ class Group(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
name = db.Column(db.Unicode(63), unique=True, nullable=False)
description = db.Column(db.Unicode(255), unique=False, nullable=True, default="")
users = db.relationship('User', secondary=user_group_table, back_populates='groups')
permissions = db.relationship('Permission', secondary=group_permission_table, back_populates='groups')
users = db.relationship("User", secondary=user_group_table, back_populates="groups")
permissions = db.relationship(
"Permission", secondary=group_permission_table, back_populates="groups"
)
def __init__(self, **kwargs):
# get permissions from kwargs and make Permission objects out of them
permissions = kwargs.pop("permissions", [])
if permissions is not None:
for p in permissions:
permission = Permission(name=p)
if permission is not None:
self.permissions.append(permission)
super(Group, self).__init__(**kwargs)
@staticmethod
@@ -473,36 +526,40 @@ class Group(db.Model):
return dict(id=self.id, name=self.name)
def toJSON(self):
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
sort_keys=True, indent=4)
return json.dumps(
self.to_dict(), default=lambda o: o.__dict__, sort_keys=True, indent=4
)
class Permission(db.Model):
"""Table containing permissions associated with groups."""
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
name = db.Column(db.Unicode(63), unique=True, nullable=False)
description = db.Column(db.Unicode(511))
groups = db.relationship(Group, secondary=group_permission_table,
back_populates='permissions')
access_control_entry = db.relationship('AccessControlEntry', back_populates='required_permission')
groups = db.relationship(
Group, secondary=group_permission_table, back_populates="permissions"
)
access_control_entry = db.relationship(
"AccessControlEntry", back_populates="required_permission"
)
@event.listens_for(User.__table__, 'after_create')
@event.listens_for(User.__table__, "after_create")
def insert_initial_users(*args, **kwargs):
for u in app.config.get("USERS", []):
db.session.add(User(**u))
db.session.commit()
@event.listens_for(Group.__table__, 'after_create')
def insert_initial_groups(*args, **kwargs):
for g in app.config.get("GROUPS", []):
db.session.add(Group(**g))
db.session.commit()
@event.listens_for(Permission.__table__, 'after_create')
@event.listens_for(Permission.__table__, "after_create")
def insert_initial_permissions(*args, **kwargs):
for p in app.config.get("PERMISSIONS", []):
db.session.add(Permission(name=p))
db.session.commit()
@event.listens_for(Group.__table__, "after_create")
def insert_initial_groups(*args, **kwargs):
for g in app.config.get("GROUPS", []):
db.session.add(Group(**g))
db.session.commit()

View File

@@ -8,31 +8,39 @@ from backend import db
# This is the association table for the many-to-many relationship between
# virtual commands and recorder commands.
virtual_command_recorder_command_table = db.Table('virtual_command_recorder_command',
db.Column('virtual_command_id', db.Integer,
db.ForeignKey('virtual_command.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True),
db.Column('recorder_command_id', db.Integer,
db.ForeignKey('recorder_command.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True))
virtual_command_recorder_command_table = db.Table(
"virtual_command_recorder_command",
db.Column(
"virtual_command_id",
db.Integer,
db.ForeignKey("virtual_command.id", onupdate="CASCADE", ondelete="CASCADE"),
primary_key=True,
),
db.Column(
"recorder_command_id",
db.Integer,
db.ForeignKey("recorder_command.id", onupdate="CASCADE", ondelete="CASCADE"),
primary_key=True,
),
)
# This is the association table for the many-to-many relationship between
# virtual commands and recorder commands.
virtual_command_recorder_table = db.Table('virtual_command_recorder',
db.Column('virtual_command_id', db.Integer,
db.ForeignKey('virtual_command.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True),
db.Column('recorder_id', db.Integer,
db.ForeignKey('recorder.id',
onupdate="CASCADE",
ondelete="CASCADE"),
primary_key=True))
virtual_command_recorder_table = db.Table(
"virtual_command_recorder",
db.Column(
"virtual_command_id",
db.Integer,
db.ForeignKey("virtual_command.id", onupdate="CASCADE", ondelete="CASCADE"),
primary_key=True,
),
db.Column(
"recorder_id",
db.Integer,
db.ForeignKey("recorder.id", onupdate="CASCADE", ondelete="CASCADE"),
primary_key=True,
),
)
class VirtualCommand(db.Model):
@@ -41,16 +49,25 @@ class VirtualCommand(db.Model):
name = db.Column(db.Unicode(63), unique=True, nullable=False)
description = db.Column(db.Unicode(255), unique=False, nullable=True, default="")
recorders = db.relationship('Recorder', secondary=virtual_command_recorder_table,
back_populates='virtual_commands')
recorders = db.relationship(
"Recorder",
secondary=virtual_command_recorder_table,
back_populates="virtual_commands",
)
recorder_commands = db.relationship('RecorderCommand', secondary=virtual_command_recorder_command_table,
back_populates='virtual_commands')
recorder_commands = db.relationship(
"RecorderCommand",
secondary=virtual_command_recorder_command_table,
back_populates="virtual_commands",
)
# parent_virtual_command = db.relationship('VirtualCommand', back_populates='child_virtual_commands')
parent_virtual_command_id = db.Column(db.Integer, db.ForeignKey('virtual_command.id'))
child_virtual_commands = db.relationship('VirtualCommand',
backref=backref('parent_virtual_command', remote_side=[id]))
parent_virtual_command_id = db.Column(
db.Integer, db.ForeignKey("virtual_command.id")
)
child_virtual_commands = db.relationship(
"VirtualCommand", backref=backref("parent_virtual_command", remote_side=[id])
)
command_order_string = db.Column(db.String)
@@ -91,5 +108,6 @@ class VirtualCommand(db.Model):
return dict(id=self.id, name=self.name, description=self.description)
def toJSON(self):
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
sort_keys=True, indent=4)
return json.dumps(
self.to_dict(), default=lambda o: o.__dict__, sort_keys=True, indent=4
)

View File

@@ -76,7 +76,7 @@ class TelnetAdapter(ABC):
def _run_cmd(self, cmd, timeout=1, auto_connect=True):
if self.tn is None and not auto_connect:
raise Exception("Not connected!")
raise LrcException("Not connected!")
elif self.tn is None:
self._login()
self.tn.write(cmd)

File diff suppressed because it is too large Load Diff

View File

@@ -16,8 +16,8 @@ if not os.path.exists(fe_path) or not os.path.exists(os.path.join(fe_path, "inde
app.logger.critical(
"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.")
print("FATAL: Frontend path wrong or index.html missing -> EXITING!")
exit()
print("ERROR: Frontend path wrong or index.html missing -> NO WEB-UI AVAILABLE!")
#exit()
fe_bp = Blueprint('frontend', __name__, url_prefix='/', template_folder=os.path.join(fe_path, ""))

View File

@@ -19,12 +19,12 @@ def print_tn(tn_response):
print(str(tn_response).rstrip())
def run_cmd(tn, cmd, timeout=1):
tn.write(cmd)
out = tn.read_until_non_empty_line()
def run_cmd(telnet_con, cmd, _timeout=1):
telnet_con.write(cmd)
out = telnet_con.read_until_non_empty_line()
res = out
while out is not None and out != "":
out = tn.read_until_non_empty_line()
out = telnet_con.read_until_non_empty_line()
print(out)
res += out
return res

View File

@@ -1,13 +1,30 @@
# pylint: disable=missing-module-docstring,missing-function-docstring,missing-class-docstring
from backend import LrcException
def exception_decorator(*exceptions):
"""
A decorator that catches specified exceptions and raises them as LrcExceptions.
Args:
*exceptions: A variable-length argument list of exceptions to catch.
Returns:
A decorator function that can be applied to other functions.
Example:
@exception_decorator(ValueError, TypeError)
def my_function():
# code here
"""
def decorator(func):
def new_func(*args, **kwargs):
try:
ret = func(*args, **kwargs)
return ret
except exceptions as e:
raise LrcException(e)
raise LrcException(e) from e
return new_func
return decorator
return decorator

View File

@@ -10,8 +10,10 @@ import requests
from requests.auth import HTTPBasicAuth
from multiprocessing.pool import ThreadPool
from multiprocessing.context import TimeoutError
from tatsu.exceptions import ParseException
from ics import Calendar
from ics.grammar.parse import ParseError
from backend import LrcException
from backend.config import Config
@@ -34,7 +36,7 @@ rec_err_state_log_stream_handler.setLevel(logging.WARNING)
logger.addHandler(rec_err_state_log_stream_handler)
#logger.addHandler(mem_handler)
base_url = "https://opencast.bibliothek.kit.edu"
base_url = "https://oc-bib-admin.bibliothek.kit.edu"
session = requests.session()
session.auth = HTTPBasicAuth(Config.OPENCAST_USER, Config.OPENCAST_PW)
@@ -66,7 +68,13 @@ def get_calender(rec_id):
url = get_service_url('org.opencastproject.scheduler') + "/calendars"
res = session.get(url, params=params)
if res.ok:
return Calendar(res.text)
try:
return Calendar(res.text)
except (ValueError, ParseException, IndexError, ParseError) as ex:
logger.debug(res.text)
logger.error("Could not parse calendar for agent {}! ({})".format(rec_id, ex))
return None
def get_capture_agents():
@@ -108,11 +116,17 @@ def get_recorder_adapter(recorder_info: dict) -> RecorderAdapter:
def check_capture_agent_state(a: dict):
logger.debug("Checking Agent {}".format(a['name']))
c = get_calender(a['name'])
if c is None:
logger.error("Could not get calendar for agent {}!".format(a['name']))
return
is_recording_in_calendar = len(list(c.timeline.now())) >= 1
if is_recording_in_calendar:
logger.info("{} has entry in Calender and should therefore be recording... checking now!".format(a['name']))
if a['state'] == "capturing":
recorder_info = get_recorder_by_name(a['name'])
if recorder_info is None:
logger.error("FATAL: Could not find recorder info for {}!".format(a['name']))
return
try:
rec = get_recorder_adapter(recorder_info)
if rec.is_recording():
@@ -131,6 +145,9 @@ def check_capture_agent_state(a: dict):
logger.error("FATAL: {} is not in capturing state...but should be!!".format(a['name']))
else:
recorder_info = get_recorder_by_name(a['name'])
if recorder_info is None:
logger.error("FATAL: Could not find recorder info for {}!".format(a['name']))
return
try:
rec = get_recorder_adapter(recorder_info)
if rec.is_recording():
@@ -147,7 +164,11 @@ def check_capture_agent_state(a: dict):
def ping_capture_agent(a: dict):
recorder_ip = get_recorder_by_name(a['name'])['ip']
logger.debug(get_recorder_by_name(a['name']))
recorder = get_recorder_by_name(a['name'])
if recorder is None:
return
recorder_ip = recorder['ip']
try:
response = subprocess.check_call(
['ping', '-W', '10', '-c', '2', recorder_ip],

1978
poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,15 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[tool.poetry]
name = "lrc-backend"
version = "0.1.0"
description = ""
authors = ["Tobias Kurze <it@t-kurze.de>"]
readme = "README.md"
[packages]
[tool.poetry.dependencies]
python = "^3.11"
flask = "*"
flask-httpauth = "*"
flask-restplus-patched = "*"
flask-sqlalchemy = "*"
flask-login = "*"
pyjwt = "*"
passlib = "*"
sqlalchemy = "*"
@@ -31,8 +32,10 @@ ics = "*"
coloredlogs = "*"
pythonping = "*"
scapy = "*"
flask-login = "^0.6.2"
werkzeug = "2.*"
flask-restx = "^1.1.0"
[dev-packages]
[requires]
python_version = "3.8"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"