71 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
c4b54357f7 automatically adding recorders, models and rooms and association of those 2019-11-22 14:26:16 +01:00
Tobias Kurze
7700b4381f now rooms, recorders and recorder models get initialized in DB 2019-11-20 16:19:59 +01:00
Tobias Kurze
60ff5bdeaf added code to initialize db with models and recodres 2019-11-20 12:41:05 +01:00
bc1347fe99 changed pw in recorders.jso 2019-11-14 15:40:57 +01:00
9ef9d98132 added logging to smp adapter 2019-11-14 15:19:44 +01:00
bab6403f91 changed thread pool code again 2019-11-14 15:08:06 +01:00
692649e08f changed thread pool code again 2019-11-14 15:05:06 +01:00
6f1e01781a changed thread pool code again 2019-11-14 15:02:20 +01:00
7224038e64 modified threadpool run to use timeout 2019-11-14 14:56:55 +01:00
c96cdfc6e1 fixed bug in smp adapter 2019-11-14 14:39:27 +01:00
c3d8a1e91a fixed bug in smp adapter 2019-11-14 14:29:12 +01:00
b214d161bf slightly modified smp adapter for testing 2019-11-14 14:23:19 +01:00
e19ce060d8 exception decorator and mail send for errors and changes to rec state checker 2019-11-14 14:15:36 +01:00
Tobias Kurze
6081486a35 using git-crypt instead of manual encrypton filters 2019-11-13 13:04:18 +01:00
Tobias Kurze
2da856dd36 using git-crypt instead of manual encrypton filters 2019-11-13 12:59:09 +01:00
Tobias Kurze
872e531ef5 added logging conf and now checking recording status with simple script ; notifications are missing 2019-11-13 08:19:39 +01:00
Tobias Kurze
4563e16137 moved creds to config 2019-11-12 12:43:45 +01:00
Tobias Kurze
8b05bb694f added excel->json recorder source generation script 2019-11-12 12:32:49 +01:00
5d731c9fba moved some models added cron and websocket base class 2019-10-31 16:13:02 +01:00
Tobias Kurze
36c889956f added websocket test flies 2019-10-30 11:54:53 +01:00
Tobias Kurze
a408fd3b4c added ws base code 2019-10-25 15:59:41 +02:00
Tobias Kurze
32c2674210 added code for saving config (might not be complete 2019-10-25 13:49:41 +02:00
d61c395d2c added access control model and more stuff around access mgmt 2019-10-23 16:33:24 +02:00
6b4f7c8118 moved everything to a new module called backend 2019-10-23 15:00:33 +02:00
310d5f4820 using current user in some placesi 2019-08-15 14:32:04 +02:00
9ab0d43f43 profile and other stuff 2019-08-14 16:38:03 +02:00
Tobias Kurze
859a5d880a working on control 2019-08-13 16:30:45 +02:00
Tobias Kurze
f70cbdc463 now scraping rooms from capmus mgmt 2019-08-13 15:29:37 +02:00
48505b76ea fixed (circumvented) bug related to hybrid_property and parameter serialization 2019-08-08 20:31:08 +02:00
c0e56cf40d now scanning model difinietons and updating db entries 2019-08-08 16:38:15 +02:00
Tobias Kurze
123eb65f8e some changes to virtual command 2019-08-05 15:28:39 +02:00
Tobias Kurze
186614bc4a added virtual commands model 2019-08-05 13:41:12 +02:00
Tobias Kurze
51536766bf using reflection to get models 2019-08-02 16:09:39 +02:00
Tobias Kurze
3c6b6ba099 finished smp extron telnet adapter (more or less) 2019-07-04 13:29:44 +02:00
4d01f7025b added more smp >API< functions 2019-07-03 16:09:10 +02:00
Tobias Kurze
3a7d8dbdd4 just added comment for TODO 2019-07-03 13:51:51 +02:00
Tobias Kurze
88f5c3023d added lot of functs for SMP 2019-06-21 16:32:08 +02:00
Tobias Kurze
4485dea583 added recorder command backend 2019-06-21 11:04:12 +02:00
70df74cecf updated recorder model 2019-05-03 18:40:43 +02:00
Tobias Kurze
fad2238b75 added ports to api model 2019-05-03 15:52:52 +02:00
Tobias Kurze
295aadfaeb fixed and extended apis 2019-04-26 15:34:23 +02:00
07d01304be added room and recorder api and added length check (for sqlite) 2019-04-26 09:42:52 +02:00
Tobias Kurze
254637bfa9 some migrations; commit just to be on 'nice' state 2019-04-17 09:07:24 +02:00
3ecc8e0955 some changes to auth and group api 2019-04-15 14:14:42 +02:00
cbc269edf2 removed old dB code and continued on group and user mgmt 2019-04-11 16:18:46 +02:00
Tobias Kurze
2451a56403 added / implemented group API 2019-04-10 15:11:21 +02:00
Tobias Kurze
f0783d97c8 changes to auth and user API 2019-04-05 16:21:24 +02:00
8b7b2f489c added user and group API and models 2019-04-04 16:05:36 +02:00
cfa12717e0 added toJSON func 2019-04-02 16:58:59 +02:00
Tobias Kurze
8cf8632c8c added db migrations and group support, still problems with json serialization 2019-04-02 16:10:46 +02:00
024f063bea better separation between api and frontend login 2019-04-02 10:47:53 +02:00
Tobias Kurze
ed57dc2720 creating users from oidc id token 2019-03-26 16:17:18 +01:00
Tobias Kurze
cad27733f0 oicd now working 2019-03-26 14:58:37 +01:00
Tobias Kurze
bc50e23a22 improved/fixed serve_frontend.py to work from different base paths (change required for wsgi) 2019-03-26 11:57:22 +01:00
Tobias Kurze
ebc34e396d slightly changed user model (sort of fix) 2019-03-22 16:38:42 +01:00
0469b8dbb5 added a lot of auth code 2019-03-21 16:17:25 +01:00
Tobias Kurze
bef3c6dc9b added authentication API 2019-03-19 16:34:05 +01:00
Tobias Kurze
9d9c58d268 added OpenID Connect support 2019-03-19 15:29:26 +01:00
bd9b6c61d3 working db and tests Nr2 2019-03-14 17:14:05 +01:00
1c8cb55b46 working db and tests 2019-03-14 17:13:02 +01:00
79 changed files with 10890 additions and 662 deletions

1
.env Normal file
View File

@@ -0,0 +1 @@
PYTHONPATH=${PYTHONPATH}:${PWD}/..

6
.gitattributes vendored Normal file
View File

@@ -0,0 +1,6 @@
backend/models/initial_recorders.json filter=git-crypt diff=git-crypt
#backend/models/initial_recorders.json filter=openssl diff=openssl
backend/config.py filter=git-crypt diff=git-crypt
#backend/config.py filter=openssl diff=openssl
[merge]
renormalize=true

120
.gitignore vendored
View File

@@ -1 +1,121 @@
app.db
# Byte-compiled / optimized / DLL files
.idea
__pycache__/ __pycache__/
node_modules/
frontend/node_modules/
backend/uploads/*
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
package-lock.json
logs

18
Pipfile
View File

@@ -1,18 +0,0 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
flask = "*"
flask-httpauth = "*"
flask-restplus-patched = "*"
flask-sqlalchemy = "*"
flask-login = "*"
pyjwt = "*"
passlib = "*"
[dev-packages]
[requires]
python_version = "3.7"

226
Pipfile.lock generated
View File

@@ -1,226 +0,0 @@
{
"_meta": {
"hash": {
"sha256": "196d1a010314c8f16ccc747ed35b4821e8e3aa63f90ec2893123ea19c95935b1"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.7"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"aniso8601": {
"hashes": [
"sha256:29ad6be3828ab6ac2a31fd2876fd84477cde11890ffca7e8a9434aad5d4acec8",
"sha256:a5c7595bb65d3919a9944a759d907b57c4d050abaa0e5cf845e84c26cdfd1218"
],
"version": "==5.1.0"
},
"apispec": {
"hashes": [
"sha256:57a7b81fd19fff0663a7e5ffd196eaea79b5364151ed2b65533be36d55e0229c",
"sha256:b45def53903516e67e8584ee41f34bc60c3e4acace6892b69340293ea20f3caa"
],
"version": "==1.0.0"
},
"attrs": {
"hashes": [
"sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79",
"sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"
],
"version": "==19.1.0"
},
"click": {
"hashes": [
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
],
"version": "==7.0"
},
"flask": {
"hashes": [
"sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
"sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"
],
"index": "pypi",
"version": "==1.0.2"
},
"flask-httpauth": {
"hashes": [
"sha256:c08b69b302f1aa7ecd0db327809132ef6ca9486a36a9174776da146d1a4adc18",
"sha256:f71b7611f385fbdf350e8c430eed17b41c3b2200dc35eae19c1734264b68e31d"
],
"index": "pypi",
"version": "==3.2.4"
},
"flask-login": {
"hashes": [
"sha256:c815c1ac7b3e35e2081685e389a665f2c74d7e077cb93cecabaea352da4752ec"
],
"index": "pypi",
"version": "==0.4.1"
},
"flask-marshmallow": {
"hashes": [
"sha256:75c9d80f22af982b1e8ccec109d3b75c14bb5570602ae3705a4ff775badd2816",
"sha256:db7aff4130eb99fd05ab78fd2e2c58843ba0f208899aeb1c14aff9cd98ae8c80"
],
"version": "==0.9.0"
},
"flask-restplus": {
"hashes": [
"sha256:3fad697e1d91dfc13c078abcb86003f438a751c5a4ff41b84c9050199d2eab62",
"sha256:cdc27b5be63f12968a7f762eaa355e68228b0c904b4c96040a314ba7dc6d0e69"
],
"version": "==0.12.1"
},
"flask-restplus-patched": {
"hashes": [
"sha256:36342775f9e0990dfc000dbe61133dfe56f9ef32c9b4c6293ba7f2c128d16efc"
],
"index": "pypi",
"version": "==0.1.10"
},
"flask-sqlalchemy": {
"hashes": [
"sha256:3bc0fac969dd8c0ace01b32060f0c729565293302f0c4269beed154b46bec50b",
"sha256:5971b9852b5888655f11db634e87725a9031e170f37c0ce7851cf83497f56e53"
],
"index": "pypi",
"version": "==2.3.2"
},
"itsdangerous": {
"hashes": [
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
],
"version": "==1.1.0"
},
"jinja2": {
"hashes": [
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
],
"version": "==2.10"
},
"jsonschema": {
"hashes": [
"sha256:0c0a81564f181de3212efa2d17de1910f8732fa1b71c42266d983cd74304e20d",
"sha256:a5f6559964a3851f59040d3b961de5e68e70971afb88ba519d27e6a039efff1a"
],
"version": "==3.0.1"
},
"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:6eeaf1301a5f5942bfe8ab2c2eaf03feb793072b56d5fae563638bddd7bb62e6",
"sha256:f72a206432a3369dd72824564d18d915761e07805c05f00d0dcc7885fac1e385"
],
"version": "==2.18.1"
},
"passlib": {
"hashes": [
"sha256:3d948f64138c25633613f303bcc471126eae67c04d5e3f6b7b8ce6242f8653e0",
"sha256:43526aea08fa32c6b6dbbbe9963c4c767285b78147b7437597f992812f69d280"
],
"index": "pypi",
"version": "==1.7.1"
},
"pyjwt": {
"hashes": [
"sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e",
"sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"
],
"index": "pypi",
"version": "==1.7.1"
},
"pyrsistent": {
"hashes": [
"sha256:3ca82748918eb65e2d89f222b702277099aca77e34843c5eb9d52451173970e2"
],
"version": "==0.14.11"
},
"pytz": {
"hashes": [
"sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9",
"sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c"
],
"version": "==2018.9"
},
"relativetimebuilder": {
"hashes": [
"sha256:5cc415b539d18a20e09a600cf7ba7199eda7b365d13aaaf9ffbbaa26cfb8062a",
"sha256:8b11e6fa6d6d4a09c61cfa9dadae4ea640bf10818e0991874d33452c0aeff2d7"
],
"version": "==0.2.0"
},
"six": {
"hashes": [
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
],
"version": "==1.12.0"
},
"sqlalchemy": {
"hashes": [
"sha256:11ead7047ff3f394ed0d4b62aded6c5d970a9b718e1dc6add9f5e79442cc5b14"
],
"version": "==1.3.0"
},
"webargs": {
"hashes": [
"sha256:10438164b41b81abe45b299eb182580f7bc6bcdbc864b0cbd62845bb6bab424d",
"sha256:3bed01136ea4a7d1468a54f6c3925d133872a83a2144e83a94f484731576bc58",
"sha256:494044344b5673e3624621d0e9d14d5dc01dd05c0b5b8952febc80a4f80181f6"
],
"version": "==5.1.2"
},
"werkzeug": {
"hashes": [
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
],
"version": "==0.14.1"
}
},
"develop": {}
}

View File

@@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
"""
Backend base module
"""
from flask import Flask
from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth, MultiAuth
from flask_sqlalchemy import SQLAlchemy
jwt_auth = HTTPTokenAuth()
basic_auth = HTTPBasicAuth()
multi_auth = MultiAuth(basic_auth, jwt_auth)
from .serve_frontend import fe_bp
from .api import api_bp
app = Flask(__name__)
app.register_blueprint(api_bp)
app.register_blueprint(fe_bp)
db = SQLAlchemy(app)

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2019. Tobias Kurze
from backend import app
def main():
app.run(debug=True)
if __name__ == '__main__':
main()

View File

@@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
from flask import Blueprint
from flask_restplus import Api
api_authorizations = {
'apikey': {
'type': 'apiKey',
'in': 'header',
'name': 'X-API-KEY'
},
'basicAuth': {
'type': 'basic',
'scheme': 'basic'
},
'bearerAuth': {
'type': 'apiKey',
'scheme': 'bearer',
'name': 'Authorization',
'in': 'header'
}
}
api_bp = Blueprint('api', __name__, url_prefix='/api')
api_v1 = Api(api_bp, prefix="/v1", version='0.1', title='Vue Test API',
description='The Vue Test API', doc='/v1/doc/', authorizations=api_authorizations, security='bearerAuth')
from .example_api import *

184
backend/__init__.py Normal file
View File

@@ -0,0 +1,184 @@
# -*- coding: utf-8 -*-
"""
Backend base module
"""
import logging
from logging.config import dictConfig
from logging.handlers import MemoryHandler
from typing import Union
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_restx import abort
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
from backend.config import Config
__author__ = "Tobias Kurze"
__copyright__ = "Copyright 2019, Tobias Kurze, KIT"
__credits__ = ["Tobias Kurze"]
__license__ = ""
__version__ = "0.9.0"
__maintainer__ = "Tobias Kurze"
__email__ = "it@t-kurze.de"
# __status__ = "Production"
__status__ = "Development"
from .tools.send_mail import get_smtp_default_handler
dictConfig({
'version': 1,
'formatters': {
'default': {
'format': '[%(asctime)s] {%(threadName)s} %(levelname)s in %(module)s, line %(lineno)d: %(message)s',
}
},
'handlers': {
'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://flask.logging.wsgi_errors_stream',
'formatter': 'default'
},
'root_file': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': Config.ROOT_LOG_FILE,
'when': 'd',
'interval': 1,
'backupCount': 3,
'formatter': 'default',
},
'file': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': Config.LOG_FILE,
'when': 'd',
'interval': 1,
'backupCount': 5,
'formatter': 'default',
},
'errors_file': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': Config.ERROR_LOG_FILE,
'when': 'd',
'interval': 1,
'backupCount': 5,
'level': 'ERROR',
'formatter': 'default',
},
},
'loggers': {
'lrc': {
'level': Config.LOG_LEVEL,
'handlers': ['wsgi', 'file', 'errors_file']
}
},
'root': {
'level': 'ERROR',
'handlers': ['root_file', 'errors_file']
}
})
main_logger = logging.getLogger("lrc")
# following might be dangerous, as buffer might be filled without a mechanism to empty it
smtp_error_handler = get_smtp_default_handler(subject="Warnings, errors and worse...!")
mem_handler = MemoryHandler(capacity=10, flushLevel=logging.ERROR, target=smtp_error_handler)
mem_handler.setLevel(logging.WARNING)
# 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)
class LrcException(Exception):
def __init__(self, message_or_exception: Union[str, Exception], html_code: int = None):
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
def __repr__(self):
if self.type is None:
msg = f"LRC Exception: \"{', '.join(super().args)}\""
else:
msg = f"LRC Exception: (original Exception: {self.type}) \"{', '.join(super().args)}\""
if self.html_code is not None:
msg += f" (HTML Code: {self.html_code})"
return msg
def __str__(self):
return self.__repr__()
app = Flask(__name__)
app.config.from_object('backend.config.Config')
db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
# flask_jwt_extended: to be used usually by API
jwt_extended = JWTManager(app)
# this is another library.... this is (probaby ->verify) used to check JWTs provided by external sources (KIT, etc.)
jwt_auth = HTTPTokenAuth('Bearer')
@jwt_extended.invalid_token_loader
def unauthorized_jwt(token):
main_logger.info("Unauthorized access; invalid token provided: %s", token)
abort(401)
@jwt_auth.verify_token
def verify_token(token):
"""This function (and HTTPTokenAuth('Bearer')) has been defined to be used together with MultiAuth. For API calls
solely using JWT authentication, jwt_required of flask_jwt_extended should be used directly."""
app.logger.info(token)
try:
decoded = decode_token(token)
except jwt.exceptions.DecodeError as e:
app.logger.warning("Could not verify token: %s", str(e))
return False
except jwt.exceptions.ExpiredSignatureError as e:
app.logger.warning("Could not verify token: %s", str(e))
return False
app.logger.info(decoded)
return True
basic_auth = HTTPBasicAuth()
multi_auth = MultiAuth(basic_auth, jwt_auth)
from backend.auth import oidc_auth, auth_bp
try:
oidc_auth.init_app(app)
except requests.exceptions.ConnectionError as 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)
# Fix flask-restplus by duck typing error handlers
jwt_extended._set_error_handler_callbacks(api_v1)

53
backend/__main__.py Normal file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2019. Tobias Kurze
import logging
import ssl
from jinja2.exceptions import TemplateNotFound
from backend import app, db
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')
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:
try:
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.load_cert_chain('cert.pem', 'key.pem')
app.run(debug=True, ssl_context=context, threaded=True)
except FileNotFoundError:
app.run(debug=True, threaded=True)
try:
db.create_all()
except Exception as e:
logging.critical(e)
app.run(debug=True, host="0.0.0.0")
if __name__ == '__main__':
main()

78
backend/api/__init__.py Normal file
View File

@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
from flask import Blueprint, abort
from flask_restx import Api, Namespace
api_authorizations = {
'apikey': {
'type': 'apiKey',
'in': 'header',
'name': 'X-API-KEY'
},
'basicAuth': {
'type': 'basic',
'scheme': 'basic'
},
'bearerAuth': {
'type': 'apiKey',
'scheme': 'bearer',
'name': 'Authorization',
'in': 'header'
}
}
api_bp = Blueprint('api', __name__, url_prefix='/api')
api_v1 = Api(api_bp, prefix="/v1", version='0.1', title='Vue Test API',
description='The Vue Test API', doc='/v1/doc/', authorizations=api_authorizations, security='bearerAuth')
api_user = Namespace('user', description="User management namespace", authorizations=api_authorizations)
api_group = Namespace('group', description="Group management namespace", authorizations=api_authorizations)
api_room = Namespace('room', description="Room management namespace", authorizations=api_authorizations)
api_recorder = Namespace('recorder', description="Recorder management namespace", authorizations=api_authorizations)
api_virtual_command = Namespace('virtual_command', description="Virtual command namespace",
authorizations=api_authorizations)
api_cron_job = Namespace('cron_job', description="Cron job namespace",
authorizations=api_authorizations)
api_control = Namespace('control', description="Control namespace",
authorizations=api_authorizations)
api_v1.add_namespace(api_user)
api_v1.add_namespace(api_group)
api_v1.add_namespace(api_room)
api_v1.add_namespace(api_recorder)
api_v1.add_namespace(api_virtual_command)
api_v1.add_namespace(api_cron_job)
api_v1.add_namespace(api_control)
auth_api_bp = Blueprint('auth_api', __name__, url_prefix='/api/auth')
auth_api_v1 = Api(auth_api_bp, prefix="/v1", version='0.1', title='Auth API',
description='Auth API', doc='/v1/doc/', authorizations=api_authorizations, security='bearerAuth')
auth_api_providers_ns = Namespace('providers')
auth_api_register_ns = Namespace('register')
auth_api_v1.add_namespace(auth_api_providers_ns)
auth_api_v1.add_namespace(auth_api_register_ns)
# user_api_bp = Blueprint('user_api', __name__, url_prefix='/api/user')
# group_api_bp = Blueprint('group_api', __name__, url_prefix='/api/group')
from .example_api import *
from .auth_api import *
from .user_api import *
from .group_api import *
from .room_api import *
from .recorder_api import *
from .control_api import *
from .virtual_command_api import *
# from .group_api import *
@api_bp.route('/<path:path>')
def catch_all_api(path):
"""
Default 404 response for undefined paths in API.
:param path:
:return:
"""
abort(404)

191
backend/api/auth_api.py Normal file
View File

@@ -0,0 +1,191 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
For example: listing of available auth providers or registration of users.
Login through API does not start a new session, but instead returns JWT.
"""
import base64
import json
from pprint import pprint
import flask
import jwt
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 typing import Iterable
from flask_restx import Resource, fields
from werkzeug.routing import BuildError
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
@auth_api_bp.route('/providers', methods=('GET',))
def get_auth_providers():
providers = dict()
for p in AUTH_PROVIDERS:
provider = dict(AUTH_PROVIDERS[p])
try:
provider["url"] = url_for(AUTH_PROVIDERS[p]["url"])
except BuildError:
provider["url"] = AUTH_PROVIDERS[p]["url"]
providers[p] = provider
return jsonify(providers)
@auth_api_providers_ns.route('/')
class AuthProviders(Resource):
def get(self):
return get_auth_providers()
@auth_api_bp.route('/register', methods=('POST',))
def register():
data = request.get_json()
user = User(**data)
db.session.add(user)
db.session.commit()
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_bp.route('/login', methods=('GET', 'POST',))
def login():
print("login")
print(request)
data = request.get_json()
if not data:
return jsonify({'message': 'Invalid request data', 'authenticated': False}), 401
print(data)
user = User.authenticate(**data)
if not user:
return jsonify({'message': 'Invalid credentials', 'authenticated': False}), 401
token = {
'access_token': create_access_token(identity=user, fresh=True),
'refresh_token': create_refresh_token(identity=user)
}
return jsonify(token), 200
# Endpoint for revoking the current users access token
@auth_api_bp.route('/logout', methods=['GET', 'DELETE'])
@jwt_required
def logout():
jti = get_jwt()['jti']
db.session.add(BlacklistToken(token=jti))
db.session.commit()
return jsonify({"msg": "Successfully logged out"}), 200
# Endpoint for revoking the current users refresh token
@auth_api_bp.route('/logout2', methods=['GET', 'DELETE'])
@jwt_required(refresh=True)
def logout2():
jti = get_jwt()['jti']
db.session.add(BlacklistToken(token=jti))
db.session.commit()
return jsonify({"msg": "Successfully logged out"}), 200
def check_and_create_groups(groups: Iterable[str]):
user_groups = []
for g in groups:
group = Group.get_by_name(g)
if group is None:
group = Group(name=g)
db.session.add(group)
user_groups.append(group)
db.session.commit()
return user_groups
def create_or_retrieve_user_from_userinfo(userinfo):
try:
email = userinfo["email"]
except KeyError:
return None
user_groups = check_and_create_groups(groups=userinfo.get("memberOf", []))
user = User.get_by_identifier(email)
if user is not None:
app.logger.info("user found -> update user")
pprint(user.to_dict())
user.first_name = userinfo.get("given_name", "")
user.last_name = userinfo.get("family_name", "")
for g in user_groups:
user.groups.append(g)
db.session.commit()
return user
user = User(email=email, first_name=userinfo.get("given_name", ""),
last_name=userinfo.get("family_name", ""), external_user=True,
groups=user_groups)
app.logger.info("creating new user")
db.session.add(user)
db.session.commit()
return user
@auth_api_bp.route('/oidc', methods=['GET'])
@auth_api_bp.route('/oidc/<redirect_url>', methods=['GET'])
@oidc_auth.oidc_auth()
def oidc(redirect_url=None):
user = create_or_retrieve_user_from_userinfo(flask.session['userinfo'])
if user is None:
return "Could not authenticate: could not find or create user.", 401
if current_app.config.get("AUTH_RETURN_EXTERNAL_JWT", False):
token = jwt.encode(flask.session['id_token'], current_app.config['SECRET_KEY'])
else:
token = json.dumps({
'access_token': create_access_token(identity=user, fresh=True),
'refresh_token': create_refresh_token(identity=user)
})
if redirect_url is None:
redirect_url = request.headers.get("Referer")
if redirect_url is None:
redirect_url = request.args.get('redirect_url')
if redirect_url is None:
redirect_url = "/"
app.logger.info("Token: {}".format(token))
response = make_response(redirect(redirect_url))
response.set_cookie('tokens', base64.b64encode(token.encode('utf-8')))
return response
@auth_api_bp.route('/refresh', methods=['GET'])
@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,
as we do not actually verify a password in this endpoint."""
jwt_identity = get_jwt_identity()
user = User.get_by_identifier(jwt_identity)
app.logger.info("Refreshing token for " + str(user))
new_token = create_access_token(identity=user, fresh=False)
ret = {'access_token': new_token}
return jsonify(ret), 200

View File

@@ -0,0 +1,42 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
For example: listing of available auth providers or registration of users.
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
from flask_restx import fields, Resource
from backend import db
from backend.api import api_control, get_jwt_identity
control_command_response_model = api_control.model('Control Command Response', {
'time': fields.DateTime(required=False, description='Creation date of the recorder'),
'state': fields.String(min_length=3, required=True, description='The recorder\'s name'),
'output': fields.String(required=False, description='The recorder\'s description'),
'error': fields.String(required=False, description='The recorder\'s description'),
})
@api_control.route('')
class ControlCommand(Resource):
control_command_parser = api_control.parser()
control_command_parser.add_argument('recorder_id', type=int, default=1, required=True)
control_command_parser.add_argument('command_id', type=int, default=1, required=True)
control_command_parser.add_argument('parameters', default=json.dumps({'p1': 'v1'}), type=dict, required=False,
location='json')
@jwt_required
@api_control.doc('run_command')
@api_control.expect(control_command_parser)
@api_control.marshal_with(control_command_response_model, skip_none=False, code=201)
def post(self):
print(get_current_user())
print(get_jwt_identity())
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

@@ -1,9 +1,13 @@
import datetime
import ipaddress
import json
import logging import logging
from random import * from random import *
from flask import jsonify, Blueprint 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 from backend import basic_auth, multi_auth, db, jwt_auth
from backend.api import api_v1, api_bp from backend.api import api_v1, api_bp
@@ -18,6 +22,18 @@ def random_number():
return jsonify(response) return jsonify(response)
@api_bp.route('/test_jwt')
@jwt_auth.login_required
def random_number_jwt():
"""
:return: a random number
"""
response = {
'randomNumber': randint(1, 100)
}
return jsonify(response)
class HelloWorld(Resource): class HelloWorld(Resource):
""" """
This is a test class. This is a test class.
@@ -59,7 +75,7 @@ class SensorData_Handler(Resource):
print("values...") print("values...")
print(args['values']) print(args['values'])
values = json.loads(args['values']) values = json.loads(args['values'])
wasss_app.logger.info("vals: " + str(values) + " (len: " + str(len(values)) + ")") app.logger.info("vals: " + str(values) + " (len: " + str(len(values)) + ")")
rough_geo_location = None rough_geo_location = None
try: try:

87
backend/api/group_api.py Normal file
View File

@@ -0,0 +1,87 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
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_restx import fields, Resource
from backend import db
from backend.api import api_group
from backend.models.user_model import Group
group_model = api_group.model('Group', {
'id': fields.String(required=False, description='The group\'s identifier'),
'name': fields.String(required=True, description='The group\'s name'),
'description': fields.String(required=False, description='The group\'s description'),
'users': fields.List(fields.Nested(api_group.model('group_member',
{'id': fields.Integer(), 'nickname': fields.String(),
'first_name': fields.String(), 'last_name': fields.String(),
'email': fields.String(), 'registered_on': fields.DateTime(),
'last_seen': fields.DateTime()})),
required=False, description='Group members.')
})
@api_group.route('/<int:id>')
@api_group.response(404, 'Group not found')
@api_group.param('id', 'The group identifier')
class GroupResource(Resource):
@jwt_required
@api_group.doc('get_group')
@api_group.marshal_with(group_model)
def get(self, id):
"""Fetch a user given its identifier"""
group = Group.get_by_id(id)
if group is not None:
return group
api_group.abort(404)
@jwt_required
@api_group.doc('delete_todo')
@api_group.response(204, 'Todo deleted')
def delete(self, id):
'''Delete a task given its identifier'''
group = Group.get_by_id(id)
if group is not None:
group.delete()
return '', 204
api_group.abort(404)
@jwt_required
@api_group.doc('update_group')
@api_group.expect(group_model)
@api_group.marshal_with(group_model)
def put(self, id):
'''Update a task given its identifier'''
group = Group.get_by_id(id)
if group is not None:
group.name = api_group["name"]
db.session.commit()
return group
api_group.abort(404)
@api_group.route('')
class GroupList(Resource):
@jwt_required
@api_group.doc('groups')
@api_group.marshal_list_with(group_model)
def get(self):
"""
List all groups
:return: groups
"""
return Group.get_all()
@jwt_required
@api_group.doc('create_group')
@api_group.expect(group_model)
@api_group.marshal_with(group_model, code=201)
def post(self):
group = Group(**api_group.payload)
db.session.add(group)
db.session.commit()
return group

102
backend/api/models.py Normal file
View File

@@ -0,0 +1,102 @@
from flask_restx import fields
from backend.api import api_user, api_recorder, api_v1
generic_id_parser = api_v1.parser()
generic_id_parser.add_argument('id', type=str, required=True, store_missing=False)
user_model = api_user.model('User', {
'id': fields.String(required=True, description='The user\'s identifier'),
'first_name': fields.String(required=True, description='The user\'s first name'),
'last_name': fields.String(required=True, description='The user\'s last name'),
'email': fields.String(required=True, description='The user\'s email address'),
'nickname': fields.String(required=False, description='The user\'s nick name'),
'last_seen': fields.DateTime(required=False, description='Last time user logged in'),
'last_time_modified': fields.DateTime(required=False, description='Last time user was modified'),
'role': fields.String(required=False, description='Role a user might have (in addition to group memberships)'),
'effective_permissions': fields.List(
fields.String(required=True), required=False, description="List of permissions (groups + (optional) role)."
),
'groups': fields.List(
fields.Nested(api_user.model('user_group', {'id': fields.Integer(), 'name': fields.String()})),
required=False, description='Group memberships.'),
'favorite_recorders': fields.List(
fields.Nested(api_user.model('favorite_recorder', {'id': fields.Integer(), 'name': fields.String()})),
required=False, description='Favorite recorders.'),
})
recorder_model = api_recorder.model('Recorder', {
'id': fields.String(required=False, description='The recorder\'s identifier'),
'created_at': fields.DateTime(required=False, description='Creation date of the recorder'),
'last_time_modified': fields.DateTime(required=False, description='Creation date of the recorder'),
'name': fields.String(min_length=3, required=True, description='The recorder\'s name'),
'model_name': fields.String(min_length=3, required=True,
description='The recorder\'s model name (might slightly '
'differ from actual name of the model)'),
'serial_number': fields.String(required=False, description='The recorder\'s serial number'),
'firmware_version': fields.String(required=False, description='The recorder\'s firmware'),
'description': fields.String(required=False, description='The recorder\'s description'),
'locked': fields.Boolean(required=False, description='Indicates whether the recorder settings can be altered'),
'lock_message': fields.String(required=False, description='Optional: message explaining lock state'),
'offline': fields.Boolean(required=False,
description='Should be set when recorder is disconnected for maintenance, etc.'),
'additional_camera_connected': fields.Boolean(required=False,
description='Indicates whether an additional camera is connected'),
'ip': fields.String(required=False, description='The recorder\'s IP address'),
'mac': fields.String(required=False, description='The recorder\'s IP address'),
'network_name': fields.String(required=False, description='The recorder\'s network name'),
'ssh_port': fields.Integer(required=True, default=22, description='The recorder\'s SSH port number'),
'telnet_port': fields.Integer(required=True, default=23, description='The recorder\'s telnet port number'),
# 'use_telnet_instead_ssh': fields.Boolean(required=False, default=False,
# description='If this is set, telnet will be used instead of ssh. '
# 'This might require specific commands.'),
'recorder_model': fields.Nested(api_recorder.model('recorder_model',
{'id': fields.Integer(),
'name': fields.String(attribute="model_name", )}),
required=False,
allow_null=True,
skip_none=False,
description='Model of the recorder.'),
'room': fields.Nested(api_recorder.model('recorder_room',
{'id': fields.Integer(), 'name': fields.String(),
'number': fields.String(), 'alternate_name': fields.String()}),
r0equired=False,
allow_null=True,
skip_none=False,
description='Room in which the recorder is located.'),
'virtual_commands': fields.List(fields.Nested(api_recorder.model('recorder_virtual_commands',
{'id': fields.Integer(),
'name': fields.String()})))
})
recorder_command_model = api_recorder.model('Recorder Command', {
'id': fields.String(required=False, description='The recorder command\'s identifier'),
'name': fields.String(required=True, description='The recorder command\'s name'),
'alternative_name': fields.String(required=False, description='The recorder command\'s alternative name'),
'disabled': fields.Boolean(required=False, description='Indicates if the recorder command is disabled'),
'created_at': fields.DateTime(required=False, description='Creation date of the recorder'),
'last_time_modified': fields.DateTime(required=False),
'description': fields.String(required=False, description='The recorder command\'s description'),
'parameters': fields.Raw(required=True, description='The recorder parameters'),
'recorder_model': fields.Nested(api_recorder.model('recorder_command_models',
{'id': fields.Integer(),
'name': fields.String(attribute="model_name", )})),
})
recorder_model_model = api_recorder.model('Recorder Model', {
'id': fields.String(required=False, description='The recorder model\'s identifier'),
'name': fields.String(attribute="model_name", required=True, description='The recorder model\'s name'),
'created_at': fields.DateTime(required=False, description='Creation date of the recorder'),
'last_time_modified': fields.DateTime(required=False),
'notes': fields.String(required=False, description='The recorder model\'s notes'),
'requires_username': fields.Boolean(),
'requires_password': fields.Boolean(),
'recorders': fields.List(fields.Nested(api_recorder.model('recorder_model',
{'id': fields.Integer(),
'name': fields.String(attribute="model_name", ),
'network_name': fields.String(),
'ip': fields.String()})), required=False,
description='Model of the recorder.'),
'commands': fields.List(fields.Nested(recorder_command_model), attribute="recorder_commands")
})

208
backend/api/recorder_api.py Normal file
View File

@@ -0,0 +1,208 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
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 datetime import datetime
from pprint import pprint
from flask_jwt_extended import jwt_required
from flask_restx import fields, Resource, inputs
from backend import db, app
from backend.api import api_recorder
from backend.api.models import recorder_model, recorder_model_model, recorder_command_model
from backend.models.recorder_model import Recorder, RecorderModel, RecorderCommand
from backend.models.room_model import Room
import backend.recorder_adapters as r_a
# ==
@api_recorder.route('/<int:id>')
@api_recorder.response(404, 'Recorder not found')
@api_recorder.param('id', 'The recorder identifier')
class RecorderResource(Resource):
@jwt_required
@api_recorder.doc('get_recorder')
@api_recorder.marshal_with(recorder_model, skip_none=False)
def get(self, id):
"""Fetch a recorder given its identifier"""
recorder = Recorder.query.get(id)
if recorder is not None:
return recorder
api_recorder.abort(404)
@jwt_required
@api_recorder.doc('delete_todo')
@api_recorder.response(204, 'Todo deleted')
def delete(self, id):
"""Delete a recorder given its identifier"""
recorder = Recorder.query.get(id)
if recorder is not None:
db.session.delete(recorder)
db.session.commit()
return '', 204
api_recorder.abort(404)
recorder_update_parser = api_recorder.parser()
recorder_update_parser.add_argument('name', type=str, required=False, nullable=False, store_missing=False)
recorder_update_parser.add_argument('network_name', type=inputs.regex(inputs.netloc_regex), required=False, store_missing=False)
recorder_update_parser.add_argument('ip', type=inputs.ipv4, required=False, store_missing=False)
recorder_update_parser.add_argument('ip6', type=inputs.ipv6, required=False, store_missing=False)
recorder_update_parser.add_argument('ssh_port', type=inputs.int_range(0,65535), required=False, default=22, store_missing=False)
recorder_update_parser.add_argument('telnet_port', type=inputs.int_range(0,65535), required=False, default=23, store_missing=False)
recorder_update_parser.add_argument('room_id', type=int, required=False, store_missing=False)
recorder_update_parser.add_argument('offline', type=inputs.boolean, required=False, default=False, store_missing=False)
recorder_update_parser.add_argument('locked', type=inputs.boolean, required=False, default=False, store_missing=False)
recorder_update_parser.add_argument('lock_message', type=str, required=False, nullable=True, default=None,
store_missing=False)
recorder_update_parser.add_argument('model_id', type=int, required=False, store_missing=False)
recorder_update_parser.add_argument('description', type=str, required=False, nullable=True, default=None,
store_missing=False)
recorder_update_parser.add_argument('virtual_command_ids', action='split', nullable=True, default=[],
required=False, store_missing=False)
@jwt_required
@api_recorder.doc('update_recorder')
@api_recorder.expect(recorder_model)
def put(self, id):
"""Update a recorder given its identifier"""
args = self.recorder_update_parser.parse_args(strict=True)
args['last_time_modified'] = datetime.utcnow()
pprint(args)
num_rows_matched = Recorder.query.filter_by(id=id).update(args)
print(num_rows_matched)
if num_rows_matched < 1:
api_recorder.abort(404)
db.session.commit()
return "ok"
@api_recorder.route('')
class RecorderList(Resource):
@jwt_required
@api_recorder.doc('recorders')
@api_recorder.marshal_list_with(recorder_model, skip_none=False)
def get(self):
"""
List all recorders
:return: recorders
"""
return Recorder.get_all()
@jwt_required
@api_recorder.doc('create_recorder')
@api_recorder.expect(recorder_model)
@api_recorder.marshal_with(recorder_model, skip_none=False, code=201)
def post(self):
if "room_id" in api_recorder.payload:
if api_recorder.payload["room_id"] is None:
api_recorder.payload["room"] = None
else:
room = Room.query.get(api_recorder.payload["room_id"])
if room is not None:
api_recorder.payload["room"] = room
else:
return "specified room (id: {}) does not exist!".format(api_recorder.payload["room_id"]), 404
if "recorder_model_id" in api_recorder.payload:
if api_recorder.payload["recorder_model_id"] is None:
api_recorder.payload["recorder_model"] = None
else:
rec_model = RecorderModel.query.get(api_recorder.payload["recorder_model_id"])
if rec_model is not None:
api_recorder.payload["recorder_model"] = rec_model
else:
return "specified recorder model (id: {}) does not exist!".format(
api_recorder.payload["recorder_model_id"]), 404
recorder = Recorder(**api_recorder.payload)
db.session.add(recorder)
db.session.commit()
return recorder
@api_recorder.route('/model/<int:id>')
@api_recorder.response(404, 'Recorder Model not found')
@api_recorder.param('id', 'The recorder model identifier')
class RecorderModelResource(Resource):
@jwt_required
@api_recorder.doc('get_recorder_model')
@api_recorder.marshal_with(recorder_model_model)
def get(self, id):
"""Fetch a recorder model given its identifier"""
recorder_model = RecorderModel.query.get(id)
if recorder_model is not None:
return recorder_model
api_recorder.abort(404)
recorder_model_parser = api_recorder.parser()
recorder_model_parser.add_argument('notes', type=str, required=True)
@jwt_required
@api_recorder.doc('update_recorder_model')
@api_recorder.expect(recorder_model_parser)
@api_recorder.marshal_with(recorder_model_model)
def put(self, id):
"""Update a recorder_model given its identifier"""
num_rows_matched = RecorderModel.query.filter_by(id=id).update(api_recorder.payload)
if num_rows_matched < 1:
api_recorder.abort(404)
db.session.commit()
return "ok"
@api_recorder.route('/model')
class RecorderModelList(Resource):
@jwt_required
@api_recorder.doc('recorders')
@api_recorder.marshal_list_with(recorder_model_model)
def get(self):
return RecorderModel.get_all()
@api_recorder.route('/command/<int:id>')
@api_recorder.response(404, 'Recorder Command not found')
@api_recorder.param('id', 'The recorder command identifier')
class RecorderCommandResource(Resource):
@jwt_required
@api_recorder.doc('get_recorder_command')
@api_recorder.marshal_with(recorder_command_model)
def get(self, id):
"""Fetch a recorder command given its identifier"""
recorder_command = RecorderCommand.query.get(id)
if recorder_command is not None:
return recorder_command
api_recorder.abort(404)
recorder_command_model_parser = api_recorder.parser()
recorder_command_model_parser.add_argument('description', type=str, required=False)
recorder_command_model_parser.add_argument('alternative_name', type=str, required=False)
@jwt_required
@api_recorder.doc('update_recorder_command')
@api_recorder.expect(recorder_command_model_parser)
@api_recorder.marshal_with(recorder_command_model)
def put(self, id):
"""Update a recorder command given its identifier"""
num_rows_matched = RecorderCommand.query.filter_by(id=id).update(api_recorder.payload)
if num_rows_matched < 1:
api_recorder.abort(404)
db.session.commit()
return "ok"
@api_recorder.route('/command')
class RecorderCommandList(Resource):
@jwt_required
@api_recorder.doc('recorder_commands')
@api_recorder.marshal_list_with(recorder_command_model)
def get(self):
"""
List all recorders commands
:return: recorder commands
"""
return RecorderCommand.get_all()

122
backend/api/room_api.py Normal file
View File

@@ -0,0 +1,122 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
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_restx import fields, Resource
from sqlalchemy import exc
from backend import db, app
from backend.api import api_room
from backend.models.room_model import Room
from backend.models.recorder_model import Recorder
room_model = api_room.model('Room', {
'id': fields.String(required=False, description='The room\'s identifier'),
'created_at': fields.DateTime(required=False, description='Creation date of the room info'),
'name': fields.String(required=True, description='The room\'s name'),
'alternate_name': fields.String(required=False, description='The room\'s alternate name'),
'comment': fields.String(required=False, description='The room\'s comment'),
'number': fields.String(required=True, description='The room\'s number'),
'building_name': fields.String(required=False, description='The building\'s name'),
'building_number': fields.String(required=False, description='The building\'s number'),
'recorder': fields.Nested(api_room.model('room_recorder',
{'id': fields.Integer(), 'name': fields.String(),
'ip': fields.String(), 'network_name': fields.String()}),
allow_null=True,
skip_none=False,
required=False,
description='Room recorder.'),
})
@api_room.route('/<int:id>')
@api_room.response(404, 'Room not found')
@api_room.param('id', 'The room identifier')
class RoomResource(Resource):
@jwt_required
@api_room.doc('get_room')
@api_room.marshal_with(room_model, skip_none=False)
def get(self, id):
"""Fetch a user given its identifier"""
room = Room.query.get(id)
if room is not None:
return room
api_room.abort(404)
@jwt_required
@api_room.doc('delete_todo')
@api_room.response(204, 'Todo deleted')
def delete(self, id):
'''Delete a task given its identifier'''
room = Room.query.get(id)
if room is not None:
db.session.delete(room)
db.session.commit()
return '', 204
api_room.abort(404)
@jwt_required
@api_room.doc('update_room')
@api_room.expect(room_model)
def put(self, id):
app.logger.debug(api_room.payload)
'''Update a task given its identifier'''
if "recorder_id" in api_room.payload:
if api_room.payload["recorder_id"] is None:
api_room.payload["recorder"] = None
else:
recorder = Recorder.query.get(api_room.payload["recorder_id"])
if recorder is not None:
api_room.payload["recorder"] = recorder
else:
return "specified recorder (id: {}) does not exist!".format(api_room.payload["recorder_id"]), 404
room = Room.query.get(id)
if room is not None:
room.recorder = api_room.payload["recorder"]
else:
num_rows_matched = Room.query.filter_by(id=id).update(api_room.payload)
db.session.commit()
return "ok"
api_room.abort(404)
@api_room.route('')
class RoomList(Resource):
@jwt_required
@api_room.doc('rooms')
@api_room.marshal_list_with(room_model, skip_none=False)
def get(self):
"""
List all rooms
:return: rooms
"""
return Room.get_all()
@jwt_required
@api_room.doc('create_room')
@api_room.expect(room_model)
@api_room.marshal_with(room_model, skip_none=False, code=201)
def post(self):
if "recorder_id" in api_room.payload:
if api_room.payload["recorder_id"] is None:
api_room.payload["recorder"] = None
else:
recorder = Recorder.query.get(api_room.payload["recorder_id"])
if recorder is not None:
api_room.payload["recorder"] = recorder
else:
return "specified recorder (id: {}) does not exist!".format(api_room.payload["recorder_id"]), 404
del api_room.payload["recorder_id"]
room = Room(**api_room.payload)
db.session.add(room)
try:
db.session.commit()
return room
except exc.IntegrityError as e:
db.session.rollback()
return str(e.detail), 400

130
backend/api/user_api.py Normal file
View File

@@ -0,0 +1,130 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
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 datetime import datetime
from pprint import pprint
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.recorder_model import Recorder
from backend.models.user_model import User
user_update_parser = api_user.parser()
user_update_parser.add_argument('email', type=inputs.email(), required=False, nullable=False, store_missing=False)
user_update_parser.add_argument('nickname', type=str, required=False, store_missing=False)
user_update_parser.add_argument('first_name', type=str, required=False, store_missing=False)
user_update_parser.add_argument('last_name', type=str, required=False, store_missing=False)
@api_user.route('/profile')
class Profile(Resource):
@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)
@jwt_required
@api_user.expect(user_update_parser)
def put(self):
args = user_update_parser.parse_args()
args['last_time_modified'] = datetime.utcnow()
pprint(args)
print(current_user)
num_rows_matched = User.query.filter_by(id=current_user.id).update(args)
print(num_rows_matched)
if num_rows_matched < 1:
api_user.abort("Nothing has been updated!")
db.session.commit()
return "ok"
@api_user.route('/profile/favorite_recorders')
class UserFavoriteRecorders(Resource):
@jwt_required
@api_user.marshal_list_with(recorder_model)
def get(self):
try:
current_user_id = get_jwt_identity()
return User.get_by_identifier(current_user_id).favorite_recorders
except AttributeError:
abort(404, "User not found!")
@jwt_required
@api_user.expect(generic_id_parser)
@api_user.marshal_list_with(recorder_model)
def put(self):
try:
args = generic_id_parser.parse_args()
current_user_id = get_jwt_identity()
user = User.get_by_identifier(current_user_id)
print(user)
recorder = Recorder.get_by_identifier(args["id"])
print(recorder)
if recorder is None:
abort(404, "(Specified [id: {}]) recorder not found!".format(args["id"]))
user.favorite_recorders.append(recorder)
db.session.commit()
return user.favorite_recorders
except AttributeError:
abort(404, "User not found!")
@api_user.route('')
class UserList(Resource):
"""
This is a test class.
"""
# @jwt_auth.login_required
@jwt_required
@api_user.doc('users')
@api_user.marshal_list_with(user_model)
def get(self):
"""
just a test!
:return: Hello: World
"""
current_user = get_jwt_identity()
app.logger.info(current_user)
return User.get_all()
@jwt_required
@api_user.doc('create_user')
@api_user.expect(user_model)
@api_user.marshal_with(user_model, code=201)
def post(self):
user = User(**api_user.payload)
db.session.add(user)
db.session.commit()
return user
@api_user.route('/<id>')
@api_user.param('id', 'The user identifier')
@api_user.response(404, 'User not found')
class UserResource(Resource):
@jwt_auth.login_required
@api_user.doc('get_user')
@api_user.marshal_with(user_model)
def get(self, id):
"""Fetch a user given its identifier"""
user = User.get_by_id(id)
if user is not None:
return user
api_user.abort(404)
# api_user.add_resource(UserResource, '/')

View File

@@ -0,0 +1,134 @@
# Copyright (c) 2019. Tobias Kurze
"""
This module provides functions related to authentication through the API.
For example: listing of available auth providers or registration of users.
Login through API does not start a new session, but instead returns JWT.
"""
import inspect
import pkgutil
from pprint import pprint
from flask_jwt_extended import jwt_required
from flask_restx import fields, Resource
from backend import db, app
from backend.api import api_virtual_command
from backend.models.recorder_model import Recorder, RecorderModel, RecorderCommand
from backend.models.room_model import Room
import backend.recorder_adapters as r_a
virtual_command_model = api_virtual_command.model('VirtualCommand', {
'id': fields.String(required=False, description='The recorder\'s identifier'),
'created_at': fields.DateTime(required=False, description='Creation date of the recorder'),
'name': fields.String(min_length=3, required=True, description='The recorder\'s name'),
'description': fields.String(required=False, description='The recorder\'s description'),
'parent_virtual_command': fields.Nested(api_virtual_command.model('VirtualCommandParent',
{
'id': fields.String(required=False,
description='The recorder\'s identifier'),
'name': fields.String(min_length=3,
required=True,
description='The recorder\'s name'),
},
required=False,
allow_null=True,
skip_none=False,
description='Parent virtual command.')),
'room': fields.Nested(api_virtual_command.model('recorder_room',
{'id': fields.Integer(), 'name': fields.String(),
'number': fields.String(), 'alternate_name': fields.String()}),
r0equired=False,
allow_null=True,
skip_none=False,
description='Room in which the recorder is located.')
})
# ==
@api_virtual_command.route('/<int:id>')
@api_virtual_command.response(404, 'Recorder not found')
@api_virtual_command.param('id', 'The recorder identifier')
class VirtualCommandResource(Resource):
@jwt_required
@api_virtual_command.doc('get_recorder')
@api_virtual_command.marshal_with(virtual_command_model, skip_none=False)
def get(self, id):
"""Fetch a recorder given its identifier"""
recorder = Recorder.query.get(id)
if recorder is not None:
return recorder
api_virtual_command.abort(404)
@jwt_required
@api_virtual_command.doc('delete_todo')
@api_virtual_command.response(204, 'Todo deleted')
def delete(self, id):
"""Delete a recorder given its identifier"""
recorder = Recorder.query.get(id)
if recorder is not None:
db.session.delete(recorder)
db.session.commit()
return '', 204
api_virtual_command.abort(404)
virtual_command_model_parser = api_virtual_command.parser()
virtual_command_model_parser.add_argument('notes', type=str, required=True)
@jwt_required
@api_virtual_command.doc('update_recorder')
@api_virtual_command.expect(virtual_command_model_parser)
def put(self, id):
"""Update a recorder given its identifier"""
num_rows_matched = Recorder.query.filter_by(id=id).update(api_virtual_command.payload)
if num_rows_matched < 1:
api_virtual_command.abort(404)
db.session.commit()
return "ok"
@api_virtual_command.route('')
class RecorderList(Resource):
@jwt_required
@api_virtual_command.doc('recorders')
@api_virtual_command.marshal_list_with(virtual_command_model, skip_none=False)
def get(self):
"""
List all recorders
:return: recorders
"""
return Recorder.get_all()
virtual_command_model_parser = api_virtual_command.parser()
virtual_command_model_parser.add_argument('notes', type=str, required=True)
@jwt_required
@api_virtual_command.doc('create_recorder')
@api_virtual_command.expect(virtual_command_model_parser)
@api_virtual_command.marshal_with(virtual_command_model, skip_none=False, code=201)
def post(self):
if "room_id" in api_virtual_command.payload:
if api_virtual_command.payload["room_id"] is None:
api_virtual_command.payload["room"] = None
else:
room = Room.query.get(api_virtual_command.payload["room_id"])
if room is not None:
api_virtual_command.payload["room"] = room
else:
return "specified room (id: {}) does not exist!".format(api_virtual_command.payload["room_id"]), 404
if "recorder_model_id" in api_virtual_command.payload:
if api_virtual_command.payload["recorder_model_id"] is None:
api_virtual_command.payload["recorder_model"] = None
else:
rec_model = RecorderModel.query.get(api_virtual_command.payload["recorder_model_id"])
if rec_model is not None:
api_virtual_command.payload["recorder_model"] = rec_model
else:
return "specified recorder model (id: {}) does not exist!".format(
api_virtual_command.payload["recorder_model_id"]), 404
recorder = Recorder(**api_virtual_command.payload)
db.session.add(recorder)
db.session.commit()
return recorder

78
backend/auth/__init__.py Normal file
View File

@@ -0,0 +1,78 @@
# Copyright (c) 2019. Tobias Kurze
"""
Base module for auth aspects.
Also this module contains mainly code for login through HTML pages served by the backend.
If frontend pages are build by frontend code (JS, etc.) authentication should consider using api functions.
(For more info, see api.auth_api.py.)
This code uses login_user and logout user (to start and end sessions) ... API code returns JWTs.
"""
from flask import Blueprint, jsonify, url_for
from flask_login import logout_user, LoginManager
from werkzeug.routing import BuildError
from backend import jwt_extended
from backend.models import BlacklistToken, User
auth_bp = Blueprint('auth', __name__, url_prefix='/auth', template_folder='templates')
from backend.auth.config import AUTH_PROVIDERS, DEFAULT_FRONTEND_PROVIDER
from backend.auth.oidc_config import OIDC_PROVIDERS
from backend.auth.oidc import oidc_auth
from .basic_auth import *
def auth_decorator(): # custom decorator
pass
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
try:
prov = AUTH_PROVIDERS[DEFAULT_FRONTEND_PROVIDER]
except KeyError:
return "No known default provider specified!"
url = prov["url"]
try:
url = url_for(prov["url"], next=request.endpoint)
except BuildError as e:
pass
#logger.log("Can't create endpoint for '{}' (specified provider: {}).".format(e.endpoint, DEFAULT_PROVIDER))
return redirect(url)
@auth_bp.route('/login_select', methods=['GET'])
def login_select():
return render_template('login_select.html', providers=AUTH_PROVIDERS)
@auth_bp.route('/logout', methods=('GET', ))
def logout():
logout_user()
@jwt_extended.additional_claims_loader
def add_claims_to_access_token(user):
if isinstance(user, str):
return {}
return {'role': user.role, 'groups': [g.to_dict() for g in user.groups]}
@jwt_extended.user_identity_loader
def user_identity_loader(user):
return user.email
@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_blocklist_loader
def check_if_token_in_blacklist(decrypted_token):
jti = decrypted_token['jti']
return BlacklistToken.get_by_token(jti) is not None

View File

@@ -0,0 +1,22 @@
# Route for handling the login page logic
from flask import request, redirect, render_template
from flask_login import login_user
from backend.auth import auth_bp
from backend.models.user_model import User
@auth_bp.route('/base_login', methods=['GET', 'POST'])
def base_login():
error = None
if request.method == 'POST':
user = User.authenticate(email=request.form['email'], password=request.form['password'])
if user is None:
error = 'Invalid Credentials. Please try again.'
else:
login_user(user)
return redirect("/")
return render_template('login.html', error=error)

29
backend/auth/config.py Normal file
View File

@@ -0,0 +1,29 @@
from typing import Dict, List
AUTH_PROVIDERS: Dict[str, Dict[str, str]] = {
"KIT OIDC":
{
"type": "oidc",
"url": "auth_api.oidc"
},
"Base Login":
{
"type": "login_form",
"url": "auth.base_login"
},
"KIT OIDC (API)":
{
"type": "api_oidc",
"url": "auth_api.oidc"
},
"User-Password (API)":
{
"type": "api_login_form",
"url": "auth_api.login"
},
}
#DEFAULT_PROVIDER: str = "Base Login"
DEFAULT_PROVIDER: str = "KIT OIDC (API)"
DEFAULT_FRONTEND_PROVIDER: str = "Base Login"

80
backend/auth/oidc.py Normal file
View File

@@ -0,0 +1,80 @@
# Copyright (c) 2019. Tobias Kurze
"""
OIDC login auth module
"""
from datetime import datetime
import flask
from flask import jsonify, redirect, url_for
from flask_login import login_user
from flask_pyoidc.flask_pyoidc import OIDCAuthentication
from flask_pyoidc.user_session import UserSession
from backend import app, db
from backend.models.user_model import User
from . import auth_bp
from .oidc_config import PROVIDER_NAME, OIDC_PROVIDERS
OIDCAuthentication.oidc_auth_orig = OIDCAuthentication.oidc_auth
OIDCAuthentication.oidc_logout_orig = OIDCAuthentication.oidc_logout
def oidc_auth_default_provider(self):
"""monkey patch oidc_auth"""
return self.oidc_auth_orig(PROVIDER_NAME)
def oidc_logout_default_provider(self):
"""monkey patch oidc_logout"""
return self.oidc_logout_orig(PROVIDER_NAME)
OIDCAuthentication.oidc_auth = oidc_auth_default_provider
OIDCAuthentication.oidc_logout = oidc_logout_default_provider
oidc_auth = OIDCAuthentication(OIDC_PROVIDERS)
def create_or_retrieve_user_from_userinfo(userinfo):
"""Updates and returns ar creates a user from userinfo (part of OIDC token)."""
try:
email = userinfo["email"]
except KeyError:
return None
user = User.get_by_identifier(email)
if user is not None:
app.logger.info("user found")
user.last_seen = datetime.utcnow()
# TODO: update user!
db.session.commit()
return user
user = User(email=email, first_name=userinfo.get("given_name", ""),
last_name=userinfo.get("family_name", ""))
app.logger.info("creating new user")
db.session.add(user)
db.session.commit()
return user
@auth_bp.route('/oidc', methods=['GET'])
@oidc_auth.oidc_auth()
def oidc():
user_session = UserSession(flask.session)
app.logger.info(user_session.userinfo)
user = create_or_retrieve_user_from_userinfo(user_session.userinfo)
login_user(user)
return jsonify(id_token=user_session.id_token,
access_token=flask.session['access_token'],
userinfo=user_session.userinfo)
@auth_bp.route('/oidc_logout', methods=['GET'])
def oidc_logout():
oidc_auth.oidc_logout()
return redirect('/')

View File

@@ -0,0 +1,15 @@
# Copyright (c) 2019. Tobias Kurze
from flask_pyoidc.provider_configuration import ClientMetadata, ProviderConfiguration
REG_RESPONSE_CLIENT_ID = "lrc-test-bibliothek-kit-edu"
REG_RESPONSE_CLIENT_SECRET = "d8531b30-0e6b-4280-b611-1e6c8b4911fa"
CLIENT_METADATA = ClientMetadata(REG_RESPONSE_CLIENT_ID, REG_RESPONSE_CLIENT_SECRET)
PROVIDER_URL = "https://oidc.scc.kit.edu/auth/realms/kit"
PROVIDER_NAME = 'kit_oidc'
PROVIDER_CONFIG = ProviderConfiguration(issuer=PROVIDER_URL,
client_metadata=CLIENT_METADATA,
auth_request_params={'scope': ['openid', 'email', 'profile']})
OIDC_PROVIDERS = {PROVIDER_NAME: PROVIDER_CONFIG}

View File

@@ -0,0 +1,23 @@
<html>
<head>
<title>Flask Intro - login page</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="static/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<body>
<div class="container">
<h1>Please login</h1>
<br>
<form action="" method="post">
<input type="text" placeholder="E-Mail" name="email" value="{{
request.form.username }}">
<input type="password" placeholder="Password" name="password" value="{{
request.form.password }}">
<input class="btn btn-default" type="submit" value="Login">
</form>
{% if error %}
<p class="error"><strong>Error:</strong> {{ error }}
{% endif %}
</div>
</body>
</html>

View File

@@ -0,0 +1,21 @@
<html>
<head>
<title>Flask Intro - login page</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="static/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<body>
<div class="container">
<h1>Please select login method</h1>
<br>
<ul>
{% for provider in providers %}
<li><a href="{{url_for(providers[provider].url)}}">{{ provider }} ({{ providers[provider].type }})</a></li>
{% endfor %}
</ul>
{% if error %}
<p class="error"><strong>Error:</strong> {{ error }}
{% endif %}
</div>
</body>
</html>

42
backend/auth/utils.py Normal file
View File

@@ -0,0 +1,42 @@
import flask_jwt_extended
from flask_jwt_extended import jwt_optional, get_jwt_identity
from functools import wraps
from backend import jwt_auth
from backend.models.user_model import User
def requires_permission_level(permission_level):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if flask_jwt_extended.verify_jwt_in_request():
current_user_id = get_jwt_identity()
user = User.get_by_identifier(current_user_id)
if user is not None:
if user.has_permission(permission_level):
#for g in user.groups:
# if g.permissions
#TODO
pass
else:
pass
# return FALSE
#if not session.get('email'):
# return redirect(url_for('users.login'))
#user = User.find_by_email(session['email'])
#elif not user.allowed(access_level):
# return redirect(url_for('users.profile', message="You do not have access to that page. Sorry!"))
return f(*args, **kwargs)
return decorated_function
return decorator
def require_jwt():
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
return jwt_auth.login_required(jwt_optional(f(*args, **kwargs)))
return decorated_function
return decorator

216
backend/config.py Normal file
View File

@@ -0,0 +1,216 @@
# -*- coding: utf-8 -*-
# ....
# available languages
import datetime
import os
import logging
from enum import Enum, auto
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
basedir = os.path.abspath(os.path.dirname(__file__))
logs_dir = os.path.abspath(os.path.join(basedir, os.path.pardir, 'logs'))
print("Logging to: {}".format(logs_dir))
if not os.path.exists(logs_dir):
print("Logging directory does not yet exist: creating it!")
os.makedirs(logs_dir)
logger.info("Basedir is: {}".format(basedir))
class Config:
LOG_LEVEL = "DEBUG"
DEBUG = True
TESTING = True
ROOT_LOG_FILE = os.path.join(logs_dir, "root.log")
LOG_FILE = os.path.join(logs_dir, "app.log")
CRON_LOG_FILE = os.path.join(logs_dir, "cron.log")
ERROR_LOG_FILE = os.path.join(logs_dir, "error.log")
# SERVER_NAME = "ubkaps154.ubka.uni-karlsruhe.de:5443"
# SERVER_NAME = "localhost.dev"
SERVER_NAME = "localhost:8080"
# SERVER_NAME = "lrc.test:5443"
# SERVER_NAME = "localhost"
# SERVER_NAME = "localhost.localdomain"
# PORT = 5443
OPENCAST_URL = "https://oc-bib-admin.bibliothek.kit.edu"
OPENCAST_USER = "admin"
OPENCAST_PW = "mz.paziuw!"
TEMPLATE_AUTO_RELOAD = True
CAMPUS_MANAGEMENT_USER = "bib"
CAMPUS_MANAGEMENT_PW = "bwTf8EVazosl7:4d2YBOz!"
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db')
SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository')
SQLALCHEMY_TRACK_MODIFICATIONS = True
WTF_CSRF_ENABLED = True
SECRET_KEY = 'you-will-never-guess'
OPENID_PROVIDERS = [
{'name': 'Google', 'url': 'https://www.google.com/accounts/o8/id'},
{'name': 'Yahoo', 'url': 'https://me.yahoo.com'},
{'name': 'AOL', 'url': 'http://openid.aol.com/<username>'},
{'name': 'Flickr', 'url': 'http://www.flickr.com/<username>'},
{'name': 'MyOpenID', 'url': 'https://www.myopenid.com'}]
OAUTH_CREDENTIALS = {
'facebook': {
'id': '1198624176930248',
'secret': '4fbc01d776834c1ffc89a5bed1cd97d0'
},
'twitter': {
'id': '3RzWQclolxWZIMq5LJqzRZPTl',
'secret': 'm9TEd58DSEtRrZHpz2EjrV9AhsBRxKMo8m3kuIZj3zLwzwIimt'
},
'google': {
'id': '1084993305658-d9n88548ssrtmt5v6s2dne57i4qpviur.apps.googleusercontent.com',
'secret': 'oNpvoAKMPMjRyiu5EDrmmX4X'
},
}
# OIDC_REDIRECT_URI = "https://ubkaps154.ubka.uni-karlsruhe.de:5443/redirect_uri" # not required if SERVER_NAME set
SESSION_PERMANENT = True # turn on flask session support
PERMANENT_SESSION_LIFETIME = datetime.timedelta(days=7).total_seconds() # session time in secs
# mail server settings
MAIL_SERVER = 'localhost'
MAIL_PORT = 25
MAIL_USERNAME = None
MAIL_PASSWORD = None
SMTP_SERVER = "smarthost.kit.edu"
FROM_MAIL = "noreply@lrc.bib.kit.edu"
ERROR_E_MAIL_TO = ["kurze@kit.edu", "andreas.reichert@kit.edu"]
ADMIN_E_MAIL_TO = ["kurze@kit.edu", "andreas.reichert@kit.edu"]
# administrator list
ADMINS = ['you@example.com']
# pagination
POSTS_PER_PAGE = 5
LOCKS_PER_PAGE = 8
LANGUAGES = {
'en': 'English',
'es': 'Español'
}
# ASSETS_DEBUG = True
# JWT_SECRET = "abcxyz"
# JWT_ALGORITHM = "HS256"
# JWT_EXP_DELTA_SECONDS = 5 * 60
JWT_SECRET_KEY = "abcxyz"
JWT_BLACKLIST_ENABLED = True
JWT_BLACKLIST_TOKEN_CHECKS = ['access', 'refresh']
JWT_TOKEN_LOCATION = ['headers', 'cookies', 'json', 'query_string']
AUTH_RETURN_EXTERNAL_JWT = False
INDEX_TEMPLATE = "index.html"
# # INITIAL VALUES # #
class Permissions(Enum):
RECODER_NEW = "RECODER_NEW"
RECORDER_EDIT = "RECORDER_EDIT"
RECODER_SHOW = "RECODER_SHOW"
RECORDER_DELETE = "RECORDER_DELETE"
RECORDERS_LIST = "RECORDERS_LIST"
RECODER_MODEL_SHOW = "RECODER_MODEL_SHOW"
RECODER_MODEL_EDIT = "RECODER_MODEL_EDIT"
RECODER_MODELS_LIST = "RECODER_MODELS_LIST"
RECORDER_COMMAND_SHOW = "RECORDER_COMMAND_SHOW"
RECORDER_COMMAND_EDIT = "RECORDER_COMMAND_EDIT"
RECORDER_COMMANDS_LIST = "RECORDER_COMMANDS_LIST"
RECORDER_COMMAND_EXECUTE = "RECORDER_COMMAND_EXECUTE"
RECORDER_COMMAND_EDIT_ACL = "RECORDER_COMMAND_EDIT_ACL"
VIRTUAL_COMMAND_CREATE = "VIRTUAL_COMMAND_CREATE"
VIRTUAL_COMMAND_EDIT = "VIRTUAL_COMMAND_EDIT"
VIRTUAL_COMMAND_SHOW = "VIRTUAL_COMMAND_SHOW"
VIRTUAL_COMMAND_DELETE = "VIRTUAL_COMMAND_DELETE"
CRON_JOB_CREATE = "CRON_JOB_CREATE"
CRON_JOB_EDIT = "CRON_JOB_EDIT"
CRON_JOB_SHOW = "CRON_JOB_SHOW"
CRON_JOB_DELETE = "CRON_JOB_DELETE"
CRON_JOBS_LIST = "CRON_JOBS_LIST"
USER_CREATE = "USER_CREATE"
USER_EDIT = "USER_EDIT"
USER_SHOW = "USER_SHOW"
USER_DELETE = "USER_DELETE"
USERS_LIST = "USERS_LIST"
def __str__(self):
return str(self.value)
PERMISSIONS = [str(e.value) for e in Permissions]
GROUPS = [ # {"name": "Admins",
# "permissions": PERMISSIONS},
{"name": "BIB-LRC-Admin", "permissions": PERMISSIONS}, # BIB Admins may do (almost) anything
{"name": "BIB-LRC-User", "permissions": ["USERS_LIST", "RECORDERS_LIST", "RECODER_SHOW", "CRON_JOBS_LIST"]},
{"name": "ZML"},
{"name": "read_only"}]
USERS = [{"nickname": "admin",
"first_name": "Tobias",
"last_name": "Kurze",
"email": "kurze@kit.edu",
"role": "admin",
"password": "admin"}
]
class Roles(Enum):
ADMIN = "admin"
def __str__(self):
return str(self.value)
ROLE_PERMISSION_MAPPINGS = { # roles are a 'special' attribute that may grant permissions in addition to groups
str(Roles.ADMIN): PERMISSIONS
}
DEFAULT_ARCHIVE_STREAM_1_NAME = "extron1"
DEFAULT_ARCHIVE_STREAM_2_NAME = "extron2"
STREAM_SANITY_CHECK_RETRIES = 3
STREAM_SANITY_CHECK_INTERVAL_SEC = 5
class ProductionConfig(Config):
DATABASE_URI = 'mysql://user@localhost/foo'
DEBUG = False
class DevelopmentConfig(Config):
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db_debug')
# SERVER_NAME = "*:5443"
USE_SSL = False
PREFERRED_URL_SCHEME = 'http'
HOST = "localhost"
PORT = 5443
SERVER_NAME = f"{HOST}:{PORT}"
# OIDC_REDIRECT_URI = "https://ubkaps154.ubka.uni-karlsruhe.de:5443/redirect_uri" # not required if SERVER_NAME set
DEBUG = True
class TestingConfig(Config):
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db_test')
TESTING = True
USE_SSL = True
PREFERRED_URL_SCHEME = 'https'
CERT = os.path.join(basedir, "cert.pem")
KEY = os.path.join(basedir, "key.pem")
HOST = "ubkaps154.ubka.uni-karlsruhe.de"
PORT = 5443
SERVER_NAME = f"{HOST}:{PORT}"

7
backend/cron/__init__.py Normal file
View File

@@ -0,0 +1,7 @@
import logging
cron_log_handler = logging.FileHandler(CRON_LOG_FILE)
cron_logger = logging.getLogger("mal.cron")
cron_logger.addHandler(cron_log_handler)
logging.getLogger("apscheduler.scheduler").addHandler(cron_log_handler)
logging.getLogger("apscheduler.executors.default").addHandler(cron_log_handler)

75
backend/manage.py Normal file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/env python
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__), os.path.pardir))
import os
import unittest
import coverage
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from backend import app, db
COV = coverage.coverage(
branch=True,
include='app/*',
omit=[
'app/tests/*',
'app/server/config.py',
'app/server/*/__init__.py'
]
)
COV.start()
migrate = Migrate(app, db)
manager = Manager(app)
# migrations
manager.add_command('db', MigrateCommand)
@manager.command
def test():
"""Runs the unit tests without test coverage."""
tests = unittest.TestLoader().discover('tests', pattern='test*.py')
result = unittest.TextTestRunner(verbosity=2).run(tests)
if result.wasSuccessful():
return 0
return 1
@manager.command
def cov():
"""Runs the unit tests with coverage."""
tests = unittest.TestLoader().discover('app/tests')
result = unittest.TextTestRunner(verbosity=2).run(tests)
if result.wasSuccessful():
COV.stop()
COV.save()
print('Coverage Summary:')
COV.report()
basedir = os.path.abspath(os.path.dirname(__file__))
covdir = os.path.join(basedir, 'tmp/coverage')
COV.html_report(directory=covdir)
print('HTML version: file://%s/index.html' % covdir)
COV.erase()
return 0
return 1
@manager.command
def create_db():
"""Creates the db tables."""
db.create_all()
@manager.command
def drop_db():
"""Drops the db tables."""
db.drop_all()
if __name__ == '__main__':
manager.run()

View File

@@ -0,0 +1 @@
Generic single-database configuration.

View File

@@ -0,0 +1,45 @@
# A generic, single database configuration.
[alembic]
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

95
backend/migrations/env.py Normal file
View File

@@ -0,0 +1,95 @@
from __future__ import with_statement
import logging
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
from flask import current_app
config.set_main_option('sqlalchemy.url',
current_app.config.get('SQLALCHEMY_DATABASE_URI'))
target_metadata = current_app.extensions['migrate'].db.metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url, target_metadata=target_metadata, literal_binds=True
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
# this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()

View File

@@ -0,0 +1,24 @@
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}

View File

@@ -0,0 +1,136 @@
"""empty message
Revision ID: b154e49921e0
Revises:
Create Date: 2019-04-11 14:44:25.836132
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'b154e49921e0'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('blacklist_tokens',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('token', sa.String(length=500), nullable=False),
sa.Column('blacklisted_on', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('token')
)
op.create_table('example_data_item',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('mac', sa.String(length=32), nullable=False),
sa.Column('uuid', sa.String(length=36), nullable=False),
sa.Column('some_string_value', sa.String(), nullable=True),
sa.Column('name', sa.String(length=128), nullable=False),
sa.Column('description', sa.String(length=4096), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_example_data_item_mac'), 'example_data_item', ['mac'], unique=True)
op.create_index(op.f('ix_example_data_item_name'), 'example_data_item', ['name'], unique=False)
op.create_index(op.f('ix_example_data_item_some_string_value'), 'example_data_item', ['some_string_value'], unique=False)
op.create_index(op.f('ix_example_data_item_uuid'), 'example_data_item', ['uuid'], unique=True)
op.create_table('group',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.Unicode(length=63), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('permission',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.Unicode(length=63), nullable=False),
sa.Column('description', sa.Unicode(length=255), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('group_permission',
sa.Column('group_id', sa.Integer(), nullable=False),
sa.Column('permission_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['group_id'], ['group.id'], onupdate='CASCADE', ondelete='CASCADE'),
sa.ForeignKeyConstraint(['permission_id'], ['permission.id'], onupdate='CASCADE', ondelete='CASCADE'),
sa.PrimaryKeyConstraint('group_id', 'permission_id')
)
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('social_id', sa.Unicode(length=63), nullable=True),
sa.Column('nickname', sa.Unicode(length=63), nullable=True),
sa.Column('first_name', sa.Unicode(length=63), nullable=True),
sa.Column('last_name', sa.Unicode(length=63), nullable=True),
sa.Column('email', sa.String(length=120), nullable=False),
sa.Column('lang', sa.Unicode(length=32), nullable=True),
sa.Column('timezone', sa.Unicode(length=63), nullable=True),
sa.Column('example_data_item_id', sa.Integer(), nullable=True),
sa.Column('about_me', sa.Unicode(length=255), nullable=True),
sa.Column('role', sa.Unicode(length=63), nullable=True),
sa.Column('password', sa.String(length=255), nullable=True),
sa.Column('registered_on', sa.DateTime(), nullable=False),
sa.Column('external_user', sa.Boolean(), nullable=True),
sa.Column('last_seen', sa.DateTime(), nullable=True),
sa.Column('jwt_exp_delta_seconds', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['example_data_item_id'], ['example_data_item.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('social_id')
)
op.create_index(op.f('ix_user_email'), 'user', ['email'], unique=True)
op.create_index(op.f('ix_user_first_name'), 'user', ['first_name'], unique=False)
op.create_index(op.f('ix_user_last_name'), 'user', ['last_name'], unique=False)
op.create_index(op.f('ix_user_nickname'), 'user', ['nickname'], unique=True)
op.create_table('acquaintances',
sa.Column('me_id', sa.Integer(), nullable=True),
sa.Column('acquaintance_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['acquaintance_id'], ['user.id'], ),
sa.ForeignKeyConstraint(['me_id'], ['user.id'], )
)
op.create_table('followers',
sa.Column('follower_id', sa.Integer(), nullable=True),
sa.Column('followed_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['followed_id'], ['user.id'], ),
sa.ForeignKeyConstraint(['follower_id'], ['user.id'], )
)
op.create_table('post',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('body', sa.String(length=140), nullable=True),
sa.Column('timestamp', sa.DateTime(), nullable=True),
sa.Column('user_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('user_group',
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('group_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['group_id'], ['group.id'], onupdate='CASCADE', ondelete='CASCADE'),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], onupdate='CASCADE', ondelete='CASCADE'),
sa.PrimaryKeyConstraint('user_id', 'group_id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('user_group')
op.drop_table('post')
op.drop_table('followers')
op.drop_table('acquaintances')
op.drop_index(op.f('ix_user_nickname'), table_name='user')
op.drop_index(op.f('ix_user_last_name'), table_name='user')
op.drop_index(op.f('ix_user_first_name'), table_name='user')
op.drop_index(op.f('ix_user_email'), table_name='user')
op.drop_table('user')
op.drop_table('group_permission')
op.drop_table('permission')
op.drop_table('group')
op.drop_index(op.f('ix_example_data_item_uuid'), table_name='example_data_item')
op.drop_index(op.f('ix_example_data_item_some_string_value'), table_name='example_data_item')
op.drop_index(op.f('ix_example_data_item_name'), table_name='example_data_item')
op.drop_index(op.f('ix_example_data_item_mac'), table_name='example_data_item')
op.drop_table('example_data_item')
op.drop_table('blacklist_tokens')
# ### end Alembic commands ###

View File

@@ -0,0 +1,10 @@
"""
Import all models...
"""
from backend.models.example_model import *
from backend.models.user_model import *
from backend.models.post_model import *
from backend.models.recorder_model import *
from backend.models.access_control_model import *
from backend.models.room_model import *
from backend.models.virtual_command_model import *

View File

@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
"""
Models for lecture recorder
"""
import json
from sqlalchemy import MetaData, CheckConstraint
from sqlalchemy.exc import IntegrityError
from datetime import datetime, timedelta
from backend import db, app, login_manager
from backend.tools.scrape_rooms import scrape_rooms
metadata = MetaData()
class AccessControlEntry(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)
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"),)
def __init__(self, **kwargs):
super(AccessControlEntry, self).__init__(**kwargs)
@staticmethod
def get_by_name(name):
"""
Find ace by name
:param name:
:return:
"""
return AccessControlEntry.query.filter(AccessControlEntry.name == name).first()
@staticmethod
def get_all():
"""
Return all ace
:return:
"""
return AccessControlEntry.query.all()
def __str__(self):
return self.name
def to_dict(self):
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
)
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
]
try:
db.session.bulk_save_objects(access_entries)
db.session.commit()
except IntegrityError as e:
db.session.rollback()

View File

@@ -7,9 +7,18 @@ class ExampleDataItem(db.Model):
""" """
just an example class... just an example class...
""" """
id = db.Column(db.Integer, primary_key=True, autoincrement=True) id = db.Column(db.Integer, primary_key=True, autoincrement=True)
mac = db.Column(db.String(32), nullable=False, unique=True, index=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) 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) description = db.Column(db.String(4096), nullable=True, unique=False)

View File

@@ -0,0 +1,301 @@
{
"recorders": [
{
"name": "CS 10.91 Grashof-Hoersaal",
"building": "10.91",
"room": "Grashof",
"username": "admin",
"password": "smpgrashof",
"ip": "129.13.51.114",
"mac": "00:05:A6:1A:4E:4B",
"type": "SMP 351",
"additional_camera": true,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"SMP 351 + LL\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 30.41 Chemie-Hoersaal Nr. 1",
"building": "30.41",
"room": "Chemie - Hörsaal 1",
"username": "admin",
"password": "smphs1",
"ip": "129.13.51.118",
"mac": "00:05:A6:1C:07:27",
"type": "SMP 351",
"additional_camera": false,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"SMP 351 + LL\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 30.41 Chemie-Hoersaal Nr. 2",
"building": "30.41",
"room": "Chemie - Hörsaal 2",
"username": "admin",
"password": "smphs2",
"ip": "129.13.51.117",
"mac": "00:05:A6:1C:07:00",
"type": "SMP 351",
"additional_camera": false,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"SMP 351 + LL\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 30.41 Rudolf-Criegee-Hoersaal",
"building": "30.41",
"room": "Rudolf-Criegee-Hörsaal (HS4)",
"username": "admin",
"password": "smphs4",
"ip": "129.13.51.116",
"mac": "00:05:A6:1C:06:CB",
"type": "SMP 351",
"additional_camera": true,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"SMP 351 + LL\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 30.41 Chemie-Hoersaal Nr. 3",
"building": "30.41",
"room": "Chemie-Hörsaal Nr. 3 (HS3)",
"username": "admin",
"password": "smphs3",
"ip": "129.13.51.115",
"mac": "00:05:A6:1C:07:0A",
"type": "SMP 351",
"additional_camera": true,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"SMP 351 + LL\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 10.91 Redtenbacher-Hoersaal",
"building": "10.91",
"room": "Redtenbacher-Hörsaal",
"username": "admin",
"password": "smpredtenbacher",
"ip": "129.13.51.113",
"mac": "00:05:A6:1C:06:F5",
"type": "SMP 351",
"additional_camera": true,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"SMP 351 + LL\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 10.50 Bauingenieure Grosser Hoersaal",
"building": "10.50",
"room": "Grosser Hörsaal Bauingenieure",
"username": "admin",
"password": "smpgrosserhs",
"ip": "129.13.51.101",
"mac": "",
"type": "SMP 351",
"additional_camera": false,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"SMP 351 \\u2013SDI Eingang (Channel B) / ZML \\u2013 Axel\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 30.95 Forum Hoersaal Audimax",
"building": "30.95",
"room": "Audimax",
"username": "admin",
"password": "audimaxsmp",
"ip": "129.13.51.102",
"mac": "00-05-A6-11-E2-6D",
"type": "SMP 351",
"additional_camera": false,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"SMP 351 \", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 30.46 Chemie Neuer Hoersaal",
"building": "30.46",
"room": "Chemie Neuer Hörsaal",
"username": "admin",
"password": "smpchemie",
"ip": "129.13.51.103",
"mac": "00-05-A6-12-CE-E0",
"type": "SMP 351",
"additional_camera": true,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 30.10 Nachrichtentechnik-Hoersaal NTI",
"building": "30.10",
"room": "Nachrichtentechnik-Hörsaal (NTI)",
"username": "admin",
"password": "smpnti",
"ip": "129.13.51.104",
"mac": "00-05-A6-12-6A-C9",
"type": "SMP 351",
"additional_camera": true,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 40.50 EBI Hoersaal",
"building": "40.50",
"room": "EBI Hörsaal",
"username": "admin",
"password": "smpebi",
"ip": "129.13.51.105",
"mac": "00-05-A6-14-77-E6",
"type": "SMP 351",
"additional_camera": true,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 40.40 Hoersaal Sport",
"building": "40.40",
"room": "Hörsaal Sport (R007)",
"username": "admin",
"password": "smpsport",
"ip": "129.13.51.111",
"mac": "00:05:A6:1A:4E:61",
"type": "SMP 351",
"additional_camera": false,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 30.34 Lichttechnik-Hoersaal",
"building": "30.34",
"room": "Lichttechnik-Hörsaal (LTI)",
"username": "admin",
"password": "smplti",
"ip": "129.13.51.112",
"mac": "00:05:A6:1A:4E:69",
"type": "SMP 351",
"additional_camera": false,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 11.40 Johann-Gottfried-Tulla-Hoersaal",
"building": "11.40",
"room": "Tulla Hörsaal",
"username": "admin",
"password": "smptulla",
"ip": "129.13.51.106",
"mac": "00-05-A6-14-D6-47",
"type": "SMP 351",
"additional_camera": true,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS",
"building": "30.22",
"room": "Otto-Lehmann-Hörsaal (Mittl. HS)",
"username": "admin",
"password": "smplehmann",
"ip": "129.13.51.107",
"mac": "00-05-A6-14-DD-0D",
"type": "SMP 352",
"additional_camera": false,
"firmware_version": "3.04",
"description": "{\"comment\": \"2 Projektionen \", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 30.22 Gaede-Hoersaal",
"building": "30.22",
"room": "Gaede Hörsaal",
"username": "admin",
"password": "smpgaede",
"ip": "129.13.51.108",
"mac": "00-05-A6-17-EF-5F",
"type": "SMP351 + DLL",
"additional_camera": false,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"2 Projektionen \", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 10.11 Hertz-Hoersaal",
"building": "10.11",
"room": "Hertz - Hörsaal",
"username": "admin",
"password": "smphertz",
"ip": "129.13.51.109",
"mac": "00-05-A6-18-41-C7",
"type": "SMP 351",
"additional_camera": true,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CO 70.04 Raum 219",
"building": "70.04",
"room": "70.04 FAST, Raum 219",
"username": "admin",
"password": "7004sr219smp",
"ip": "129.13.51.110",
"mac": "00-05-A6-18-41-C2",
"type": "SMP 351",
"additional_camera": false,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"FAST Gauterin\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 30.21 Gerthsen-Hoersaal",
"building": "30.21",
"room": "Gerthsen-Hörsaal",
"username": "admin",
"password": "smpgerthsen",
"ip": "129.13.51.119",
"mac": "00-05-A6-1D-66-DF",
"type": "SMP351 + DLL",
"additional_camera": true,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"1+2 Projektionen \", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 10.21 Gottlieb-Daimler-Hoersaal",
"building": "10.21",
"room": "Gottlieb-Daimler-Hörsaal",
"username": "admin",
"password": "smpdaimler",
"ip": "129.13.51.99",
"mac": "00-05-A6-20-13-5D",
"type": "SMP351 + DLL",
"additional_camera": true,
"firmware_version": "3.06",
"description": "{\"comment\": \"\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 10.21 Carl-Benz-Hoersaal",
"building": "10.21",
"room": "Carl-Benz-Hörsaal",
"username": "admin",
"password": "smpbenz",
"ip": "129.13.51.100",
"mac": "00-05-A6-20-13-57",
"type": "SMP351 + DLL",
"additional_camera": true,
"firmware_version": "3.06",
"description": "{\"comment\": \"\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "Opencast-qa: Test-SMP KIT",
"building": "30.50",
"room": "Test-SMP",
"username": "admin",
"password": "123mzsmp",
"ip": "172.22.246.207",
"mac": "00-05-A6-16-A3-E4",
"type": "SMP352",
"additional_camera": false,
"firmware_version": "3.05b002",
"description": "{\"comment\": \"von FM\", \"network_port\": \"MZ\", \"rsync_name\": \"\"}"
}
],
"types": {
"smp": {
"protocol": "telnet",
"port": 23
},
"epiphan": {
"protocol": "http",
"port": 80
}
}
}

View File

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

View File

@@ -0,0 +1,271 @@
# -*- coding: utf-8 -*-
"""
Models for lecture recorder
"""
import importlib
import ipaddress
import json
import pkgutil
import os
import re
from sqlalchemy import MetaData
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import validates
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,
)
metadata = MetaData()
class RecorderModel(db.Model):
__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)
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")
@staticmethod
def get_all():
return RecorderModel.query.all()
@staticmethod
def get_by_name(name):
return RecorderModel.query.filter(RecorderModel.model_name == name).first()
@staticmethod
def get_by_adapter_id(name):
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()
@staticmethod
def get_by_checksum(md5_sum):
return RecorderModel.query.filter(RecorderModel.checksum == md5_sum).first()
@hybrid_property
def requires_username(self):
return self._requires_user > 0
@requires_username.setter
def requires_username(self, val: bool):
self._requires_user = 1 if val else 0
@hybrid_property
def requires_password(self):
return self._requires_password > 0
@requires_password.setter
def requires_password(self, val: bool):
self._requires_password = 1 if val else 0
def __str__(self):
return self.model_name + " (record adapter: {})".format(self.record_adapter_id)
class Recorder(db.Model):
__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()
)
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)
locked = db.Column(db.Boolean, default=False) # no modifications allowed
lock_message = db.Column(db.String, nullable=True, default=None)
offline = db.Column(db.Boolean, default=False) # maintenance, etc.
description = db.Column(db.Unicode(255), unique=False, nullable=True, default="")
_mac = db.Column(db.String(17), unique=True, nullable=True)
_ip = db.Column(db.String(15), unique=True, nullable=True, default=None)
_ip6 = db.Column(db.String(46), unique=True, nullable=True, default=None)
network_name = db.Column(db.String(127), unique=True, nullable=True, default=None)
telnet_port = db.Column(db.Integer, unique=False, nullable=False, default=23)
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="")
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",
)
def __init__(self, **kwargs):
super(Recorder, self).__init__(**kwargs)
@staticmethod
def get_by_name(name):
return Recorder.query.filter(Recorder.name == name).first()
@staticmethod
def get_by_identifier(identifier):
return Recorder.query.filter(Recorder.id == identifier).first()
@staticmethod
def get_by_mac(mac: str):
if mac is None or mac == "":
return None
mac = mac.replace("-", ":").lower()
return Recorder.query.filter(Recorder._mac == mac).first()
@staticmethod
def get_all():
return Recorder.query.all()
@validates("name")
def validate_name(self, key, value):
assert len(value) > 2
return value
@hybrid_property
def configured_options(self) -> list:
return json.loads(self._configured_options_json_string)
@configured_options.setter
def configured_options(self, value: list):
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)
)
@hybrid_property
def additional_notes(self) -> list:
return json.loads(self._additional_notes_json_string)
@additional_notes.setter
def additional_notes(self, value: list):
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)
)
@hybrid_property
def mac(self) -> str:
return self._mac.upper()
@mac.setter
def mac(self, value: str):
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()
else:
raise LrcException("'{}' is not a valid MAC Address!".format(value))
@hybrid_property
def ip(self) -> str:
return self._ip
@ip.setter
def ip(self, value: str):
try:
ipaddress.IPv4Interface(value)
self._ip = value
except (ipaddress.AddressValueError, ipaddress.NetmaskValueError):
raise LrcException("'{}' is not a valid IPv4 Address!".format(value))
@hybrid_property
def ip6(self) -> str:
return self._ip6
@ip6.setter
def ip6(self, value: str):
try:
ipaddress.IPv6Interface(value)
self._ip6 = value
except (ipaddress.AddressValueError, ipaddress.NetmaskValueError):
raise LrcException("'{}' is not a valid IPv6 Address!".format(value))
# handle bad ip
def __str__(self):
return self.name
def to_dict(self):
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
)
class RecorderCommand(db.Model):
__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()
)
name = db.Column(db.Unicode(63), unique=True, nullable=False)
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",
)
@staticmethod
def get_all():
return RecorderCommand.query.all()
@property
def parameters(self):
if self.parameters_string is None:
return None
return json.loads(self.parameters_string)
@parameters.setter
def parameters(self, parameters_dict: dict):
self.parameters_string = json.dumps(parameters_dict)

View File

@@ -0,0 +1,101 @@
# -*- coding: utf-8 -*-
"""
Models for lecture recorder
"""
import json
import logging
from sqlalchemy import MetaData, CheckConstraint
from sqlalchemy.exc import IntegrityError
from datetime import datetime
from backend import db
from backend.models.recorder_model import Recorder
from backend.tools.scrape_rooms import scrape_rooms
logger = logging.getLogger("lrc." + __name__)
metadata = MetaData()
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
)
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)
__table_args__ = (CheckConstraint("length(name) > 2", name="name_min_length"),)
def __init__(self, **kwargs):
db.Model.__init__(self, **kwargs)
@staticmethod
def get_by_name(name):
"""
Find group by name
:param name:
:return:
"""
return Room.query.filter(Room.name == name).first()
@staticmethod
def get_by_building_number(building_number):
"""
Find group by name
:param name:
:return:
"""
return Room.query.filter(Room.building_number == building_number)
@staticmethod
def get_all():
"""
Return all rooms
:return:
"""
return Room.query.all()
def __str__(self):
return self.name
def to_dict(self):
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
)
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
]
try:
db.session.bulk_save_objects(db_rooms)
db.session.commit()
logger.debug("rooms commited to DB!")
except IntegrityError as e:
logger.error("Could not add rooms! ({})".format(e))
db.session.rollback()

View File

@@ -0,0 +1,565 @@
# -*- coding: utf-8 -*-
"""
Example user model and related models
"""
import json
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
import re
import jwt
from flask_login import UserMixin
from sqlalchemy import or_, event
from datetime import datetime, timedelta
from passlib.hash import sha256_crypt
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")),
)
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,
),
)
# 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,
),
)
# 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,
),
)
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)
first_name = db.Column(db.Unicode(63), index=True, nullable=True)
last_name = db.Column(db.Unicode(63), index=True, nullable=True)
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")
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"
)
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",
)
favorite_recorders = db.relationship(
Recorder, secondary=user_favorite_recorders_table
)
def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
password = kwargs.get("password", None)
external_user = kwargs.get("external_user", None)
if password is not None:
self.password = sha256_crypt.encrypt(password)
if external_user is not None:
self.external_user = external_user
@staticmethod
@login_manager.user_loader
def get_by_identifier(identifier):
"""
Find user by identifier, which might be the nickname or the e-mail address.
:param identifier:
:return:
"""
return User.query.filter(
or_(
User.nickname == identifier,
User.email == identifier,
User.id == identifier,
)
).first()
@staticmethod
@login_manager.user_loader
def get_by_id(identifier):
"""
Find user by ID.
:param identifier:
:return:
"""
return User.query.filter(User.id == identifier).first()
@staticmethod
def get_all():
"""
Return all users
:return:
"""
return User.query.all()
@staticmethod
def make_unique_nickname(nickname):
"""
Add suffix (counter) to nickname in order to get a unique nickname.
:param nickname:
:return:
"""
if User.query.filter_by(nickname=nickname).first() is None:
return nickname
version = 2
while True:
new_nickname = nickname + str(version)
if User.query.filter_by(nickname=new_nickname).first() is None:
break
version += 1
return new_nickname
@staticmethod
def make_valid_nickname(nickname):
"""
Replaces certain characters (except a-zA-Z0-9_.) in nickname with blancs.
:param nickname:
:return:
"""
return re.sub("[^a-zA-Z0-9_.]", "", nickname)
@classmethod
def authenticate(cls, **kwargs):
email = kwargs.get("email")
password = kwargs.get("password")
if not email or not password:
return None
user = cls.query.filter_by(email=email).first()
if not user or not user.verify_password(password):
return None
return user
@property
def is_authenticated(self):
"""
Returns true if user is authenticated.
:return:
"""
# TODO: implement correctly
return True
@property
def is_active(self):
"""
Returns true if user is active.
:return:
"""
# TODO: implement correctly
return True
@property
def is_anonymous(self):
"""
Returns true if user is anonymous.
:return:
"""
# TODO: implement correctly
return False
@property
def is_read_only(self):
"""
Returns true if user is active.
:return:
"""
# TODO: implement correctly
return True
@property
def effective_permissions(self):
permissions = Config.ROLE_PERMISSION_MAPPINGS.get(self.role, [])
for g in self.groups:
print(g)
for p in g.permissions:
print(p)
permissions.append(p)
return permissions
@staticmethod
def decode_auth_token(auth_token):
"""
Decodes the auth token
:param auth_token:
:return: integer|string
"""
try:
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."
else:
return payload["sub"]
except jwt.ExpiredSignatureError:
return "Signature expired. Please log in again."
except jwt.InvalidTokenError:
return "Invalid token. Please log in again."
def encode_auth_token(self):
"""
Generates the Auth Token
:return: string
"""
try:
payload = {
"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")
except Exception as e:
return e
def set_password(self, password):
"""
SHA256 encrypts the given password and sets it on the user.
:param password:
:return:
"""
self.password = sha256_crypt.encrypt(password)
def verify_password(self, password):
"""
Verifies that the given password matches the SHA256 encrypted password stored on the user.
:param password:
:return:
"""
if self.password is None:
return False
return sha256_crypt.verify(password, self.password)
def get_id(self):
"""
Returns the ID of the user.
:return:
"""
try:
# noinspection PyUnresolvedReferences
return unicode(self.id) # python 2
except NameError:
return str(self.id) # python 3
def avatar(self, size):
"""
Returns an avatar URL.
:param size:
:return:
"""
return "https://s.gravatar.com/avatar/%s?d=mm&s=%d" % (
md5(self.email.encode("utf-8")).hexdigest(),
size,
)
def acquaint(self, user):
"""
Adds an acquaintance to the user object.
:param user:
:return:
"""
if not self.is_acquainted(user):
self.acquainted.append(user)
return self
def unacquaint(self, user):
"""
Removes the user from the list of acquaintances.
:param user:
:return:
"""
if self.is_acquainted(user):
self.acquainted.remove(user)
return self
def is_acquainted(self, user):
"""
Check if the provided user is an acquaintance.
:param user:
:return:
"""
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())
)
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())
)
def follow(self, user):
"""
Add user to list of followers.
:param user:
:return:
"""
if not self.is_following(user):
self.followed.append(user)
return self
def unfollow(self, user):
"""
Remove user from the list of followers.
:param user:
:return:
"""
if self.is_following(user):
self.followed.remove(user)
return self
def is_following(self, user):
"""
Checks if specified user is a follower.
:param user:
:return:
"""
return self.followed.filter(followers.c.followed_id == user.id).count() > 0
def followed_posts(self):
"""
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())
)
def to_dict(self):
# return self.__dict__
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
)
def __repr__(self):
return "<User %r>" % self.email
class BlacklistToken(db.Model):
"""
Token Model for storing JWT tokens
"""
__tablename__ = "blacklist_tokens"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
token = db.Column(db.String(500), unique=True, nullable=False)
blacklisted_on = db.Column(db.DateTime, nullable=False)
def __init__(self, token):
self.token = token
self.blacklisted_on = datetime.now()
def __repr__(self):
return "<id: token: {}".format(self.token)
@staticmethod
def get_by_token(jwt_id):
return BlacklistToken.query.filter(BlacklistToken.token == jwt_id).first()
@staticmethod
def check_blacklist(auth_token):
"""
check whether auth token has been blacklisted
:param auth_token:
:return:
"""
res = BlacklistToken.query.filter_by(token=str(auth_token)).first()
if res:
return True
else:
return False
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"
)
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
def get_by_name(name):
"""
Find group by name
:param name:
:return:
"""
return Group.query.filter(Group.name == name).first()
@staticmethod
def get_all():
"""
Return all groups
:return:
"""
return Group.query.all()
def __str__(self):
return self.name
def to_dict(self):
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
)
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"
)
@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(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

@@ -0,0 +1,113 @@
import json
from datetime import datetime
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import backref
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,
),
)
# 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,
),
)
class VirtualCommand(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(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",
)
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])
)
command_order_string = db.Column(db.String)
def __init__(self, **kwargs):
super(VirtualCommand, self).__init__(**kwargs)
@staticmethod
def get_by_name(name):
"""
Find group by name
:param name:
:return:
"""
return VirtualCommand.query.filter(VirtualCommand.name == name).first()
@staticmethod
def get_all():
"""
Return all groups
:return:
"""
return VirtualCommand.query.all()
@hybrid_property
def command_order(self):
if self.command_order_string is None:
return []
return json.loads(self.command_order_string)
@command_order.setter
def command_order(self, ordered_list_of_commands: list):
self.command_order_string = json.dumps(ordered_list_of_commands)
def __str__(self):
return self.name
def to_dict(self):
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
)

View File

@@ -0,0 +1,178 @@
import importlib
import inspect
import pkgutil
import sys
import telnetlib
from abc import ABC, abstractmethod
defined_recorder_adapters = None
# monkey patching of telnet lib
from pprint import pprint
original_read_until = telnetlib.Telnet.read_until
original_write = telnetlib.Telnet.write
def new_read_until(self, match, timeout=None):
if isinstance(match, str):
return original_read_until(self, match.encode("ascii"), timeout)
else:
return original_read_until(self, match, timeout)
def new_write(self, buffer):
if isinstance(buffer, str):
return original_write(self, buffer.encode("ascii"))
else:
return original_write(self, buffer)
telnetlib.Telnet.read_until = new_read_until
telnetlib.Telnet.write = new_write
def read_line(self, timeout=2):
return self.read_until("\n", timeout)
telnetlib.Telnet.read_line = read_line
def read_until_non_empty_line(self):
line = self.read_line()
if line is None:
return None
while len(line.rstrip()) <= 0:
line = self.read_line()
return line
telnetlib.Telnet.read_until_non_empty_line = read_until_non_empty_line
def assert_string_in_output(self, string, timeout=2):
resp = self.read_until(string, timeout)
if resp is None:
return False, resp,
resp = resp.decode("ascii")
if string in resp:
return True, resp
return False, resp
telnetlib.Telnet.assert_string_in_output = assert_string_in_output
class TelnetAdapter(ABC):
def __init__(self, address, esc_char="W"):
self.address = address
self.tn = None
self.esc_char = esc_char
@abstractmethod
def _login(self):
pass
def _run_cmd(self, cmd, timeout=1, auto_connect=True):
if self.tn is None and not auto_connect:
raise LrcException("Not connected!")
elif self.tn is None:
self._login()
self.tn.write(cmd)
out = self.tn.read_until_non_empty_line()
res = out
while out is not None and out != "":
out = self.tn.read_until_non_empty_line()
print(out)
res += out
return res
@staticmethod
def _get_response_str(tn_response):
if isinstance(tn_response, bytes):
return str(tn_response.decode("ascii").rstrip())
else:
return str(tn_response).rstrip()
class RecorderAdapter:
def __init__(self, address: str, user: str, password: str):
self.address = address
self.user = user
self.password = password
@classmethod
@abstractmethod
def get_recorder_params(cls) -> dict:
pass
@abstractmethod
def _get_name(self):
pass
@abstractmethod
def _get_version(self):
pass
@abstractmethod
def is_recording(self) -> bool:
pass
def get_recording_status(self) -> str:
pass
def get_defined_recorder_adapters() -> list:
rec_adapters_module = importlib.import_module(".recorder_adapters", package='backend')
rec_adapter_class = getattr(rec_adapters_module, "RecorderAdapter") # needed, otherwise subclass check may fail
models = []
found_packages = list(pkgutil.iter_modules(rec_adapters_module.__path__))
for f_p in found_packages:
importer = f_p[0]
rec_model_module = importer.find_module(f_p[1]).load_module(f_p[1])
rec_model = {'id': f_p[1], 'name': f_p[1], 'commands': {}, 'path': rec_model_module.__file__}
if hasattr(rec_model_module, 'RECORDER_MODEL_NAME'):
rec_model['name'] = rec_model_module.RECORDER_MODEL_NAME
if hasattr(rec_model_module, 'REQUIRES_USER'):
rec_model['requires_user'] = rec_model_module.REQUIRES_USER
if hasattr(rec_model_module, 'REQUIRES_PW'):
rec_model['requires_password'] = rec_model_module.REQUIRES_PW
for name, obj in inspect.getmembers(rec_model_module, inspect.isclass):
if issubclass(obj, rec_adapter_class) and name != "RecorderAdapter":
rec_model['id'] = rec_model['id'] + "." + obj.__name__
rec_model['class'] = obj
commands = {}
for method_name, method in inspect.getmembers(obj, predicate=inspect.isfunction):
if len(method_name) > 0 and "_" == method_name[0]:
continue
signature = inspect.signature(method)
parameters = {}
for params in signature.parameters:
if params == "self":
continue
param_type = signature.parameters[params].annotation.__name__
param_type = "_unknown_type" if param_type == "_empty" else param_type
parameters[signature.parameters[params].name] = param_type
if len(parameters) <= 0:
parameters = None
commands[method_name] = parameters
rec_model["commands"] = commands
models.append(rec_model)
return models
def get_recorder_adapter_by_id(id: str, **kwargs):
global defined_recorder_adapters
if defined_recorder_adapters is None:
defined_recorder_adapters = get_defined_recorder_adapters()
for rec_adapter in defined_recorder_adapters:
if id in rec_adapter.get('id', '').split("."):
return rec_adapter['class'](**kwargs)
return None
if __name__ == '__main__':
print(get_defined_recorder_adapters())
get_recorder_adapter_by_id('SMP35x', address="172.22.246.207", password="123mzsmp")
exit()

View File

@@ -0,0 +1,164 @@
# Copyright (c) 2019. Tobias Kurze
"""
This is the recorder adapter implementation for Epiphan Recorders. The following Epiphan recorder models are supported:
- LectureRecorder X2
- LectureRecorder
- VGADVI Recorder
- DVI Broadcaster DL
- DVIRecorderDL
"""
import shutil
import time
from datetime import datetime
from pprint import pprint
import requests
from requests.auth import HTTPBasicAuth
from requests.exceptions import ConnectionError
from backend import LrcException
from backend.recorder_adapters import RecorderAdapter
# HOST = "localhost"
from backend.tools.exception_decorator import exception_decorator
RECORDER_MODEL_NAME = "Epiphan Recorder Adapter (for: LectureRecorder X2, LectureRecorder, VGADVI Recorder, " \
"DVI Broadcaster DL and DVIRecorderDL)"
BASE_URL = "http://172.23.8.102" # Audimax SMP 351
USER = "admin"
PW = "lrgrashof+-"
class Epiphan(RecorderAdapter):
def __init__(self, address: str, user: str, password: str, firmware_version: str = "", **kwargs):
if not address.startswith('http'):
address = 'http://' + address
super().__init__(address, user, password)
self.firmware_version = firmware_version
self.session = requests.Session()
self.session.auth = HTTPBasicAuth(self.user, self.password)
@classmethod
def get_recorder_params(cls) -> dict:
return {'_requires_user': True,
'_requires_password': True}
def _get_name(self):
return RECORDER_MODEL_NAME
def _get_version(self):
pass
@exception_decorator(ConnectionError)
def get_recording_status(self) -> dict:
res = self.session.get(self.address + "/admin/ajax/recorder_status.cgi")
if res.ok:
return res.json()
raise LrcException(res.text, res.status_code)
@exception_decorator(ConnectionError)
def get_sysinfo(self) -> dict:
res = self.session.get(self.address + "/ajax/sysinfo.cgi")
if res.ok:
return res.json()
raise LrcException(res.text, res.status_code)
def is_recording(self) -> bool:
state = self.get_recording_status().get('state', None)
return state == "up"
def get_recording_time(self):
"""
Returns recording time in seconds. Also returns 0 if not recording.
:return:
"""
return self.get_recording_status().get('seconds', None)
def start_recording(self):
res = self.session.get(self.address + "/admin/ajax/start_recorder.cgi")
if not res.ok:
raise LrcException(res.text, res.status_code)
time.sleep(2) # just a little bit of waiting time -> it takes a bit for the Epiphan to update its state
def stop_recording(self):
res = self.session.get(self.address + "/admin/ajax/stop_recorder.cgi")
if not res.ok:
raise LrcException(res.text, res.status_code)
time.sleep(4) # just a little bit of waiting time -> it takes a bit for the Epiphan to update its state
def get_ip_address(self):
try:
return self.get_sysinfo().get("system").get("network").get("interfaces")[0].get('ipaddr', None)
except Exception as err:
raise LrcException(str(err))
def get_disk_space(self):
try:
data = self.get_sysinfo().get("system").get("data")
return {'available': data.get("available", None), 'free': data.get("free", None),
'total': data.get("total", None), 'used': data.get("total", 0) - data.get("available", 0)}
except Exception as err:
raise LrcException(str(err))
def get_video_inputs(self) -> list:
ret = []
try:
video = self.get_sysinfo().get("inputs").get("video")
for v in video:
ret.append(
{'id': v.get('id', None), 'name': v.get('name', None), 'resolution': v.get('resolution', None)})
return ret
except Exception as err:
raise LrcException(str(err))
def get_hardware_revision(self):
try:
return self.get_sysinfo().get("system").get("firmware")
except Exception as err:
raise LrcException(str(err))
def get_system_time(self):
try:
time_stamp = self.get_sysinfo().get("time")
return {'unix_time_stamp': time_stamp,
'date_time_utc': datetime.utcfromtimestamp(time_stamp).strftime('%Y-%m-%dT%H:%M:%SZ')}
except Exception as err:
raise LrcException(str(err))
def get_screenshot(self):
ret = self.session.get(self.address + "/admin/grab_frame.cgi?size=256x192&device=DAV93133.vga&_t=1573471990578",
stream=True)
print(ret)
pprint(ret.headers)
with open('out.jpg', 'wb') as out_file:
shutil.copyfileobj(ret.raw, out_file)
del ret
if __name__ == '__main__':
e = Epiphan(BASE_URL, USER, PW)
try:
# print(e.is_recording())
"""
if e.is_recording():
e.stop_recording()
else:
e.start_recording()
print(e.is_recording())
"""
"""
print(e.get_ip_address())
print(e.get_disk_space())
print(e.get_video_inputs())
print(e.get_hardware_revision())
print(e.get_system_time())
"""
e.get_screenshot()
except LrcException as e:
print(e)

File diff suppressed because it is too large Load Diff

77
backend/serve_frontend.py Normal file
View File

@@ -0,0 +1,77 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import flask
from flask.json import dump
from jose import jwt, jwk
import os
from flask import render_template, send_from_directory, Blueprint, jsonify, url_for
from flask_pyoidc.user_session import UserSession
from backend import app
from backend.auth import oidc_auth
fe_path = os.path.abspath(os.path.join(app.root_path, os.pardir, os.pardir, "frontend", "dist"))
if not os.path.exists(fe_path) or not os.path.exists(os.path.join(fe_path, "index.html")):
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("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, ""))
@fe_bp.route('/js/<path:path>')
def send_js(path):
return send_from_directory(os.path.join(fe_path, "js"), path)
@fe_bp.route('/css/<path:path>')
def send_css(path):
return send_from_directory(os.path.join(fe_path, "css"), path)
@fe_bp.route('/img/<path:path>')
def send_img(path):
return send_from_directory(os.path.join(fe_path, "img"), path)
@fe_bp.route('/test')
@oidc_auth.oidc_auth()
def test_oidc():
user_session = UserSession(flask.session)
access_token = user_session.access_token
token_claim = jwt.get_unverified_claims(access_token)
token_header = jwt.get_unverified_header(access_token)
return jsonify(id_token=flask.session['id_token'], access_token=flask.session['access_token'],
userinfo=flask.session['userinfo'],
token_claim=token_claim,
token_header=token_header)
def has_no_empty_params(rule):
defaults = rule.defaults if rule.defaults is not None else ()
arguments = rule.arguments if rule.arguments is not None else ()
return len(defaults) >= len(arguments)
@fe_bp.route("/site-map")
def site_map():
print("# serving site-map!!")
links = []
for rule in app.url_map.iter_rules():
# Filter out rules we can't navigate to in a browser
# and rules that require parameters
if has_no_empty_params(rule):
# if "GET" in rule.methods and has_no_empty_params(rule):
url = url_for(rule.endpoint, **(rule.defaults or {}))
links.append((url, rule.endpoint))
# links is now a list of url, endpoint tuples
# dump(links)
return jsonify(links)
@fe_bp.route('/', defaults={'path': ''})
@fe_bp.route('/<path:path>')
def catch_all(path):
return render_template("index.html")

View File

20
backend/tests/base.py Normal file
View File

@@ -0,0 +1,20 @@
from flask_testing import TestCase
from backend import app, db
class BaseTestCase(TestCase):
""" Base Tests """
def create_app(self):
app.config.from_object('backend.config.Config')
return app
def setUp(self):
db.create_all()
db.session.commit()
def tearDown(self):
db.session.remove()
db.drop_all()

View File

@@ -0,0 +1,65 @@
import getpass
import sys
from abc import ABC, abstractmethod
from backend.recorder_adapters import telnetlib
# HOST = "localhost"
# HOST = "129.13.51.102" # Audimax SMP 351
# HOST = "129.13.51.106" # Tulla SMP 351
HOST = "172.22.246.207" # Test SMP MZ
user = "admin"
pw = "123mzsmp"
def print_tn(tn_response):
if isinstance(tn_response, bytes):
print(tn_response.decode("ascii").rstrip())
else:
print(str(tn_response).rstrip())
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 = telnet_con.read_until_non_empty_line()
print(out)
res += out
return res
tn = telnetlib.Telnet(HOST)
tn.read_until("\r\nPassword:")
# password = getpass.getpass()
password = pw
tn.write(password + "\n\r")
if not tn.assert_string_in_output("Login Administrator")[0]:
print("WRONG (admin) password!! Exiting!")
exit(1)
print("OK, we have admin rights!")
tn.write("1Q\n")
# print_tn(read_line(tn))
print_tn(tn.read_until_non_empty_line())
print("test")
# print(run_cmd(tn, "I\n"))
# run_cmd(tn, "X1CERT\n")
# tn.write(chr(27)+"X1CERT")
# tn.write("WX1CERT\n")
# tn.write(chr(27)+"1BOOT")
# tn.write("W1BOOT\n")
# print_tn(tn.read_until_non_empty_line())
# tn.write("I\n")
# print_tn(tn.read_some())
# tn.write("exit\n\r".encode("ascii"))
# print_tn(tn.read_eager())

View File

@@ -0,0 +1,49 @@
import os
import unittest
from flask import current_app
from flask_testing import TestCase
from backend import app
basedir = os.path.abspath(os.path.join(os.path.abspath(app.root_path), os.pardir))
class TestDevelopmentConfig(TestCase):
def create_app(self):
app.config.from_object('backend.config.DevelopmentConfig')
return app
def test_app_is_development(self):
self.assertFalse(app.config['SECRET_KEY'] is 'you-will-never-guess')
self.assertTrue(app.config['DEBUG'] is True)
self.assertFalse(current_app is None)
self.assertTrue(
app.config['SQLALCHEMY_DATABASE_URI'] == 'sqlite:///' + os.path.join(basedir, 'app.db_debug')
)
class TestTestingConfig(TestCase):
def create_app(self):
app.config.from_object('backend.config.TestingConfig')
return app
def test_app_is_testing(self):
self.assertFalse(app.config['SECRET_KEY'] is 'you-will-never-guess')
self.assertTrue(app.config['DEBUG'])
self.assertTrue(
app.config['SQLALCHEMY_DATABASE_URI'] == 'sqlite:///' + os.path.join(basedir, 'app.db_test')
)
class TestProductionConfig(TestCase):
def create_app(self):
app.config.from_object('backend.config.Config')
return app
def test_app_is_production(self):
self.assertTrue(app.config['DEBUG'] is False)
if __name__ == '__main__':
unittest.main()

287
backend/tests/test_auth.py Normal file
View File

@@ -0,0 +1,287 @@
import unittest
import json
import time
from backend import db
from backend.models.user_model import User, BlacklistToken
from backend.tests.base import BaseTestCase
def register_user(self, email, password):
return self.client.post(
'/auth/register',
data=json.dumps(dict(
email=email,
password=password
)),
content_type='application/json',
)
class TestAuthBlueprint(BaseTestCase):
def test_registration(self):
""" Test for user registration """
with self.client:
response = register_user(self, 'joe@gmail.com', '123456')
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'success')
self.assertTrue(data['message'] == 'Successfully registered.')
self.assertTrue(data['auth_token'])
self.assertTrue(response.content_type == 'application/json')
self.assertEqual(response.status_code, 201)
def test_registered_with_already_registered_user(self):
""" Test registration with already registered email"""
user = User(email='joe@gmail.com', password='test')
db.session.add(user)
db.session.commit()
with self.client:
response = register_user(self, 'joe@gmail.com', '123456')
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'fail')
self.assertTrue(
data['message'] == 'User already exists. Please Log in.')
self.assertTrue(response.content_type == 'application/json')
self.assertEqual(response.status_code, 202)
def test_registered_user_login(self):
""" Test for login of registered-user login """
with self.client:
# user registration
resp_register = register_user(self, 'joe@gmail.com', '123456')
data_register = json.loads(resp_register.data.decode())
self.assertTrue(data_register['status'] == 'success')
self.assertTrue(
data_register['message'] == 'Successfully registered.'
)
self.assertTrue(data_register['auth_token'])
self.assertTrue(resp_register.content_type == 'application/json')
self.assertEqual(resp_register.status_code, 201)
# registered user login
response = self.client.post(
'/auth/login',
data=json.dumps(dict(
nickname='test_nick',
email='joe@gmail.com',
password='123456'
)),
content_type='application/json'
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'success')
self.assertTrue(data['message'] == 'Successfully logged in.')
self.assertTrue(data['auth_token'])
self.assertTrue(response.content_type == 'application/json')
self.assertEqual(response.status_code, 200)
def test_non_registered_user_login(self):
""" Test for login of non-registered user """
with self.client:
response = self.client.post(
'/auth/login',
data=json.dumps(dict(
nickname='test_nick',
email='joe@gmail.com',
password='123456'
)),
content_type='application/json'
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'fail')
self.assertTrue(data['message'] == 'User does not exist.')
self.assertTrue(response.content_type == 'application/json')
self.assertEqual(response.status_code, 404)
def test_user_status(self):
""" Test for user status """
with self.client:
resp_register = register_user(self, 'joe@gmail.com', '123456')
response = self.client.get(
'/auth/status',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_register.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'success')
self.assertTrue(data['data'] is not None)
self.assertTrue(data['data']['email'] == 'joe@gmail.com')
# self.assertTrue(data['data']['admin'] is 'true' or 'false')
self.assertEqual(response.status_code, 200)
def test_valid_logout(self):
""" Test for logout before token expires """
with self.client:
# user registration
resp_register = register_user(self, 'joe@gmail.com', '123456')
data_register = json.loads(resp_register.data.decode())
self.assertTrue(data_register['status'] == 'success')
self.assertTrue(
data_register['message'] == 'Successfully registered.')
self.assertTrue(data_register['auth_token'])
self.assertTrue(resp_register.content_type == 'application/json')
self.assertEqual(resp_register.status_code, 201)
# user login
resp_login = self.client.post(
'/auth/login',
data=json.dumps(dict(
email='joe@gmail.com',
password='123456'
)),
content_type='application/json'
)
data_login = json.loads(resp_login.data.decode())
self.assertTrue(data_login['status'] == 'success')
self.assertTrue(data_login['message'] == 'Successfully logged in.')
self.assertTrue(data_login['auth_token'])
self.assertTrue(resp_login.content_type == 'application/json')
self.assertEqual(resp_login.status_code, 200)
# valid token logout
response = self.client.post(
'/auth/logout',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'success')
self.assertTrue(data['message'] == 'Successfully logged out.')
self.assertEqual(response.status_code, 200)
def test_invalid_logout(self):
""" Testing logout after the token expires """
with self.client:
# user registration
resp_register = register_user(self, 'joe@gmail.com', '123456')
data_register = json.loads(resp_register.data.decode())
self.assertTrue(data_register['status'] == 'success')
self.assertTrue(
data_register['message'] == 'Successfully registered.')
self.assertTrue(data_register['auth_token'])
self.assertTrue(resp_register.content_type == 'application/json')
self.assertEqual(resp_register.status_code, 201)
# user login
resp_login = self.client.post(
'/auth/login',
data=json.dumps(dict(
email='joe@gmail.com',
password='123456'
)),
content_type='application/json'
)
data_login = json.loads(resp_login.data.decode())
self.assertTrue(data_login['status'] == 'success')
self.assertTrue(data_login['message'] == 'Successfully logged in.')
self.assertTrue(data_login['auth_token'])
self.assertTrue(resp_login.content_type == 'application/json')
self.assertEqual(resp_login.status_code, 200)
# invalid token logout
time.sleep(6)
response = self.client.post(
'/auth/logout',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
print(response.data)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'fail')
self.assertTrue(
data['message'] == 'Signature expired. Please log in again.')
self.assertEqual(response.status_code, 401)
def test_valid_blacklisted_token_logout(self):
""" Test for logout after a valid token gets blacklisted """
with self.client:
# user registration
resp_register = register_user(self, 'joe@gmail.com', '123456')
data_register = json.loads(resp_register.data.decode())
self.assertTrue(data_register['status'] == 'success')
self.assertTrue(
data_register['message'] == 'Successfully registered.')
self.assertTrue(data_register['auth_token'])
self.assertTrue(resp_register.content_type == 'application/json')
self.assertEqual(resp_register.status_code, 201)
# user login
resp_login = self.client.post(
'/auth/login',
data=json.dumps(dict(
email='joe@gmail.com',
password='123456'
)),
content_type='application/json'
)
data_login = json.loads(resp_login.data.decode())
self.assertTrue(data_login['status'] == 'success')
self.assertTrue(data_login['message'] == 'Successfully logged in.')
self.assertTrue(data_login['auth_token'])
self.assertTrue(resp_login.content_type == 'application/json')
self.assertEqual(resp_login.status_code, 200)
# blacklist a valid token
blacklist_token = BlacklistToken(
token=json.loads(resp_login.data.decode())['auth_token'])
db.session.add(blacklist_token)
db.session.commit()
# blacklisted valid token logout
response = self.client.post(
'/auth/logout',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'fail')
self.assertTrue(data['message'] == 'Token blacklisted. Please log in again.')
self.assertEqual(response.status_code, 401)
def test_valid_blacklisted_token_user(self):
""" Test for user status with a blacklisted valid token """
with self.client:
resp_register = register_user(self, 'joe@gmail.com', '123456')
# blacklist a valid token
blacklist_token = BlacklistToken(
token=json.loads(resp_register.data.decode())['auth_token'])
db.session.add(blacklist_token)
db.session.commit()
response = self.client.get(
'/auth/status',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_register.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'fail')
self.assertTrue(data['message'] == 'Token blacklisted. Please log in again.')
self.assertEqual(response.status_code, 401)
def test_user_status_malformed_bearer_token(self):
""" Test for user status with malformed bearer token"""
with self.client:
resp_register = register_user(self, 'joe@gmail.com', '123456')
response = self.client.get(
'/auth/status',
headers=dict(
Authorization='Bearer' + json.loads(
resp_register.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
self.assertTrue(data['status'] == 'fail')
self.assertTrue(data['message'] == 'Bearer token malformed.')
self.assertEqual(response.status_code, 401)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,36 @@
import unittest
from backend import db
from backend.models.user_model import User
from backend.tests.base import BaseTestCase
class TestUserModel(BaseTestCase):
def test_encode_auth_token(self):
user = User(
nickname='testheini',
email='test@test.com',
password='test'
)
db.session.add(user)
db.session.commit()
auth_token = user.encode_auth_token()
self.assertTrue(isinstance(auth_token, bytes))
def test_decode_auth_token(self):
user = User(
nickname='testheini',
email='test@test.com',
password='test'
)
db.session.add(user)
db.session.commit()
auth_token = user.encode_auth_token()
self.assertTrue(isinstance(auth_token, bytes))
self.assertTrue(User.decode_auth_token(
auth_token.decode("utf-8")) == 1)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,2 @@
# Copyright (c) 2019. Tobias Kurze, KIT

View File

@@ -0,0 +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) from e
return new_func
return decorator

17
backend/tools/helpers.py Normal file
View File

@@ -0,0 +1,17 @@
import hashlib
def calculate_md5_checksum(string_to_md5_sum: str):
return hashlib.md5(string_to_md5_sum.encode('utf-8')).hexdigest()
def file_md5(fname: str) -> str:
hash_md5 = hashlib.md5()
with open(fname, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
if __name__ == '__main__':
print(file_md5(__file__))

View File

@@ -0,0 +1,56 @@
import json
from pprint import pprint
import xlrd
MAX_CONSECUTIVE_EMPTY_ROWS_BEFORE_CANCEL = 5
file_location = "/home/tobias/tmp/Hoersaal-Rec-Liste.xlsx"
wb = xlrd.open_workbook(file_location)
sheet = wb.sheet_by_index(0)
headers = None
recorders = []
a_lot_of_empty_rows = False
consecutive_empty_rows = 0
ix = 0
while not a_lot_of_empty_rows:
try:
vals = sheet.row_values(ix)
except IndexError:
break
if len(set(vals)) == 1 and set(vals).pop() == '':
consecutive_empty_rows += 1
if consecutive_empty_rows > MAX_CONSECUTIVE_EMPTY_ROWS_BEFORE_CANCEL:
a_lot_of_empty_rows = True
else:
consecutive_empty_rows = 0
if len(set(vals)) > 5 and headers is None: # get table header
headers = {ix: vals[ix] for ix in range(0, len(vals))}
elif len(set(vals)) > 5: # regular rows
recorders.append({headers[ix]: vals[ix] for ix in range(0, len(vals))})
ix += 1
if ix >= 100:
a_lot_of_empty_rows = True
#pprint(recorders)
print(len(recorders))
nicely_formatted_recorders = []
for r in recorders:
rec = {'name': r['Opencast / CM'],
'building': r['Gebäude'],
'room': r['Hörsaal'],
'username': r['Benutzer'],
'password': r['PW'],
'ip': r['IP'],
'mac': r['MAC'],
'type': 'SMP 351' if 'SMP 351' in r['Rekorder-Typ'] else r['Rekorder-Typ'],
'additional_camera': r['Zus. Kamera'] == 'Ja',
'firmware_version': r['FW Vers.'],
'network_name': r['DNS'],
'description': json.dumps(
{'comment': r['Bemerkung'], 'network_port': r['Dosennummer'], 'rsync_name': r['Rsync-Name']})}
nicely_formatted_recorders.append(rec)
print(json.dumps(nicely_formatted_recorders))

View File

@@ -0,0 +1,192 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2019. Tobias Kurze
import hashlib
import json
import logging
import os
import re
from datetime import datetime
from json import dumps
from pprint import pprint
from sqlalchemy import and_
from sqlalchemy.exc import IntegrityError
from backend import db
from backend.models import Room
from backend.models.recorder_model import RecorderModel, RecorderCommand, Recorder
from backend.recorder_adapters import get_defined_recorder_adapters
from backend.tools.helpers import calculate_md5_checksum
logger = logging.getLogger("lrc." + __name__)
KNOWN_RECORDERS = {re.compile(r'(?P<name>SMP)[\s]*(?P<number>[\d]+)[\s]*.?[\s]*(?P<options>[\S]*)'): 'SMP',
re.compile(
r'(?P<name>LectureRecorder X2|LectureRecorder|VGADVI Recorder|DVI Broadcaster DL|DVIRecorderDL)'): 'Epiphan'}
def create_recorder_commands_for_recorder_adapter(command_definitions: dict, recorder_model: RecorderModel):
logger.debug("Received {} command definitions to create "
"for recoder model {}".format(len(command_definitions),
recorder_model.record_adapter_id))
existing_recorder_commands = RecorderCommand.query.filter(
and_(
RecorderCommand.name.in_([recorder_model.record_adapter_id + ":" + k for k in command_definitions.keys()])),
RecorderCommand.recorder_model == recorder_model)
existing_commands = set()
for existing_command in existing_recorder_commands:
existing_commands.add(existing_command.name)
args = command_definitions.get(existing_command.name)
if dumps(existing_command.parameters) != dumps(args):
logger.warning(
"The function definition {} collides with an existing definition of the same name "
"but different parameters!".format(
existing_command.name))
existing_command.last_time_modified = datetime.utcnow()
existing_command.parameters = args
db.session.commit()
for c_d in set(command_definitions.keys()) - existing_commands:
args = command_definitions.get(c_d)
# print(args)
# create new recorder command(s)
r_c = RecorderCommand(name=recorder_model.record_adapter_id + ":" + c_d, parameters=args,
recorder_model=recorder_model)
db.session.add(r_c)
db.session.flush()
db.session.commit()
def update_recorder_models_database(drop: bool = False):
if drop:
for r in RecorderModel.get_all():
db.session.delete(r)
db.session.commit()
r_as = get_defined_recorder_adapters()
for r_a in r_as:
try:
r_m = RecorderModel.get_by_adapter_id(r_a["id"])
model_checksum = calculate_md5_checksum(dumps(r_a["commands"]))
if r_m is None:
r_m = RecorderModel(record_adapter_id=r_a["id"], model_name=r_a["name"], checksum=model_checksum,
**r_a.get('class', {}).get_recorder_params())
db.session.add(r_m)
db.session.flush()
db.session.refresh(r_m)
logger.debug("Creating command definitions for rec mod adapter {}".format(r_m.record_adapter_id))
create_recorder_commands_for_recorder_adapter(r_a["commands"], r_m)
else:
if r_m.model_name != r_a["name"]:
r_m.model_name = r_a["name"]
r_m.last_time_modified = datetime.utcnow()
if model_checksum != r_m.checksum:
r_m.last_time_modified = datetime.utcnow()
r_m.checksum = model_checksum
r_m.last_checksum_change = datetime.utcnow()
logger.debug("Updating command definitions for rec mod adapter {}".format(r_m.record_adapter_id))
create_recorder_commands_for_recorder_adapter(r_a["commands"], r_m)
except IntegrityError as e:
logger.error(e)
db.session.rollback()
db.session.commit()
def get_recorder_room(rec: dict) -> Room():
rooms = Room.get_by_building_number(rec.get('building', None))
if rooms.count() <= 0:
logger.warning("Building {} unknown! Can not find room for recorder {}.".format(rec['building'], rec['name']))
return None
if rooms.count() == 1:
return rooms.first()
room_name = rec.get('room')
room_name = room_name.replace('', ' ')
for room in rooms:
if all([r_n in room.name for r_n in room_name.split()]):
return room
logger.warning("No room found for recorder {}".format(rec['name']))
def create_default_recorders():
f = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, 'models', 'initial_recorders.json'))
with open(f, 'r') as json_file:
recorders = json.load(json_file)['recorders']
for r in recorders:
type = r.get('type')
firmware_version = r.get('firmware_version', None)
room_rec_name = r.get('name')
username = r.get('username', None)
password = r.get('password', None)
mac = r.get('mac', None)
ip4 = r.get('ip', None)
additional_camera = r.get('additional_camera', False)
description = r.get('description', '')
for k_r in KNOWN_RECORDERS:
if match := k_r.search(type):
name = match.groupdict().get('name')
model_number = match.groupdict().get('number', None)
options = match.groupdict().get('options', None)
if options is not None and options != "":
options = options.split(',')
if model_number is not None:
model_name = name + " " + model_number
model_search_name = name + model_number[:-1] # just get prefix (remove last digit); SMP 35x -> 35
else:
model_name = name
model_search_name = KNOWN_RECORDERS[k_r]
rec_model = RecorderModel.get_where_adapter_id_contains(model_search_name)
rec = Recorder.get_by_mac(mac)
if rec is None:
rec = Recorder.get_by_name(room_rec_name + " Recorder")
if rec is None:
rec = Recorder()
rec.mac = mac
db.session.add(rec)
rec.name = room_rec_name + " Recorder"
rec.model_name = model_name
rec.recorder_model = rec_model
rec.username = username
rec.password = password
rec.firmware_version = firmware_version
rec.ip = ip4
rec.additional_camera_connected = additional_camera
rec.additional_note = description
rec.configured_options = options
rec.room = get_recorder_room(r)
db.session.flush()
db.session.refresh(rec)
db.session.commit()
if __name__ == '__main__':
# for r in Room.get_all():
# print(r)
# exit()
commands = RecorderCommand.get_all()
for c in commands:
print(c)
print(c.recorder_model)
for r_m in RecorderModel.get_all():
print(r_m.recorder_commands)
exit()
recorders = Recorder.get_all()
for r in recorders:
if r.room is None:
print("{}: {}".format(r, r.room))
# db.drop_all()
# db.create_all()
update_recorder_models_database()
create_default_recorders()
db.session.commit()
# print(get_recorder_room({"room": "Grosser Hörsaal Bauingenieure", "building": "10.50"}))
# print(get_recorder_room({"room": "Grosser Hörsaal Bauingenieure", "building": "30.95"}))

View File

@@ -0,0 +1,60 @@
from pprint import pprint
import re
import requests
from bs4 import BeautifulSoup
def scrape_rooms():
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
room_url = "https://campus.kit.edu/live-stud/campus/all/roomgroup.asp?roomgroupcolumn1=H%F6r%2D%2FLehrsaal&tguid=0x1A35C3A1490748388EBEBA3943EFCDD5"
page = requests.get(room_url, headers=headers)
# soup = BeautifulSoup(page.content, 'html5lib')
soup = BeautifulSoup(page.content, 'html.parser')
# pprint(page.content)
# pprint(soup.prettify())
idx = 0
rooms = []
re_string = r"^(\d\d.\d\d)?\s(.*)"
re_exp = re.compile(re_string)
for tr in soup.find_all('tr'):
idx += 1
if idx == 1: # skip first row
continue
a_name = tr.find_all('a')[0].string
a_building = tr.find_all('a')[3].string
match = re_exp.match(a_name)
if match is not None:
building_number, name = re_exp.match(a_name).groups()
else:
name = a_name
building_number = None
match = re_exp.match(a_building)
if match is not None:
building_number, building_name = re_exp.match(a_building).groups()
else:
building_name = a_name
building_number = None
room = {'name': name,
'room_number': tr.find_all('a')[1].string if tr.find_all('a')[0].string != "None" else tr.find_all('a')[
1].string,
'building_name': building_name,
'building_number': building_number}
rooms.append(room)
return rooms
if __name__ == '__main__':
pprint(scrape_rooms())

View File

@@ -0,0 +1,60 @@
import smtplib
import traceback
from email.message import EmailMessage
from logging.handlers import SMTPHandler
from typing import List, Union
from backend import 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:
print(
"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
def get_smtp_default_handler(receiver_mail_addresses=Config.ADMIN_E_MAIL_TO, subject: str = None,
subject_prefix: str = "[LRC] Log: "):
subject = subject if subject.startswith("[LRC]") else subject_prefix + subject
return SMTPHandler(Config.SMTP_SERVER, Config.FROM_MAIL, receiver_mail_addresses, subject)
def get_smtp_error_handler(receiver_mail_addresses=Config.ERROR_E_MAIL_TO, subject: str = None,
subject_prefix: str = "[LRC] Error: "):
subject = subject if subject.startswith("[LRC]") else subject_prefix + subject
return SMTPHandler(Config.SMTP_SERVER, Config.FROM_MAIL, receiver_mail_addresses, subject)

View File

@@ -0,0 +1,221 @@
import json
import os
import logging
import subprocess
import threading
from io import StringIO
from logging.handlers import MemoryHandler
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
from backend.recorder_adapters import RecorderAdapter
from backend.recorder_adapters.epiphan_base import Epiphan
from backend.recorder_adapters.extron_smp import SMP35x
from backend.tools.send_mail import send_error_mail, get_smtp_error_handler
logger = logging.getLogger("lrc.tools.simple_state_checker")
smtp_error_handler = get_smtp_error_handler(subject="Errors have been detected while checking recorder states!")
#mem_handler = MemoryHandler(capacity=100, flushLevel=logging.FATAL, target=smtp_error_handler)
#mem_handler.setLevel(logging.WARNING)
rec_err_state_log_stream = StringIO()
rec_err_state_log_stream_handler = logging.StreamHandler(stream=rec_err_state_log_stream)
rec_err_state_log_stream_handler.setLevel(logging.WARNING)
logger.addHandler(rec_err_state_log_stream_handler)
#logger.addHandler(mem_handler)
base_url = "https://oc-bib-admin.bibliothek.kit.edu"
session = requests.session()
session.auth = HTTPBasicAuth(Config.OPENCAST_USER, Config.OPENCAST_PW)
config = {'service_urls': {}}
recorders = None
agent_states_lock = threading.RLock()
agent_states = {}
def get_service_url(service_type: str):
if service_type in config['service_urls']:
return config['service_urls'][service_type]
params = {'serviceType': service_type}
url = base_url + "/services/available.json"
res = session.get(url, params=params)
if res.ok:
service = res.json()["services"]["service"]
config["service_urls"][service_type] = service["host"] + \
service["path"]
return service["host"] + service["path"]
return None
def get_calender(rec_id):
params = {'agentid': rec_id}
url = get_service_url('org.opencastproject.scheduler') + "/calendars"
res = session.get(url, params=params)
if res.ok:
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():
url = get_service_url("org.opencastproject.capture.admin") + "/agents.json"
res = session.get(url)
if res.ok:
return res.json()["agents"]["agent"]
def get_recorder_details():
"""Temporary implementation using initial_recorders.json. Should be replaced by DB layer later!"""
global recorders
if recorders is None:
f = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, 'models', 'initial_recorders.json'))
with open(f, 'r') as json_file:
recorders = json.load(json_file)['recorders']
return recorders
def get_recorder_by_name(name: str):
for r in get_recorder_details():
if r["name"] == name:
return r
return None
def notify_users_of_problem(msg: str):
pass
def get_recorder_adapter(recorder_info: dict) -> RecorderAdapter:
if "SMP" in recorder_info["type"]:
rec = SMP35x(recorder_info['ip'], recorder_info['password'])
else:
rec = Epiphan(recorder_info['ip'], recorder_info["username"], recorder_info["password"])
return rec
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():
logger.info("OK recorder {} is recording :)".format(a['name']))
with agent_states_lock:
agent_states[a['name']] = 'OK - recorder is recording'
else:
logger.info(rec.get_recording_status())
logger.error("FATAL - recorder {} must be recording but is not!!!!".format(a['name']))
with agent_states_lock:
agent_states[a['name']] = 'FATAL - recorder is NOT recording, but should!'
except LrcException as e:
logger.fatal("Exception occurred: {}".format(str(e)))
logger.error("Could not check state of recorder {}, Address: {}".format(a['name'], recorder_info['ip']))
else:
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():
logger.error("FATAL - recorder must not be recording!!!!")
with agent_states_lock:
agent_states[a['name']] = 'FATAL - recorder IS recording, but should NOT!'
else:
logger.info("OK recorder is not recording :)")
with agent_states_lock:
agent_states[a['name']] = 'OK - recorder is NOT recording'
except LrcException as e:
logger.fatal("Exception occurred: {}".format(str(e)))
logger.error("Could not check state of recorder {}, Address: {}".format(a['name'], recorder_info['ip']))
def ping_capture_agent(a: dict):
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],
# stderr=subprocess.STDOUT, # get all output
stdout=subprocess.DEVNULL, # suppress output
stderr=subprocess.DEVNULL,
universal_newlines=True # return string not bytes
)
logger.info("Successfully pinged {} ({}). :-)".format(a['name'], recorder_ip))
except subprocess.CalledProcessError:
logger.error("Can not ping {} ({})!!".format(a['name'], recorder_ip))
agents = get_capture_agents()
logger.info("Got {} capture agents that will be checked...".format(len(agents)))
for a in agents:
agent_states[a['name']] = 'PROBLEMATIC - unknown'
# pool = ThreadPool(5)
# pool.map(check_capture_agent_state, agents)
NUM_THREADS = 8
with ThreadPool(NUM_THREADS) as pool:
results = [pool.apply_async(ping_capture_agent, (agent,)) for agent in agents]
try:
[res.get(timeout=12) for res in results]
except TimeoutError as e:
logger.error("Timeout while pinging capture agent! {}".format(e))
with ThreadPool(NUM_THREADS) as pool:
results = [pool.apply_async(check_capture_agent_state, (agent,)) for agent in agents]
try:
[res.get(timeout=12) for res in results]
except TimeoutError as e:
logger.error("Timeout while getting capture agent state! {}".format(e))
logger.info("DONE checking capture agents / recorders!")
logged_events = rec_err_state_log_stream.getvalue()
if len(logged_events) > 0:
logged_events += "\n\n=============\nAgent States:\n\n{}".format(''.join(
"{:<48}: {}\n".format(a, agent_states[a]) for a in agent_states
))
send_error_mail(logged_events, "Errors have been detected while checking recorder states!")
#mem_handler.close()

View File

@@ -0,0 +1,2 @@
# Copyright (c) 2019. Tobias Kurze

59
backend/websocket/base.py Normal file
View File

@@ -0,0 +1,59 @@
import logging
import threading
from flask_login import current_user
from flask_socketio import SocketIO, emit
from backend import app
logger = logging.getLogger("lrc.websocket")
async_mode = 'threading' # set to traditional python threading model
# async_mode = None
socketio = SocketIO(app, cors_allowed_origins="*", async_mode=async_mode)
class WebSocketBase:
def __init__(self, flask_app_context=None):
if flask_app_context is None:
self.flask_app_context = app
self.socket_thread = None
def start_websocket_in_thread(self, host=None, port=None, debug=None):
self.socket_thread = threading.Thread(
target=self.start_websocket,
args=(host, port, debug))
self.socket_thread.start()
return self.socket_thread
def start_websocket(self, host=None, port=None, debug=None):
if debug is None:
debug = self.flask_app_context.debug
socketio.run(self.flask_app_context, host=host, port=port, debug=debug)
@staticmethod
@socketio.on('connect')
def connect_handler():
logger.debug("new connection...")
print(current_user)
if current_user.is_authenticated:
logger.debug("user is authenticated")
print("allowed!")
emit('my response',
{'message': '{0} has joined'.format(current_user.name)},
broadcast=True)
else:
logger.info("user is not authenticated!")
print("not allowed!!")
return False # not allowed here
@socketio.on_error()
def handle_error(self, error):
logger.error(error)
print(error)
if __name__ == '__main__':
wsb = WebSocketBase()
#wsb.start_websocket_in_thread(debug=True)
wsb.start_websocket(debug=True)

View File

@@ -0,0 +1,127 @@
# Copyright (c) 2019. Tobias Kurze
import logging
import threading
import time
from flask import Flask, request
from flask_socketio import SocketIO, emit
from backend import app
logging.basicConfig()
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
async_mode = 'threading'
async_mode = None
socketio = SocketIO(app, cors_allowed_origins="*", async_mode=async_mode)
thread = None
thread_lock = threading.Lock()
clients = []
def background_thread():
"""Example of how to send server generated events to clients."""
count = 0
while True:
socketio.sleep(3)
print("server_event ")
count += 1
socketio.emit('server_event',
{'data': 'Server generated event', 'count': count},
)
def ack():
print('message was received!')
@socketio.on('my_event')
def test_message(message: dict):
print("received msg!")
print(message)
if isinstance(message, str):
emit('my_response', 'tolle Antwort! (got only a string!)', callback=ack)
else:
emit('my_response', {'data': message['data']}, callback=ack)
@socketio.on('my broadcast event', namespace='/')
def test_message(message):
emit('my response', {'data': message['data']}, broadcast=True)
@socketio.on('connect')
def test_connect():
print("connected")
global thread
with thread_lock:
if thread is None:
thread = socketio.start_background_task(background_thread)
emit('connect', "You are connected!")
@socketio.on('disconnect', namespace='/')
def test_disconnect():
print('Client disconnected')
@socketio.on_error()
def handle_error(error):
print(error)
def start_in_thread():
socket_thread = threading.Thread(target=lambda appl, host, port: socketio.run(app=appl, host=host, port=port),
args=(app, "localhost", 5000))
socket_thread.start()
return socket_thread
@app.route("/")
def root():
return """<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
var socket = io();
socket.on('connect', function() {
console.log("connected!");
socket.emit('my_event', {data: 'I am connected!'});
});
socket.on('my_response', function(resp) {
console.log('got response:');
console.log(resp);
});
</script>"""
if __name__ == '__main__':
print("running main")
# socketio.init_app(app, cors_allowed_origins="*")
#while len(clients) <= 0:
# time.sleep(1)
#while True:
# time.sleep(2)
# print("sending message...")
# socketio.send("lala")
# print("send lala")
# print(clients[0])
# socketio.emit("server_event", {'msg': "tolle nachricht"}, room=clients[0])
# with app.test_request_context('/'):
# socketio.emit('server_event', "You!: server_event", namespace="/")
# print("send bla")
#socketio.run(app, host="localhost", port=5000, debug=True)
start_in_thread()
while True:
time.sleep(2)
print("still running! :)")
# socketio.run(app, debug=True)
# ENDE
# t.join()

View File

@@ -0,0 +1,27 @@
# Copyright (c) 2019. Tobias Kurze
import logging
import threading
import time
from flask import Flask
from flask_socketio import SocketIO, emit
from backend import app
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
logging.basicConfig()
#socketio = SocketIO(message_queue="redis://")
socketio = SocketIO(app, port=5443, debug=True)
#socketio.run(app, host="localhost", port=5000)
#socketio.init_app(app, host="localhost", port=5000, cors_allowed_origins="*", )
#socketio.init_app(app, host="localhost", port=5000, cors_allowed_origins="*", )
socketio.emit("server_event", {'data': 42, 'msg': 'toll'})
print("sent message!")
socketio.emit({'data': 42, 'msg': 'toll'})
print("sent message 2!")

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

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

620
logs/app.log.2019-11-15 Normal file
View File

@@ -0,0 +1,620 @@
[2019-11-14 14:16:53,247] {MainThread} INFO in simple_state_checker, line 136: Got 19 capture agents that will be checked...
[2019-11-14 14:16:53,255] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 14:16:53,255] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 14:16:53,256] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 14:16:53,261] {Thread-4} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 14:16:53,261] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 14:16:53,386] {Thread-4} INFO in extron_smp, line 32: Connecting to 129.13.51.101 ...
[2019-11-14 14:16:54,344] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:54,355] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 14:16:54,811] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:54,827] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 14:16:55,195] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:55,206] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 14:16:55,988] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:56,019] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 14:16:56,265] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:56,276] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 14:16:56,323] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therfor be recording... checking now!
[2019-11-14 14:16:56,365] {Thread-1} INFO in simple_state_checker, line 107: CS 10.11 Hertz-Hoersaal is in capturing state, so there should be an entry in the calendar of the recorder, right? -> True
[2019-11-14 14:16:56,380] {Thread-1} INFO in extron_smp, line 32: Connecting to 129.13.51.109 ...
[2019-11-14 14:16:57,008] {Thread-2} INFO in extron_smp, line 32: Connecting to 129.13.51.106 ...
[2019-11-14 14:16:57,095] {Thread-5} INFO in extron_smp, line 32: Connecting to 129.13.51.104 ...
[2019-11-14 14:16:57,272] {Thread-1} INFO in simple_state_checker, line 115: 1
[2019-11-14 14:16:57,283] {Thread-1} ERROR in simple_state_checker, line 116: FATAL - recorder CS 10.11 Hertz-Hoersaal must be recording but is not!!!!
[2019-11-14 14:16:57,321] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 14:16:57,530] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:57,541] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 14:16:57,744] {Thread-1} INFO in extron_smp, line 32: Connecting to 129.13.51.108 ...
[2019-11-14 14:16:57,936] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:57,952] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 14:16:57,954] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:57,965] {Thread-3} INFO in extron_smp, line 32: Connecting to 129.13.51.107 ...
[2019-11-14 14:16:57,966] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 14:16:58,634] {Thread-1} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:58,655] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 14:16:58,902] {Thread-2} INFO in extron_smp, line 32: Connecting to 129.13.51.103 ...
[2019-11-14 14:16:58,904] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:58,904] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 14:16:59,563] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:59,579] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 14:16:59,668] {Thread-3} INFO in extron_smp, line 32: Connecting to 129.13.51.105 ...
[2019-11-14 14:16:59,797] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:59,818] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 14:17:00,764] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:17:00,780] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 14:17:00,983] {Thread-3} INFO in extron_smp, line 32: Connecting to 129.13.51.110 ...
[2019-11-14 14:17:01,618] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:17:01,670] {Thread-1} INFO in extron_smp, line 32: Connecting to 129.13.51.102 ...
[2019-11-14 14:17:01,960] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:19:03,660] {Thread-4} CRITICAL in simple_state_checker, line 131: Exception occurred: LRC Exception: "[Errno 110] Connection timed out"
[2019-11-14 14:19:03,661] {Thread-4} ERROR in simple_state_checker, line 132: Could not check state of recorder CS 10.50 Bauingenieure Grosser Hoersaal, Address: 129.13.51.101
[2019-11-14 14:23:51,783] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:25:33,337] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:27:00,957] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:27:14,952] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:28:15,602] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:29:24,029] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:29:58,640] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:32:30,592] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:34:08,425] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:36:35,216] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:38:11,521] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:39:43,884] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:39:53,493] {MainThread} INFO in simple_state_checker, line 136: Got 19 capture agents that will be checked...
[2019-11-14 14:39:53,497] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 14:39:53,497] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 14:39:53,497] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 14:39:53,500] {Thread-4} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 14:39:53,500] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 14:39:53,619] {Thread-4} INFO in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 14:39:54,913] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:54,942] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 14:39:55,178] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:55,220] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 14:39:55,395] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:55,416] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 14:39:56,048] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:56,092] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therfor be recording... checking now!
[2019-11-14 14:39:56,098] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 14:39:56,108] {Thread-1} INFO in simple_state_checker, line 107: CS 10.11 Hertz-Hoersaal is in capturing state, so there should be an entry in the calendar of the recorder, right? -> True
[2019-11-14 14:39:56,127] {Thread-1} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:39:56,248] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:56,269] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 14:39:56,761] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 14:39:57,066] {Thread-1} INFO in simple_state_checker, line 113: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 14:39:57,087] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 14:39:57,545] {Thread-3} INFO in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 14:39:57,770] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:57,817] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 14:39:58,182] {Thread-1} INFO in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 14:39:58,362] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:58,378] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 14:39:58,425] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 14:39:58,599] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:58,610] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 14:39:58,950] {Thread-1} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:58,951] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 14:39:59,487] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:59,513] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 14:39:59,604] {Thread-3} INFO in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 14:39:59,908] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:59,918] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 14:40:00,356] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 14:40:00,436] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:40:00,451] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 14:40:01,582] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:40:01,608] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 14:40:01,789] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 14:40:02,326] {Thread-1} INFO in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 14:40:02,497] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:40:02,648] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:57:02,691] {MainThread} INFO in simple_state_checker, line 132: Got 19 capture agents that will be checked...
[2019-11-14 14:57:50,259] {MainThread} INFO in simple_state_checker, line 132: Got 19 capture agents that will be checked...
[2019-11-14 14:57:50,261] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 14:57:51,265] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 14:57:51,266] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:57:52,257] {Thread-1} INFO in simple_state_checker, line 109: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 14:57:52,259] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 14:57:53,279] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 14:57:53,279] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 14:57:53,873] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 14:57:53,873] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 14:57:53,892] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:02:35,956] {MainThread} INFO in simple_state_checker, line 132: Got 19 capture agents that will be checked...
[2019-11-14 15:02:35,961] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:02:35,961] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:02:35,961] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:02:35,962] {Thread-4} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:02:35,966] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:02:36,101] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:02:36,867] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:36,878] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:02:37,586] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:37,616] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:02:38,200] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:38,232] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:02:38,487] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:38,503] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:02:38,698] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:38,710] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:02:38,856] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:02:38,908] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:02:39,323] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:02:39,609] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:02:39,673] {Thread-1} INFO in simple_state_checker, line 109: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:02:39,693] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:02:40,001] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,011] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:02:40,115] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:02:40,400] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:02:40,409] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,410] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:02:40,604] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,621] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:02:40,828] {Thread-1} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,828] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:02:41,529] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:41,549] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:02:41,621] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:02:41,849] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:41,850] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:02:42,655] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:42,687] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:02:43,620] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:02:44,782] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:44,876] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:02:45,342] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:02:45,550] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:45,716] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:02:46,265] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:05:15,774] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:05:15,776] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:05:15,776] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:05:15,778] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:05:15,778] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:05:15,780] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:05:15,840] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:05:17,298] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:17,314] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:05:17,677] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:17,694] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:05:17,842] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:17,853] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:05:18,841] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:18,887] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:05:19,101] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:19,137] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:05:19,149] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:05:19,210] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:05:19,575] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:05:19,886] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:05:20,281] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:05:20,282] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:05:20,333] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:20,333] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:05:20,383] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:20,383] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:05:20,616] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:20,632] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:05:21,026] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:05:21,456] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:05:21,827] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:21,848] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:05:22,128] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:05:22,566] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:22,567] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:05:22,813] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:22,819] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:05:23,169] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:23,205] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:05:23,731] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:05:24,776] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:05:24,963] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:24,963] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:05:25,042] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:25,131] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:05:25,828] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:32,282] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:07:35,727] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:07:35,729] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:07:35,729] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:07:35,729] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:07:35,730] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:07:35,730] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:07:35,863] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:07:37,438] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:37,453] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:07:37,481] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:37,497] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:07:37,744] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:07:37,760] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:07:37,996] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:38,011] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:07:38,259] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:38,259] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:07:38,503] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:38,519] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:07:38,612] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:07:38,612] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:07:38,633] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:07:38,813] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:07:39,478] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:39,504] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:07:39,592] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:07:39,602] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:39,625] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:07:39,837] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:39,871] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:07:39,886] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:07:40,494] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:40,520] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:07:40,903] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:07:41,107] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:41,108] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:07:41,186] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:41,186] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:07:41,731] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:41,747] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:07:41,869] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:07:42,952] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:42,973] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:07:43,268] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:07:44,224] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:44,634] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:07:44,636] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:50,654] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:07:50,706] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-14 15:20:07,570] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:20:07,572] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:20:07,572] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:20:07,572] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:20:07,575] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:20:07,576] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:20:07,702] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:20:09,335] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:09,341] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:20:09,527] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:09,543] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:20:10,343] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:10,375] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:20:11,090] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:11,106] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:20:11,158] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:20:11,164] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:20:11,194] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:11,215] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:20:11,464] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:20:11,990] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:20:12,017] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:20:12,028] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:20:12,376] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:12,387] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:20:12,399] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:20:12,400] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:12,401] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:20:12,906] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:12,922] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:20:13,086] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:20:13,264] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:13,264] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:20:13,943] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:20:13,999] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:13,999] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:20:14,191] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:14,192] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:20:14,849] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:14,938] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:20:16,840] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:20:18,101] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:18,112] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:20:18,197] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:20:18,231] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:18,279] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:20:18,965] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:20,327] {Thread-1} WARNING in extron_smp, line 52: Could not login (as admin) with given password! 129.13.51.102
[2019-11-14 15:20:22,329] {Thread-1} ERROR in extron_smp, line 59: Could definitely not login (as admin) with given password! 129.13.51.102
[2019-11-14 15:20:24,046] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:20:24,118] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-14 15:41:07,178] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:41:07,180] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:41:07,180] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:41:07,180] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:41:07,180] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:41:07,180] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:41:07,312] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:41:08,619] {Thread-2} INFO in simple_state_checker, line 104: CS 10.21 Carl-Benz-Hörsaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:41:08,634] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:41:08,640] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:41:08,822] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:08,864] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:41:08,864] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:08,919] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:41:10,309] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:41:10,319] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:41:10,595] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:10,610] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:41:10,683] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:10,706] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:41:10,708] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:41:11,243] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:41:11,253] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:41:11,261] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:41:11,594] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:11,594] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:41:11,606] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:41:11,624] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:11,624] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:41:12,061] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:12,092] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:41:12,311] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:12,327] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:41:12,600] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:41:13,130] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:41:13,666] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:13,677] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:41:13,757] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:13,777] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:41:14,070] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:14,096] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:41:15,923] {Thread-1} INFO in simple_state_checker, line 104: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:41:15,944] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:41:16,093] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:41:16,804] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:16,805] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:41:16,964] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:41:17,043] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-14 15:41:17,168] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:17,905] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:23,261] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:41:23,280] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-14 15:45:17,132] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:45:17,136] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:45:17,136] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:45:17,136] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:45:17,138] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:45:17,140] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:45:17,246] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:45:18,711] {Thread-2} INFO in simple_state_checker, line 104: CS 10.21 Carl-Benz-Hörsaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:45:18,727] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:45:18,763] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:45:18,861] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:18,872] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:45:18,931] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:18,941] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:45:19,971] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:45:20,433] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:20,448] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:45:20,537] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:20,547] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:45:20,571] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:45:21,177] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:21,197] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:45:21,408] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:45:21,543] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:21,564] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:45:22,149] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:22,165] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:45:22,247] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:45:22,247] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:22,268] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:45:22,378] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:45:22,958] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:22,978] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:45:23,300] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:45:23,351] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:23,351] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:45:23,400] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:23,400] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:45:24,216] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:45:24,306] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:24,337] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:45:25,245] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:25,266] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:45:25,600] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:45:26,328] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:26,923] {Thread-1} INFO in simple_state_checker, line 104: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:45:26,923] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:45:27,178] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:27,986] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-14 15:45:33,213] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:45:33,239] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-15 09:00:02,960] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 09:00:02,962] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 09:00:02,962] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 09:00:02,963] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 09:00:02,963] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 09:00:02,963] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 09:00:03,163] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 09:00:04,443] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:04,454] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 09:00:04,925] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:04,941] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 09:00:05,486] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:05,507] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 09:00:05,732] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:05,753] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 09:00:05,807] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 09:00:06,018] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:06,028] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 09:00:06,443] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 09:00:06,557] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:06,583] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 09:00:06,654] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 09:00:07,016] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 09:00:07,028] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,028] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 09:00:07,313] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,333] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 09:00:07,435] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 09:00:07,681] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,696] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 09:00:07,847] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,848] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 09:00:08,514] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:08,514] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 09:00:08,955] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:08,970] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 09:00:09,158] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 09:00:09,479] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 09:00:10,422] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:10,443] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 09:00:10,679] {Thread-1} INFO in simple_state_checker, line 110: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-15 09:00:10,679] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 09:00:10,756] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:10,757] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 09:00:10,870] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 09:00:11,648] {Thread-1} INFO in simple_state_checker, line 116: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-15 09:00:11,726] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:11,959] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:18,601] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:00:18,945] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!
[2019-11-15 09:01:48,428] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 09:01:48,431] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 09:01:48,431] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 09:01:48,431] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 09:01:48,432] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 09:01:48,432] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 09:01:48,538] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 09:01:49,684] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:49,690] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:49,705] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 09:01:49,716] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 09:01:50,134] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 09:01:50,252] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:50,268] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 09:01:50,800] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:50,806] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 09:01:50,914] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 09:01:50,915] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:50,915] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 09:01:51,069] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:51,080] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 09:01:51,673] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:51,720] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 09:01:51,726] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 09:01:51,893] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 09:01:52,152] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 09:01:52,231] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,232] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 09:01:52,598] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,618] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,623] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 09:01:52,637] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 09:01:52,956] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,956] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 09:01:53,679] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:53,721] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 09:01:54,025] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 09:01:54,184] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 09:01:54,998] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:55,019] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 09:01:55,087] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:55,108] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 09:01:55,254] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 09:01:55,445] {Thread-3} INFO in simple_state_checker, line 110: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-15 09:01:55,445] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 09:01:55,943] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:56,200] {Thread-3} INFO in simple_state_checker, line 116: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-15 09:01:56,274] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:02:02,915] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:02:03,114] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!
[2019-11-15 09:03:16,872] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 09:03:16,875] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 09:03:16,875] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 09:03:16,875] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 09:03:16,875] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 09:03:16,875] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 09:03:16,991] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 09:03:17,901] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:17,917] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:17,917] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 09:03:17,933] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 09:03:18,497] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 09:03:18,639] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:18,655] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 09:03:19,037] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:19,047] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 09:03:19,189] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:19,210] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 09:03:19,310] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:19,329] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 09:03:19,329] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 09:03:19,638] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 09:03:20,151] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 09:03:20,331] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:20,331] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 09:03:20,462] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:20,462] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 09:03:20,494] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:20,510] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 09:03:20,633] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 09:03:21,032] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:21,053] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 09:03:21,466] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 09:03:21,730] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:21,731] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 09:03:22,061] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:22,072] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 09:03:22,445] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:22,492] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 09:03:23,370] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 09:03:24,285] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:24,306] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 09:03:24,454] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 09:03:24,681] {Thread-3} INFO in simple_state_checker, line 110: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-15 09:03:24,682] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 09:03:24,682] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:25,308] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:25,616] {Thread-3} INFO in simple_state_checker, line 116: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-15 09:03:31,225] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:03:31,461] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!
[2019-11-15 15:56:02,776] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 15:56:02,783] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 15:56:02,783] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 15:56:02,784] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 15:56:02,787] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 15:56:02,787] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 15:56:02,903] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 15:56:04,320] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:04,331] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 15:56:04,366] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:04,377] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 15:56:04,654] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:04,741] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 15:56:04,779] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 15:56:05,377] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:05,388] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 15:56:05,479] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:05,492] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 15:56:05,698] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 15:56:06,048] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:06,105] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 15:56:06,320] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 15:56:06,752] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 15:56:06,834] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:06,834] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 15:56:06,844] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:06,845] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 15:56:07,320] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:07,336] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 15:56:07,555] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 15:56:07,567] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:07,568] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 15:56:08,323] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:08,324] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 15:56:08,638] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:08,655] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 15:56:08,687] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 15:56:09,544] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 15:56:09,757] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:09,773] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 15:56:10,425] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:10,441] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 15:56:10,740] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 15:56:11,549] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:11,664] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 15:56:12,063] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:12,450] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:18,121] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 15:56:18,512] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!

View File

@@ -0,0 +1 @@
[2019-11-12 16:17:10,872] {Thread-3} ERROR in simple_state_checker, line 104: FATAL - recorder CS 30.46 Chemie Neuer Hoersaal must be recording!!!!

30
logs/error.log.2019-11-15 Normal file
View File

@@ -0,0 +1,30 @@
[2019-11-14 14:16:57,283] {Thread-1} ERROR in simple_state_checker, line 116: FATAL - recorder CS 10.11 Hertz-Hoersaal must be recording but is not!!!!
[2019-11-14 14:16:57,283] {Thread-1} ERROR in simple_state_checker, line 116: FATAL - recorder CS 10.11 Hertz-Hoersaal must be recording but is not!!!!
[2019-11-14 14:19:03,660] {Thread-4} CRITICAL in simple_state_checker, line 131: Exception occurred: LRC Exception: "[Errno 110] Connection timed out"
[2019-11-14 14:19:03,660] {Thread-4} CRITICAL in simple_state_checker, line 131: Exception occurred: LRC Exception: "[Errno 110] Connection timed out"
[2019-11-14 14:19:03,661] {Thread-4} ERROR in simple_state_checker, line 132: Could not check state of recorder CS 10.50 Bauingenieure Grosser Hoersaal, Address: 129.13.51.101
[2019-11-14 14:19:03,661] {Thread-4} ERROR in simple_state_checker, line 132: Could not check state of recorder CS 10.50 Bauingenieure Grosser Hoersaal, Address: 129.13.51.101
[2019-11-14 15:05:32,282] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:05:32,282] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:07:50,654] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:07:50,654] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:20:22,329] {Thread-1} ERROR in extron_smp, line 59: Could definitely not login (as admin) with given password! 129.13.51.102
[2019-11-14 15:20:22,329] {Thread-1} ERROR in extron_smp, line 59: Could definitely not login (as admin) with given password! 129.13.51.102
[2019-11-14 15:20:24,046] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:20:24,046] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:41:08,634] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:41:08,634] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:41:23,261] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:41:23,261] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:45:18,727] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:45:18,727] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:45:33,213] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:45:33,213] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-15 09:00:18,601] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:00:18,601] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:02:02,915] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:02:02,915] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:03:31,225] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:03:31,225] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 15:56:18,121] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 15:56:18,121] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!

68
logs/root.log.2019-11-12 Normal file
View File

@@ -0,0 +1,68 @@
[2019-11-12 16:13:10,529] {MainThread} INFO in simple_state_checker, line 83: Got 19 capture agents that will be checked...
[2019-11-12 16:15:41,995] {MainThread} INFO in simple_state_checker, line 121: Got 19 capture agents that will be checked...
[2019-11-12 16:15:41,998] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-12 16:15:41,998] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-12 16:15:41,998] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-12 16:15:42,000] {Thread-4} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-12 16:15:42,001] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-12 16:15:42,963] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-12 16:15:42,996] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-12 16:15:43,018] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-12 16:15:44,138] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-12 16:15:46,348] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-12 16:15:46,405] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-12 16:15:47,356] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-12 16:15:50,079] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-12 16:15:50,510] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-12 16:15:50,692] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-12 16:15:50,850] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-12 16:15:51,893] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 50.24 Hörsaal-101
[2019-11-12 16:15:52,190] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-12 16:15:52,980] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent Campus Ost 70.04 SR219
[2019-11-12 16:16:59,911] {MainThread} INFO in simple_state_checker, line 121: Got 19 capture agents that will be checked...
[2019-11-12 16:16:59,914] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-12 16:16:59,914] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-12 16:16:59,914] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-12 16:16:59,915] {Thread-4} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-12 16:16:59,917] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-12 16:17:00,018] {Thread-4} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:01,983] {Thread-3} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:01,983] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-12 16:17:02,078] {Thread-5} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:02,078] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-12 16:17:02,414] {Thread-2} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:02,414] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-12 16:17:04,596] {Thread-3} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:04,616] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-12 16:17:04,784] {Thread-5} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:04,789] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-12 16:17:05,311] {Thread-2} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:05,765] {Thread-1} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:05,780] {Thread-3} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:06,242] {Thread-2} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:06,257] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-12 16:17:06,429] {Thread-1} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:06,430] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-12 16:17:06,631] {Thread-5} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:06,631] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-12 16:17:06,657] {Thread-3} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:06,658] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-12 16:17:08,598] {Thread-2} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:08,714] {Thread-1} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:09,251] {Thread-2} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:09,266] {Thread-2} DEBUG in simple_state_checker, line 84: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-12 16:17:09,386] {Thread-5} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:09,397] {Thread-5} DEBUG in simple_state_checker, line 84: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-12 16:17:09,520] {Thread-1} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:09,536] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 50.24 Hörsaal-101
[2019-11-12 16:17:09,795] {Thread-1} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:09,795] {Thread-1} DEBUG in simple_state_checker, line 84: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-12 16:17:10,460] {Thread-5} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:10,851] {Thread-3} INFO in simple_state_checker, line 103: 1
[2019-11-12 16:17:10,872] {Thread-3} ERROR in simple_state_checker, line 104: FATAL - recorder CS 30.46 Chemie Neuer Hoersaal must be recording!!!!
[2019-11-12 16:17:10,873] {Thread-3} DEBUG in simple_state_checker, line 84: Checking Agent Campus Ost 70.04 SR219
[2019-11-12 16:17:11,002] {Thread-3} DEBUG in simple_state_checker, line 110: using SMP adapter
[2019-11-12 16:17:11,588] {Thread-5} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:11,594] {Thread-1} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:11,829] {Thread-3} INFO in simple_state_checker, line 117: OK recorder is not recording :)
[2019-11-12 16:17:12,075] {Thread-2} DEBUG in simple_state_checker, line 110: using SMP adapter

620
logs/root.log.2019-11-15 Normal file
View File

@@ -0,0 +1,620 @@
[2019-11-14 14:16:53,247] {MainThread} INFO in simple_state_checker, line 136: Got 19 capture agents that will be checked...
[2019-11-14 14:16:53,255] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 14:16:53,255] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 14:16:53,256] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 14:16:53,261] {Thread-4} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 14:16:53,261] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 14:16:53,386] {Thread-4} INFO in extron_smp, line 32: Connecting to 129.13.51.101 ...
[2019-11-14 14:16:54,344] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:54,355] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 14:16:54,811] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:54,827] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 14:16:55,195] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:55,206] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 14:16:55,988] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:56,019] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 14:16:56,265] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:56,276] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 14:16:56,323] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therfor be recording... checking now!
[2019-11-14 14:16:56,365] {Thread-1} INFO in simple_state_checker, line 107: CS 10.11 Hertz-Hoersaal is in capturing state, so there should be an entry in the calendar of the recorder, right? -> True
[2019-11-14 14:16:56,380] {Thread-1} INFO in extron_smp, line 32: Connecting to 129.13.51.109 ...
[2019-11-14 14:16:57,008] {Thread-2} INFO in extron_smp, line 32: Connecting to 129.13.51.106 ...
[2019-11-14 14:16:57,095] {Thread-5} INFO in extron_smp, line 32: Connecting to 129.13.51.104 ...
[2019-11-14 14:16:57,272] {Thread-1} INFO in simple_state_checker, line 115: 1
[2019-11-14 14:16:57,283] {Thread-1} ERROR in simple_state_checker, line 116: FATAL - recorder CS 10.11 Hertz-Hoersaal must be recording but is not!!!!
[2019-11-14 14:16:57,321] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 14:16:57,530] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:57,541] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 14:16:57,744] {Thread-1} INFO in extron_smp, line 32: Connecting to 129.13.51.108 ...
[2019-11-14 14:16:57,936] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:57,952] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 14:16:57,954] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:57,965] {Thread-3} INFO in extron_smp, line 32: Connecting to 129.13.51.107 ...
[2019-11-14 14:16:57,966] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 14:16:58,634] {Thread-1} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:58,655] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 14:16:58,902] {Thread-2} INFO in extron_smp, line 32: Connecting to 129.13.51.103 ...
[2019-11-14 14:16:58,904] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:58,904] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 14:16:59,563] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:59,579] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 14:16:59,668] {Thread-3} INFO in extron_smp, line 32: Connecting to 129.13.51.105 ...
[2019-11-14 14:16:59,797] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:16:59,818] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 14:17:00,764] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:17:00,780] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 14:17:00,983] {Thread-3} INFO in extron_smp, line 32: Connecting to 129.13.51.110 ...
[2019-11-14 14:17:01,618] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:17:01,670] {Thread-1} INFO in extron_smp, line 32: Connecting to 129.13.51.102 ...
[2019-11-14 14:17:01,960] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:19:03,660] {Thread-4} CRITICAL in simple_state_checker, line 131: Exception occurred: LRC Exception: "[Errno 110] Connection timed out"
[2019-11-14 14:19:03,661] {Thread-4} ERROR in simple_state_checker, line 132: Could not check state of recorder CS 10.50 Bauingenieure Grosser Hoersaal, Address: 129.13.51.101
[2019-11-14 14:23:51,783] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:25:33,337] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:27:00,957] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:27:14,952] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:28:15,602] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:29:24,029] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:29:58,640] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:32:30,592] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:34:08,425] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:36:35,216] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:38:11,521] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:39:43,884] {MainThread} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:39:53,493] {MainThread} INFO in simple_state_checker, line 136: Got 19 capture agents that will be checked...
[2019-11-14 14:39:53,497] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 14:39:53,497] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 14:39:53,497] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 14:39:53,500] {Thread-4} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 14:39:53,500] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 14:39:53,619] {Thread-4} INFO in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 14:39:54,913] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:54,942] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 14:39:55,178] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:55,220] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 14:39:55,395] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:55,416] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 14:39:56,048] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:56,092] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therfor be recording... checking now!
[2019-11-14 14:39:56,098] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 14:39:56,108] {Thread-1} INFO in simple_state_checker, line 107: CS 10.11 Hertz-Hoersaal is in capturing state, so there should be an entry in the calendar of the recorder, right? -> True
[2019-11-14 14:39:56,127] {Thread-1} INFO in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:39:56,248] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:56,269] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 14:39:56,761] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 14:39:57,066] {Thread-1} INFO in simple_state_checker, line 113: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 14:39:57,087] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 14:39:57,545] {Thread-3} INFO in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 14:39:57,770] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:57,817] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 14:39:58,182] {Thread-1} INFO in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 14:39:58,362] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:58,378] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 14:39:58,425] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 14:39:58,599] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:58,610] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 14:39:58,950] {Thread-1} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:58,951] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 14:39:59,487] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:59,513] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 14:39:59,604] {Thread-3} INFO in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 14:39:59,908] {Thread-5} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:39:59,918] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 14:40:00,356] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 14:40:00,436] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:40:00,451] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 14:40:01,582] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:40:01,608] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 14:40:01,789] {Thread-2} INFO in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 14:40:02,326] {Thread-1} INFO in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 14:40:02,497] {Thread-3} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:40:02,648] {Thread-2} INFO in simple_state_checker, line 129: OK recorder is not recording :)
[2019-11-14 14:57:02,691] {MainThread} INFO in simple_state_checker, line 132: Got 19 capture agents that will be checked...
[2019-11-14 14:57:50,259] {MainThread} INFO in simple_state_checker, line 132: Got 19 capture agents that will be checked...
[2019-11-14 14:57:50,261] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 14:57:51,265] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 14:57:51,266] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 14:57:52,257] {Thread-1} INFO in simple_state_checker, line 109: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 14:57:52,259] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 14:57:53,279] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 14:57:53,279] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 14:57:53,873] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 14:57:53,873] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 14:57:53,892] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:02:35,956] {MainThread} INFO in simple_state_checker, line 132: Got 19 capture agents that will be checked...
[2019-11-14 15:02:35,961] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:02:35,961] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:02:35,961] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:02:35,962] {Thread-4} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:02:35,966] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:02:36,101] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:02:36,867] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:36,878] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:02:37,586] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:37,616] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:02:38,200] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:38,232] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:02:38,487] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:38,503] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:02:38,698] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:38,710] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:02:38,856] {Thread-1} INFO in simple_state_checker, line 103: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:02:38,908] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:02:39,323] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:02:39,609] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:02:39,673] {Thread-1} INFO in simple_state_checker, line 109: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:02:39,693] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:02:40,001] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,011] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:02:40,115] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:02:40,400] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:02:40,409] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,410] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:02:40,604] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,621] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:02:40,828] {Thread-1} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:40,828] {Thread-1} DEBUG in simple_state_checker, line 99: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:02:41,529] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:41,549] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:02:41,621] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:02:41,849] {Thread-5} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:41,850] {Thread-5} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:02:42,655] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:42,687] {Thread-2} DEBUG in simple_state_checker, line 99: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:02:43,620] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:02:44,782] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:44,876] {Thread-3} DEBUG in simple_state_checker, line 99: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:02:45,342] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:02:45,550] {Thread-2} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:02:45,716] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:02:46,265] {Thread-3} INFO in simple_state_checker, line 125: OK recorder is not recording :)
[2019-11-14 15:05:15,774] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:05:15,776] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:05:15,776] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:05:15,778] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:05:15,778] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:05:15,780] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:05:15,840] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:05:17,298] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:17,314] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:05:17,677] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:17,694] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:05:17,842] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:17,853] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:05:18,841] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:18,887] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:05:19,101] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:19,137] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:05:19,149] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:05:19,210] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:05:19,575] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:05:19,886] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:05:20,281] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:05:20,282] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:05:20,333] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:20,333] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:05:20,383] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:20,383] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:05:20,616] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:20,632] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:05:21,026] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:05:21,456] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:05:21,827] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:21,848] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:05:22,128] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:05:22,566] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:22,567] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:05:22,813] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:22,819] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:05:23,169] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:23,205] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:05:23,731] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:05:24,776] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:05:24,963] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:24,963] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:05:25,042] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:25,131] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:05:25,828] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:05:32,282] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:07:35,727] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:07:35,729] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:07:35,729] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:07:35,729] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:07:35,730] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:07:35,730] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:07:35,863] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:07:37,438] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:37,453] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:07:37,481] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:37,497] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:07:37,744] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:07:37,760] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:07:37,996] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:38,011] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:07:38,259] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:38,259] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:07:38,503] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:38,519] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:07:38,612] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:07:38,612] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:07:38,633] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:07:38,813] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:07:39,478] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:39,504] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:07:39,592] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:07:39,602] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:39,625] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:07:39,837] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:39,871] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:07:39,886] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:07:40,494] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:40,520] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:07:40,903] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:07:41,107] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:41,108] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:07:41,186] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:41,186] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:07:41,731] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:41,747] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:07:41,869] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:07:42,952] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:42,973] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:07:43,268] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:07:44,224] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:44,634] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:07:44,636] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:07:50,654] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:07:50,706] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-14 15:20:07,570] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:20:07,572] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:20:07,572] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:20:07,572] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:20:07,575] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:20:07,576] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:20:07,702] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:20:09,335] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:09,341] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:20:09,527] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:09,543] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:20:10,343] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:10,375] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:20:11,090] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:11,106] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:20:11,158] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:20:11,164] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:20:11,194] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:11,215] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:20:11,464] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:20:11,990] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:20:12,017] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:20:12,028] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:20:12,376] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:12,387] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:20:12,399] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:20:12,400] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:12,401] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:20:12,906] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:12,922] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:20:13,086] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:20:13,264] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:13,264] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:20:13,943] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:20:13,999] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:13,999] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:20:14,191] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:14,192] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:20:14,849] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:14,938] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:20:16,840] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:20:18,101] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:18,112] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:20:18,197] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:20:18,231] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:18,279] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:20:18,965] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:20:20,327] {Thread-1} WARNING in extron_smp, line 52: Could not login (as admin) with given password! 129.13.51.102
[2019-11-14 15:20:22,329] {Thread-1} ERROR in extron_smp, line 59: Could definitely not login (as admin) with given password! 129.13.51.102
[2019-11-14 15:20:24,046] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:20:24,118] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-14 15:41:07,178] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:41:07,180] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:41:07,180] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:41:07,180] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:41:07,180] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:41:07,180] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:41:07,312] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:41:08,619] {Thread-2} INFO in simple_state_checker, line 104: CS 10.21 Carl-Benz-Hörsaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:41:08,634] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:41:08,640] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:41:08,822] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:08,864] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:41:08,864] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:08,919] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:41:10,309] {Thread-1} INFO in simple_state_checker, line 104: CS 10.11 Hertz-Hoersaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:41:10,319] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:41:10,595] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:10,610] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:41:10,683] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:10,706] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:41:10,708] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:41:11,243] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 10.11 Hertz-Hoersaal is recording :)
[2019-11-14 15:41:11,253] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:41:11,261] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:41:11,594] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:11,594] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:41:11,606] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:41:11,624] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:11,624] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:41:12,061] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:12,092] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:41:12,311] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:12,327] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:41:12,600] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:41:13,130] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:41:13,666] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:13,677] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:41:13,757] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:13,777] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:41:14,070] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:14,096] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:41:15,923] {Thread-1} INFO in simple_state_checker, line 104: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:41:15,944] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:41:16,093] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:41:16,804] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:16,805] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:41:16,964] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:41:17,043] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-14 15:41:17,168] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:17,905] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:41:23,261] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:41:23,280] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-14 15:45:17,132] {MainThread} INFO in simple_state_checker, line 133: Got 19 capture agents that will be checked...
[2019-11-14 15:45:17,136] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-14 15:45:17,136] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-14 15:45:17,136] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-14 15:45:17,138] {Thread-4} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-14 15:45:17,140] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-14 15:45:17,246] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-14 15:45:18,711] {Thread-2} INFO in simple_state_checker, line 104: CS 10.21 Carl-Benz-Hörsaal has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:45:18,727] {Thread-2} ERROR in simple_state_checker, line 118: FATAL: CS 10.21 Carl-Benz-Hörsaal is not in capturing state...but should be!!
[2019-11-14 15:45:18,763] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-14 15:45:18,861] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:18,872] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-14 15:45:18,931] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:18,941] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-14 15:45:19,971] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-14 15:45:20,433] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:20,448] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-14 15:45:20,537] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:20,547] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-14 15:45:20,571] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-14 15:45:21,177] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:21,197] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-14 15:45:21,408] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-14 15:45:21,543] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:21,564] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-14 15:45:22,149] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:22,165] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-14 15:45:22,247] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-14 15:45:22,247] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:22,268] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-14 15:45:22,378] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-14 15:45:22,958] {Thread-1} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:22,978] {Thread-1} DEBUG in simple_state_checker, line 100: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-14 15:45:23,300] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-14 15:45:23,351] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:23,351] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-14 15:45:23,400] {Thread-5} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:23,400] {Thread-5} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.24 Hörsaal-101
[2019-11-14 15:45:24,216] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-14 15:45:24,306] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:24,337] {Thread-2} DEBUG in simple_state_checker, line 100: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-14 15:45:25,245] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:25,266] {Thread-3} DEBUG in simple_state_checker, line 100: Checking Agent Campus Ost 70.04 SR219
[2019-11-14 15:45:25,600] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-14 15:45:26,328] {Thread-3} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:26,923] {Thread-1} INFO in simple_state_checker, line 104: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-14 15:45:26,923] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-14 15:45:27,178] {Thread-2} INFO in simple_state_checker, line 126: OK recorder is not recording :)
[2019-11-14 15:45:27,986] {Thread-1} INFO in simple_state_checker, line 110: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-14 15:45:33,213] {MainThread} ERROR in simple_state_checker, line 145: Timeout while getting capture agent state!
[2019-11-14 15:45:33,239] {MainThread} INFO in simple_state_checker, line 147: DONE checking capture agents / recorders!
[2019-11-15 09:00:02,960] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 09:00:02,962] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 09:00:02,962] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 09:00:02,963] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 09:00:02,963] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 09:00:02,963] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 09:00:03,163] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 09:00:04,443] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:04,454] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 09:00:04,925] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:04,941] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 09:00:05,486] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:05,507] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 09:00:05,732] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:05,753] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 09:00:05,807] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 09:00:06,018] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:06,028] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 09:00:06,443] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 09:00:06,557] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:06,583] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 09:00:06,654] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 09:00:07,016] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 09:00:07,028] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,028] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 09:00:07,313] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,333] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 09:00:07,435] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 09:00:07,681] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,696] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 09:00:07,847] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:07,848] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 09:00:08,514] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:08,514] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 09:00:08,955] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:08,970] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 09:00:09,158] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 09:00:09,479] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 09:00:10,422] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:10,443] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 09:00:10,679] {Thread-1} INFO in simple_state_checker, line 110: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-15 09:00:10,679] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 09:00:10,756] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:10,757] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 09:00:10,870] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 09:00:11,648] {Thread-1} INFO in simple_state_checker, line 116: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-15 09:00:11,726] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:11,959] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:00:18,601] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:00:18,945] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!
[2019-11-15 09:01:48,428] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 09:01:48,431] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 09:01:48,431] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 09:01:48,431] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 09:01:48,432] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 09:01:48,432] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 09:01:48,538] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 09:01:49,684] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:49,690] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:49,705] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 09:01:49,716] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 09:01:50,134] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 09:01:50,252] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:50,268] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 09:01:50,800] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:50,806] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 09:01:50,914] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 09:01:50,915] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:50,915] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 09:01:51,069] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:51,080] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 09:01:51,673] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:51,720] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 09:01:51,726] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 09:01:51,893] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 09:01:52,152] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 09:01:52,231] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,232] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 09:01:52,598] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,618] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,623] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 09:01:52,637] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 09:01:52,956] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:52,956] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 09:01:53,679] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:53,721] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 09:01:54,025] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 09:01:54,184] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 09:01:54,998] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:55,019] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 09:01:55,087] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:55,108] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 09:01:55,254] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 09:01:55,445] {Thread-3} INFO in simple_state_checker, line 110: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-15 09:01:55,445] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 09:01:55,943] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:01:56,200] {Thread-3} INFO in simple_state_checker, line 116: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-15 09:01:56,274] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:02:02,915] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:02:03,114] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!
[2019-11-15 09:03:16,872] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 09:03:16,875] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 09:03:16,875] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 09:03:16,875] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 09:03:16,875] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 09:03:16,875] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 09:03:16,991] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 09:03:17,901] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:17,917] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:17,917] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 09:03:17,933] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 09:03:18,497] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 09:03:18,639] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:18,655] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 09:03:19,037] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:19,047] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 09:03:19,189] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:19,210] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 09:03:19,310] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:19,329] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 09:03:19,329] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 09:03:19,638] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 09:03:20,151] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 09:03:20,331] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:20,331] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 09:03:20,462] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:20,462] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 09:03:20,494] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:20,510] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 09:03:20,633] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 09:03:21,032] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:21,053] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 09:03:21,466] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 09:03:21,730] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:21,731] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 09:03:22,061] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:22,072] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 09:03:22,445] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:22,492] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 09:03:23,370] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 09:03:24,285] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:24,306] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 09:03:24,454] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 09:03:24,681] {Thread-3} INFO in simple_state_checker, line 110: CS 30.95 Forum Hoersaal Audimax has entry in Calender and should therefore be recording... checking now!
[2019-11-15 09:03:24,682] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 09:03:24,682] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:25,308] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 09:03:25,616] {Thread-3} INFO in simple_state_checker, line 116: OK recorder CS 30.95 Forum Hoersaal Audimax is recording :)
[2019-11-15 09:03:31,225] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 09:03:31,461] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!
[2019-11-15 15:56:02,776] {MainThread} INFO in simple_state_checker, line 139: Got 19 capture agents that will be checked...
[2019-11-15 15:56:02,783] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.11 Hertz-Hoersaal
[2019-11-15 15:56:02,783] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Carl-Benz-Hörsaal
[2019-11-15 15:56:02,784] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.21 Gottlieb-Daimler-Hörsaal
[2019-11-15 15:56:02,787] {Thread-4} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure Grosser Hoersaal
[2019-11-15 15:56:02,787] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.50 Bauingenieure, Kleiner Hörsaal
[2019-11-15 15:56:02,903] {Thread-4} DEBUG in extron_smp, line 34: Connecting to 129.13.51.101 ...
[2019-11-15 15:56:04,320] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:04,331] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Grashof-Hörsaal
[2019-11-15 15:56:04,366] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:04,377] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 10.91 Redtenbacher-Hörsaal
[2019-11-15 15:56:04,654] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:04,741] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 11.40 Johann-Gottfried-Tulla-Hoersaal
[2019-11-15 15:56:04,779] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.109 ...
[2019-11-15 15:56:05,377] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:05,388] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.10 Nachrichtentechnik-Hoersaal NTI
[2019-11-15 15:56:05,479] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:05,492] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.21 Gerthsen-Hörsaal
[2019-11-15 15:56:05,698] {Thread-2} DEBUG in extron_smp, line 34: Connecting to 129.13.51.106 ...
[2019-11-15 15:56:06,048] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:06,105] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Gaede-Hoersaal
[2019-11-15 15:56:06,320] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.104 ...
[2019-11-15 15:56:06,752] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.108 ...
[2019-11-15 15:56:06,834] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:06,834] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS
[2019-11-15 15:56:06,844] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:06,845] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.41 Chemie-Hörsaal Nr.3
[2019-11-15 15:56:07,320] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:07,336] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.46 Chemie Neuer Hoersaal
[2019-11-15 15:56:07,555] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.107 ...
[2019-11-15 15:56:07,567] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:07,568] {Thread-1} DEBUG in simple_state_checker, line 106: Checking Agent CS 30.95 Forum Hoersaal Audimax
[2019-11-15 15:56:08,323] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:08,324] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent CS 40.50 EBI Hoersaal
[2019-11-15 15:56:08,638] {Thread-2} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:08,655] {Thread-2} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.24 Hörsaal-101
[2019-11-15 15:56:08,687] {Thread-3} DEBUG in extron_smp, line 34: Connecting to 129.13.51.103 ...
[2019-11-15 15:56:09,544] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.105 ...
[2019-11-15 15:56:09,757] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:09,773] {Thread-3} DEBUG in simple_state_checker, line 106: Checking Agent CS 50.35 Fasansengarten-Hörsaal (Hs a.F.)
[2019-11-15 15:56:10,425] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:10,441] {Thread-5} DEBUG in simple_state_checker, line 106: Checking Agent Campus Ost 70.04 SR219
[2019-11-15 15:56:10,740] {Thread-5} DEBUG in extron_smp, line 34: Connecting to 129.13.51.110 ...
[2019-11-15 15:56:11,549] {Thread-5} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:11,664] {Thread-1} DEBUG in extron_smp, line 34: Connecting to 129.13.51.102 ...
[2019-11-15 15:56:12,063] {Thread-3} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:12,450] {Thread-1} INFO in simple_state_checker, line 132: OK recorder is not recording :)
[2019-11-15 15:56:18,121] {MainThread} ERROR in simple_state_checker, line 151: Timeout while getting capture agent state!
[2019-11-15 15:56:18,512] {MainThread} INFO in simple_state_checker, line 153: DONE checking capture agents / recorders!

View File

@@ -1,318 +0,0 @@
# -*- coding: utf-8 -*-
"""
Example user model and related models
"""
from backend import db, app
from backend.models.post_model import Post
from backend.models.example_model import ExampleDataItem
import re
import jwt
from flask_login import UserMixin
from sqlalchemy import or_
from datetime import datetime, timedelta
from passlib.hash import sha256_crypt
from hashlib import md5
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'))
)
class User(UserMixin, db.Model):
"""
Example user model representation.
"""
id = db.Column(db.Integer, primary_key=True)
social_id = db.Column(db.String(64), nullable=True, unique=True)
nickname = db.Column(db.String(64), index=True, unique=True)
first_name = db.Column(db.String(64), index=True, nullable=True)
last_name = db.Column(db.String(64), index=True, nullable=True)
email = db.Column(db.String(120), nullable=False, index=True, unique=True)
lang = db.Column(db.String(16), index=False, unique=False)
timezone = db.Column(db.String(32), index=False, unique=False)
posts = db.relationship('Post', backref='author', lazy='dynamic')
example_data_item = db.relationship('ExampleDataItem', backref='owner', lazy='dynamic')
about_me = db.Column(db.String(140))
role = db.Column(db.String(64))
password = db.Column(db.String(255), nullable=True)
registered_on = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
last_seen = 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')
@staticmethod
def get_by_identifier(identifier):
"""
Find user by identifier, which might be the nickname or the e-mail address.
:param identifier:
:return:
"""
return User.query.filter(or_(User.nickname == identifier,
User.email == identifier)).first()
@staticmethod
def get_all():
"""
Return all users
:return:
"""
return User.query.all()
@staticmethod
def make_unique_nickname(nickname):
"""
Add suffix (counter) to nickname in order to get a unique nickname.
:param nickname:
:return:
"""
if User.query.filter_by(nickname=nickname).first() is None:
return nickname
version = 2
while True:
new_nickname = nickname + str(version)
if User.query.filter_by(nickname=new_nickname).first() is None:
break
version += 1
return new_nickname
@staticmethod
def make_valid_nickname(nickname):
"""
Replaces certain characters (except a-zA-Z0-9_.) in nickname with blancs.
:param nickname:
:return:
"""
return re.sub('[^a-zA-Z0-9_.]', '', nickname)
@property
def is_authenticated(self):
"""
Returns true if user is authenticated.
:return:
"""
# TODO: implement correctly
return True
@property
def is_active(self):
"""
Returns true if user is active.
:return:
"""
# TODO: implement correctly
return True
@property
def is_anonymous(self):
"""
Returns true if user is anonymous.
:return:
"""
# TODO: implement correctly
return False
@staticmethod
def decode_auth_token(auth_token):
"""
Decodes the auth token
:param auth_token:
:return: integer|string
"""
try:
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.'
else:
return payload['sub']
except jwt.ExpiredSignatureError:
return 'Signature expired. Please log in again.'
except jwt.InvalidTokenError:
return 'Invalid token. Please log in again.'
def encode_auth_token(self):
"""
Generates the Auth Token
:return: string
"""
try:
payload = {
'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'
)
except Exception as e:
return e
def set_password(self, password):
"""
SHA256 encrypts the given password and sets it on the user.
:param password:
:return:
"""
self.password = sha256_crypt.encrypt(password)
def verify_password(self, password):
"""
Verifies that the given password matches the SHA256 encrypted password stored on the user.
:param password:
:return:
"""
return sha256_crypt.verify(password, self.password)
def get_id(self):
"""
Returns the ID of the user.
:return:
"""
try:
# noinspection PyUnresolvedReferences
return unicode(self.id) # python 2
except NameError:
return str(self.id) # python 3
def avatar(self, size):
"""
Returns an avatar URL.
:param size:
:return:
"""
return 'https://s.gravatar.com/avatar/%s?d=mm&s=%d' % (md5(self.email.encode('utf-8')).hexdigest(), size)
def acquaint(self, user):
"""
Adds an acquaintance to the user object.
:param user:
:return:
"""
if not self.is_acquainted(user):
self.acquainted.append(user)
return self
def unacquaint(self, user):
"""
Removes the user from the list of acquaintances.
:param user:
:return:
"""
if self.is_acquainted(user):
self.acquainted.remove(user)
return self
def is_acquainted(self, user):
"""
Check if the provided user is an acquaintance.
:param user:
:return:
"""
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())
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())
def follow(self, user):
"""
Add user to list of followers.
:param user:
:return:
"""
if not self.is_following(user):
self.followed.append(user)
return self
def unfollow(self, user):
"""
Remove user from the list of followers.
:param user:
:return:
"""
if self.is_following(user):
self.followed.remove(user)
return self
def is_following(self, user):
"""
Checks if specified user is a follower.
:param user:
:return:
"""
return self.followed.filter(followers.c.followed_id == user.id).count() > 0
def followed_posts(self):
"""
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())
def __repr__(self):
return '<User %r>' % self.nickname
class BlacklistToken(db.Model):
"""
Token Model for storing JWT tokens
"""
__tablename__ = 'blacklist_tokens'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
token = db.Column(db.String(500), unique=True, nullable=False)
blacklisted_on = db.Column(db.DateTime, nullable=False)
def __init__(self, token):
self.token = token
self.blacklisted_on = datetime.now()
def __repr__(self):
return '<id: token: {}'.format(self.token)
@staticmethod
def check_blacklist(auth_token):
"""
check whether auth token has been blacklisted
:param auth_token:
:return:
"""
res = BlacklistToken.query.filter_by(token=str(auth_token)).first()
if res:
return True
else:
return False

1978
poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

41
pyproject.toml Normal file
View File

@@ -0,0 +1,41 @@
[tool.poetry]
name = "lrc-backend"
version = "0.1.0"
description = ""
authors = ["Tobias Kurze <it@t-kurze.de>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.11"
flask = "*"
flask-httpauth = "*"
flask-sqlalchemy = "*"
pyjwt = "*"
passlib = "*"
sqlalchemy = "*"
sqlalchemy-migrate = "*"
flask-script = "*"
flask-migrate = "*"
coverage = "*"
flask-testing = "*"
flask-pyoidc = "*"
python-jose = "*"
flask-jwt-extended = "*"
ssh2-python = "*"
update = "*"
flask-cors = "*"
html5lib = "*"
beautifulsoup4 = "*"
flask-socketio = "*"
eventlet = "*"
ics = "*"
coloredlogs = "*"
pythonping = "*"
scapy = "*"
flask-login = "^0.6.2"
werkzeug = "2.*"
flask-restx = "^1.1.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

View File

@@ -1,30 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from flask import render_template, send_from_directory, Blueprint
fe_path = os.path.join(os.getcwd(), "frontend", "dist")
fe_bp = Blueprint('frontend', __name__, url_prefix='/', template_folder=os.path.join(fe_path, ""))
@fe_bp.route('/js/<path:path>')
def send_js(path):
return send_from_directory(os.path.join(fe_path, "js"), path)
@fe_bp.route('/css/<path:path>')
def send_css(path):
return send_from_directory(os.path.join(fe_path, "css"), path)
@fe_bp.route('/img/<path:path>')
def send_img(path):
return send_from_directory(os.path.join(fe_path, "img"), path)
@fe_bp.route('/', defaults={'path': ''})
@fe_bp.route('/<path:path>')
def catch_all(path):
return render_template("index.html")