9 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
17 changed files with 1966 additions and 674 deletions

View File

@@ -167,7 +167,7 @@ except requests.exceptions.ConnectionError as err:
# oidc_multi_auth = MultiAuth(oidc_auth, jwt_auth) <- can't work as OIDCAuthentication not implementing HTTPAuth # oidc_multi_auth = MultiAuth(oidc_auth, jwt_auth) <- can't work as OIDCAuthentication not implementing HTTPAuth
#from .serve_frontend import fe_bp from .serve_frontend import fe_bp
from .api import auth_api_bp, api_v1, api_bp from .api import auth_api_bp, api_v1, api_bp
CORS(app) CORS(app)
@@ -176,7 +176,7 @@ CORS(api_bp)
app.register_blueprint(auth_bp) app.register_blueprint(auth_bp)
app.register_blueprint(auth_api_bp) app.register_blueprint(auth_api_bp)
app.register_blueprint(api_bp) app.register_blueprint(api_bp)
#app.register_blueprint(fe_bp) app.register_blueprint(fe_bp)

View File

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

View File

@@ -37,7 +37,7 @@ class Config:
# SERVER_NAME = "localhost.localdomain" # SERVER_NAME = "localhost.localdomain"
# PORT = 5443 # PORT = 5443
OPENCAST_URL = "https://opencast.bibliothek.kit.edu" OPENCAST_URL = "https://oc-bib-admin.bibliothek.kit.edu"
OPENCAST_USER = "admin" OPENCAST_USER = "admin"
OPENCAST_PW = "mz.paziuw!" OPENCAST_PW = "mz.paziuw!"

View File

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

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

@@ -1,133 +1,95 @@
{ {
"recorders": [ "recorders": [
{ {
"name": "CS 50.35 Fasansengarten-H\u00f6rsaal (Hs a.F.)", "name": "CS 10.91 Grashof-Hoersaal",
"building": "50.35",
"room": "HS Fasanengarten",
"username": "admin",
"password": "lrhsafg+-",
"ip": "129.13.51.82",
"mac": "00:55:56:4d:68:fa",
"type": "VGADVI Recorder",
"additional_camera": false,
"firmware_version": "2.5.0f",
"description": "{\"comment\": \"pyCA v2.1\", \"network_port\": \"006 / 8 L\", \"rsync_name\": \"LRHSAF\"}"
},
{
"name": "CS 30.21 Gerthsen-H\u00f6rsaal",
"building": "30.21",
"room": "Gerthsen",
"username": "admin",
"password": "lrgerthsen+-",
"ip": "129.13.51.83",
"mac": "00:55:56:69:91:a9",
"type": "VGADVI Recorder",
"additional_camera": false,
"firmware_version": "2.5.0f",
"description": "{\"comment\": \"pyCA v2.1\", \"network_port\": \"003 / 3\", \"rsync_name\": \"LRGerthsen\"}"
},
{
"name": "CS 10.91 Grashof-H\u00f6rsaal",
"building": "10.91", "building": "10.91",
"room": "Grashof", "room": "Grashof",
"username": "admin", "username": "admin",
"password": "lrgrashof+-", "password": "smpgrashof",
"ip": "129.13.51.84", "ip": "129.13.51.114",
"mac": "00:55:56:78:96:2f", "mac": "00:05:A6:1A:4E:4B",
"type": "LectureRecorder X2", "type": "SMP 351",
"additional_camera": false, "additional_camera": true,
"firmware_version": "3.12.0k", "firmware_version": "3.05b002",
"description": "{\"comment\": \"pyCA v2.1\", \"network_port\": \"EDV 6 L\", \"rsync_name\": \"LRGrashof\"}" "description": "{\"comment\": \"SMP 351 + LL\", \"network_port\": \"\", \"rsync_name\": \"\"}"
}, },
{ {
"name": "CS 50.24 H\u00f6rsaal-101", "name": "CS 30.41 Chemie-Hoersaal Nr. 1",
"building": "50.24",
"room": "HS-101 (Informatik)",
"username": "admin",
"password": "lr-101+-",
"ip": "129.13.51.85",
"mac": "00:55:56:40:97:2d",
"type": "VGADVI Recorder",
"additional_camera": false,
"firmware_version": "2.5.0f",
"description": "{\"comment\": \"pyCA v2.1\", \"network_port\": \"IT 3.3\", \"rsync_name\": \"LR101\"}"
},
{
"name": "CS 10.21 Carl-Benz-H\u00f6rsaal",
"building": "10.21",
"room": "Carl-Benz H\u00f6rsaal",
"username": "admin",
"password": "lrbenz+-",
"ip": "129.13.51.87",
"mac": "00:55:56:b3:01:9d",
"type": "LectureRecorder X2",
"additional_camera": false,
"firmware_version": "3.12.0k",
"description": "{\"comment\": \"pyCA v2.1\", \"network_port\": \"\", \"rsync_name\": \"LRBenz\"}"
},
{
"name": "CS 10.21 Gottlieb-Daimler-H\u00f6rsaal",
"building": "10.21",
"room": "Gottlieb-Daimler H\u00f6rsaal",
"username": "admin",
"password": "lrdaimler+-",
"ip": "129.13.51.88",
"mac": "00:55:56:61:47:48",
"type": "DVIRecorderDL",
"additional_camera": false,
"firmware_version": "2.5.0f",
"description": "{\"comment\": \"pyCA v2.1\", \"network_port\": \"\", \"rsync_name\": \"LRDaimler\"}"
},
{
"name": "CS 10.50 Bauingenieure, Kleiner H\u00f6rsaal",
"building": "10.50",
"room": "Kleiner H\u00f6rsaal Bauingenieure",
"username": "admin",
"password": "lrkleinerhs+-",
"ip": "129.13.51.89",
"mac": "00:55:56:bb:d7:86",
"type": "LectureRecorder",
"additional_camera": false,
"firmware_version": "2.5.0f",
"description": "{\"comment\": \"pyCA v2.1\", \"network_port\": \"\", \"rsync_name\": \"LRkleinerHS\"}"
},
{
"name": "CS 30.41 Chemie-H\u00f6rsaal Nr.3",
"building": "30.41", "building": "30.41",
"room": "Chemie \u2013 H\u00f6rsaal 3", "room": "Chemie - Hörsaal 1",
"username": "admin", "username": "admin",
"password": "lrhs3+-", "password": "smphs1",
"ip": "129.13.51.91", "ip": "129.13.51.118",
"mac": "00:55:56:f1:7c:84", "mac": "00:05:A6:1C:07:27",
"type": "LectureRecorder X2", "type": "SMP 351",
"additional_camera": false, "additional_camera": false,
"firmware_version": "3.12.0k", "firmware_version": "3.05b002",
"description": "{\"comment\": \"pyCA v2.1\", \"network_port\": \"\", \"rsync_name\": \"LRHS3\"}" "description": "{\"comment\": \"SMP 351 + LL\", \"network_port\": \"\", \"rsync_name\": \"\"}"
}, },
{ {
"name": "CS 10.91 Redtenbacher-H\u00f6rsaal", "name": "CS 30.41 Chemie-Hoersaal Nr. 2",
"building": "10.91", "building": "30.41",
"room": "Redtenbacher H\u00f6rsaal", "room": "Chemie - Hörsaal 2",
"username": "admin", "username": "admin",
"password": "lrredtenbacher+-", "password": "smphs2",
"ip": "129.13.51.79", "ip": "129.13.51.117",
"mac": "00:55:56:75:29:19", "mac": "00:05:A6:1C:07:00",
"type": "VGADVI Recorder", "type": "SMP 351",
"additional_camera": false, "additional_camera": false,
"firmware_version": "2.5.0f", "firmware_version": "3.05b002",
"description": "{\"comment\": \"pyCA v2.1\", \"network_port\": \"\", \"rsync_name\": \"Redtenbacher_HS\"}" "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", "name": "CS 10.50 Bauingenieure Grosser Hoersaal",
"building": "10.50", "building": "10.50",
"room": "Grosser H\u00f6rsaal Bauingenieure", "room": "Grosser Hörsaal Bauingenieure",
"username": "admin", "username": "admin",
"password": "smpgrosserhs", "password": "smpgrosserhs",
"ip": "129.13.51.101", "ip": "129.13.51.101",
"mac": "", "mac": "",
"type": "SMP 351", "type": "SMP 351",
"additional_camera": false, "additional_camera": false,
"firmware_version": "2.11b0", "firmware_version": "3.05b002",
"description": "{\"comment\": \"SMP 351 \\u2013SDI Eingang (Channel B) / ZML \\u2013 Axel\", \"network_port\": \"\", \"rsync_name\": \"\"}" "description": "{\"comment\": \"SMP 351 \\u2013SDI Eingang (Channel B) / ZML \\u2013 Axel\", \"network_port\": \"\", \"rsync_name\": \"\"}"
}, },
{ {
@@ -140,125 +102,177 @@
"mac": "00-05-A6-11-E2-6D", "mac": "00-05-A6-11-E2-6D",
"type": "SMP 351", "type": "SMP 351",
"additional_camera": false, "additional_camera": false,
"firmware_version": "2.11b0", "firmware_version": "3.05b002",
"description": "{\"comment\": \"SMP 351 \", \"network_port\": \"\", \"rsync_name\": \"\"}" "description": "{\"comment\": \"SMP 351 \", \"network_port\": \"\", \"rsync_name\": \"\"}"
}, },
{ {
"name": "CS 30.46 Chemie Neuer Hoersaal", "name": "CS 30.46 Chemie Neuer Hoersaal",
"building": "30.46", "building": "30.46",
"room": "Chemie Neuer H\u00f6rsaal", "room": "Chemie Neuer Hörsaal",
"username": "admin", "username": "admin",
"password": "smpchemie", "password": "smpchemie",
"ip": "129.13.51.103", "ip": "129.13.51.103",
"mac": "00-05-A6-12-CE-E0", "mac": "00-05-A6-12-CE-E0",
"type": "SMP 351", "type": "SMP 351",
"additional_camera": true, "additional_camera": true,
"firmware_version": "2.11b0", "firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}" "description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
}, },
{ {
"name": "CS 30.10 Nachrichtentechnik-Hoersaal NTI", "name": "CS 30.10 Nachrichtentechnik-Hoersaal NTI",
"building": "30.10", "building": "30.10",
"room": "Nachrichtentechnik-Hörsaal NTI", "room": "Nachrichtentechnik-Hörsaal (NTI)",
"username": "admin", "username": "admin",
"password": "smpnti", "password": "smpnti",
"ip": "129.13.51.104", "ip": "129.13.51.104",
"mac": "00-05-A6-12-6A-C9", "mac": "00-05-A6-12-6A-C9",
"type": "SMP 351", "type": "SMP 351",
"additional_camera": true, "additional_camera": true,
"firmware_version": "2.11b0", "firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}" "description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
}, },
{ {
"name": "CS 40.50 EBI Hoersaal", "name": "CS 40.50 EBI Hoersaal",
"building": "40.50", "building": "40.50",
"room": "Engler Bunte H\u00f6rsaal RBI", "room": "EBI Hörsaal",
"username": "admin", "username": "admin",
"password": "smpebi", "password": "smpebi",
"ip": "129.13.51.105", "ip": "129.13.51.105",
"mac": "00-05-A6-14-77-E6", "mac": "00-05-A6-14-77-E6",
"type": "SMP 351", "type": "SMP 351",
"additional_camera": true, "additional_camera": true,
"firmware_version": "2.11b0", "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\": \"\"}" "description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
}, },
{ {
"name": "CS 11.40 Johann-Gottfried-Tulla-Hoersaal", "name": "CS 11.40 Johann-Gottfried-Tulla-Hoersaal",
"building": "11.40", "building": "11.40",
"room": "Tulla H\u00f6rsaal", "room": "Tulla Hörsaal",
"username": "admin", "username": "admin",
"password": "smptulla", "password": "smptulla",
"ip": "129.13.51.106", "ip": "129.13.51.106",
"mac": "00-05-A6-14-D6-47", "mac": "00-05-A6-14-D6-47",
"type": "SMP 351", "type": "SMP 351",
"additional_camera": true, "additional_camera": true,
"firmware_version": "2.11b0", "firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}" "description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
}, },
{ {
"name": "CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS", "name": "CS 30.22 Otto-Lehmann-Hoersaal - Mittl. HS",
"building": "30.22", "building": "30.22",
"room": "Otto-Lehmann H\u00f6rsaal", "room": "Otto-Lehmann-Hörsaal (Mittl. HS)",
"username": "admin", "username": "admin",
"password": "smplehmann", "password": "smplehmann",
"ip": "129.13.51.107", "ip": "129.13.51.107",
"mac": "00-05-A6-14-DD-0D", "mac": "00-05-A6-14-DD-0D",
"type": "SMP 352", "type": "SMP 352",
"additional_camera": false, "additional_camera": false,
"firmware_version": "2.11b0", "firmware_version": "3.04",
"description": "{\"comment\": \"2 Projektionen \", \"network_port\": \"\", \"rsync_name\": \"\"}" "description": "{\"comment\": \"2 Projektionen \", \"network_port\": \"\", \"rsync_name\": \"\"}"
}, },
{ {
"name": "CS 30.22 Gaede-Hoersaal", "name": "CS 30.22 Gaede-Hoersaal",
"building": "30.22", "building": "30.22",
"room": "Gaede H\u00f6rsaal", "room": "Gaede Hörsaal",
"username": "admin", "username": "admin",
"password": "smpgaede", "password": "smpgaede",
"ip": "129.13.51.108", "ip": "129.13.51.108",
"mac": "00-05-A6-17-EF-5F", "mac": "00-05-A6-17-EF-5F",
"type": "SMP351 + DLL", "type": "SMP351 + DLL",
"additional_camera": false, "additional_camera": false,
"firmware_version": "2.11b0", "firmware_version": "3.05b002",
"description": "{\"comment\": \"2 Projektionen \", \"network_port\": \"\", \"rsync_name\": \"\"}" "description": "{\"comment\": \"2 Projektionen \", \"network_port\": \"\", \"rsync_name\": \"\"}"
}, },
{ {
"name": "CS 10.11 Hertz-Hoersaal", "name": "CS 10.11 Hertz-Hoersaal",
"building": "10.11", "building": "10.11",
"room": "Hertz \u2013 H\u00f6rsaal", "room": "Hertz - Hörsaal",
"username": "admin", "username": "admin",
"password": "smphertz", "password": "smphertz",
"ip": "129.13.51.109", "ip": "129.13.51.109",
"mac": "00-05-A6-18-41-C7", "mac": "00-05-A6-18-41-C7",
"type": "SMP 351", "type": "SMP 351",
"additional_camera": true, "additional_camera": true,
"firmware_version": "2.11b0", "firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}" "description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
}, },
{ {
"name": "Campus Ost 70.04 SR219", "name": "CO 70.04 Raum 219",
"building": "70.04", "building": "70.04",
"room": "CO 70.04 SR219", "room": "70.04 FAST, Raum 219",
"username": "admin", "username": "admin",
"password": "7004sr219smp", "password": "7004sr219smp",
"ip": "129.13.51.110", "ip": "129.13.51.110",
"mac": "00-05-A6-18-41-C2", "mac": "00-05-A6-18-41-C2",
"type": "SMP 351", "type": "SMP 351",
"additional_camera": false, "additional_camera": false,
"firmware_version": "2.11b0", "firmware_version": "3.05b002",
"description": "{\"comment\": \"FAST Gauterin\", \"network_port\": \"\", \"rsync_name\": \"\"}" "description": "{\"comment\": \"FAST Gauterin\", \"network_port\": \"\", \"rsync_name\": \"\"}"
}, },
{ {
"name": "ILIAS-HS_3", "name": "CS 30.21 Gerthsen-Hoersaal",
"building": "30.50", "building": "30.21",
"room": "Test-LR", "room": "Gerthsen-Hörsaal",
"username": "admin", "username": "admin",
"password": "lrgrashof+-", "password": "smpgerthsen",
"ip": "172.23.8.102", "ip": "129.13.51.119",
"mac": "00:55:56:f4:88:e1", "mac": "00-05-A6-1D-66-DF",
"type": "DVI Broadcaster DL", "type": "SMP351 + DLL",
"additional_camera": false, "additional_camera": true,
"firmware_version": "3.12.0k", "firmware_version": "3.05b002",
"description": "{\"comment\": \"von Axel\", \"network_port\": \"MZ\", \"rsync_name\": \"\"}" "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", "name": "Opencast-qa: Test-SMP KIT",
@@ -270,7 +284,7 @@
"mac": "00-05-A6-16-A3-E4", "mac": "00-05-A6-16-A3-E4",
"type": "SMP352", "type": "SMP352",
"additional_camera": false, "additional_camera": false,
"firmware_version": "2.11b0", "firmware_version": "3.05b002",
"description": "{\"comment\": \"von FM\", \"network_port\": \"MZ\", \"rsync_name\": \"\"}" "description": "{\"comment\": \"von FM\", \"network_port\": \"MZ\", \"rsync_name\": \"\"}"
} }
], ],

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

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -1,13 +1,30 @@
# pylint: disable=missing-module-docstring,missing-function-docstring,missing-class-docstring
from backend import LrcException from backend import LrcException
def exception_decorator(*exceptions): 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 decorator(func):
def new_func(*args, **kwargs): def new_func(*args, **kwargs):
try: try:
ret = func(*args, **kwargs) ret = func(*args, **kwargs)
return ret return ret
except exceptions as e: except exceptions as e:
raise LrcException(e) raise LrcException(e) from e
return new_func return new_func
return decorator
return decorator

View File

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