diff --git a/.gitignore b/.gitignore index ff08f874..eb398718 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ gdrive_credentials client_secrets.json gmail.json /.key + +pages/ diff --git a/cps/editpage.py b/cps/editpage.py new file mode 100644 index 00000000..1942bfd2 --- /dev/null +++ b/cps/editpage.py @@ -0,0 +1,108 @@ +import os +import flask +from flask import Blueprint, Flask, abort, request +from functools import wraps +from pathlib import Path +from flask_login import current_user, login_required +from werkzeug.exceptions import NotFound + +from .render_template import render_title_template +from . import logger, config, ub +from .constants import CONFIG_DIR as _CONFIG_DIR + +log = logger.create() + +editpage = Blueprint('editpage', __name__) + +def edit_required(f): + @wraps(f) + def inner(*args, **kwargs): + if current_user.role_edit() or current_user.role_admin(): + return f(*args, **kwargs) + abort(403) + + return inner + +def _get_checkbox(dictionary, field, default): + new_value = dictionary.get(field, default) + convertor = lambda y: y == "on" + new_value = convertor(new_value) + + return new_value + +@editpage.route("/admin/page/", methods=["GET", "POST"]) +@login_required +@edit_required +def edit_page(file): + doc = "" + title = "" + name = "" + icon = "file" + is_enabled = True + order = 0 + position = "0" + + page = ub.session.query(ub.Page).filter(ub.Page.id == file).first() + + try: + title = page.title + name = page.name + icon = page.icon + is_enabled = page.is_enabled + order = page.order + position = page.position + except AttributeError: + if file != "new": + abort(404) + + if request.method == "POST": + to_save = request.form.to_dict() + title = to_save.get("title", "").strip() + name = to_save.get("name", "").strip() + icon = to_save.get("icon", "").strip() + position = to_save.get("position", "").strip() + order = int(to_save.get("order", 0)) + content = to_save.get("content", "").strip() + is_enabled = _get_checkbox(to_save, "is_enabled", True) + + if page: + page.title = title + page.name = name + page.icon = icon + page.is_enabled = is_enabled + page.order = order + page.position = position + ub.session_commit("Page edited {}".format(file)) + else: + new_page = ub.Page(title=title, name=name, icon=icon, is_enabled=is_enabled, order=order, position=position) + ub.session.add(new_page) + ub.session_commit("Page added {}".format(file)) + + if (file == "new"): + file = str(new_page.id) + dir_config_path = os.path.join(_CONFIG_DIR, 'pages') + file_name = Path(name + '.md') + file_path = dir_config_path / file_name + os.makedirs(dir_config_path, exist_ok=True) + + try: + with open(file_path, 'w') as f: + f.write(content) + f.close() + except Exception as ex: + log.error(ex) + + if file != "new": + try: + dir_config_path = Path(_CONFIG_DIR) / 'pages' + file_path = dir_config_path / f"{name}.md" + + with open(file_path, 'r') as f: + doc = f.read() + except NotFound: + log.error("'%s' was accessed but file doesn't exists." % file) + + else: + doc = "## New file\n\nInformation" + + return render_title_template("edit_page.html", title=title, name=name, icon=icon, is_enabled=is_enabled, order=order, position=position, content=doc, file=file) diff --git a/cps/listpages.py b/cps/listpages.py new file mode 100644 index 00000000..8016f5ee --- /dev/null +++ b/cps/listpages.py @@ -0,0 +1,28 @@ +import flask +import json +from flask import Blueprint, jsonify, make_response,abort +from flask_login import current_user, login_required +from functools import wraps +from flask_babel import gettext as _ + +from .render_template import render_title_template +from . import ub, db + +listpages = Blueprint('listpages', __name__) + +def edit_required(f): + @wraps(f) + def inner(*args, **kwargs): + if current_user.role_edit() or current_user.role_admin(): + return f(*args, **kwargs) + abort(403) + + return inner + +@listpages.route("/admin/pages/", methods=["GET"]) +@login_required +@edit_required +def show_list(): + pages = ub.session.query(ub.Page).order_by(ub.Page.position).order_by(ub.Page.order).all() + + return render_title_template('list_pages.html', title=_("Pages List"), page="book_table", pages=pages) diff --git a/cps/main.py b/cps/main.py index 286b2b27..ad990bb7 100644 --- a/cps/main.py +++ b/cps/main.py @@ -36,6 +36,9 @@ def main(): from .gdrive import gdrive from .editbooks import editbook from .about import about + from .page import page + from .listpages import listpages + from .editpage import editpage from .search import search from .search_metadata import meta from .shelf import shelf @@ -65,6 +68,9 @@ def main(): limiter.limit("3/minute",key_func=request_username)(opds) app.register_blueprint(jinjia) app.register_blueprint(about) + app.register_blueprint(page) + app.register_blueprint(listpages) + app.register_blueprint(editpage) app.register_blueprint(shelf) app.register_blueprint(admi) app.register_blueprint(remotelogin) diff --git a/cps/page.py b/cps/page.py new file mode 100644 index 00000000..b3e42faa --- /dev/null +++ b/cps/page.py @@ -0,0 +1,38 @@ +import os +import flask +import markdown +from flask import abort +from pathlib import Path +from flask_babel import gettext as _ +from werkzeug.exceptions import NotFound + +from . import logger, config, ub +from .render_template import render_title_template +from .constants import CONFIG_DIR as _CONFIG_DIR + +page = flask.Blueprint('page', __name__) + +log = logger.create() + +@page.route('/page/', methods=['GET']) +def get_page(file): + page = ub.session.query(ub.Page)\ + .filter(ub.Page.name == file)\ + .filter(ub.Page.is_enabled)\ + .first() + + if not page: + log.error(f"'{file}' was accessed but is not enabled or it's not in database.") + abort(404) + + try: + dir_config_path = Path(_CONFIG_DIR) / 'pages' + file_path = dir_config_path / f"{file}.md" + with open(file_path, 'r') as f: + temp_md = f.read() + body = markdown.markdown(temp_md) + + return render_title_template('page.html', body=body, title=page.title, page=page.name) + except NotFound: + log.error("'%s' was accessed but file doesn't exists." % file) + abort(404) diff --git a/cps/render_template.py b/cps/render_template.py index 68b46459..0f6e68ef 100644 --- a/cps/render_template.py +++ b/cps/render_template.py @@ -104,14 +104,24 @@ def get_sidebar_config(kwargs=None): g.shelves_access = ub.session.query(ub.Shelf).filter( or_(ub.Shelf.is_public == 1, ub.Shelf.user_id == current_user.id)).order_by(ub.Shelf.name).all() - return sidebar, simple + top_pages = ub.session.query(ub.Page)\ + .filter(ub.Page.position == "1")\ + .filter(ub.Page.is_enabled)\ + .order_by(ub.Page.order) + bottom_pages = ub.session.query(ub.Page)\ + .filter(ub.Page.position == "0")\ + .filter(ub.Page.is_enabled)\ + .order_by(ub.Page.order) + + return sidebar, simple, top_pages, bottom_pages # Returns the template for rendering and includes the instance name def render_title_template(*args, **kwargs): - sidebar, simple = get_sidebar_config(kwargs) + sidebar, simple, top_pages, bottom_pages = get_sidebar_config(kwargs) try: return render_template(instance=config.config_calibre_web_title, sidebar=sidebar, simple=simple, + top_pages=top_pages, bottom_pages=bottom_pages, accept=constants.EXTENSIONS_UPLOAD, *args, **kwargs) except PermissionError: diff --git a/cps/templates/admin.html b/cps/templates/admin.html index ac124fe8..3f7bf788 100644 --- a/cps/templates/admin.html +++ b/cps/templates/admin.html @@ -159,6 +159,7 @@ {{_('Edit Calibre Database Configuration')}} {{_('Edit Basic Configuration')}} {{_('Edit UI Configuration')}} + {{_('List Pages')}} {% if feature_support['scheduler'] %} diff --git a/cps/templates/edit_page.html b/cps/templates/edit_page.html new file mode 100644 index 00000000..e612a133 --- /dev/null +++ b/cps/templates/edit_page.html @@ -0,0 +1,45 @@ +{% extends "layout.html" %} +{% block body %} +
+
{{_('Back')}}
+

{{_('Edit page')}}

+
+ +
+ + +
+
+ + +
+
+ + + {{_('Icons list')}} +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + {{_('Cancel')}} +
+
+{% endblock %} diff --git a/cps/templates/layout.html b/cps/templates/layout.html index 1bee1c1d..c4716615 100644 --- a/cps/templates/layout.html +++ b/cps/templates/layout.html @@ -142,6 +142,9 @@