From d07471f08d84a8f4700247b658a8e706e48ddd15 Mon Sep 17 00:00:00 2001 From: David Romero Date: Mon, 19 Feb 2024 12:26:31 +0100 Subject: [PATCH] fix: Fixes dynamic loading of blueprints --- app/__init__.py | 56 +++++++++++-------- app/blueprints/__init__.py | 0 app/{ => blueprints}/auth/__init__.py | 0 app/{ => blueprints}/auth/forms.py | 0 app/{ => blueprints}/auth/models.py | 0 app/{ => blueprints}/auth/routes.py | 13 ++--- .../auth/templates/auth/login_form.html | 0 .../auth/templates/auth/signup_form.html | 0 app/{ => blueprints}/dataset/__init__.py | 0 app/{ => blueprints}/dataset/forms.py | 3 +- app/{ => blueprints}/dataset/models.py | 0 app/{ => blueprints}/dataset/routes.py | 16 ++---- .../templates/dataset/list_datasets.html | 0 .../templates/dataset/upload_dataset.html | 0 .../templates/dataset/view_dataset.html | 0 app/{ => blueprints}/explore/__init__.py | 0 app/{ => blueprints}/explore/forms.py | 0 app/{ => blueprints}/explore/routes.py | 10 ++-- .../explore/templates/explore/index.html | 0 app/{ => blueprints}/profile/__init__.py | 0 app/{ => blueprints}/profile/forms.py | 0 app/{ => blueprints}/profile/models.py | 0 app/{ => blueprints}/profile/routes.py | 7 +-- .../profile/templates/profile/edit.html | 0 app/{ => blueprints}/public/__init__.py | 7 +-- app/{ => blueprints}/public/routes.py | 7 +-- .../public/templates/public/index.html | 0 app/{ => blueprints}/team/__init__.py | 0 app/blueprints/team/routes.py | 8 +++ .../team/templates/team/index.html | 0 app/team/routes.py | 9 --- app/zenodo.py | 4 +- 32 files changed, 69 insertions(+), 71 deletions(-) create mode 100644 app/blueprints/__init__.py rename app/{ => blueprints}/auth/__init__.py (100%) rename app/{ => blueprints}/auth/forms.py (100%) rename app/{ => blueprints}/auth/models.py (100%) rename app/{ => blueprints}/auth/routes.py (85%) rename app/{ => blueprints}/auth/templates/auth/login_form.html (100%) rename app/{ => blueprints}/auth/templates/auth/signup_form.html (100%) rename app/{ => blueprints}/dataset/__init__.py (100%) rename app/{ => blueprints}/dataset/forms.py (94%) rename app/{ => blueprints}/dataset/models.py (100%) rename app/{ => blueprints}/dataset/routes.py (97%) rename app/{ => blueprints}/dataset/templates/dataset/list_datasets.html (100%) rename app/{ => blueprints}/dataset/templates/dataset/upload_dataset.html (100%) rename app/{ => blueprints}/dataset/templates/dataset/view_dataset.html (100%) rename app/{ => blueprints}/explore/__init__.py (100%) rename app/{ => blueprints}/explore/forms.py (100%) rename app/{ => blueprints}/explore/routes.py (90%) rename app/{ => blueprints}/explore/templates/explore/index.html (100%) rename app/{ => blueprints}/profile/__init__.py (100%) rename app/{ => blueprints}/profile/forms.py (100%) rename app/{ => blueprints}/profile/models.py (100%) rename app/{ => blueprints}/profile/routes.py (81%) rename app/{ => blueprints}/profile/templates/profile/edit.html (100%) rename app/{ => blueprints}/public/__init__.py (97%) rename app/{ => blueprints}/public/routes.py (79%) rename app/{ => blueprints}/public/templates/public/index.html (100%) rename app/{ => blueprints}/team/__init__.py (100%) create mode 100644 app/blueprints/team/routes.py rename app/{ => blueprints}/team/templates/team/index.html (100%) delete mode 100644 app/team/routes.py diff --git a/app/__init__.py b/app/__init__.py index d45894038..fda5b52ae 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -8,7 +8,6 @@ from flask_sqlalchemy import SQLAlchemy from dotenv import load_dotenv from flask_migrate import Migrate -from flask_wtf import CSRFProtect # Load environment variables load_dotenv() @@ -41,24 +40,9 @@ def create_app(config_name=None): db.init_app(app) migrate.init_app(app, db) - # Automatically scan and register blueprints - blueprints_directory = app.root_path - excluded_folders = {'static', 'templates', 'tests'} - - for folder_name in os.listdir(blueprints_directory): - folder_path = os.path.join(blueprints_directory, folder_name) - if os.path.isdir(folder_path) and folder_name not in excluded_folders: - for filename in os.listdir(folder_path): - if filename.endswith('.py') and not filename.startswith('__'): - module_name = filename[:-3] - module_path = os.path.join(folder_path, filename) - spec = importlib.util.spec_from_file_location(module_name, module_path) - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - for item_name in dir(module): - item = getattr(module, item_name) - if isinstance(item, Blueprint): - app.register_blueprint(item) + # Register blueprints + register_blueprints(app) + print_registered_blueprints(app) from flask_login import LoginManager login_manager = LoginManager() @@ -67,7 +51,7 @@ def create_app(config_name=None): @login_manager.user_loader def load_user(user_id): - from app.auth.models import User + from app.blueprints.auth import User return User.query.get(int(user_id)) # Logging @@ -121,7 +105,7 @@ def upload_folder_name(): def get_user_by_token(token): # TODO - from app.auth.models import User + from app.blueprints.auth import User return User.query.first() @@ -132,15 +116,41 @@ def get_authenticated_user_profile(): def datasets_counter() -> int: - from app.dataset.models import DataSet + from app.blueprints.dataset.models import DataSet count = DataSet.query.count() return count def feature_models_counter() -> int: - from app.dataset.models import FeatureModel + from app.blueprints.dataset.models import FeatureModel count = FeatureModel.query.count() return count +def register_blueprints(app): + app.blueprint_url_prefixes = {} + base_dir = os.path.abspath(os.path.dirname(__file__)) + blueprints_dir = os.path.join(base_dir, 'blueprints') + for blueprint_name in os.listdir(blueprints_dir): + blueprint_path = os.path.join(blueprints_dir, blueprint_name) + if os.path.isdir(blueprint_path) and not blueprint_name.startswith('__'): + try: + routes_module = importlib.import_module(f'app.blueprints.{blueprint_name}.routes') + for item in dir(routes_module): + if isinstance(getattr(routes_module, item), Blueprint): + blueprint = getattr(routes_module, item) + url_prefix = f'/{blueprint_name if blueprint_name != "public" else ""}' + app.register_blueprint(blueprint, url_prefix=url_prefix) + app.blueprint_url_prefixes[blueprint.name] = url_prefix + except ModuleNotFoundError as e: + print(f"Could not load the module for Blueprint '{blueprint_name}': {e}") + + +def print_registered_blueprints(app): + print("Registered blueprints") + for name, blueprint in app.blueprints.items(): + url_prefix = app.blueprint_url_prefixes.get(name, 'No URL prefix set') + print(f"Name: {name}, URL prefix: {url_prefix}") + + app = create_app() diff --git a/app/blueprints/__init__.py b/app/blueprints/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/app/auth/__init__.py b/app/blueprints/auth/__init__.py similarity index 100% rename from app/auth/__init__.py rename to app/blueprints/auth/__init__.py diff --git a/app/auth/forms.py b/app/blueprints/auth/forms.py similarity index 100% rename from app/auth/forms.py rename to app/blueprints/auth/forms.py diff --git a/app/auth/models.py b/app/blueprints/auth/models.py similarity index 100% rename from app/auth/models.py rename to app/blueprints/auth/models.py diff --git a/app/auth/routes.py b/app/blueprints/auth/routes.py similarity index 85% rename from app/auth/routes.py rename to app/blueprints/auth/routes.py index 1f4338902..894212e28 100644 --- a/app/auth/routes.py +++ b/app/blueprints/auth/routes.py @@ -1,11 +1,10 @@ -from flask import (render_template, redirect, url_for, - request, current_app) +from flask import (render_template, redirect, url_for) from flask_login import current_user, login_user, logout_user -from app.auth import auth_bp -from app.auth.forms import SignupForm, LoginForm +from app.blueprints.auth import auth_bp +from app.blueprints.auth.forms import SignupForm, LoginForm -from app.profile.models import UserProfile +from app.blueprints.profile.models import UserProfile @auth_bp.route("/signup/", methods=["GET", "POST"]) @@ -20,7 +19,7 @@ def show_signup_form(): email = form.email.data password = form.password.data - from app.auth.models import User + from app.blueprints.auth.models import User user = User.get_by_email(email) if user is not None: error = f'Email {email} in use' @@ -47,7 +46,7 @@ def login(): return redirect(url_for('public.index')) form = LoginForm() if form.validate_on_submit(): - from app.auth.models import User + from app.blueprints.auth.models import User user = User.get_by_email(form.email.data) if user is not None and user.check_password(form.password.data): diff --git a/app/auth/templates/auth/login_form.html b/app/blueprints/auth/templates/auth/login_form.html similarity index 100% rename from app/auth/templates/auth/login_form.html rename to app/blueprints/auth/templates/auth/login_form.html diff --git a/app/auth/templates/auth/signup_form.html b/app/blueprints/auth/templates/auth/signup_form.html similarity index 100% rename from app/auth/templates/auth/signup_form.html rename to app/blueprints/auth/templates/auth/signup_form.html diff --git a/app/dataset/__init__.py b/app/blueprints/dataset/__init__.py similarity index 100% rename from app/dataset/__init__.py rename to app/blueprints/dataset/__init__.py diff --git a/app/dataset/forms.py b/app/blueprints/dataset/forms.py similarity index 94% rename from app/dataset/forms.py rename to app/blueprints/dataset/forms.py index 6b38669ad..3be424de7 100644 --- a/app/dataset/forms.py +++ b/app/blueprints/dataset/forms.py @@ -1,9 +1,8 @@ from flask_wtf import FlaskForm from wtforms import StringField, SelectField, FieldList, FormField, SubmitField, TextAreaField from wtforms.validators import DataRequired, URL, Optional -from enum import Enum -from app.dataset.models import PublicationType +from app.blueprints.dataset.models import PublicationType class AuthorForm(FlaskForm): diff --git a/app/dataset/models.py b/app/blueprints/dataset/models.py similarity index 100% rename from app/dataset/models.py rename to app/blueprints/dataset/models.py diff --git a/app/dataset/routes.py b/app/blueprints/dataset/routes.py similarity index 97% rename from app/dataset/routes.py rename to app/blueprints/dataset/routes.py index 885b8e369..c889a5512 100644 --- a/app/dataset/routes.py +++ b/app/blueprints/dataset/routes.py @@ -1,4 +1,3 @@ -import io import logging import os import json @@ -11,19 +10,16 @@ from typing import List from zipfile import ZipFile -from flask import flash, redirect, render_template, url_for, request, jsonify, send_file, send_from_directory, abort, \ - current_app, make_response +from flask import render_template, request, jsonify, send_from_directory, current_app, make_response from flask_login import login_required, current_user -from werkzeug.utils import secure_filename import app -from app.dataset.forms import DataSetForm -from app.dataset.models import DataSet, DSMetrics, FeatureModel, File, FMMetaData, FMMetrics, DSMetaData, Author, \ +from app.blueprints.dataset.forms import DataSetForm +from app.blueprints.dataset.models import DataSet, FeatureModel, File, FMMetaData, DSMetaData, Author, \ PublicationType, DSDownloadRecord, DSViewRecord, FileDownloadRecord -from app.dataset import dataset_bp -from app.auth.models import User -from app.flama import flamapy_valid_model -from app.zenodo import zenodo_create_new_deposition, test_zenodo_connection, zenodo_upload_file, \ +from app.blueprints.dataset import dataset_bp +from app.blueprints.auth.models import User +from app.zenodo import zenodo_create_new_deposition, zenodo_upload_file, \ zenodo_publish_deposition, zenodo_get_doi, test_full_zenodo_connection diff --git a/app/dataset/templates/dataset/list_datasets.html b/app/blueprints/dataset/templates/dataset/list_datasets.html similarity index 100% rename from app/dataset/templates/dataset/list_datasets.html rename to app/blueprints/dataset/templates/dataset/list_datasets.html diff --git a/app/dataset/templates/dataset/upload_dataset.html b/app/blueprints/dataset/templates/dataset/upload_dataset.html similarity index 100% rename from app/dataset/templates/dataset/upload_dataset.html rename to app/blueprints/dataset/templates/dataset/upload_dataset.html diff --git a/app/dataset/templates/dataset/view_dataset.html b/app/blueprints/dataset/templates/dataset/view_dataset.html similarity index 100% rename from app/dataset/templates/dataset/view_dataset.html rename to app/blueprints/dataset/templates/dataset/view_dataset.html diff --git a/app/explore/__init__.py b/app/blueprints/explore/__init__.py similarity index 100% rename from app/explore/__init__.py rename to app/blueprints/explore/__init__.py diff --git a/app/explore/forms.py b/app/blueprints/explore/forms.py similarity index 100% rename from app/explore/forms.py rename to app/blueprints/explore/forms.py diff --git a/app/explore/routes.py b/app/blueprints/explore/routes.py similarity index 90% rename from app/explore/routes.py rename to app/blueprints/explore/routes.py index 9637a0297..34a5944c5 100644 --- a/app/explore/routes.py +++ b/app/blueprints/explore/routes.py @@ -2,12 +2,12 @@ import unidecode -from flask import render_template, request, abort, jsonify -from sqlalchemy import or_, desc, asc, any_ +from flask import render_template, request, jsonify +from sqlalchemy import or_, any_ -from app.explore import explore_bp -from app.explore.forms import ExploreForm -from app.dataset.models import DataSet, DSMetaData, Author, FeatureModel, FMMetaData, PublicationType +from app.blueprints.explore import explore_bp +from app.blueprints.explore.forms import ExploreForm +from app.blueprints.dataset.models import DataSet, DSMetaData, Author, FeatureModel, FMMetaData, PublicationType @explore_bp.route('/explore', methods=['GET', 'POST']) diff --git a/app/explore/templates/explore/index.html b/app/blueprints/explore/templates/explore/index.html similarity index 100% rename from app/explore/templates/explore/index.html rename to app/blueprints/explore/templates/explore/index.html diff --git a/app/profile/__init__.py b/app/blueprints/profile/__init__.py similarity index 100% rename from app/profile/__init__.py rename to app/blueprints/profile/__init__.py diff --git a/app/profile/forms.py b/app/blueprints/profile/forms.py similarity index 100% rename from app/profile/forms.py rename to app/blueprints/profile/forms.py diff --git a/app/profile/models.py b/app/blueprints/profile/models.py similarity index 100% rename from app/profile/models.py rename to app/blueprints/profile/models.py diff --git a/app/profile/routes.py b/app/blueprints/profile/routes.py similarity index 81% rename from app/profile/routes.py rename to app/blueprints/profile/routes.py index d6a0df0ee..fb293f476 100644 --- a/app/profile/routes.py +++ b/app/blueprints/profile/routes.py @@ -1,10 +1,9 @@ -from flask import request, render_template, flash, redirect, url_for +from flask import request, render_template, flash from flask_login import login_required -from app.profile import profile_bp -from app.profile.forms import UserProfileForm +from app.blueprints.profile import profile_bp +from app.blueprints.profile.forms import UserProfileForm -from app.profile.models import UserProfile from app import get_authenticated_user_profile diff --git a/app/profile/templates/profile/edit.html b/app/blueprints/profile/templates/profile/edit.html similarity index 100% rename from app/profile/templates/profile/edit.html rename to app/blueprints/profile/templates/profile/edit.html diff --git a/app/public/__init__.py b/app/blueprints/public/__init__.py similarity index 97% rename from app/public/__init__.py rename to app/blueprints/public/__init__.py index 70af4ef9a..0f29c2c44 100644 --- a/app/public/__init__.py +++ b/app/blueprints/public/__init__.py @@ -1,4 +1,3 @@ -from flask import Blueprint - -public_bp = Blueprint('public', __name__, template_folder='templates') - +from flask import Blueprint + +public_bp = Blueprint('public', __name__, template_folder='templates') diff --git a/app/public/routes.py b/app/blueprints/public/routes.py similarity index 79% rename from app/public/routes.py rename to app/blueprints/public/routes.py index ed24437b3..0a469263a 100644 --- a/app/public/routes.py +++ b/app/blueprints/public/routes.py @@ -1,10 +1,9 @@ import logging import app -from flask import request, current_app, render_template - -from app.public import public_bp -from app.dataset.models import DataSet, DSMetaData +from flask import request, current_app, render_template, Blueprint +from app.blueprints.public import public_bp +from ..dataset.models import DataSet, DSMetaData logger = logging.getLogger(__name__) diff --git a/app/public/templates/public/index.html b/app/blueprints/public/templates/public/index.html similarity index 100% rename from app/public/templates/public/index.html rename to app/blueprints/public/templates/public/index.html diff --git a/app/team/__init__.py b/app/blueprints/team/__init__.py similarity index 100% rename from app/team/__init__.py rename to app/blueprints/team/__init__.py diff --git a/app/blueprints/team/routes.py b/app/blueprints/team/routes.py new file mode 100644 index 000000000..69da13de0 --- /dev/null +++ b/app/blueprints/team/routes.py @@ -0,0 +1,8 @@ +from flask import render_template + +from app.blueprints.team import team_bp + + +@team_bp.route('/team', methods=['GET']) +def index(): + return render_template('team/index.html') diff --git a/app/team/templates/team/index.html b/app/blueprints/team/templates/team/index.html similarity index 100% rename from app/team/templates/team/index.html rename to app/blueprints/team/templates/team/index.html diff --git a/app/team/routes.py b/app/team/routes.py deleted file mode 100644 index ae8d8ae55..000000000 --- a/app/team/routes.py +++ /dev/null @@ -1,9 +0,0 @@ -from flask import request, render_template, flash, redirect, url_for -from flask_login import login_required - -from app.team import team_bp - - -@team_bp.route('/team', methods=['GET']) -def index(): - return render_template('team/index.html') diff --git a/app/zenodo.py b/app/zenodo.py index 86cd45bb9..7620da01e 100644 --- a/app/zenodo.py +++ b/app/zenodo.py @@ -3,7 +3,6 @@ """ import os -from typing import Tuple, List import requests @@ -12,7 +11,7 @@ from flask_login import current_user import app -from app.dataset.models import DataSet, FeatureModel +from app.blueprints.dataset.models import DataSet, FeatureModel load_dotenv() @@ -156,7 +155,6 @@ def zenodo_upload_file(deposition_id: int, feature_model: FeatureModel, user=Non Returns: dict: The response in JSON format with the details of the uploaded file. """ - from app.auth.models import User uvl_filename = feature_model.fm_meta_data.uvl_filename data = {'name': uvl_filename} user_id = current_user.id if user is None else user.id