"""
Create Flask Application.
====================================
This module defines the factory function `create_app` for creating and configuring
the Gemini web application. It handles:
- Configuration of Flask application
- Database setup with SQLAlchemy
- Authentication management with Flask-Login
- Session management with Flask-Session
- Admin interface for managing users and projects
"""
import os
from pathlib import Path
from flask import Flask
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from flask_login import LoginManager, current_user
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash
from flask_session import Session
db = SQLAlchemy()
gemini_root_dir = Path(__file__).parents[2]
if not os.path.exists(os.path.join(gemini_root_dir, "gemini-project")):
os.mkdir(os.path.join(gemini_root_dir, "gemini-project"))
[docs]
def create_app():
"""Create and configure the Gemini web application using Flask and importing the blueprints."""
app = Flask(__name__)
app.config["SECRET_KEY"] = b"0\xbf\xb6\x04q\xf2\x12,\xfa\xfa\xf8T"
app.config["SQLALCHEMY_DATABASE_URI"] = (
f"mysql+pymysql://root:root@{os.getenv('GEMINI_MYSQLDB_URL')}:3306/{os.getenv('MYSQL_DATABASE')}"
)
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
app.config["GEMINI_PROJECT_FOLDER"] = os.getenv(
"GEMINI_PROJECT_FOLDER", os.path.join(gemini_root_dir, "gemini-project")
)
app.config["GEMINI_DOCUMENTATION_FOLDER"] = os.getenv(
"GEMINI_DOCUMENTATION_FOLDER", os.path.join(gemini_root_dir, "src/gemini_documentation")
)
app.config["MAX_CONTENT_LENGTH"] = 500 * 1000 * 1000
Session(app)
db.init_app(app)
login_manager = LoginManager()
login_manager.login_view = "auth.login"
login_manager.init_app(app)
from gemini_interface.blueprint.dbmodels import Project, User
@login_manager.user_loader
def load_user(user_id):
"""Load user from database by ID."""
return User.query.get(int(user_id))
# for admin manager
app.config["FLASK_ADMIN_SWATCH"] = "slate"
class UserModelView(ModelView):
can_create = False
column_exclude_list = ["password"]
def is_accessible(self):
return current_user.is_authenticated and current_user.role == "admin"
class ProjectModelView(ModelView):
def is_accessible(self):
return current_user.is_authenticated and current_user.role == "admin"
admin = Admin(app, name="Admin Manager", template_mode="bootstrap4")
admin.add_view(UserModelView(User, db.session))
admin.add_view(ProjectModelView(Project, db.session))
# for migration database
Migrate(app, db)
# blueprint for auth routes in our app
from gemini_interface.blueprint.auth.routes import auth as auth_blueprint
app.register_blueprint(auth_blueprint)
# blueprint for project routes in our app
from gemini_interface.blueprint.project.routes import projectmanager as projectmanager_blueprint
app.register_blueprint(projectmanager_blueprint)
# blueprint for pages route
from gemini_interface.blueprint.routes import main as main_blueprint
app.register_blueprint(main_blueprint)
# blueprint for builder routes in our app
from gemini_interface.blueprint.app_builder.routes import app_builder as app_builder_blueprint
app.register_blueprint(app_builder_blueprint)
# blueprint for esp routes in our app
from gemini_interface.blueprint.app_esp.routes import app_esp as app_esp_blueprint
app.register_blueprint(app_esp_blueprint)
# blueprint for report routes in our app
from gemini_interface.blueprint.report.routes import report as report_blueprint
app.register_blueprint(report_blueprint)
# blueprint for setting plant routes in our app
from gemini_interface.blueprint.setting_plant.routes import (
setting_plant as setting_plant_blueprint,
)
app.register_blueprint(setting_plant_blueprint)
# blueprint for app tagbrowser routes in our app
from gemini_interface.blueprint.app_tagbrowser.routes import (
app_tagbrowser as app_tagbrowser_blueprint,
)
app.register_blueprint(app_tagbrowser_blueprint)
# blueprint for app productionwellperformance routes in our app
from gemini_interface.blueprint.app_productionwellperformance.routes import (
app_productionwellperformance as app_productionwellperformance_blueprint,
)
app.register_blueprint(app_productionwellperformance_blueprint)
# blueprint for app injectionwellmonitoring routes in our app
from gemini_interface.blueprint.app_injectionwellmonitoring.routes import (
app_injectionwellmonitoring as app_injectionwellmonitoring_blueprint,
)
app.register_blueprint(app_injectionwellmonitoring_blueprint)
# blueprint for app well_schematics routes in our app
from gemini_interface.blueprint.app_well_schematics.routes import (
app_well_schematics as app_well_schematics_blueprint,
)
app.register_blueprint(app_well_schematics_blueprint)
# blueprint for app parameters_overview routes in our app
from gemini_interface.blueprint.app_parameters_overview.routes import (
app_parameters_overview as app_parameters_overview_blueprint,
)
app.register_blueprint(app_parameters_overview_blueprint)
# blueprint for app reportgenerator routes in our app
from gemini_interface.blueprint.app_reportgenerator.routes import (
app_reportgenerator as app_reportgenerator_blueprint,
)
app.register_blueprint(app_reportgenerator_blueprint)
# blueprint for app dashboard routes in our app
from gemini_interface.blueprint.dashboard.routes import dashboard as dashboard_blueprint
app.register_blueprint(dashboard_blueprint)
# blueprint for app wellintegrity_monitoring routes in our app
from gemini_interface.blueprint.app_wellintegrity_monitoring.routes import (
app_wellintegrity_monitoring as app_wellintegrity_monitoring_blueprint,
)
app.register_blueprint(app_wellintegrity_monitoring_blueprint)
# blueprint for app chatpopup in our app
from gemini_interface.blueprint.app_chatpopup.routes import app_chatpopup as app_chatpopup
app.register_blueprint(app_chatpopup)
with app.app_context():
db.create_all()
user = User.query.filter_by(email="admin@localhost").first()
if not user:
new_user = User(
email=os.getenv("GEMINI_ADMIN_EMAIL"),
name=os.getenv("GEMINI_ADMIN_NAME"),
password=generate_password_hash(
os.getenv("GEMINI_ADMIN_PASSWORD"), method="scrypt"
),
role="admin",
)
db.session.add(new_user)
db.session.commit()
template_project = Project.query.filter_by(name="geothermal_example").first()
if not template_project:
new_project = Project(name="geothermal_example", user="admin")
db.session.add(new_project)
db.session.commit()
return app