mirror of
https://github.com/janeczku/calibre-web
synced 2024-09-28 23:10:48 +00:00
Merge 84182e791a
into c30460d76b
This commit is contained in:
commit
4d66f8c31f
2
.gitignore
vendored
2
.gitignore
vendored
@ -35,3 +35,5 @@ gdrive_credentials
|
|||||||
client_secrets.json
|
client_secrets.json
|
||||||
gmail.json
|
gmail.json
|
||||||
/.key
|
/.key
|
||||||
|
|
||||||
|
pages/
|
||||||
|
@ -68,6 +68,7 @@ ROLE_ANONYMOUS = 1 << 5
|
|||||||
ROLE_EDIT_SHELFS = 1 << 6
|
ROLE_EDIT_SHELFS = 1 << 6
|
||||||
ROLE_DELETE_BOOKS = 1 << 7
|
ROLE_DELETE_BOOKS = 1 << 7
|
||||||
ROLE_VIEWER = 1 << 8
|
ROLE_VIEWER = 1 << 8
|
||||||
|
ROLE_SEND_TO_EREADER = 1 << 9
|
||||||
|
|
||||||
ALL_ROLES = {
|
ALL_ROLES = {
|
||||||
"admin_role": ROLE_ADMIN,
|
"admin_role": ROLE_ADMIN,
|
||||||
@ -78,6 +79,7 @@ ALL_ROLES = {
|
|||||||
"edit_shelf_role": ROLE_EDIT_SHELFS,
|
"edit_shelf_role": ROLE_EDIT_SHELFS,
|
||||||
"delete_role": ROLE_DELETE_BOOKS,
|
"delete_role": ROLE_DELETE_BOOKS,
|
||||||
"viewer_role": ROLE_VIEWER,
|
"viewer_role": ROLE_VIEWER,
|
||||||
|
"send_to_ereader": ROLE_SEND_TO_EREADER,
|
||||||
}
|
}
|
||||||
|
|
||||||
DETAIL_RANDOM = 1 << 0
|
DETAIL_RANDOM = 1 << 0
|
||||||
|
108
cps/editpage.py
Normal file
108
cps/editpage.py
Normal file
@ -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/<string:file>", 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)
|
28
cps/listpages.py
Normal file
28
cps/listpages.py
Normal file
@ -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)
|
@ -36,6 +36,9 @@ def main():
|
|||||||
from .gdrive import gdrive
|
from .gdrive import gdrive
|
||||||
from .editbooks import editbook
|
from .editbooks import editbook
|
||||||
from .about import about
|
from .about import about
|
||||||
|
from .page import page
|
||||||
|
from .listpages import listpages
|
||||||
|
from .editpage import editpage
|
||||||
from .search import search
|
from .search import search
|
||||||
from .search_metadata import meta
|
from .search_metadata import meta
|
||||||
from .shelf import shelf
|
from .shelf import shelf
|
||||||
@ -65,6 +68,9 @@ def main():
|
|||||||
limiter.limit("3/minute",key_func=request_username)(opds)
|
limiter.limit("3/minute",key_func=request_username)(opds)
|
||||||
app.register_blueprint(jinjia)
|
app.register_blueprint(jinjia)
|
||||||
app.register_blueprint(about)
|
app.register_blueprint(about)
|
||||||
|
app.register_blueprint(page)
|
||||||
|
app.register_blueprint(listpages)
|
||||||
|
app.register_blueprint(editpage)
|
||||||
app.register_blueprint(shelf)
|
app.register_blueprint(shelf)
|
||||||
app.register_blueprint(admi)
|
app.register_blueprint(admi)
|
||||||
app.register_blueprint(remotelogin)
|
app.register_blueprint(remotelogin)
|
||||||
|
38
cps/page.py
Normal file
38
cps/page.py
Normal file
@ -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/<string:file>', 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)
|
@ -104,14 +104,24 @@ def get_sidebar_config(kwargs=None):
|
|||||||
g.shelves_access = ub.session.query(ub.Shelf).filter(
|
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()
|
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
|
# Returns the template for rendering and includes the instance name
|
||||||
def render_title_template(*args, **kwargs):
|
def render_title_template(*args, **kwargs):
|
||||||
sidebar, simple = get_sidebar_config(kwargs)
|
sidebar, simple, top_pages, bottom_pages = get_sidebar_config(kwargs)
|
||||||
try:
|
try:
|
||||||
return render_template(instance=config.config_calibre_web_title, sidebar=sidebar, simple=simple,
|
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,
|
accept=constants.EXTENSIONS_UPLOAD,
|
||||||
*args, **kwargs)
|
*args, **kwargs)
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
<th class="hidden-xs hidden-sm">{{_('Upload')}}</th>
|
<th class="hidden-xs hidden-sm">{{_('Upload')}}</th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<th class="hidden-xs hidden-sm">{{_('Download')}}</th>
|
<th class="hidden-xs hidden-sm">{{_('Download')}}</th>
|
||||||
|
<th class="hidden-xs hidden-sm">{{_('Send to eReader')}}</th>
|
||||||
<th class="hidden-xs hidden-sm hidden-md">{{_('View Books')}}</th>
|
<th class="hidden-xs hidden-sm hidden-md">{{_('View Books')}}</th>
|
||||||
<th class="hidden-xs hidden-sm hidden-md">{{_('Edit')}}</th>
|
<th class="hidden-xs hidden-sm hidden-md">{{_('Edit')}}</th>
|
||||||
<th class="hidden-xs hidden-sm hidden-md">{{_('Delete')}}</th>
|
<th class="hidden-xs hidden-sm hidden-md">{{_('Delete')}}</th>
|
||||||
@ -38,6 +39,7 @@
|
|||||||
<td class="hidden-xs hidden-sm">{{ display_bool_setting(user.role_upload()) }}</td>
|
<td class="hidden-xs hidden-sm">{{ display_bool_setting(user.role_upload()) }}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td class="hidden-xs hidden-sm">{{ display_bool_setting(user.role_download()) }}</td>
|
<td class="hidden-xs hidden-sm">{{ display_bool_setting(user.role_download()) }}</td>
|
||||||
|
<td class="hidden-xs hidden-sm">{{ display_bool_setting(user.role_send_to_ereader()) }}</td>
|
||||||
<td class="hidden-xs hidden-sm hidden-md">{{ display_bool_setting(user.role_viewer()) }}</td>
|
<td class="hidden-xs hidden-sm hidden-md">{{ display_bool_setting(user.role_viewer()) }}</td>
|
||||||
<td class="hidden-xs hidden-sm hidden-md">{{ display_bool_setting(user.role_edit()) }}</td>
|
<td class="hidden-xs hidden-sm hidden-md">{{ display_bool_setting(user.role_edit()) }}</td>
|
||||||
<td class="hidden-xs hidden-sm hidden-md">{{ display_bool_setting(user.role_delete_books()) }}</td>
|
<td class="hidden-xs hidden-sm hidden-md">{{ display_bool_setting(user.role_delete_books()) }}</td>
|
||||||
@ -159,6 +161,7 @@
|
|||||||
<a class="btn btn-default" id="db_config" href="{{url_for('admin.db_configuration')}}">{{_('Edit Calibre Database Configuration')}}</a>
|
<a class="btn btn-default" id="db_config" href="{{url_for('admin.db_configuration')}}">{{_('Edit Calibre Database Configuration')}}</a>
|
||||||
<a class="btn btn-default" id="basic_config" href="{{url_for('admin.configuration')}}">{{_('Edit Basic Configuration')}}</a>
|
<a class="btn btn-default" id="basic_config" href="{{url_for('admin.configuration')}}">{{_('Edit Basic Configuration')}}</a>
|
||||||
<a class="btn btn-default" id="view_config" href="{{url_for('admin.view_configuration')}}">{{_('Edit UI Configuration')}}</a>
|
<a class="btn btn-default" id="view_config" href="{{url_for('admin.view_configuration')}}">{{_('Edit UI Configuration')}}</a>
|
||||||
|
<a class="btn btn-default" id="list_pages" href="{{url_for('listpages.show_list')}}">{{_('List Pages')}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if feature_support['scheduler'] %}
|
{% if feature_support['scheduler'] %}
|
||||||
|
@ -43,6 +43,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if current_user.role_send_to_ereader() %}
|
||||||
{% if current_user.kindle_mail and entry.email_share_list %}
|
{% if current_user.kindle_mail and entry.email_share_list %}
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
{% if entry.email_share_list.__len__() == 1 %}
|
{% if entry.email_share_list.__len__() == 1 %}
|
||||||
|
45
cps/templates/edit_page.html
Normal file
45
cps/templates/edit_page.html
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block body %}
|
||||||
|
<div class="discover">
|
||||||
|
<div><a class="session" href="{{url_for('listpages.show_list')}}">{{_('Back')}}</a></div>
|
||||||
|
<h2>{{_('Edit page')}}</h2>
|
||||||
|
<form role="form" class="col-md-10 col-lg-6" method="POST" action="{{ url_for('editpage.edit_page', file=file) }}"
|
||||||
|
autocomplete="off">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="title">{{_('Title')}}</label>
|
||||||
|
<input type="text" class="form-control" name="title" id="title" value="{{ title }}" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">{{_('Name')}}</label>
|
||||||
|
<input type="text" class="form-control" name="name" id="name" value="{{ name }}" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="icon">{{_('Icon')}}</label>
|
||||||
|
<input type="text" class="form-control" name="icon" id="icon" value="{{ icon }}" required>
|
||||||
|
<a href="https://www.w3schools.com/bootstrap/bootstrap_ref_comp_glyphs.asp" target="_blank" rel="noopener">{{_('Icons list')}}</a>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="content">{{_('Content')}}</label>
|
||||||
|
<textarea class="form-control" name="content" id="content" rows="15">{{ content }}</textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="position">{{_('Position')}}</label>
|
||||||
|
<select name="position" id="position" class="form-control">
|
||||||
|
<option value="0" {% if position=="0" %}selected{% endif %}>{{ _("Sidebar Bottom") }}</option>
|
||||||
|
<option value="1" {% if position=="1" %}selected{% endif %}>{{ _("Sidebar Top") }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="checkbox" id="is_enabled" name="is_enabled" {% if is_enabled %}checked{% endif %}>
|
||||||
|
<label for="is_enabled">{{_('Enabled')}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="order">{{_('Order')}}</label>
|
||||||
|
<input type="number" class="form-control" name="order" id="order" value="{{ order }}" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" name="submit" id="page_submit" class="btn btn-default">{{_('Save')}}</button>
|
||||||
|
<a href="{{ url_for('admin.admin') }}" id="config_back" class="btn btn-default">{{_('Cancel')}}</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -142,6 +142,9 @@
|
|||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<nav class="navigation">
|
<nav class="navigation">
|
||||||
<ul class="list-unstyled" id="scnd-nav" intent in-standard-append="nav.navigation" in-mobile-after="#main-nav" in-mobile-class="nav navbar-nav">
|
<ul class="list-unstyled" id="scnd-nav" intent in-standard-append="nav.navigation" in-mobile-after="#main-nav" in-mobile-class="nav navbar-nav">
|
||||||
|
{% for element in top_pages %}
|
||||||
|
<li id="nav_{{element['name']}}" {% if page == element['name'] %}class="active"{% endif %}><a href="{{url_for('page.get_page', file=element['name'])}}"><span class="glyphicon glyphicon-{{element['icon']}}"></span> {{element['title']}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
<li class="nav-head hidden-xs">{{_('Browse')}}</li>
|
<li class="nav-head hidden-xs">{{_('Browse')}}</li>
|
||||||
{% for element in sidebar %}
|
{% for element in sidebar %}
|
||||||
{% if current_user.check_visibility(element['visibility']) and element['public'] %}
|
{% if current_user.check_visibility(element['visibility']) and element['public'] %}
|
||||||
@ -157,6 +160,9 @@
|
|||||||
<li id="nav_createshelf" class="create-shelf"><a href="{{url_for('shelf.create_shelf')}}">{{_('Create a Shelf')}}</a></li>
|
<li id="nav_createshelf" class="create-shelf"><a href="{{url_for('shelf.create_shelf')}}">{{_('Create a Shelf')}}</a></li>
|
||||||
<li id="nav_about" {% if page == 'stat' %}class="active"{% endif %}><a href="{{url_for('about.stats')}}"><span class="glyphicon glyphicon-info-sign"></span> {{_('About')}}</a></li>
|
<li id="nav_about" {% if page == 'stat' %}class="active"{% endif %}><a href="{{url_for('about.stats')}}"><span class="glyphicon glyphicon-info-sign"></span> {{_('About')}}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% for element in bottom_pages %}
|
||||||
|
<li id="nav_{{element['name']}}" {% if page == element['name'] %}class="active"{% endif %}><a href="{{url_for('page.get_page', file=element['name'])}}"><span class="glyphicon glyphicon-{{element['icon']}}"></span> {{element['title']}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
52
cps/templates/list_pages.html
Normal file
52
cps/templates/list_pages.html
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block header %}
|
||||||
|
<link href="{{ url_for('static', filename='css/libs/bootstrap-table.min.css') }}" rel="stylesheet">
|
||||||
|
<link href="{{ url_for('static', filename='css/libs/bootstrap-editable.css') }}" rel="stylesheet">
|
||||||
|
<link href="{{ url_for('static', filename='css/libs/bootstrap-select.min.css') }}" rel="stylesheet" >
|
||||||
|
{% endblock %}
|
||||||
|
{% block body %}
|
||||||
|
<h2 class="{{page}}">{{_(title)}}</h2>
|
||||||
|
<table class="table table-striped" id="table_user">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{_('Name')}}</th>
|
||||||
|
<th>{{_('Title')}}</th>
|
||||||
|
<th>{{_('Icon')}}</th>
|
||||||
|
<th>{{_('Position')}}</th>
|
||||||
|
<th>{{_('Enabled')}}</th>
|
||||||
|
<th>{{_('Order')}}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for page in pages %}
|
||||||
|
<tr>
|
||||||
|
<td><a class="session" href="{{url_for('editpage.edit_page', file=page.id)}}">{{page.name}}</a></td>
|
||||||
|
<td>{{page.title}}</td>
|
||||||
|
<td>{{page.icon}}</td>
|
||||||
|
<td>{{_('bottom') if page.position == "0" else _('top')}}</td>
|
||||||
|
<td>
|
||||||
|
{% if page.is_enabled %}
|
||||||
|
<span class="glyphicon glyphicon-ok"></span>
|
||||||
|
{% else %}
|
||||||
|
<span class="glyphicon glyphicon-remove"></span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>{{page.order}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<a class="session" id="new_page" href="{{url_for('editpage.edit_page', file="new")}}">{{_('New Page')}}</a>
|
||||||
|
{% endblock %}
|
||||||
|
{% block js %}
|
||||||
|
<script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table.min.js') }}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table-locale-all.min.js') }}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table-editable.min.js') }}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-editable.min.js') }}"></script>
|
||||||
|
{% if not current_user.locale == 'en' %}
|
||||||
|
<script
|
||||||
|
src="{{ url_for('static', filename='js/libs/bootstrap-table/locale/bootstrap-table-' + current_user.locale + '.min.js') }}"
|
||||||
|
charset="UTF-8"></script>
|
||||||
|
{% endif %}
|
||||||
|
<script src="{{ url_for('static', filename='js/table.js') }}"></script>
|
||||||
|
{% endblock %}
|
4
cps/templates/page.html
Normal file
4
cps/templates/page.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block body %}
|
||||||
|
<div>{{body|safe}}</div>
|
||||||
|
{% endblock %}
|
16
cps/ub.py
16
cps/ub.py
@ -160,6 +160,9 @@ class UserBase:
|
|||||||
def role_viewer(self):
|
def role_viewer(self):
|
||||||
return self._has_role(constants.ROLE_VIEWER)
|
return self._has_role(constants.ROLE_VIEWER)
|
||||||
|
|
||||||
|
def role_send_to_ereader(self):
|
||||||
|
return self._has_role(constants.ROLE_SEND_TO_EREADER)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_active(self):
|
def is_active(self):
|
||||||
return True
|
return True
|
||||||
@ -535,6 +538,16 @@ class Thumbnail(Base):
|
|||||||
generated_at = Column(DateTime, default=lambda: datetime.datetime.utcnow())
|
generated_at = Column(DateTime, default=lambda: datetime.datetime.utcnow())
|
||||||
expiration = Column(DateTime, nullable=True)
|
expiration = Column(DateTime, nullable=True)
|
||||||
|
|
||||||
|
class Page(Base):
|
||||||
|
__tablename__ = 'page'
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
title = Column(String)
|
||||||
|
name = Column(String)
|
||||||
|
icon = Column(String)
|
||||||
|
order = Column(Integer)
|
||||||
|
position = Column(String)
|
||||||
|
is_enabled = Column(Boolean, default=True)
|
||||||
|
|
||||||
# Add missing tables during migration of database
|
# Add missing tables during migration of database
|
||||||
def add_missing_tables(engine, _session):
|
def add_missing_tables(engine, _session):
|
||||||
@ -558,7 +571,8 @@ def add_missing_tables(engine, _session):
|
|||||||
trans = conn.begin()
|
trans = conn.begin()
|
||||||
conn.execute("insert into registration (domain, allow) values('%.%',1)")
|
conn.execute("insert into registration (domain, allow) values('%.%',1)")
|
||||||
trans.commit()
|
trans.commit()
|
||||||
|
if not engine.dialect.has_table(engine.connect(), "page"):
|
||||||
|
Page.__table__.create(bind=engine)
|
||||||
|
|
||||||
# migrate all settings missing in registration table
|
# migrate all settings missing in registration table
|
||||||
def migrate_registration_table(engine, _session):
|
def migrate_registration_table(engine, _session):
|
||||||
|
@ -18,3 +18,4 @@ flask-wtf>=0.14.2,<1.3.0
|
|||||||
chardet>=3.0.0,<4.1.0
|
chardet>=3.0.0,<4.1.0
|
||||||
advocate>=1.0.0,<1.1.0
|
advocate>=1.0.0,<1.1.0
|
||||||
Flask-Limiter>=2.3.0,<3.6.0
|
Flask-Limiter>=2.3.0,<3.6.0
|
||||||
|
markdown>=3.5.1
|
||||||
|
Loading…
Reference in New Issue
Block a user