DoorAdmin/imaginaerraum_door_admin/__init__.py

116 lines
4.1 KiB
Python

import logging
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_security import Security, SQLAlchemyUserDatastore, hash_password
from email_validator import validate_email
from pathlib import Path
from .door_handle import DoorHandle
security = Security()
db = SQLAlchemy()
# create admin users (only if they don't exist already)
def create_super_admins(app, user_datastore):
admin_file = Path(app.config.get('ADMIN_FILE'))
# setup user database when starting the app
new_admin_data = []
if not admin_file.exists():
app.logger.warning(
f"Admin user creation file not found at path "
f"{admin_file.absolute()}."
f"No super admins have been created in the datastore."
)
else:
# store data for new admins in memory s.t. the file can be deleted
# afterwards
admin_data = admin_file.read_text().split('\n')
for i, line in enumerate(admin_data):
if not line.strip().startswith('#'):
try:
user, email, pw = line.split()
validate_email(email)
new_admin_data.append(
{'username': user, 'email': email,
'password': pw})
except Exception as e:
app.logger.error(
f"Error while parsing line {i} in admin config file. "
f"Config file should contain lines of <username> "
f"<email> <password>\\n'\n "
f"Exception: {e}\nAdmin account could not be created."
)
with app.app_context():
db.create_all()
super_admin_role = user_datastore.find_or_create_role(
'super_admin') # root admin = can create other admins
admin_role = user_datastore.find_or_create_role(
'admin') # 'normal' admin
local_role = user_datastore.find_or_create_role(
'local') # LDAP user or local user
for d in new_admin_data:
if user_datastore.find_user(email=d['email'],
username=d['username']) is None:
roles = [super_admin_role, admin_role]
if not d['password'] == 'LDAP':
roles.append(local_role)
# create new admin (only if admin does not already exist)
new_admin = user_datastore.create_user(
email=d['email'], username=d['username'],
password=hash_password(d['password']), roles=roles
)
app.logger.info(
f"New super admin user created with username "
f"'{new_admin.username}' and email '{new_admin.email}'"
f", roles = {[r.name for r in new_admin.roles]}"
)
db.session.commit()
def create_app():
app = Flask(__name__)
app.config.from_object(
'imaginaerraum_door_admin.default_app_config.DefaultConfig'
)
app.config.from_envvar('APPLICATION_SETTINGS')
token_file = Path(app.config.get('TOKEN_FILE'))
if not token_file.exists():
app.logger.warning(
f"Token file not found at {token_file.absolute()}. "
"An empty token file will be created."
)
token_file.touch()
# create door objects which provides access to the token file and current
# door state via MQTT
app.door = DoorHandle(
token_file=token_file, mqtt_host=app.config['MQTT_HOST'],
nfc_socket=app.config['NFC_SOCKET'], logger=app.logger
)
# Mail Config
#mail = Mail(app)
# Create database connection object
db.init_app(app)
from . webapp import door_app
app.register_blueprint(door_app)
# Setup Flask-Security
from .auth import ExtendedLoginForm, User, Role
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security.init_app(app, user_datastore, login_form=ExtendedLoginForm)
create_super_admins(app, user_datastore)
return app