diff --git a/src/app.py b/src/app.py
index 4237739..069e7c2 100644
--- a/src/app.py
+++ b/src/app.py
@@ -7,12 +7,15 @@ from healthcheck import HealthCheck
from flask_cors import CORS
from flask_mail import Mail
+from flask_admin import Admin
+
from utils import Config
-from utils import health_database_status, init_security_real_good
+from utils import health_database_status
+from utils import init_security_real_good, user_datastore, AuthenticatedModelView, AuthenticatedAdminIndexView
from utils import storage
from views import ItemView, ProfileView, UploadView, IndexView, ContentView, PurchaseView
-from models import db
+from models import db, Comment, Item, Purchase, User, Role
"""
Main Flask entrypoint
@@ -51,7 +54,31 @@ for view in [ItemView, ProfileView, UploadView, IndexView, ContentView, Purchase
health.add_check(health_database_status)
app.add_url_rule("/healthz", "healthcheck", view_func=lambda: health.run())
+admin = Admin(app, index_view=AuthenticatedAdminIndexView())
+admin.add_view(AuthenticatedModelView(User, db.session))
+admin.add_view(AuthenticatedModelView(Comment, db.session))
+admin.add_view(AuthenticatedModelView(Item, db.session))
+admin.add_view(AuthenticatedModelView(Purchase, db.session))
+
@app.before_first_request
def init_db():
db.create_all()
+
+ if Role.query.count() == 0:
+ user_datastore.create_role(name='administrator')
+ app.logger.info("Roles table is empty. Default roles created!")
+
+ default_admin_email = app.config.get('DEFAULT_ADMIN_EMAIL')
+ default_admin_password = app.config.get('DEFAULT_ADMIN_PASSWORD')
+
+ if default_admin_email and default_admin_password: # Create only if the default credentials are provided
+ if User.query.count() == 0: # Create default user, only if the user table is empty
+ default_admin_username = app.config.get('DEFAULT_ADMIN_USER')
+
+ user = user_datastore.create_user(email=default_admin_email, password=default_admin_password,
+ roles=['administrator'])
+ user.name = default_admin_username
+ db.session.add(user)
+
+ db.session.commit()
diff --git a/src/templates/base.html b/src/templates/base.html
index fa90c52..2c814b3 100644
--- a/src/templates/base.html
+++ b/src/templates/base.html
@@ -36,9 +36,15 @@
Upload
+ {% if current_user.has_role('administrator') %}
+
+ Administrate
+
+ {% endif %}
Logout
+
{% else %}
Login
diff --git a/src/utils/__init__.py b/src/utils/__init__.py
index 3b5967b..5e2b265 100644
--- a/src/utils/__init__.py
+++ b/src/utils/__init__.py
@@ -1,5 +1,5 @@
from .healthchecks import health_database_status
-from .security import security, init_security_real_good
+from .security import security, user_datastore, init_security_real_good, AuthenticatedModelView, AuthenticatedAdminIndexView
from .config import Config
from .storage import storage
from .md5stuffs import calculate_md5_sum_for_file, write_file_from_stream_to_file_like_while_calculating_md5
diff --git a/src/utils/config.py b/src/utils/config.py
index 17d5e18..67bcd58 100644
--- a/src/utils/config.py
+++ b/src/utils/config.py
@@ -38,6 +38,11 @@ class Config:
MINIO_SECRET_KEY = os.environ["MINIO_SECRET_KEY"]
MINIO_SECURE = os.environ.get("MINIO_SECURE", "true").upper() == 'TRUE'
+ # Admin stuff
+ DEFAULT_ADMIN_USER = os.environ.get("DEFAULT_ADMIN_USER")
+ DEFAULT_ADMIN_PASSWORD = os.environ.get("DEFAULT_ADMIN_PASSWORD")
+ DEFAULT_ADMIN_EMAIL = os.environ.get("DEFAULT_ADMIN_EMAIL")
+
# Some constant configured stuff configs
SQLALCHEMY_TRACK_MODIFICATIONS = False
SECURITY_REGISTERABLE = True
diff --git a/src/utils/security.py b/src/utils/security.py
index 3602824..33b3142 100644
--- a/src/utils/security.py
+++ b/src/utils/security.py
@@ -1,9 +1,12 @@
#!/usr/bin/env python3
-
-from flask_security import Security, SQLAlchemyUserDatastore
+from flask import abort
+from flask_security import Security, SQLAlchemyUserDatastore, current_user
from flask_security.forms import RegisterForm, Required
from wtforms import StringField
+from flask_admin.contrib.sqla import ModelView
+from flask_admin import AdminIndexView
+
from models import db, User, Role
"""
@@ -26,3 +29,29 @@ security = Security() # Will be initiated at init_app
def init_security_real_good(app):
security.init_app(app, datastore=user_datastore, register_form=ExtendedRegisterForm)
+
+
+class AuthenticatedModelView(ModelView):
+ def is_accessible(self):
+ return (
+ current_user.is_active and
+ current_user.is_authenticated and
+ current_user.has_role('administrator')
+ )
+
+ def _handle_view(self, name):
+ if not self.is_accessible():
+ abort(401)
+
+
+class AuthenticatedAdminIndexView(AdminIndexView):
+ def is_accessible(self):
+ return (
+ current_user.is_active and
+ current_user.is_authenticated and
+ current_user.has_role('administrator')
+ )
+
+ def _handle_view(self, name):
+ if not self.is_accessible():
+ abort(401)