migrated to poetry; updated all packages
This commit is contained in:
@@ -3,19 +3,18 @@
|
||||
Backend base module
|
||||
"""
|
||||
import logging
|
||||
from io import StringIO
|
||||
from logging.config import dictConfig
|
||||
from logging.handlers import MemoryHandler
|
||||
from typing import Union
|
||||
|
||||
import coloredlogs as coloredlogs
|
||||
import coloredlogs
|
||||
import jwt
|
||||
import requests
|
||||
from flask import Flask, jsonify
|
||||
from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth, MultiAuth
|
||||
from flask_jwt_extended import JWTManager, decode_token
|
||||
from flask_login import LoginManager
|
||||
from flask_restplus import abort
|
||||
from flask_restx import abort
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_cors import CORS
|
||||
from backend.config import Config
|
||||
@@ -109,11 +108,11 @@ class LrcException(Exception):
|
||||
|
||||
def __repr__(self):
|
||||
if self.type is None:
|
||||
msg = "LRC Exception: \"{}\"".format(', '.join(super().args))
|
||||
msg = f"LRC Exception: \"{', '.join(super().args)}\""
|
||||
else:
|
||||
msg = "LRC Exception: (original Exception: {}) \"{}\"".format(self.type, ', '.join(super().args))
|
||||
msg = f"LRC Exception: (original Exception: {self.type}) \"{', '.join(super().args)}\""
|
||||
if self.html_code is not None:
|
||||
msg += " (HTML Code: {})".format(self.html_code)
|
||||
msg += f" (HTML Code: {self.html_code})"
|
||||
return msg
|
||||
|
||||
def __str__(self):
|
||||
@@ -135,7 +134,7 @@ jwt_auth = HTTPTokenAuth('Bearer')
|
||||
|
||||
@jwt_extended.invalid_token_loader
|
||||
def unauthorized_jwt(token):
|
||||
main_logger.info("Unauthorized access; invalid token provided: {}".format(token))
|
||||
main_logger.info("Unauthorized access; invalid token provided: %s", token)
|
||||
abort(401)
|
||||
|
||||
|
||||
@@ -147,10 +146,10 @@ def verify_token(token):
|
||||
try:
|
||||
decoded = decode_token(token)
|
||||
except jwt.exceptions.DecodeError as e:
|
||||
app.logger.warn("Could not verify token: {}".format(str(e)))
|
||||
app.logger.warning("Could not verify token: %s", str(e))
|
||||
return False
|
||||
except jwt.exceptions.ExpiredSignatureError as e:
|
||||
app.logger.warn("Could not verify token: {}".format(str(e)))
|
||||
app.logger.warning("Could not verify token: %s", str(e))
|
||||
return False
|
||||
app.logger.info(decoded)
|
||||
return True
|
||||
@@ -164,20 +163,22 @@ from backend.auth import oidc_auth, auth_bp
|
||||
try:
|
||||
oidc_auth.init_app(app)
|
||||
except requests.exceptions.ConnectionError as err:
|
||||
app.logger.error("Could not connect to OIDC!!", err)
|
||||
app.logger.exception("Could not connect to OIDC!!", exc_info=err)
|
||||
|
||||
# oidc_multi_auth = MultiAuth(oidc_auth, jwt_auth) <- can't work as OIDCAuthentication not implementing HTTPAuth
|
||||
|
||||
from .serve_frontend import fe_bp
|
||||
#from .serve_frontend import fe_bp
|
||||
from .api import auth_api_bp, api_v1, api_bp
|
||||
|
||||
app.register_blueprint(auth_bp)
|
||||
app.register_blueprint(auth_api_bp)
|
||||
app.register_blueprint(api_bp)
|
||||
app.register_blueprint(fe_bp)
|
||||
|
||||
CORS(app)
|
||||
CORS(api_bp)
|
||||
|
||||
app.register_blueprint(auth_bp)
|
||||
app.register_blueprint(auth_api_bp)
|
||||
app.register_blueprint(api_bp)
|
||||
#app.register_blueprint(fe_bp)
|
||||
|
||||
|
||||
|
||||
# Fix flask-restplus by duck typing error handlers
|
||||
jwt_extended._set_error_handler_callbacks(api_v1)
|
||||
|
||||
@@ -12,16 +12,25 @@ from backend.models import room_model, recorder_model, RecorderCommand
|
||||
from backend.recorder_adapters import get_defined_recorder_adapters
|
||||
from backend.tools.model_updater import update_recorder_models_database, create_default_recorders
|
||||
|
||||
def setup_database(app):
|
||||
with app.app_context():
|
||||
#db.drop_all()
|
||||
db.create_all()
|
||||
room_model.pre_fill_table()
|
||||
update_recorder_models_database(drop=False)
|
||||
create_default_recorders()
|
||||
|
||||
|
||||
def get_app():
|
||||
setup_database(app)
|
||||
|
||||
#app.register_blueprint(api_blueprint)
|
||||
return app
|
||||
|
||||
def main():
|
||||
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
|
||||
#db.drop_all()
|
||||
#db.create_all()
|
||||
room_model.pre_fill_table()
|
||||
update_recorder_models_database(drop=False)
|
||||
create_default_recorders()
|
||||
|
||||
app = get_app()
|
||||
|
||||
print(app.config.get("SERVER_NAME", None))
|
||||
server_name = app.config.get("SERVER_NAME", None)
|
||||
if server_name is not None and "ubkaps154.ubka.uni-karlsruhe.de" in server_name:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from flask import Blueprint, abort
|
||||
from flask_restplus import Api, Namespace
|
||||
from flask_restx import Api, Namespace
|
||||
|
||||
api_authorizations = {
|
||||
'apikey': {
|
||||
|
||||
@@ -10,21 +10,16 @@ import json
|
||||
from pprint import pprint
|
||||
|
||||
import flask
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import jwt
|
||||
from flask import request, jsonify, current_app, url_for, Response, session, redirect, make_response
|
||||
from flask_jwt_extended import create_access_token, create_refresh_token, jwt_refresh_token_required, get_jwt_identity, \
|
||||
get_raw_jwt, jwt_required
|
||||
from functools import wraps
|
||||
from random import randint
|
||||
from flask import request, jsonify, current_app, url_for, redirect, make_response
|
||||
from flask_jwt_extended import create_access_token, create_refresh_token, get_jwt, get_jwt_identity, jwt_required
|
||||
|
||||
from flask_login import logout_user, login_user
|
||||
from typing import Iterable
|
||||
|
||||
from flask_restplus import Resource, fields
|
||||
from flask_restx import Resource, fields
|
||||
from werkzeug.routing import BuildError
|
||||
|
||||
from backend import db, app, jwt_extended
|
||||
from backend import db, app
|
||||
from backend.api import auth_api_bp, auth_api_providers_ns, auth_api_register_ns
|
||||
from backend.auth import AUTH_PROVIDERS, oidc_auth
|
||||
from backend.models.user_model import User, Group, BlacklistToken
|
||||
@@ -58,19 +53,19 @@ def register():
|
||||
return jsonify(user.to_dict()), 201
|
||||
|
||||
|
||||
@auth_api_register_ns.route('/')
|
||||
@auth_api_register_ns.expect(auth_api_register_ns.model('RegisterModel', {
|
||||
'nickname': fields.String(required=False, description='The user\'s nickname'),
|
||||
'first_name': fields.String(required=False, description='The user\'s first name'),
|
||||
'last_name': fields.String(required=False, description='The user\'s last name'),
|
||||
'lang': fields.String(required=False, description='The user\'s preferred language'),
|
||||
'timezone': fields.String(required=False, description='The user\'s preferred timezone'),
|
||||
'email': fields.String(required=True, description='The user\'s e-mail address'),
|
||||
'password': fields.String(required=False, description='The group\'s name')
|
||||
}))
|
||||
class AuthProviders(Resource):
|
||||
def get(self):
|
||||
return register()
|
||||
# @auth_api_register_ns.route('/')
|
||||
# @auth_api_register_ns.expect(auth_api_register_ns.model('RegisterModel', {
|
||||
# 'nickname': fields.String(required=False, description='The user\'s nickname'),
|
||||
# 'first_name': fields.String(required=False, description='The user\'s first name'),
|
||||
# 'last_name': fields.String(required=False, description='The user\'s last name'),
|
||||
# 'lang': fields.String(required=False, description='The user\'s preferred language'),
|
||||
# 'timezone': fields.String(required=False, description='The user\'s preferred timezone'),
|
||||
# 'email': fields.String(required=True, description='The user\'s e-mail address'),
|
||||
# 'password': fields.String(required=False, description='The group\'s name')
|
||||
# }))
|
||||
# class AuthProviders(Resource):
|
||||
# def get(self):
|
||||
# return register()
|
||||
|
||||
|
||||
@auth_api_bp.route('/login', methods=('GET', 'POST',))
|
||||
@@ -96,7 +91,7 @@ def login():
|
||||
@auth_api_bp.route('/logout', methods=['GET', 'DELETE'])
|
||||
@jwt_required
|
||||
def logout():
|
||||
jti = get_raw_jwt()['jti']
|
||||
jti = get_jwt()['jti']
|
||||
db.session.add(BlacklistToken(token=jti))
|
||||
db.session.commit()
|
||||
return jsonify({"msg": "Successfully logged out"}), 200
|
||||
@@ -104,9 +99,9 @@ def logout():
|
||||
|
||||
# Endpoint for revoking the current users refresh token
|
||||
@auth_api_bp.route('/logout2', methods=['GET', 'DELETE'])
|
||||
@jwt_refresh_token_required
|
||||
@jwt_required(refresh=True)
|
||||
def logout2():
|
||||
jti = get_raw_jwt()['jti']
|
||||
jti = get_jwt()['jti']
|
||||
db.session.add(BlacklistToken(token=jti))
|
||||
db.session.commit()
|
||||
return jsonify({"msg": "Successfully logged out"}), 200
|
||||
@@ -182,7 +177,7 @@ def oidc(redirect_url=None):
|
||||
|
||||
|
||||
@auth_api_bp.route('/refresh', methods=['GET'])
|
||||
@jwt_refresh_token_required
|
||||
@jwt_required(refresh=True)
|
||||
def refresh():
|
||||
"""Refresh token endpoint. This will generate a new access token from
|
||||
the refresh token, but will mark that access token as non-fresh,
|
||||
|
||||
@@ -8,8 +8,8 @@ Login through API does not start a new session, but instead returns JWT.
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
from flask_jwt_extended import jwt_required, get_current_user, get_jwt_claims
|
||||
from flask_restplus import fields, Resource
|
||||
from flask_jwt_extended import jwt_required, get_current_user, get_jwt
|
||||
from flask_restx import fields, Resource
|
||||
|
||||
from backend import db
|
||||
from backend.api import api_control, get_jwt_identity
|
||||
@@ -37,6 +37,6 @@ class ControlCommand(Resource):
|
||||
def post(self):
|
||||
print(get_current_user())
|
||||
print(get_jwt_identity())
|
||||
current_user = {'user': get_current_user(), 'claims': get_jwt_claims()}
|
||||
current_user = {'user': get_current_user(), 'claims': get_jwt()}
|
||||
args = self.control_command_parser.parse_args()
|
||||
return {'time': datetime.utcnow(), 'output': args, 'state': current_user}
|
||||
|
||||
@@ -5,7 +5,7 @@ import json
|
||||
import logging
|
||||
from random import *
|
||||
from flask import jsonify, Blueprint, request
|
||||
from flask_restplus import Resource, reqparse
|
||||
from flask_restx import Resource, reqparse
|
||||
|
||||
from backend import basic_auth, multi_auth, db, jwt_auth
|
||||
from backend.api import api_v1, api_bp
|
||||
|
||||
@@ -6,7 +6,7 @@ For example: listing of available auth providers or registration of users.
|
||||
Login through API does not start a new session, but instead returns JWT.
|
||||
"""
|
||||
from flask_jwt_extended import jwt_required
|
||||
from flask_restplus import fields, Resource
|
||||
from flask_restx import fields, Resource
|
||||
|
||||
from backend import db
|
||||
from backend.api import api_group
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask_restplus import fields
|
||||
from flask_restx import fields
|
||||
from backend.api import api_user, api_recorder, api_v1
|
||||
|
||||
generic_id_parser = api_v1.parser()
|
||||
|
||||
@@ -9,7 +9,7 @@ from datetime import datetime
|
||||
from pprint import pprint
|
||||
|
||||
from flask_jwt_extended import jwt_required
|
||||
from flask_restplus import fields, Resource, inputs
|
||||
from flask_restx import fields, Resource, inputs
|
||||
|
||||
from backend import db, app
|
||||
from backend.api import api_recorder
|
||||
|
||||
@@ -6,7 +6,7 @@ For example: listing of available auth providers or registration of users.
|
||||
Login through API does not start a new session, but instead returns JWT.
|
||||
"""
|
||||
from flask_jwt_extended import jwt_required
|
||||
from flask_restplus import fields, Resource
|
||||
from flask_restx import fields, Resource
|
||||
from sqlalchemy import exc
|
||||
|
||||
from backend import db, app
|
||||
|
||||
@@ -9,7 +9,7 @@ from datetime import datetime
|
||||
from pprint import pprint
|
||||
|
||||
from flask_jwt_extended import get_jwt_identity, jwt_required, current_user
|
||||
from flask_restplus import Resource, fields, inputs, abort
|
||||
from flask_restx import Resource, fields, inputs, abort
|
||||
|
||||
from backend import db, app, jwt_auth
|
||||
from backend.api import api_user
|
||||
|
||||
@@ -10,7 +10,7 @@ import pkgutil
|
||||
from pprint import pprint
|
||||
|
||||
from flask_jwt_extended import jwt_required
|
||||
from flask_restplus import fields, Resource
|
||||
from flask_restx import fields, Resource
|
||||
|
||||
from backend import db, app
|
||||
from backend.api import api_virtual_command
|
||||
|
||||
@@ -54,7 +54,7 @@ def logout():
|
||||
logout_user()
|
||||
|
||||
|
||||
@jwt_extended.user_claims_loader
|
||||
@jwt_extended.additional_claims_loader
|
||||
def add_claims_to_access_token(user):
|
||||
if isinstance(user, str):
|
||||
return {}
|
||||
@@ -66,13 +66,13 @@ def user_identity_loader(user):
|
||||
return user.email
|
||||
|
||||
|
||||
@jwt_extended.user_loader_callback_loader
|
||||
@jwt_extended.user_lookup_loader
|
||||
def user_loader_callback(identity):
|
||||
print("### user_loader_callback_loader")
|
||||
return User.get_by_identifier(identity)
|
||||
|
||||
|
||||
@jwt_extended.token_in_blacklist_loader
|
||||
@jwt_extended.token_in_blocklist_loader
|
||||
def check_if_token_in_blacklist(decrypted_token):
|
||||
jti = decrypted_token['jti']
|
||||
return BlacklistToken.get_by_token(jti) is not None
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -8,9 +8,10 @@ import logging
|
||||
from sqlalchemy import MetaData, CheckConstraint
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime
|
||||
|
||||
from backend import db, app, login_manager
|
||||
from backend import db
|
||||
from backend.models.recorder_model import Recorder
|
||||
from backend.tools.scrape_rooms import scrape_rooms
|
||||
|
||||
logger = logging.getLogger("lrc."+__name__)
|
||||
@@ -28,7 +29,7 @@ class Room(db.Model):
|
||||
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',
|
||||
@@ -36,7 +37,7 @@ class Room(db.Model):
|
||||
)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(Room, self).__init__(**kwargs)
|
||||
db.Model.__init__(self, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def get_by_name(name):
|
||||
|
||||
@@ -4,10 +4,10 @@ Example user model and related models
|
||||
"""
|
||||
import json
|
||||
|
||||
from sqlalchemy.orm import relation
|
||||
from sqlalchemy import MetaData
|
||||
|
||||
from backend import db, app, login_manager
|
||||
from backend.models.recorder_model import Recorder
|
||||
from backend.config import Config
|
||||
from backend.models.post_model import Post
|
||||
from backend.models.example_model import ExampleDataItem
|
||||
@@ -84,8 +84,8 @@ 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))
|
||||
@@ -109,7 +109,7 @@ class User(UserMixin, db.Model):
|
||||
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)
|
||||
@@ -447,6 +447,13 @@ class Group(db.Model):
|
||||
permissions = db.relationship('Permission', secondary=group_permission_table, back_populates='groups')
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
#get permissions from kwargs and make Permission objects out of them
|
||||
permissions = kwargs.pop("permissions", [])
|
||||
if permissions is not None:
|
||||
for p in permissions:
|
||||
permission = Permission(name=p)
|
||||
if permission is not None:
|
||||
self.permissions.append(permission)
|
||||
super(Group, self).__init__(**kwargs)
|
||||
|
||||
@staticmethod
|
||||
@@ -494,15 +501,16 @@ def insert_initial_users(*args, **kwargs):
|
||||
db.session.commit()
|
||||
|
||||
|
||||
@event.listens_for(Group.__table__, 'after_create')
|
||||
def insert_initial_groups(*args, **kwargs):
|
||||
for g in app.config.get("GROUPS", []):
|
||||
db.session.add(Group(**g))
|
||||
db.session.commit()
|
||||
|
||||
|
||||
@event.listens_for(Permission.__table__, 'after_create')
|
||||
def insert_initial_permissions(*args, **kwargs):
|
||||
for p in app.config.get("PERMISSIONS", []):
|
||||
db.session.add(Permission(name=p))
|
||||
db.session.commit()
|
||||
|
||||
@event.listens_for(Group.__table__, 'after_create')
|
||||
def insert_initial_groups(*args, **kwargs):
|
||||
for g in app.config.get("GROUPS", []):
|
||||
db.session.add(Group(**g))
|
||||
db.session.commit()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user