From 298096e126f20e58dcbf72da98bb5965440f929f Mon Sep 17 00:00:00 2001 From: SvyatoslavArtymovych Date: Thu, 8 Jun 2023 14:35:40 +0300 Subject: [PATCH] customized admin panel --- app/__init__.py | 24 +++++--- app/controllers/admin/__init__.py | 10 ++++ app/controllers/admin/book.py | 46 +++++++++++++++ app/controllers/admin/collection.py | 56 +++++++++++++++++++ app/controllers/admin/comment.py | 54 ++++++++++++++++++ .../custom_admin_index_view.py | 0 app/controllers/admin/interpretation.py | 53 ++++++++++++++++++ app/controllers/admin/protected_model_view.py | 11 ++++ app/controllers/admin/section.py | 53 ++++++++++++++++++ app/controllers/admin/tag.py | 51 +++++++++++++++++ app/controllers/admin/user.py | 11 ++++ .../flask_admin_customization/__init__.py | 3 - .../protected_model_view.py | 36 ------------ 13 files changed, 360 insertions(+), 48 deletions(-) create mode 100644 app/controllers/admin/__init__.py create mode 100644 app/controllers/admin/book.py create mode 100644 app/controllers/admin/collection.py create mode 100644 app/controllers/admin/comment.py rename app/controllers/{flask_admin_customization => admin}/custom_admin_index_view.py (100%) create mode 100644 app/controllers/admin/interpretation.py create mode 100644 app/controllers/admin/protected_model_view.py create mode 100644 app/controllers/admin/section.py create mode 100644 app/controllers/admin/tag.py create mode 100644 app/controllers/admin/user.py delete mode 100644 app/controllers/flask_admin_customization/__init__.py delete mode 100644 app/controllers/flask_admin_customization/protected_model_view.py diff --git a/app/__init__.py b/app/__init__.py index e69f62c..2357b2f 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -91,9 +91,15 @@ def create_app(environment="development"): return render_template("error.html", error=exc), exc.code # flask admin - from app.controllers.flask_admin_customization import ( + from app.controllers.admin import ( CustomAdminIndexView, - ProtectedModelView, + UsersView, + BooksView, + CollectionsView, + SectionsView, + InterpretationView, + CommentView, + TagView, ) app.config["FLASK_ADMIN_SWATCH"] = "Flatly" @@ -105,20 +111,20 @@ def create_app(environment="development"): ) for view in [ - ProtectedModelView(m.User, db.session, name="User", endpoint="/user_"), - ProtectedModelView(m.Book, db.session, name="Book", endpoint="/book_"), - ProtectedModelView( + UsersView(m.User, db.session, name="User", endpoint="/user_"), + BooksView(m.Book, db.session, name="Book", endpoint="/book_"), + CollectionsView( m.Collection, db.session, name="Collection", endpoint="/collection_" ), - ProtectedModelView(m.Section, db.session, name="Section", endpoint="/section_"), - ProtectedModelView( + SectionsView(m.Section, db.session, name="Section", endpoint="/section_"), + InterpretationView( m.Interpretation, db.session, name="Interpretation", endpoint="/interpretation_", ), - ProtectedModelView(m.Comment, db.session, name="Comment", endpoint="/comment_"), - ProtectedModelView(m.Tag, db.session, name="Tag", endpoint="/tag_"), + CommentView(m.Comment, db.session, name="Comment", endpoint="/comment_"), + TagView(m.Tag, db.session, name="Tag", endpoint="/tag_"), ]: admin.add_view(view) diff --git a/app/controllers/admin/__init__.py b/app/controllers/admin/__init__.py new file mode 100644 index 0000000..00a65c6 --- /dev/null +++ b/app/controllers/admin/__init__.py @@ -0,0 +1,10 @@ +# flake8: noqa F401 +from .custom_admin_index_view import CustomAdminIndexView +from .protected_model_view import ProtectedModelView +from .user import UsersView +from .book import BooksView +from .collection import CollectionsView +from .section import SectionsView +from .interpretation import InterpretationView +from .comment import CommentView +from .tag import TagView diff --git a/app/controllers/admin/book.py b/app/controllers/admin/book.py new file mode 100644 index 0000000..ab39ca0 --- /dev/null +++ b/app/controllers/admin/book.py @@ -0,0 +1,46 @@ +from flask_admin.base import expose +from flask_admin.helpers import get_redirect_target, flash_errors +from flask import redirect, flash +from flask_admin.babel import gettext + +from app.controllers.delete_nested_book_entities import delete_nested_book_entities +from .protected_model_view import ProtectedModelView + + +class BooksView(ProtectedModelView): + column_list = ("id", "label", "about", "is_deleted", "user_id", "created_at") + column_labels = dict(user_id="Created by") + + @expose("/delete/", methods=("POST",)) + def delete_view(self): + return_url = get_redirect_target() or self.get_url(".index_view") + + if not self.can_delete: + return redirect(return_url) + + form = self.delete_form() + + if self.validate_form(form): + # id is InputRequired() + id = form.id.data + + model = self.get_one(id) + + if model is None: + flash(gettext("Record does not exist."), "error") + return redirect(return_url) + + model.is_deleted = True + delete_nested_book_entities(model) + model.save() + flash( + gettext( + "Book and nested entities were successfully deleted.", + ), + "success", + ) + return redirect(return_url) + else: + flash_errors(form, message="Failed to delete record. %(error)s") + + return redirect(return_url) diff --git a/app/controllers/admin/collection.py b/app/controllers/admin/collection.py new file mode 100644 index 0000000..50aa6b9 --- /dev/null +++ b/app/controllers/admin/collection.py @@ -0,0 +1,56 @@ +from flask_admin.base import expose +from flask_admin.helpers import get_redirect_target, flash_errors +from flask import redirect, flash +from flask_admin.babel import gettext + +from app.controllers.delete_nested_book_entities import ( + delete_nested_collection_entities, +) +from .protected_model_view import ProtectedModelView + + +class CollectionsView(ProtectedModelView): + column_list = ( + "id", + "label", + "about", + "is_root", + "is_leaf", + "position", + "is_deleted", + "created_at", + ) + + @expose("/delete/", methods=("POST",)) + def delete_view(self): + return_url = get_redirect_target() or self.get_url(".index_view") + + if not self.can_delete: + return redirect(return_url) + + form = self.delete_form() + + if self.validate_form(form): + # id is InputRequired() + id = form.id.data + + model = self.get_one(id) + + if model is None: + flash(gettext("Record does not exist."), "error") + return redirect(return_url) + + model.is_deleted = True + delete_nested_collection_entities(model) + model.save() + flash( + gettext( + "Collection and nested entities were successfully deleted.", + ), + "success", + ) + return redirect(return_url) + else: + flash_errors(form, message="Failed to delete record. %(error)s") + + return redirect(return_url) diff --git a/app/controllers/admin/comment.py b/app/controllers/admin/comment.py new file mode 100644 index 0000000..cc7eb24 --- /dev/null +++ b/app/controllers/admin/comment.py @@ -0,0 +1,54 @@ +from flask_admin.base import expose +from flask_admin.helpers import get_redirect_target, flash_errors +from flask import redirect, flash +from flask_admin.babel import gettext + +from app.controllers.delete_nested_book_entities import ( + delete_nested_comment_entities, +) +from .protected_model_view import ProtectedModelView + + +class CommentView(ProtectedModelView): + column_list = ( + "id", + "text", + "approved", + "edited", + "is_deleted", + "created_at", + ) + + @expose("/delete/", methods=("POST",)) + def delete_view(self): + return_url = get_redirect_target() or self.get_url(".index_view") + + if not self.can_delete: + return redirect(return_url) + + form = self.delete_form() + + if self.validate_form(form): + # id is InputRequired() + id = form.id.data + + model = self.get_one(id) + + if model is None: + flash(gettext("Record does not exist."), "error") + return redirect(return_url) + + model.is_deleted = True + delete_nested_comment_entities(model) + model.save() + flash( + gettext( + "Section and nested entities were successfully deleted.", + ), + "success", + ) + return redirect(return_url) + else: + flash_errors(form, message="Failed to delete record. %(error)s") + + return redirect(return_url) diff --git a/app/controllers/flask_admin_customization/custom_admin_index_view.py b/app/controllers/admin/custom_admin_index_view.py similarity index 100% rename from app/controllers/flask_admin_customization/custom_admin_index_view.py rename to app/controllers/admin/custom_admin_index_view.py diff --git a/app/controllers/admin/interpretation.py b/app/controllers/admin/interpretation.py new file mode 100644 index 0000000..aeb92d7 --- /dev/null +++ b/app/controllers/admin/interpretation.py @@ -0,0 +1,53 @@ +from flask_admin.base import expose +from flask_admin.helpers import get_redirect_target, flash_errors +from flask import redirect, flash +from flask_admin.babel import gettext + +from app.controllers.delete_nested_book_entities import ( + delete_nested_interpretation_entities, +) +from .protected_model_view import ProtectedModelView + + +class InterpretationView(ProtectedModelView): + column_list = ( + "id", + "plain_text", + "approved", + "is_deleted", + "created_at", + ) + + @expose("/delete/", methods=("POST",)) + def delete_view(self): + return_url = get_redirect_target() or self.get_url(".index_view") + + if not self.can_delete: + return redirect(return_url) + + form = self.delete_form() + + if self.validate_form(form): + # id is InputRequired() + id = form.id.data + + model = self.get_one(id) + + if model is None: + flash(gettext("Record does not exist."), "error") + return redirect(return_url) + + model.is_deleted = True + delete_nested_interpretation_entities(model) + model.save() + flash( + gettext( + "Section and nested entities were successfully deleted.", + ), + "success", + ) + return redirect(return_url) + else: + flash_errors(form, message="Failed to delete record. %(error)s") + + return redirect(return_url) diff --git a/app/controllers/admin/protected_model_view.py b/app/controllers/admin/protected_model_view.py new file mode 100644 index 0000000..feae816 --- /dev/null +++ b/app/controllers/admin/protected_model_view.py @@ -0,0 +1,11 @@ +from flask_admin.contrib.sqla import ModelView +from flask_login import current_user + + +class ProtectedModelView(ModelView): + action_disallowed_list = ["delete"] + column_default_sort = "id" + can_create = False + + def is_accessible(self): + return current_user.is_super_user diff --git a/app/controllers/admin/section.py b/app/controllers/admin/section.py new file mode 100644 index 0000000..53b2079 --- /dev/null +++ b/app/controllers/admin/section.py @@ -0,0 +1,53 @@ +from flask_admin.base import expose +from flask_admin.helpers import get_redirect_target, flash_errors +from flask import redirect, flash +from flask_admin.babel import gettext + +from app.controllers.delete_nested_book_entities import ( + delete_nested_section_entities, +) +from .protected_model_view import ProtectedModelView + + +class SectionsView(ProtectedModelView): + column_list = ( + "id", + "label", + "position", + "is_deleted", + "created_at", + ) + + @expose("/delete/", methods=("POST",)) + def delete_view(self): + return_url = get_redirect_target() or self.get_url(".index_view") + + if not self.can_delete: + return redirect(return_url) + + form = self.delete_form() + + if self.validate_form(form): + # id is InputRequired() + id = form.id.data + + model = self.get_one(id) + + if model is None: + flash(gettext("Record does not exist."), "error") + return redirect(return_url) + + model.is_deleted = True + delete_nested_section_entities(model) + model.save() + flash( + gettext( + "Section and nested entities were successfully deleted.", + ), + "success", + ) + return redirect(return_url) + else: + flash_errors(form, message="Failed to delete record. %(error)s") + + return redirect(return_url) diff --git a/app/controllers/admin/tag.py b/app/controllers/admin/tag.py new file mode 100644 index 0000000..ddcd26c --- /dev/null +++ b/app/controllers/admin/tag.py @@ -0,0 +1,51 @@ +from flask_admin.base import expose +from flask_admin.helpers import get_redirect_target, flash_errors +from flask import redirect, flash +from flask_admin.babel import gettext + +from app.controllers.delete_nested_book_entities import ( + delete_nested_comment_entities, +) +from .protected_model_view import ProtectedModelView + + +class TagView(ProtectedModelView): + column_list = ( + "id", + "name", + "created_at", + ) + + @expose("/delete/", methods=("POST",)) + def delete_view(self): + return_url = get_redirect_target() or self.get_url(".index_view") + + if not self.can_delete: + return redirect(return_url) + + form = self.delete_form() + + if self.validate_form(form): + # id is InputRequired() + id = form.id.data + + model = self.get_one(id) + + if model is None: + flash(gettext("Record does not exist."), "error") + return redirect(return_url) + + model.is_deleted = True + delete_nested_comment_entities(model) + model.save() + flash( + gettext( + "Section and nested entities were successfully deleted.", + ), + "success", + ) + return redirect(return_url) + else: + flash_errors(form, message="Failed to delete record. %(error)s") + + return redirect(return_url) diff --git a/app/controllers/admin/user.py b/app/controllers/admin/user.py new file mode 100644 index 0000000..fd0ea98 --- /dev/null +++ b/app/controllers/admin/user.py @@ -0,0 +1,11 @@ +from .protected_model_view import ProtectedModelView + + +class UsersView(ProtectedModelView): + column_list = ( + "id", + "username", + "is_activated", + "wallet_id", + "is_super_user", + ) diff --git a/app/controllers/flask_admin_customization/__init__.py b/app/controllers/flask_admin_customization/__init__.py deleted file mode 100644 index 451da8d..0000000 --- a/app/controllers/flask_admin_customization/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# flake8: noqa F401 -from .custom_admin_index_view import CustomAdminIndexView -from .protected_model_view import ProtectedModelView diff --git a/app/controllers/flask_admin_customization/protected_model_view.py b/app/controllers/flask_admin_customization/protected_model_view.py deleted file mode 100644 index 4a84cac..0000000 --- a/app/controllers/flask_admin_customization/protected_model_view.py +++ /dev/null @@ -1,36 +0,0 @@ -from flask_admin.contrib.sqla import ModelView -from flask_login import current_user -from flask import redirect, url_for, flash -from app.logger import log - - -class ProtectedModelView(ModelView): - def is_accessible(self): - return current_user.is_super_user - - def inaccessible_callback(self, name, **kwargs): - # redirect to login page if user doesn't have access - return redirect(url_for("main.index")) - - def delete_model(self, model): - """ - Delete model. - :param model: - Model to delete - """ - try: - self.on_model_delete(model) - # Add your custom logic here and don't forget to commit any changes e.g. - # self.session.commit() - except Exception as ex: - if not self.handle_view_exception(ex): - flash("Failed to delete record.", "danger") - log(log.WARNING, "Failed to delete record.Because [%s]", ex) - - self.session.rollback() - - return False - else: - self.after_model_delete(model) - - return True