now scraping rooms from capmus mgmt
This commit is contained in:
2
Pipfile
2
Pipfile
@@ -23,6 +23,8 @@ flask-jwt-extended = "*"
|
||||
ssh2-python = "*"
|
||||
update = "*"
|
||||
flask-cors = "*"
|
||||
html5lib = "*"
|
||||
beautifulsoup4 = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
|
||||
46
Pipfile.lock
generated
46
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "79518b33814e3afda968f02d6de17856076a2d7a81183eb7ee1c219eccc114cc"
|
||||
"sha256": "10fe25a82139020ea4ed6a7615b6f77965ebb4a96824b6f0d8989da081db892f"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@@ -63,6 +63,15 @@
|
||||
],
|
||||
"version": "==1.10.1"
|
||||
},
|
||||
"beautifulsoup4": {
|
||||
"hashes": [
|
||||
"sha256:05668158c7b85b791c5abde53e50265e16f98ad601c402ba44d70f96c4159612",
|
||||
"sha256:25288c9e176f354bf277c0a10aa96c782a6a18a17122dba2e8cec4a97e03343b",
|
||||
"sha256:f040590be10520f2ea4c2ae8c3dae441c7cfff5308ec9d58a0ec0c1b8f81d469"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.8.0"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939",
|
||||
@@ -252,10 +261,10 @@
|
||||
},
|
||||
"flask-restplus": {
|
||||
"hashes": [
|
||||
"sha256:3fad697e1d91dfc13c078abcb86003f438a751c5a4ff41b84c9050199d2eab62",
|
||||
"sha256:cdc27b5be63f12968a7f762eaa355e68228b0c904b4c96040a314ba7dc6d0e69"
|
||||
"sha256:a15d251923a8feb09a5d805c2f4d188555910a42c64d58f7dd281b8cac095f1b",
|
||||
"sha256:a66e442d0bca08f389fc3d07b4d808fc89961285d12fb8013f7cf15516fa9f5c"
|
||||
],
|
||||
"version": "==0.12.1"
|
||||
"version": "==0.13.0"
|
||||
},
|
||||
"flask-restplus-patched": {
|
||||
"hashes": [
|
||||
@@ -292,6 +301,14 @@
|
||||
],
|
||||
"version": "==0.17.1"
|
||||
},
|
||||
"html5lib": {
|
||||
"hashes": [
|
||||
"sha256:20b159aa3badc9d5ee8f5c647e5efd02ed2a66ab8d354930bd9ff139fc1dc0a3",
|
||||
"sha256:66cb0dcfdbbc4f9c3ba1a63fdb511ffdbd4f513b2b6d81b80cd26ce6b3fb3736"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.0.1"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
|
||||
@@ -361,10 +378,10 @@
|
||||
},
|
||||
"marshmallow": {
|
||||
"hashes": [
|
||||
"sha256:9cedfc5b6f568d57e8a2cf3d293fbd81b05e5ef557854008d03e25660a39ccfd",
|
||||
"sha256:a4d99922116a76e5abd8f997ec0519086e24814b7e1e1344bebe2a312ba50235"
|
||||
"sha256:43bef4d33b7adb1f66eba8074095208b38dec96bed51f7a9bf2e687750f226d8",
|
||||
"sha256:b240f5e14bc641c257f4b7bda3951d7e71963ebf66bd519078267f1f961cbd15"
|
||||
],
|
||||
"version": "==2.19.5"
|
||||
"version": "==2.20.1"
|
||||
},
|
||||
"oic": {
|
||||
"hashes": [
|
||||
@@ -396,7 +413,6 @@
|
||||
},
|
||||
"pycparser": {
|
||||
"hashes": [
|
||||
"sha256:50f84b9531cf541192a39303722ea4d69cab456fc1104ca47f66b9b8dd7be740",
|
||||
"sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"
|
||||
],
|
||||
"version": "==2.19"
|
||||
@@ -512,6 +528,13 @@
|
||||
],
|
||||
"version": "==1.12.0"
|
||||
},
|
||||
"soupsieve": {
|
||||
"hashes": [
|
||||
"sha256:72b5f1aea9101cf720a36bb2327ede866fd6f1a07b1e87c92a1cc18113cbc946",
|
||||
"sha256:e4e9c053d59795e440163733a7fec6c5972210e1790c507e4c7b051d6c5259de"
|
||||
],
|
||||
"version": "==1.9.2"
|
||||
},
|
||||
"sqlalchemy": {
|
||||
"hashes": [
|
||||
"sha256:217e7fc52199a05851eee9b6a0883190743c4fb9c8ac4313ccfceaffd852b0ff"
|
||||
@@ -595,6 +618,13 @@
|
||||
],
|
||||
"version": "==5.4.0"
|
||||
},
|
||||
"webencodings": {
|
||||
"hashes": [
|
||||
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
|
||||
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
|
||||
],
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"werkzeug": {
|
||||
"hashes": [
|
||||
"sha256:87ae4e5b5366da2347eb3116c0e6c681a0e939a33b2805e2c0cbd282664932c4",
|
||||
|
||||
@@ -8,6 +8,8 @@ import ssl
|
||||
from jinja2.exceptions import TemplateNotFound
|
||||
|
||||
from backend import app, db
|
||||
from backend.models import pre_fill_table
|
||||
from backend.tools.model_updater import update_recorder_models_database
|
||||
|
||||
|
||||
def main():
|
||||
@@ -28,8 +30,11 @@ def main():
|
||||
except Exception as e:
|
||||
logging.CRITICAL(e)
|
||||
|
||||
pre_fill_table()
|
||||
update_recorder_models_database()
|
||||
|
||||
app.run(debug=True)
|
||||
|
||||
app.run(debug=True, host="0.0.0.0")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -29,11 +29,17 @@ api_user = Namespace('user', description="User management namespace", authorizat
|
||||
api_group = Namespace('group', description="Group management namespace", authorizations=api_authorizations)
|
||||
api_room = Namespace('room', description="Room management namespace", authorizations=api_authorizations)
|
||||
api_recorder = Namespace('recorder', description="Recorder management namespace", authorizations=api_authorizations)
|
||||
api_virtual_command = Namespace('virtual_command', description="Virtual command namespace",
|
||||
authorizations=api_authorizations)
|
||||
api_cron_job = Namespace('cron_job', description="Cron job namespace",
|
||||
authorizations=api_authorizations)
|
||||
|
||||
api_v1.add_namespace(api_user)
|
||||
api_v1.add_namespace(api_group)
|
||||
api_v1.add_namespace(api_room)
|
||||
api_v1.add_namespace(api_recorder)
|
||||
api_v1.add_namespace(api_virtual_command)
|
||||
api_v1.add_namespace(api_cron_job)
|
||||
|
||||
auth_api_bp = Blueprint('auth_api', __name__, url_prefix='/api/auth')
|
||||
# user_api_bp = Blueprint('user_api', __name__, url_prefix='/api/user')
|
||||
@@ -45,7 +51,9 @@ from .user_api import *
|
||||
from .group_api import *
|
||||
from .room_api import *
|
||||
from .recorder_api import *
|
||||
#from .group_api import *
|
||||
|
||||
|
||||
# from .group_api import *
|
||||
|
||||
|
||||
@api_bp.route('/<path:path>')
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import datetime
|
||||
import ipaddress
|
||||
import json
|
||||
|
||||
@@ -5,12 +5,11 @@ For example: listing of available auth providers or registration of users.
|
||||
|
||||
Login through API does not start a new session, but instead returns JWT.
|
||||
"""
|
||||
import inspect
|
||||
import pkgutil
|
||||
from datetime import datetime
|
||||
from pprint import pprint
|
||||
|
||||
from flask_jwt_extended import jwt_required
|
||||
from flask_restplus import fields, Resource
|
||||
from flask_restplus import fields, Resource, inputs
|
||||
|
||||
from backend import db, app
|
||||
from backend.api import api_recorder
|
||||
@@ -21,17 +20,23 @@ import backend.recorder_adapters as r_a
|
||||
recorder_model = api_recorder.model('Recorder', {
|
||||
'id': fields.String(required=False, description='The recorder\'s identifier'),
|
||||
'created_at': fields.DateTime(required=False, description='Creation date of the recorder'),
|
||||
'last_time_modified': fields.DateTime(required=False, description='Creation date of the recorder'),
|
||||
'name': fields.String(min_length=3, required=True, description='The recorder\'s name'),
|
||||
'description': fields.String(required=False, description='The recorder\'s description'),
|
||||
'locked': fields.Boolean(required=False, description='Indicates whether the recorder settings can be altered'),
|
||||
'lock_message': fields.String(required=False, description='Optional: message explaining lock state'),
|
||||
'offline': fields.Boolean(required=False,
|
||||
description='Should be set when recorder is disconnected for maintenance, etc.'),
|
||||
'ip': fields.String(required=False, description='The recorder\'s IP address'),
|
||||
'network_name': fields.String(required=False, description='The recorder\'s network name'),
|
||||
'ssh_port': fields.Integer(required=True, default=22, description='The recorder\'s SSH port number'),
|
||||
'telnet_port': fields.Integer(required=True, default=23, description='The recorder\'s telnet port number'),
|
||||
'use_telnet_instead_ssh': fields.Boolean(required=False, default=False,
|
||||
description='If this is set, telnet will be used instead of ssh. '
|
||||
'This might require specific commands.'),
|
||||
# 'use_telnet_instead_ssh': fields.Boolean(required=False, default=False,
|
||||
# description='If this is set, telnet will be used instead of ssh. '
|
||||
# 'This might require specific commands.'),
|
||||
'recorder_model': fields.Nested(api_recorder.model('recorder_model',
|
||||
{'id': fields.Integer(), 'name': fields.String()}),
|
||||
{'id': fields.Integer(),
|
||||
'name': fields.String(attribute="model_name", )}),
|
||||
required=False,
|
||||
allow_null=True,
|
||||
skip_none=False,
|
||||
@@ -39,30 +44,41 @@ recorder_model = api_recorder.model('Recorder', {
|
||||
'room': fields.Nested(api_recorder.model('recorder_room',
|
||||
{'id': fields.Integer(), 'name': fields.String(),
|
||||
'number': fields.String(), 'alternate_name': fields.String()}),
|
||||
required=False,
|
||||
r0equired=False,
|
||||
allow_null=True,
|
||||
skip_none=False,
|
||||
description='Room in which the recorder is located.')
|
||||
description='Room in which the recorder is located.'),
|
||||
'virtual_commands': fields.List(fields.Nested(api_recorder.model('recorder_virtual_commands',
|
||||
{'id': fields.Integer(),
|
||||
'name': fields.String()})))
|
||||
})
|
||||
|
||||
recorder_command_model = api_recorder.model('Recorder Command', {
|
||||
'id': fields.String(required=False, description='The recorder command\'s identifier'),
|
||||
'name': fields.String(required=True, description='The recorder command\'s name'),
|
||||
'alternative_name': fields.String(required=False, description='The recorder command\'s alternative name'),
|
||||
'disabled': fields.Boolean(required=False, description='Indicates if the recorder command is disabled'),
|
||||
'created_at': fields.DateTime(required=False, description='Creation date of the recorder'),
|
||||
'last_time_modified': fields.DateTime(required=False),
|
||||
'description': fields.String(required=False, description='The recorder command\'s description'),
|
||||
'parameters': fields.Raw(required=True, description='The recorder parameters'),
|
||||
'recorder_model': fields.Nested(api_recorder.model('recorder_command_models',
|
||||
{'id': fields.Integer(), 'name': fields.String()})),
|
||||
{'id': fields.Integer(),
|
||||
'name': fields.String(attribute="model_name", )})),
|
||||
})
|
||||
|
||||
recorder_model_model = api_recorder.model('Recorder Model', {
|
||||
'id': fields.String(required=False, description='The recorder model\'s identifier'),
|
||||
'name': fields.String(attribute="model_name", required=True, description='The recorder model\'s name'),
|
||||
'created_at': fields.DateTime(required=False, description='Creation date of the recorder'),
|
||||
'last_time_modified': fields.DateTime(required=False),
|
||||
'notes': fields.String(required=False, description='The recorder model\'s notes'),
|
||||
'requires_username': fields.Boolean(),
|
||||
'requires_password': fields.Boolean(),
|
||||
|
||||
'recorders': fields.List(fields.Nested(api_recorder.model('recorder_model',
|
||||
{'id': fields.Integer(), 'name': fields.String(),
|
||||
{'id': fields.Integer(),
|
||||
'name': fields.String(attribute="model_name", ),
|
||||
'network_name': fields.String(),
|
||||
'ip': fields.String()})), required=False,
|
||||
description='Model of the recorder.'),
|
||||
@@ -98,12 +114,36 @@ class RecorderResource(Resource):
|
||||
return '', 204
|
||||
api_recorder.abort(404)
|
||||
|
||||
recorder_update_parser = api_recorder.parser()
|
||||
recorder_update_parser.add_argument('name', type=str, required=False, nullable=False, store_missing=False)
|
||||
recorder_update_parser.add_argument('network_name', type=inputs.regex(inputs.netloc_regex), required=False, store_missing=False)
|
||||
recorder_update_parser.add_argument('ip', type=inputs.ipv4, required=False, store_missing=False)
|
||||
recorder_update_parser.add_argument('ip6', type=inputs.ipv6, required=False, store_missing=False)
|
||||
recorder_update_parser.add_argument('ssh_port', type=inputs.int_range(0,65535), required=False, default=22, store_missing=False)
|
||||
recorder_update_parser.add_argument('telnet_port', type=inputs.int_range(0,65535), required=False, default=23, store_missing=False)
|
||||
recorder_update_parser.add_argument('room_id', type=int, required=False, store_missing=False)
|
||||
recorder_update_parser.add_argument('offline', type=inputs.boolean, required=False, default=False, store_missing=False)
|
||||
recorder_update_parser.add_argument('locked', type=inputs.boolean, required=False, default=False, store_missing=False)
|
||||
recorder_update_parser.add_argument('lock_message', type=str, required=False, nullable=True, default=None,
|
||||
store_missing=False)
|
||||
recorder_update_parser.add_argument('model_id', type=int, required=False, store_missing=False)
|
||||
recorder_update_parser.add_argument('description', type=str, required=False, nullable=True, default=None,
|
||||
store_missing=False)
|
||||
recorder_update_parser.add_argument('virtual_command_ids', action='split', nullable=True, default=[],
|
||||
required=False, store_missing=False)
|
||||
|
||||
@jwt_required
|
||||
@api_recorder.doc('update_recorder')
|
||||
@api_recorder.expect(recorder_model)
|
||||
def put(self, id):
|
||||
"""Update a recorder given its identifier"""
|
||||
num_rows_matched = Recorder.query.filter_by(id=id).update(api_recorder.payload)
|
||||
args = self.recorder_update_parser.parse_args(strict=True)
|
||||
args['last_time_modified'] = datetime.utcnow()
|
||||
pprint(args)
|
||||
|
||||
num_rows_matched = Recorder.query.filter_by(id=id).update(args)
|
||||
print(num_rows_matched)
|
||||
|
||||
if num_rows_matched < 1:
|
||||
api_recorder.abort(404)
|
||||
db.session.commit()
|
||||
@@ -205,21 +245,13 @@ class RecorderCommandResource(Resource):
|
||||
return recorder_command
|
||||
api_recorder.abort(404)
|
||||
|
||||
@jwt_required
|
||||
@api_recorder.doc('delete_recorder_command')
|
||||
@api_recorder.response(204, 'Recorder_command deleted')
|
||||
def delete(self, id):
|
||||
"""Delete a recorder command given its identifier"""
|
||||
recorder_command = RecorderCommand.query.get(id)
|
||||
if recorder_command is not None:
|
||||
db.session.delete(recorder_command)
|
||||
db.session.commit()
|
||||
return '', 204
|
||||
api_recorder.abort(404)
|
||||
recorder_command_model_parser = api_recorder.parser()
|
||||
recorder_command_model_parser.add_argument('description', type=str, required=False)
|
||||
recorder_command_model_parser.add_argument('alternative_name', type=str, required=False)
|
||||
|
||||
@jwt_required
|
||||
@api_recorder.doc('update_recorder_command')
|
||||
@api_recorder.expect(recorder_command_model)
|
||||
@api_recorder.expect(recorder_command_model_parser)
|
||||
@api_recorder.marshal_with(recorder_command_model)
|
||||
def put(self, id):
|
||||
"""Update a recorder command given its identifier"""
|
||||
@@ -241,13 +273,3 @@ class RecorderCommandList(Resource):
|
||||
:return: recorder commands
|
||||
"""
|
||||
return RecorderCommand.get_all()
|
||||
|
||||
@jwt_required
|
||||
@api_recorder.doc('create_recorder_commands')
|
||||
@api_recorder.expect(recorder_command_model)
|
||||
@api_recorder.marshal_with(recorder_command_model, code=201)
|
||||
def post(self):
|
||||
recorder_command = RecorderCommand(**api_recorder.payload)
|
||||
db.session.add(recorder_command)
|
||||
db.session.commit()
|
||||
return recorder_command
|
||||
|
||||
@@ -21,6 +21,8 @@ room_model = api_room.model('Room', {
|
||||
'alternate_name': fields.String(required=False, description='The room\'s alternate name'),
|
||||
'comment': fields.String(required=False, description='The room\'s comment'),
|
||||
'number': fields.String(required=True, description='The room\'s number'),
|
||||
'building_name': fields.String(required=False, description='The building\'s name'),
|
||||
'building_number': fields.String(required=False, description='The building\'s number'),
|
||||
'recorder': fields.Nested(api_room.model('room_recorder',
|
||||
{'id': fields.Integer(), 'name': fields.String(),
|
||||
'ip': fields.String(), 'network_name': fields.String()}),
|
||||
|
||||
127
api/virtual_command_api.py
Normal file
127
api/virtual_command_api.py
Normal file
@@ -0,0 +1,127 @@
|
||||
# Copyright (c) 2019. Tobias Kurze
|
||||
"""
|
||||
This module provides functions related to authentication through the API.
|
||||
For example: listing of available auth providers or registration of users.
|
||||
|
||||
Login through API does not start a new session, but instead returns JWT.
|
||||
"""
|
||||
import inspect
|
||||
import pkgutil
|
||||
from pprint import pprint
|
||||
|
||||
from flask_jwt_extended import jwt_required
|
||||
from flask_restplus import fields, Resource
|
||||
|
||||
from backend import db, app
|
||||
from backend.api import api_virtual_command
|
||||
from backend.models.recorder_model import Recorder, RecorderModel, RecorderCommand
|
||||
from backend.models.room_model import Room
|
||||
import backend.recorder_adapters as r_a
|
||||
|
||||
virtual_command_model = api_virtual_command.model('VirtualCommand', {
|
||||
'id': fields.String(required=False, description='The recorder\'s identifier'),
|
||||
'created_at': fields.DateTime(required=False, description='Creation date of the recorder'),
|
||||
'name': fields.String(min_length=3, required=True, description='The recorder\'s name'),
|
||||
'description': fields.String(required=False, description='The recorder\'s description'),
|
||||
|
||||
'parent_virtual_command': fields.Nested('virtual_command_model',
|
||||
required=False,
|
||||
allow_null=True,
|
||||
skip_none=False,
|
||||
description='Parent virtual command.'),
|
||||
'room': fields.Nested(api_virtual_command.model('recorder_room',
|
||||
{'id': fields.Integer(), 'name': fields.String(),
|
||||
'number': fields.String(), 'alternate_name': fields.String()}),
|
||||
r0equired=False,
|
||||
allow_null=True,
|
||||
skip_none=False,
|
||||
description='Room in which the recorder is located.')
|
||||
})
|
||||
|
||||
|
||||
# ==
|
||||
|
||||
@api_virtual_command.route('/<int:id>')
|
||||
@api_virtual_command.response(404, 'Recorder not found')
|
||||
@api_virtual_command.param('id', 'The recorder identifier')
|
||||
class VirtualCommandResource(Resource):
|
||||
@jwt_required
|
||||
@api_virtual_command.doc('get_recorder')
|
||||
@api_virtual_command.marshal_with(virtual_command_model, skip_none=False)
|
||||
def get(self, id):
|
||||
"""Fetch a recorder given its identifier"""
|
||||
recorder = Recorder.query.get(id)
|
||||
if recorder is not None:
|
||||
return recorder
|
||||
api_virtual_command.abort(404)
|
||||
|
||||
@jwt_required
|
||||
@api_virtual_command.doc('delete_todo')
|
||||
@api_virtual_command.response(204, 'Todo deleted')
|
||||
def delete(self, id):
|
||||
"""Delete a recorder given its identifier"""
|
||||
recorder = Recorder.query.get(id)
|
||||
if recorder is not None:
|
||||
db.session.delete(recorder)
|
||||
db.session.commit()
|
||||
return '', 204
|
||||
api_virtual_command.abort(404)
|
||||
|
||||
virtual_command_model_parser = api_virtual_command.parser()
|
||||
virtual_command_model_parser.add_argument('notes', type=str, required=True)
|
||||
|
||||
@jwt_required
|
||||
@api_virtual_command.doc('update_recorder')
|
||||
@api_virtual_command.expect(virtual_command_model_parser)
|
||||
def put(self, id):
|
||||
"""Update a recorder given its identifier"""
|
||||
num_rows_matched = Recorder.query.filter_by(id=id).update(api_virtual_command.payload)
|
||||
if num_rows_matched < 1:
|
||||
api_virtual_command.abort(404)
|
||||
db.session.commit()
|
||||
return "ok"
|
||||
|
||||
|
||||
@api_virtual_command.route('')
|
||||
class RecorderList(Resource):
|
||||
@jwt_required
|
||||
@api_virtual_command.doc('recorders')
|
||||
@api_virtual_command.marshal_list_with(virtual_command_model, skip_none=False)
|
||||
def get(self):
|
||||
"""
|
||||
List all recorders
|
||||
:return: recorders
|
||||
"""
|
||||
return Recorder.get_all()
|
||||
|
||||
virtual_command_model_parser = api_virtual_command.parser()
|
||||
virtual_command_model_parser.add_argument('notes', type=str, required=True)
|
||||
|
||||
@jwt_required
|
||||
@api_virtual_command.doc('create_recorder')
|
||||
@api_virtual_command.expect(virtual_command_model_parser)
|
||||
@api_virtual_command.marshal_with(virtual_command_model, skip_none=False, code=201)
|
||||
def post(self):
|
||||
if "room_id" in api_virtual_command.payload:
|
||||
if api_virtual_command.payload["room_id"] is None:
|
||||
api_virtual_command.payload["room"] = None
|
||||
else:
|
||||
room = Room.query.get(api_virtual_command.payload["room_id"])
|
||||
if room is not None:
|
||||
api_virtual_command.payload["room"] = room
|
||||
else:
|
||||
return "specified room (id: {}) does not exist!".format(api_virtual_command.payload["room_id"]), 404
|
||||
if "recorder_model_id" in api_virtual_command.payload:
|
||||
if api_virtual_command.payload["recorder_model_id"] is None:
|
||||
api_virtual_command.payload["recorder_model"] = None
|
||||
else:
|
||||
rec_model = RecorderModel.query.get(api_virtual_command.payload["recorder_model_id"])
|
||||
if rec_model is not None:
|
||||
api_virtual_command.payload["recorder_model"] = rec_model
|
||||
else:
|
||||
return "specified recorder model (id: {}) does not exist!".format(
|
||||
api_virtual_command.payload["recorder_model_id"]), 404
|
||||
recorder = Recorder(**api_virtual_command.payload)
|
||||
db.session.add(recorder)
|
||||
db.session.commit()
|
||||
return recorder
|
||||
@@ -1,14 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os, sys
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), os.path.pardir))
|
||||
import os
|
||||
import unittest
|
||||
import coverage
|
||||
|
||||
from backend import app, db
|
||||
|
||||
|
||||
from flask_script import Manager
|
||||
from flask_migrate import Migrate, MigrateCommand
|
||||
|
||||
from backend import app, db
|
||||
|
||||
COV = coverage.coverage(
|
||||
branch=True,
|
||||
include='app/*',
|
||||
|
||||
@@ -4,3 +4,6 @@ Import all models...
|
||||
from backend.models.example_model import *
|
||||
from backend.models.user_model import *
|
||||
from backend.models.post_model import *
|
||||
from backend.models.recorder_model import *
|
||||
from backend.models.room_model import *
|
||||
from backend.models.virtual_command_model import *
|
||||
|
||||
@@ -6,6 +6,7 @@ import json
|
||||
|
||||
from sqlalchemy import MetaData
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from sqlalchemy.orm import validates
|
||||
|
||||
from backend import db, app, login_manager
|
||||
import re
|
||||
@@ -19,6 +20,7 @@ metadata = MetaData()
|
||||
|
||||
class RecorderModel(db.Model):
|
||||
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)
|
||||
@@ -26,6 +28,8 @@ class RecorderModel(db.Model):
|
||||
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)
|
||||
requires_user = db.Column(db.Boolean)
|
||||
requires_password = db.Column(db.Boolean)
|
||||
|
||||
@staticmethod
|
||||
def get_all():
|
||||
@@ -49,13 +53,19 @@ class Recorder(db.Model):
|
||||
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
|
||||
last_time_modified = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
|
||||
name = db.Column(db.Unicode(63), unique=True, nullable=False)
|
||||
locked = db.Column(db.Boolean, default=False)
|
||||
lock_message = db.Column(db.String, nullable=True, default=None)
|
||||
offline = db.Column(db.Boolean, default=False)
|
||||
description = db.Column(db.Unicode(255), unique=False, nullable=True, default="")
|
||||
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)
|
||||
ip = db.Column(db.String(15), unique=True, nullable=True, default=None)
|
||||
ip6 = db.Column(db.String(46), unique=True, nullable=True, default=None)
|
||||
network_name = db.Column(db.String(127), unique=True, nullable=True, default=None)
|
||||
telnet_port = db.Column(db.Integer, unique=False, nullable=False, default=23)
|
||||
ssh_port = db.Column(db.Integer, unique=False, nullable=False, default=22)
|
||||
username = db.column(db.String(127))
|
||||
password = db.column(db.String(127))
|
||||
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')
|
||||
@@ -71,6 +81,11 @@ class Recorder(db.Model):
|
||||
def get_all():
|
||||
return Recorder.query.all()
|
||||
|
||||
@validates('name')
|
||||
def validate_name(self, key, value):
|
||||
assert len(value) > 2
|
||||
return value
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@@ -85,8 +100,11 @@ class Recorder(db.Model):
|
||||
class RecorderCommand(db.Model):
|
||||
"""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=None)
|
||||
name = db.Column(db.Unicode(63), unique=True, nullable=False)
|
||||
alternative_name = db.Column(db.Unicode(63), unique=True, nullable=True, default=None)
|
||||
disabled = db.Column(db.Boolean, default=False)
|
||||
description = db.Column(db.Unicode(511), nullable=True, default=None)
|
||||
parameters_string = db.Column(db.String(2047), nullable=True)
|
||||
recorder_model = db.relationship('RecorderModel', back_populates='recorder_commands')
|
||||
|
||||
@@ -5,13 +5,12 @@ Models for lecture recorder
|
||||
import json
|
||||
|
||||
from sqlalchemy import MetaData, CheckConstraint
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from backend import db, app, login_manager
|
||||
import re
|
||||
from sqlalchemy import or_
|
||||
from datetime import datetime, timedelta
|
||||
from backend.models.recorder_model import Recorder
|
||||
|
||||
from backend.tools.scrape_rooms import scrape_rooms
|
||||
|
||||
metadata = MetaData()
|
||||
|
||||
@@ -19,10 +18,12 @@ metadata = MetaData()
|
||||
class Room(db.Model):
|
||||
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
|
||||
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
|
||||
name = db.Column(db.Unicode(127), unique=True, nullable=False)
|
||||
alternate_name = db.Column(db.Unicode(127), unique=True, nullable=True, default=None)
|
||||
name = db.Column(db.Unicode(127), unique=False, nullable=False)
|
||||
alternate_name = db.Column(db.Unicode(127), unique=False, nullable=True, default=None)
|
||||
comment = db.Column(db.Unicode(2047), unique=False, nullable=True, default="")
|
||||
number = db.Column(db.Unicode(63), unique=True, nullable=True)
|
||||
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)
|
||||
|
||||
@@ -34,7 +35,6 @@ class Room(db.Model):
|
||||
def __init__(self, **kwargs):
|
||||
super(Room, self).__init__(**kwargs)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_by_name(name):
|
||||
"""
|
||||
@@ -47,7 +47,7 @@ class Room(db.Model):
|
||||
@staticmethod
|
||||
def get_all():
|
||||
"""
|
||||
Return all groups
|
||||
Return all rooms
|
||||
:return:
|
||||
"""
|
||||
return Room.query.all()
|
||||
@@ -61,3 +61,16 @@ class Room(db.Model):
|
||||
def toJSON(self):
|
||||
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
|
||||
sort_keys=True, indent=4)
|
||||
|
||||
|
||||
def pre_fill_table():
|
||||
rooms = scrape_rooms()
|
||||
i_tunes_u_mappings = [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(i_tunes_u_mappings)
|
||||
db.session.commit()
|
||||
except IntegrityError as e:
|
||||
db.session.rollback()
|
||||
|
||||
@@ -110,6 +110,10 @@ def get_defined_recorder_adapters():
|
||||
rec_model = {'id': f_p[1], 'name': f_p[1], 'commands': {}}
|
||||
if hasattr(rec_model_module, 'RECORDER_MODEL_NAME'):
|
||||
rec_model['name'] = rec_model_module.RECORDER_MODEL_NAME
|
||||
if hasattr(rec_model_module, 'REQUIRES_USER'):
|
||||
rec_model['requires_user'] = rec_model_module.REQUIRES_USER
|
||||
if hasattr(rec_model_module, 'REQUIRES_PW'):
|
||||
rec_model['requires_password'] = rec_model_module.REQUIRES_PW
|
||||
for name, obj in inspect.getmembers(rec_model_module, inspect.isclass):
|
||||
if issubclass(obj, RecorderAdapter):
|
||||
commands = {}
|
||||
|
||||
@@ -2,6 +2,8 @@ from backend.recorder_adapters import telnetlib, TelnetAdapter, RecorderAdapter
|
||||
|
||||
RECORDER_MODEL_NAME = "SMP 351 / 352"
|
||||
VERSION = "0.9.0"
|
||||
REQUIRES_USER = False
|
||||
REQUIRES_PW = True
|
||||
|
||||
# HOST = "localhost"
|
||||
# HOST = "129.13.51.102" # Audimax SMP 351
|
||||
@@ -13,9 +15,9 @@ PW = "123mzsmp"
|
||||
|
||||
|
||||
class SMP(TelnetAdapter, RecorderAdapter):
|
||||
def __init__(self, address, admin_password):
|
||||
def __init__(self, address, password, **kwargs):
|
||||
super().__init__(address)
|
||||
self.admin_pw = admin_password
|
||||
self.admin_pw = password
|
||||
|
||||
def _login(self):
|
||||
self.tn = telnetlib.Telnet(HOST)
|
||||
|
||||
@@ -21,8 +21,9 @@ def calculate_md5_checksum(string_to_md5_sum: str):
|
||||
|
||||
|
||||
def create_recorder_commands_for_recorder_adapter(command_definitions: dict, recorder_model: RecorderModel):
|
||||
existing_recorder_commands = RecorderCommand.query.filter(and_(RecorderCommand.name.in_(command_definitions.keys())),
|
||||
RecorderCommand.recorder_model == recorder_model)
|
||||
existing_recorder_commands = RecorderCommand.query.filter(
|
||||
and_(RecorderCommand.name.in_(command_definitions.keys())),
|
||||
RecorderCommand.recorder_model == recorder_model)
|
||||
existing_commands = set()
|
||||
for existing_command in existing_recorder_commands:
|
||||
existing_commands.add(existing_command.name)
|
||||
@@ -51,7 +52,9 @@ def update_recorder_models_database():
|
||||
r_m = RecorderModel.get_by_adapter_id(r_a["id"])
|
||||
model_checksum = calculate_md5_checksum(dumps(r_a["commands"]))
|
||||
if r_m is None:
|
||||
r_m = RecorderModel(record_adapter_id=r_a["id"], model_name=r_a["name"], checksum=model_checksum)
|
||||
r_m = RecorderModel(record_adapter_id=r_a["id"], model_name=r_a["name"], checksum=model_checksum,
|
||||
requires_user=r_a.get('requires_user', None),
|
||||
requires_password=r_a.get('requires_password', None))
|
||||
db.session.add(r_m)
|
||||
db.session.flush()
|
||||
db.session.refresh(r_m)
|
||||
|
||||
60
tools/scrape_rooms.py
Normal file
60
tools/scrape_rooms.py
Normal file
@@ -0,0 +1,60 @@
|
||||
from pprint import pprint
|
||||
|
||||
import re
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
|
||||
def scrape_rooms():
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
|
||||
|
||||
room_url = "https://campus.kit.edu/live-stud/campus/all/roomgroup.asp?roomgroupcolumn1=H%F6r%2D%2FLehrsaal&tguid=0x1A35C3A1490748388EBEBA3943EFCDD5"
|
||||
page = requests.get(room_url, headers=headers)
|
||||
# soup = BeautifulSoup(page.content, 'html5lib')
|
||||
soup = BeautifulSoup(page.content, 'html.parser')
|
||||
|
||||
# pprint(page.content)
|
||||
|
||||
# pprint(soup.prettify())
|
||||
|
||||
idx = 0
|
||||
|
||||
rooms = []
|
||||
|
||||
re_string = r"^(\d\d.\d\d)?\s(.*)"
|
||||
re_exp = re.compile(re_string)
|
||||
|
||||
for tr in soup.find_all('tr'):
|
||||
idx += 1
|
||||
if idx == 1: # skip first row
|
||||
continue
|
||||
a_name = tr.find_all('a')[0].string
|
||||
a_building = tr.find_all('a')[3].string
|
||||
match = re_exp.match(a_name)
|
||||
if match is not None:
|
||||
building_number, name = re_exp.match(a_name).groups()
|
||||
else:
|
||||
name = a_name
|
||||
building_number = None
|
||||
|
||||
match = re_exp.match(a_building)
|
||||
if match is not None:
|
||||
building_number, building_name = re_exp.match(a_building).groups()
|
||||
else:
|
||||
building_name = a_name
|
||||
building_number = None
|
||||
|
||||
room = {'name': name,
|
||||
'room_number': tr.find_all('a')[1].string if tr.find_all('a')[0].string != "None" else tr.find_all('a')[
|
||||
1].string,
|
||||
'building_name': building_name,
|
||||
'building_number': building_number}
|
||||
|
||||
rooms.append(room)
|
||||
|
||||
return rooms
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
scrape_rooms()
|
||||
Reference in New Issue
Block a user