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
#from .serve_frontend import fe_bp
from .serve_frontend import fe_bp
from .api import auth_api_bp, api_v1, api_bp
CORS(app)
@@ -176,7 +176,7 @@ CORS(api_bp)
app.register_blueprint(auth_bp)
app.register_blueprint(auth_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 pprint import pprint
from flask_jwt_extended import get_jwt_identity, jwt_required, current_user
from flask_restx import Resource, fields, inputs, abort
from flask_jwt_extended import get_jwt_identity, jwt_required, current_user, verify_jwt_in_request
from flask_restx import Resource, inputs, abort
from backend import db, app, jwt_auth
from backend.api import api_user
from backend.api.models import user_model, recorder_model, generic_id_parser
from backend.models import Recorder
from backend.models.user_model import User, Group
from backend.models.recorder_model import Recorder
from backend.models.user_model import User
user_update_parser = api_user.parser()
@@ -27,10 +27,11 @@ user_update_parser.add_argument('last_name', type=str, required=False, store_mis
@api_user.route('/profile')
class Profile(Resource):
@jwt_required
@jwt_required()
@api_user.marshal_with(user_model)
def get(self):
"""Get infos about logged in user."""
print("hey!")
current_user_id = get_jwt_identity()
app.logger.info(current_user_id)
return User.get_by_identifier(current_user_id)
@@ -102,7 +103,7 @@ class UserList(Resource):
return User.get_all()
@jwt_required
@api_user.doc('create_group')
@api_user.doc('create_user')
@api_user.expect(user_model)
@api_user.marshal_with(user_model, code=201)
def post(self):

View File

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

View File

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

View File

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

View File

@@ -1,133 +1,95 @@
{
"recorders": [
{
"name": "CS 50.35 Fasansengarten-H\u00f6rsaal (Hs a.F.)",
"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",
"name": "CS 10.91 Grashof-Hoersaal",
"building": "10.91",
"room": "Grashof",
"username": "admin",
"password": "lrgrashof+-",
"ip": "129.13.51.84",
"mac": "00:55:56:78:96:2f",
"type": "LectureRecorder X2",
"additional_camera": false,
"firmware_version": "3.12.0k",
"description": "{\"comment\": \"pyCA v2.1\", \"network_port\": \"EDV 6 L\", \"rsync_name\": \"LRGrashof\"}"
"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 50.24 H\u00f6rsaal-101",
"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",
"name": "CS 30.41 Chemie-Hoersaal Nr. 1",
"building": "30.41",
"room": "Chemie \u2013 H\u00f6rsaal 3",
"room": "Chemie - Hörsaal 1",
"username": "admin",
"password": "lrhs3+-",
"ip": "129.13.51.91",
"mac": "00:55:56:f1:7c:84",
"type": "LectureRecorder X2",
"password": "smphs1",
"ip": "129.13.51.118",
"mac": "00:05:A6:1C:07:27",
"type": "SMP 351",
"additional_camera": false,
"firmware_version": "3.12.0k",
"description": "{\"comment\": \"pyCA v2.1\", \"network_port\": \"\", \"rsync_name\": \"LRHS3\"}"
"firmware_version": "3.05b002",
"description": "{\"comment\": \"SMP 351 + LL\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 10.91 Redtenbacher-H\u00f6rsaal",
"building": "10.91",
"room": "Redtenbacher H\u00f6rsaal",
"name": "CS 30.41 Chemie-Hoersaal Nr. 2",
"building": "30.41",
"room": "Chemie - Hörsaal 2",
"username": "admin",
"password": "lrredtenbacher+-",
"ip": "129.13.51.79",
"mac": "00:55:56:75:29:19",
"type": "VGADVI Recorder",
"password": "smphs2",
"ip": "129.13.51.117",
"mac": "00:05:A6:1C:07:00",
"type": "SMP 351",
"additional_camera": false,
"firmware_version": "2.5.0f",
"description": "{\"comment\": \"pyCA v2.1\", \"network_port\": \"\", \"rsync_name\": \"Redtenbacher_HS\"}"
"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\u00f6rsaal Bauingenieure",
"room": "Grosser Hörsaal Bauingenieure",
"username": "admin",
"password": "smpgrosserhs",
"ip": "129.13.51.101",
"mac": "",
"type": "SMP 351",
"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\": \"\"}"
},
{
@@ -140,125 +102,177 @@
"mac": "00-05-A6-11-E2-6D",
"type": "SMP 351",
"additional_camera": false,
"firmware_version": "2.11b0",
"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\u00f6rsaal",
"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": "2.11b0",
"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",
"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": "2.11b0",
"firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 40.50 EBI Hoersaal",
"building": "40.50",
"room": "Engler Bunte H\u00f6rsaal RBI",
"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": "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\": \"\"}"
},
{
"name": "CS 11.40 Johann-Gottfried-Tulla-Hoersaal",
"building": "11.40",
"room": "Tulla H\u00f6rsaal",
"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": "2.11b0",
"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\u00f6rsaal",
"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": "2.11b0",
"firmware_version": "3.04",
"description": "{\"comment\": \"2 Projektionen \", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 30.22 Gaede-Hoersaal",
"building": "30.22",
"room": "Gaede H\u00f6rsaal",
"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": "2.11b0",
"firmware_version": "3.05b002",
"description": "{\"comment\": \"2 Projektionen \", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "CS 10.11 Hertz-Hoersaal",
"building": "10.11",
"room": "Hertz \u2013 H\u00f6rsaal",
"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": "2.11b0",
"firmware_version": "3.05b002",
"description": "{\"comment\": \"Dual Link License\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "Campus Ost 70.04 SR219",
"name": "CO 70.04 Raum 219",
"building": "70.04",
"room": "CO 70.04 SR219",
"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": "2.11b0",
"firmware_version": "3.05b002",
"description": "{\"comment\": \"FAST Gauterin\", \"network_port\": \"\", \"rsync_name\": \"\"}"
},
{
"name": "ILIAS-HS_3",
"building": "30.50",
"room": "Test-LR",
"name": "CS 30.21 Gerthsen-Hoersaal",
"building": "30.21",
"room": "Gerthsen-Hörsaal",
"username": "admin",
"password": "lrgrashof+-",
"ip": "172.23.8.102",
"mac": "00:55:56:f4:88:e1",
"type": "DVI Broadcaster DL",
"additional_camera": false,
"firmware_version": "3.12.0k",
"description": "{\"comment\": \"von Axel\", \"network_port\": \"MZ\", \"rsync_name\": \"\"}"
"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",
@@ -270,7 +284,7 @@
"mac": "00-05-A6-16-A3-E4",
"type": "SMP352",
"additional_camera": false,
"firmware_version": "2.11b0",
"firmware_version": "3.05b002",
"description": "{\"comment\": \"von FM\", \"network_port\": \"MZ\", \"rsync_name\": \"\"}"
}
],

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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