mirror of
https://codeberg.org/Mo8it/AdvLabDB.git
synced 2024-12-02 22:33:05 +00:00
Use app factory pattern
This commit is contained in:
parent
e1e9c0e42e
commit
bdabc9f32a
15 changed files with 179 additions and 132 deletions
|
@ -1,47 +1,51 @@
|
|||
from os import environ
|
||||
|
||||
from flask import Flask
|
||||
from flask_admin import Admin
|
||||
from flask_security import Security, SQLAlchemyUserDatastore
|
||||
from flask_security.models import fsqla_v2 as fsqla
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_migrate import Migrate
|
||||
from flask_security import SQLAlchemyUserDatastore
|
||||
|
||||
from .config import set_config
|
||||
from .config import get_settings
|
||||
from .models import db, User, Role
|
||||
|
||||
app = Flask(__name__)
|
||||
migrate = Migrate()
|
||||
|
||||
# Config
|
||||
settings = set_config(app)
|
||||
settings = get_settings()
|
||||
|
||||
# Setup Flask-SQLAlchemy
|
||||
db = SQLAlchemy(app)
|
||||
fsqla.FsModels.set_db_info(db)
|
||||
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
|
||||
|
||||
# Setup Flask-Migrate
|
||||
migrate = Migrate(app, db)
|
||||
|
||||
# Setup Flask-Admin
|
||||
from .custom_classes import SecureAdminIndexView, SecureAssistantIndexView
|
||||
def create_app(create_for_server=True):
|
||||
from flask import Flask
|
||||
|
||||
adminSpace = Admin(
|
||||
app,
|
||||
name="Admin@AdvLabDB",
|
||||
url="/admin",
|
||||
template_mode="bootstrap3",
|
||||
index_view=SecureAdminIndexView(name="Home", url="/admin", endpoint="admin"),
|
||||
)
|
||||
assistantSpace = Admin(
|
||||
app,
|
||||
name="Assistant@AdvLabDB",
|
||||
url="/assistant",
|
||||
template_mode="bootstrap3",
|
||||
index_view=SecureAssistantIndexView(name="Home", url="/assistant", endpoint="assistant"),
|
||||
)
|
||||
app = Flask(__name__)
|
||||
|
||||
from . import models
|
||||
# Config
|
||||
from .config import set_config
|
||||
|
||||
user_datastore = SQLAlchemyUserDatastore(db, models.User, models.Role)
|
||||
Security(app, user_datastore)
|
||||
set_config(app)
|
||||
|
||||
from . import routes, adminModelViews, assistantModelViews
|
||||
# Setup Flask-SQLAlchemy
|
||||
|
||||
db.init_app(app)
|
||||
|
||||
# Setup Flask-Migrate
|
||||
migrate.init_app(app, db)
|
||||
|
||||
# Setup Flask-Security-Too
|
||||
from flask_security import Security
|
||||
|
||||
Security(app, user_datastore)
|
||||
|
||||
if create_for_server:
|
||||
# Setup views
|
||||
from .adminModelViews import init_admin_model_views
|
||||
|
||||
init_admin_model_views(app)
|
||||
|
||||
from .assistantModelViews import init_assistant_model_views
|
||||
|
||||
init_assistant_model_views(app)
|
||||
|
||||
# Register blueprints
|
||||
from .routes import bp as routes_bp
|
||||
|
||||
app.register_blueprint(routes_bp)
|
||||
|
||||
return app
|
||||
|
|
|
@ -4,6 +4,7 @@ from pathlib import Path
|
|||
|
||||
import numpy as np
|
||||
from flask import flash, has_request_context, redirect, url_for
|
||||
from flask_admin import Admin as FlaskAdmin
|
||||
from flask_admin import expose
|
||||
from flask_admin.contrib.sqla.fields import QuerySelectField, QuerySelectMultipleField
|
||||
from flask_admin.contrib.sqla.filters import BooleanEqualFilter, FilterEqual
|
||||
|
@ -28,7 +29,7 @@ from wtforms.fields import (
|
|||
from wtforms.validators import URL, DataRequired, Email, NumberRange, Optional
|
||||
from wtforms.widgets import NumberInput
|
||||
|
||||
from . import adminSpace, assistantSpace, db, user_datastore
|
||||
from . import user_datastore
|
||||
from .admin_link_formatters import (
|
||||
admin_formatter,
|
||||
appointment_date_formatter,
|
||||
|
@ -56,7 +57,12 @@ from .advlabdb_independent_funs import (
|
|||
flashRandomPassword,
|
||||
str_without_semester_formatter,
|
||||
)
|
||||
from .custom_classes import SecureAdminBaseView, SecureAdminModelView
|
||||
from .assistantModelViews import assistantSpace
|
||||
from .custom_classes import (
|
||||
SecureAdminBaseView,
|
||||
SecureAdminIndexView,
|
||||
SecureAdminModelView,
|
||||
)
|
||||
from .database_import import importFromFile
|
||||
from .exceptions import ModelViewException
|
||||
from .model_dependent_funs import (
|
||||
|
@ -86,6 +92,15 @@ from .models import (
|
|||
SemesterExperiment,
|
||||
Student,
|
||||
User,
|
||||
db,
|
||||
)
|
||||
|
||||
adminSpace = FlaskAdmin(
|
||||
name="Admin@AdvLabDB",
|
||||
url="/admin",
|
||||
template_mode="bootstrap4",
|
||||
static_url_path="/static/a",
|
||||
index_view=SecureAdminIndexView(name="Home", url="/admin", endpoint="admin"),
|
||||
)
|
||||
|
||||
|
||||
|
@ -356,7 +371,7 @@ class SemesterView(SecureAdminModelView):
|
|||
categoryText = "Active semester"
|
||||
link = MenuLink(
|
||||
name=str(newSemester),
|
||||
url=url_for("set_semester") + "?semester_id=" + str(newSemester.id),
|
||||
url=url_for("main.set_semester") + "?semester_id=" + str(newSemester.id),
|
||||
category=categoryText,
|
||||
)
|
||||
|
||||
|
@ -1282,7 +1297,7 @@ class ImportView(SecureAdminBaseView):
|
|||
except Exception as ex:
|
||||
flash(str(ex), "error")
|
||||
|
||||
return redirect(url_for("index"))
|
||||
return redirect(url_for("main.index"))
|
||||
|
||||
return self.render("import.html", form=form)
|
||||
|
||||
|
@ -1304,7 +1319,7 @@ class ActionsView(SecureAdminBaseView):
|
|||
|
||||
flash("Manually updated all final experiment and part marks", "success")
|
||||
|
||||
return redirect(url_for("index"))
|
||||
return redirect(url_for("main.index"))
|
||||
|
||||
return self.render("actions.html", form=form)
|
||||
|
||||
|
@ -1469,23 +1484,26 @@ class DocsView(SecureAdminBaseView):
|
|||
return self.render("docs/docs.html", role="admin")
|
||||
|
||||
|
||||
adminSpace.add_view(StudentView(Student, url="student"))
|
||||
adminSpace.add_view(PartStudentView(PartStudent, url="part_student"))
|
||||
adminSpace.add_view(GroupView(Group, url="group"))
|
||||
adminSpace.add_view(GroupExperimentView(GroupExperiment, url="group_experiment"))
|
||||
adminSpace.add_view(AppointmentView(Appointment, url="appointment"))
|
||||
adminSpace.add_view(ExperimentMarkView(ExperimentMark, url="experiment_mark"))
|
||||
adminSpace.add_view(ExperimentView(Experiment, url="experiment"))
|
||||
adminSpace.add_view(SemesterExperimentView(SemesterExperiment, url="semester_experiment"))
|
||||
adminSpace.add_view(SemesterView(Semester, url="semester"))
|
||||
adminSpace.add_view(PartView(Part, url="part"))
|
||||
adminSpace.add_view(AssistantView(Assistant, url="assistant"))
|
||||
adminSpace.add_view(AdminView(Admin, url="admin"))
|
||||
adminSpace.add_view(UserView(User, url="user"))
|
||||
adminSpace.add_view(ProgramView(Program, url="program"))
|
||||
adminSpace.add_view(ImportView(name="Import", url="import"))
|
||||
adminSpace.add_view(ActionsView(name="Actions", url="actions"))
|
||||
adminSpace.add_view(AnalysisView(name="Analysis", url="analysis"))
|
||||
adminSpace.add_view(DocsView(name="Docs", url="docs"))
|
||||
def init_admin_model_views(app):
|
||||
adminSpace.init_app(app)
|
||||
|
||||
initActiveSemesterMenuLinks(adminSpace)
|
||||
adminSpace.add_view(StudentView(Student, url="student"))
|
||||
adminSpace.add_view(PartStudentView(PartStudent, url="part_student"))
|
||||
adminSpace.add_view(GroupView(Group, url="group"))
|
||||
adminSpace.add_view(GroupExperimentView(GroupExperiment, url="group_experiment"))
|
||||
adminSpace.add_view(AppointmentView(Appointment, url="appointment"))
|
||||
adminSpace.add_view(ExperimentMarkView(ExperimentMark, url="experiment_mark"))
|
||||
adminSpace.add_view(ExperimentView(Experiment, url="experiment"))
|
||||
adminSpace.add_view(SemesterExperimentView(SemesterExperiment, url="semester_experiment"))
|
||||
adminSpace.add_view(SemesterView(Semester, url="semester"))
|
||||
adminSpace.add_view(PartView(Part, url="part"))
|
||||
adminSpace.add_view(AssistantView(Assistant, url="assistant"))
|
||||
adminSpace.add_view(AdminView(Admin, url="admin"))
|
||||
adminSpace.add_view(UserView(User, url="user"))
|
||||
adminSpace.add_view(ProgramView(Program, url="program"))
|
||||
adminSpace.add_view(ImportView(name="Import", url="import"))
|
||||
adminSpace.add_view(ActionsView(name="Actions", url="actions"))
|
||||
adminSpace.add_view(AnalysisView(name="Analysis", url="analysis"))
|
||||
adminSpace.add_view(DocsView(name="Docs", url="docs"))
|
||||
|
||||
initActiveSemesterMenuLinks(adminSpace, app)
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
from flask import flash, redirect, request, url_for
|
||||
from flask_admin import Admin as FlaskAdmin
|
||||
from flask_admin import expose
|
||||
from flask_admin.model.template import EndpointLinkRowAction
|
||||
from flask_security import admin_change_password, current_user
|
||||
from flask_wtf import FlaskForm
|
||||
|
||||
from . import assistantSpace, db
|
||||
from .advlabdb_independent_funs import (
|
||||
deep_getattr,
|
||||
experiment_marks_missing_formatter,
|
||||
flashRandomPassword,
|
||||
str_formatter,
|
||||
)
|
||||
from .custom_classes import SecureAssistantBaseView, SecureAssistantModelView
|
||||
from .custom_classes import (
|
||||
SecureAssistantBaseView,
|
||||
SecureAssistantIndexView,
|
||||
SecureAssistantModelView,
|
||||
)
|
||||
from .exceptions import ModelViewException
|
||||
from .forms import assistant_group_experiment_form_factory
|
||||
from .model_dependent_funs import (
|
||||
|
@ -21,7 +25,15 @@ from .model_dependent_funs import (
|
|||
user_info_fields,
|
||||
)
|
||||
from .model_independent_funs import randomPassword, reportBadAttempt
|
||||
from .models import Assistant, GroupExperiment, SemesterExperiment, User
|
||||
from .models import Assistant, GroupExperiment, SemesterExperiment, User, db
|
||||
|
||||
assistantSpace = FlaskAdmin(
|
||||
name="Assistant@AdvLabDB",
|
||||
url="/assistant",
|
||||
template_mode="bootstrap4",
|
||||
static_url_path="/static/a",
|
||||
index_view=SecureAssistantIndexView(name="Home", url="/assistant", endpoint="assistant"),
|
||||
)
|
||||
|
||||
|
||||
class AssistantGroupExperimentView(SecureAssistantModelView):
|
||||
|
@ -89,7 +101,7 @@ class AssistantGroupExperimentView(SecureAssistantModelView):
|
|||
try:
|
||||
group_experiment = db.session.get(GroupExperiment, int(group_experiment_id_str))
|
||||
except Exception:
|
||||
red = url_for("index") + "assistant/group_experiment"
|
||||
red = url_for("main.index") + "assistant/group_experiment"
|
||||
flash("No valid group experiment id")
|
||||
return redirect(red)
|
||||
|
||||
|
@ -146,7 +158,7 @@ class AssistantGroupExperimentView(SecureAssistantModelView):
|
|||
|
||||
db.session.commit()
|
||||
|
||||
red = url_for("index") + "assistant/group_experiment"
|
||||
red = url_for("main.index") + "assistant/group_experiment"
|
||||
return redirect(red)
|
||||
except Exception as ex:
|
||||
flash(str(ex), "error")
|
||||
|
@ -211,8 +223,11 @@ class AssistantDocsView(SecureAssistantBaseView):
|
|||
return self.render("docs/docs.html", role="assistant")
|
||||
|
||||
|
||||
assistantSpace.add_view(AssistantGroupExperimentView(GroupExperiment, url="group_experiment"))
|
||||
assistantSpace.add_view(AssistantUserView(User, url="user"))
|
||||
assistantSpace.add_view(AssistantDocsView(name="Docs", url="docs"))
|
||||
def init_assistant_model_views(app):
|
||||
assistantSpace.init_app(app)
|
||||
|
||||
initActiveSemesterMenuLinks(assistantSpace)
|
||||
assistantSpace.add_view(AssistantGroupExperimentView(GroupExperiment, url="group_experiment"))
|
||||
assistantSpace.add_view(AssistantUserView(User, url="user"))
|
||||
assistantSpace.add_view(AssistantDocsView(name="Docs", url="docs"))
|
||||
|
||||
initActiveSemesterMenuLinks(assistantSpace, app)
|
||||
|
|
|
@ -3,14 +3,14 @@ from configparser import ConfigParser
|
|||
from pathlib import Path
|
||||
|
||||
|
||||
def load_config(app, *files):
|
||||
def load_config(*files):
|
||||
config = ConfigParser()
|
||||
|
||||
for file in files:
|
||||
file = Path(file)
|
||||
|
||||
if not file.is_file():
|
||||
app.logger.critical(str(file) + " is missing")
|
||||
print(f"{file} is missing!")
|
||||
sys.exit(1)
|
||||
|
||||
config.read(file)
|
||||
|
@ -18,8 +18,15 @@ def load_config(app, *files):
|
|||
return config
|
||||
|
||||
|
||||
def get_settings():
|
||||
config = load_config("settings.ini")
|
||||
settings = config["Settings"]
|
||||
|
||||
return settings
|
||||
|
||||
|
||||
def set_config(app):
|
||||
config = load_config(app, "secrets.ini", "settings.ini")
|
||||
config = load_config("secrets.ini", "settings.ini")
|
||||
secrets = config["Secrets"]
|
||||
settings = config["Settings"]
|
||||
|
||||
|
@ -55,5 +62,3 @@ def set_config(app):
|
|||
app.config["SECURITY_PASSWORD_SALT"] = secrets["SECURITY_PASSWORD_SALT"]
|
||||
app.config["SECURITY_PASSWORD_LENGTH_MIN"] = settings.getint("SECURITY_PASSWORD_LENGTH_MIN", 15)
|
||||
# TODO: app.config["SECURITY_LOGIN_USER_TEMPLATE"] =
|
||||
|
||||
return settings
|
||||
|
|
|
@ -6,9 +6,8 @@ from flask_admin.model.helpers import get_mdict_item_or_list
|
|||
from flask_security import current_user
|
||||
from sqlalchemy import select
|
||||
|
||||
from . import db
|
||||
from .exceptions import DataBaseException, ModelViewException
|
||||
from .model_independent_funs import get_count, reportBadAttempt
|
||||
from .model_independent_funs import reportBadAttempt
|
||||
from .models import (
|
||||
Assistant,
|
||||
ExperimentMark,
|
||||
|
@ -16,6 +15,8 @@ from .models import (
|
|||
Part,
|
||||
PartStudent,
|
||||
SemesterExperiment,
|
||||
db,
|
||||
get_count,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -5,9 +5,8 @@ from shutil import copy2
|
|||
from flask import flash, has_request_context
|
||||
from sqlalchemy import select
|
||||
|
||||
from . import db, settings
|
||||
from . import settings
|
||||
from .exceptions import DataBaseImportException
|
||||
from .model_independent_funs import get_first
|
||||
from .models import (
|
||||
Appointment,
|
||||
Assistant,
|
||||
|
@ -21,6 +20,8 @@ from .models import (
|
|||
SemesterExperiment,
|
||||
Student,
|
||||
User,
|
||||
db,
|
||||
get_first,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -10,11 +10,11 @@ from flask_security import current_user
|
|||
from wtforms.fields import BooleanField, IntegerField, SelectField, StringField
|
||||
from wtforms.validators import DataRequired, NumberRange, Optional
|
||||
|
||||
from . import app, settings
|
||||
from . import settings
|
||||
from .models import MAX_MARK, MIN_MARK, Semester
|
||||
|
||||
|
||||
def initActiveSemesterMenuLinks(space):
|
||||
def initActiveSemesterMenuLinks(space, app):
|
||||
with app.app_context():
|
||||
try:
|
||||
semesters = Semester.sortedSemestersStartingWithNewest()
|
||||
|
|
|
@ -5,25 +5,15 @@ Functions not dependent on advlabdb.models.
|
|||
import secrets
|
||||
from string import ascii_letters, digits
|
||||
|
||||
from sqlalchemy import func, select
|
||||
|
||||
from . import app, db
|
||||
from flask import current_app
|
||||
|
||||
PASSWORD_CHARS: str = ascii_letters + digits + "!%*+=?"
|
||||
|
||||
|
||||
def randomPassword() -> str:
|
||||
password_length = app.config["SECURITY_PASSWORD_LENGTH_MIN"]
|
||||
password_length = current_app.config["SECURITY_PASSWORD_LENGTH_MIN"]
|
||||
return "".join(secrets.choice(PASSWORD_CHARS) for i in range(password_length))
|
||||
|
||||
|
||||
def reportBadAttempt(message: str) -> None:
|
||||
print("BAD ATTEMPT:", message) # TODO: Log
|
||||
|
||||
|
||||
def get_count(table):
|
||||
return db.session.scalar(select(func.count()).select_from(table))
|
||||
|
||||
|
||||
def get_first(table):
|
||||
return db.session.execute(table.limit(1)).scalars().first()
|
||||
|
|
|
@ -10,12 +10,12 @@ from decimal import ROUND_HALF_UP, Decimal
|
|||
|
||||
from flask import flash
|
||||
from flask_security import current_user
|
||||
from flask_security.models import fsqla_v2 as fsqla
|
||||
from flask_security.models.fsqla_v2 import FsRoleMixin, FsUserMixin
|
||||
from sqlalchemy import select
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy import func, select
|
||||
|
||||
from . import db
|
||||
from .exceptions import DataBaseException
|
||||
from .model_independent_funs import get_first
|
||||
|
||||
MIN_MARK = 0
|
||||
MAX_MARK = 15
|
||||
|
@ -27,6 +27,19 @@ MIN_GROUP_NUMBER = 1
|
|||
MIN_DURATION_IN_DAYS = 1
|
||||
MIN_PART_NUMBER = 1
|
||||
|
||||
db = SQLAlchemy()
|
||||
|
||||
# For Flask-Security-Too
|
||||
fsqla.FsModels.set_db_info(db)
|
||||
|
||||
|
||||
def get_count(table):
|
||||
return db.session.scalar(select(func.count()).select_from(table))
|
||||
|
||||
|
||||
def get_first(table):
|
||||
return db.session.execute(table.limit(1)).scalars().first()
|
||||
|
||||
|
||||
def roundHalfUpToInt(number):
|
||||
return int(Decimal(number).quantize(Decimal(0), rounding=ROUND_HALF_UP))
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
from flask import flash, redirect, request, url_for
|
||||
from flask import Blueprint, flash, redirect, request, url_for
|
||||
from flask_security import auth_required, current_user
|
||||
|
||||
from . import app, db
|
||||
from .model_dependent_funs import active_semester_str
|
||||
from .models import Semester
|
||||
from .models import Semester, db
|
||||
|
||||
bp = Blueprint("main", __name__, root_path="/", template_folder="templates")
|
||||
|
||||
|
||||
@app.context_processor
|
||||
@bp.app_context_processor
|
||||
def util_processor():
|
||||
author_email = "mobitar@students.uni-mainz.de"
|
||||
footer = f"<hr><p style='font-size:14px;'>This website is still under development (beta release)! If you have any questions, find any bugs or want some feature, please write a formless email (german/english) to Mo Bitar: <a href='mailto:{author_email}'>{author_email}</a>. Feedback is also welcome :)</p><br>"
|
||||
|
||||
return dict(active_semester_str=active_semester_str, current_user=current_user, footer=footer)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
@bp.route("/")
|
||||
def index():
|
||||
if current_user.has_role("admin"):
|
||||
endpoint_base = "admin"
|
||||
|
@ -30,7 +32,7 @@ def index():
|
|||
return redirect(url)
|
||||
|
||||
|
||||
@app.route("/set_semester")
|
||||
@bp.route("/set_semester")
|
||||
@auth_required()
|
||||
def set_semester():
|
||||
try:
|
||||
|
@ -41,5 +43,5 @@ def set_semester():
|
|||
semester = db.session.get(Semester, semesterId)
|
||||
current_user.setActiveSemester(semester)
|
||||
|
||||
red = request.referrer or url_for("index")
|
||||
red = request.referrer or url_for("main.index")
|
||||
return redirect(red)
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
{% macro information(current_user, active_semester_str, role) %}
|
||||
User: <a href="{{ url_for('index') }}{{ role }}/user/details/?id={{ current_user.id }}">{{ current_user }}</a>
|
||||
{% macro information(current_user, active_semester_str, role) %} User:
|
||||
<a
|
||||
href="{{ url_for('main.index') }}{{ role }}/user/details/?id={{ current_user.id }}"
|
||||
>{{ current_user }}</a
|
||||
>
|
||||
|
||||
| Active semester: {{ active_semester_str() }}
|
||||
|
||||
{% if (role == "admin") and (current_user.has_role("assistant")) %}
|
||||
| <a href="{{ url_for('index') }}assistant">Assistant space</a>.
|
||||
{% elif (role == "assistant") and (current_user.has_role("admin")) %}
|
||||
| <a href="{{ url_for('index') }}admin">Admin space</a>.
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro missing_final_experiment_marks(number_of_missing_final_experiment_marks, number_of_all_experiment_marks) %}
|
||||
<p>
|
||||
Number of <strong>missing</strong> final experiment marks:
|
||||
{{ number_of_missing_final_experiment_marks }} / {{ number_of_all_experiment_marks }}
|
||||
</p>
|
||||
| Active semester: {{ active_semester_str() }} {% if (role == "admin") and
|
||||
(current_user.has_role("assistant")) %} |
|
||||
<a href="{{ url_for('main.index') }}assistant">Assistant space</a>. {% elif
|
||||
(role == "assistant") and (current_user.has_role("admin")) %} |
|
||||
<a href="{{ url_for('main.index') }}admin">Admin space</a>. {% endif %} {%
|
||||
endmacro %} {% macro
|
||||
missing_final_experiment_marks(number_of_missing_final_experiment_marks,
|
||||
number_of_all_experiment_marks) %}
|
||||
<p>
|
||||
Number of <strong>missing</strong> final experiment marks: {{
|
||||
number_of_missing_final_experiment_marks }} / {{
|
||||
number_of_all_experiment_marks }}
|
||||
</p>
|
||||
{% endmacro %}
|
||||
|
|
|
@ -117,7 +117,7 @@ cd ~/advlabdb
|
|||
+
|
||||
[source,bash]
|
||||
----
|
||||
poetry run python3 manage.py setup initialize-database
|
||||
poetry run python3 manage.py setup init-db
|
||||
----
|
||||
|
||||
.. *Done!* Now go to your SERVER_NAME using a browser to verify that everything is working.
|
||||
|
|
17
manage.py
17
manage.py
|
@ -12,9 +12,9 @@ from flask_admin import __file__ as flask_admin_path
|
|||
from flask_security import admin_change_password, hash_password
|
||||
from sqlalchemy import select
|
||||
|
||||
from advlabdb import app, db, settings, user_datastore
|
||||
from advlabdb import create_app, settings, user_datastore
|
||||
from advlabdb.model_independent_funs import randomPassword
|
||||
from advlabdb.models import MAX_YEAR, MIN_YEAR, Admin, Semester, User
|
||||
from advlabdb.models import MAX_YEAR, MIN_YEAR, Admin, Semester, User, db
|
||||
|
||||
|
||||
def run(command: str, **kwargs):
|
||||
|
@ -76,23 +76,16 @@ def generate_secrets():
|
|||
short_help="Initialize the database.",
|
||||
help="Initialize the database if it does not already exist.",
|
||||
)
|
||||
def initialize_database():
|
||||
def init_db():
|
||||
db_file = Path(settings["SQLITE_DB_PATH"])
|
||||
if db_file.is_file():
|
||||
click.echo(f"Skipping database initialization because the database does already exist at {db_file}.")
|
||||
return
|
||||
|
||||
click.echo("\nThis script should only be used to initialize the database after setting up a server")
|
||||
click.echo(click.style("The old database will be DELETED and a new database will be created!", bg="red"))
|
||||
|
||||
if not click.confirm(click.style("Are you sure that you want to continue?", fg="red"), default=False):
|
||||
click.echo(click.style("Aborted!", fg="yellow"))
|
||||
return
|
||||
app = create_app(create_for_server=False)
|
||||
|
||||
with app.app_context():
|
||||
with db.session.begin():
|
||||
# Delete old database
|
||||
db.drop_all()
|
||||
# Create new database
|
||||
db.create_all()
|
||||
|
||||
|
@ -170,6 +163,8 @@ def maintain():
|
|||
def reset_admin_password():
|
||||
click.echo("This script will generate a new random password for a chosen admin.\n")
|
||||
|
||||
app = create_app(create_for_server=False)
|
||||
|
||||
with app.app_context():
|
||||
with db.session.begin():
|
||||
admins = db.session.execute(select(Admin).join(User).where(User.active == True)).scalars().all()
|
||||
|
|
|
@ -167,7 +167,7 @@ commands = [
|
|||
# Install Python requirements in the container
|
||||
"buildah run builder -- pip3 install -r requirements.txt",
|
||||
"buildah run builder -- python3 manage.py setup generate-secrets",
|
||||
"buildah run builder -- python3 manage.py setup initialize-database",
|
||||
"buildah run builder -- python3 manage.py setup init-db",
|
||||
"buildah config --cmd 'gunicorn --bind 0.0.0.0:80 --workers 5 --log-file /volumes/logs/gunicorn.log run:app' builder",
|
||||
]
|
||||
|
||||
|
|
3
run.py
3
run.py
|
@ -1,4 +1,5 @@
|
|||
from advlabdb import app
|
||||
from advlabdb import create_app
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = create_app()
|
||||
app.run(debug=True)
|
||||
|
|
Loading…
Reference in a new issue