UI Improvements

Added additional restrictions to Calibre DB interface
This commit is contained in:
Ozzieisaacs 2020-05-03 10:55:33 +02:00
parent fcefd8031a
commit 0adcd1b3d9
10 changed files with 112 additions and 75 deletions

View File

@ -772,8 +772,7 @@ def new_user():
@admin_required @admin_required
def edit_mailsettings(): def edit_mailsettings():
content = config.get_mail_settings() content = config.get_mail_settings()
# log.debug("edit_mailsettings %r", content) return render_title_template("email_edit.html", content=content, title=_(u"Edit E-mail Server Settings"),
return render_title_template("email_edit.html", content=content, title=_(u"Edit e-mail server settings"),
page="mailset") page="mailset")

View File

@ -44,6 +44,7 @@ class _Settings(_Base):
mail_login = Column(String, default='mail@example.com') mail_login = Column(String, default='mail@example.com')
mail_password = Column(String, default='mypassword') mail_password = Column(String, default='mypassword')
mail_from = Column(String, default='automailer <mail@example.com>') mail_from = Column(String, default='automailer <mail@example.com>')
mail_size = Column(Integer, default=25)
config_calibre_dir = Column(String) config_calibre_dir = Column(String)
config_port = Column(Integer, default=constants.DEFAULT_PORT) config_port = Column(Integer, default=constants.DEFAULT_PORT)

View File

@ -22,10 +22,11 @@ import sys
import os import os
import re import re
import ast import ast
from datetime import datetime
from sqlalchemy import create_engine from sqlalchemy import create_engine
from sqlalchemy import Table, Column, ForeignKey from sqlalchemy import Table, Column, ForeignKey, CheckConstraint
from sqlalchemy import String, Integer, Boolean, TIMESTAMP, Float, DateTime from sqlalchemy import String, Integer, Boolean, TIMESTAMP, Float, DateTime, REAL
from sqlalchemy.orm import relationship, sessionmaker, scoped_session from sqlalchemy.orm import relationship, sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
@ -72,9 +73,9 @@ class Identifiers(Base):
__tablename__ = 'identifiers' __tablename__ = 'identifiers'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
type = Column(String) type = Column(String(collation='NOCASE'), nullable=False, default="isbn")
val = Column(String) val = Column(String(collation='NOCASE'), nullable=False)
book = Column(Integer, ForeignKey('books.id')) book = Column(Integer, ForeignKey('books.id'), nullable=False)
def __init__(self, val, id_type, book): def __init__(self, val, id_type, book):
self.val = val self.val = val
@ -126,8 +127,8 @@ class Comments(Base):
__tablename__ = 'comments' __tablename__ = 'comments'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
text = Column(String) text = Column(String(collation='NOCASE'), nullable=False)
book = Column(Integer, ForeignKey('books.id')) book = Column(Integer, ForeignKey('books.id'), nullable=False)
def __init__(self, text, book): def __init__(self, text, book):
self.text = text self.text = text
@ -141,7 +142,7 @@ class Tags(Base):
__tablename__ = 'tags' __tablename__ = 'tags'
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String) name = Column(String(collation='NOCASE'), unique=True, nullable=False)
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
@ -154,9 +155,9 @@ class Authors(Base):
__tablename__ = 'authors' __tablename__ = 'authors'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
name = Column(String) name = Column(String(collation='NOCASE'), unique=True, nullable=False)
sort = Column(String) sort = Column(String(collation='NOCASE'))
link = Column(String) link = Column(String, nullable=False, default="")
def __init__(self, name, sort, link): def __init__(self, name, sort, link):
self.name = name self.name = name
@ -171,8 +172,8 @@ class Series(Base):
__tablename__ = 'series' __tablename__ = 'series'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
name = Column(String) name = Column(String(collation='NOCASE'), unique=True, nullable=False)
sort = Column(String) sort = Column(String(collation='NOCASE'))
def __init__(self, name, sort): def __init__(self, name, sort):
self.name = name self.name = name
@ -186,7 +187,7 @@ class Ratings(Base):
__tablename__ = 'ratings' __tablename__ = 'ratings'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
rating = Column(Integer) rating = Column(Integer, CheckConstraint('rating>-1 AND rating<11'), unique=True)
def __init__(self, rating): def __init__(self, rating):
self.rating = rating self.rating = rating
@ -199,7 +200,7 @@ class Languages(Base):
__tablename__ = 'languages' __tablename__ = 'languages'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
lang_code = Column(String) lang_code = Column(String(collation='NOCASE'), nullable=False, unique=True)
def __init__(self, lang_code): def __init__(self, lang_code):
self.lang_code = lang_code self.lang_code = lang_code
@ -212,8 +213,8 @@ class Publishers(Base):
__tablename__ = 'publishers' __tablename__ = 'publishers'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
name = Column(String) name = Column(String(collation='NOCASE'), nullable=False, unique=True)
sort = Column(String) sort = Column(String(collation='NOCASE'))
def __init__(self, name, sort): def __init__(self, name, sort):
self.name = name self.name = name
@ -227,10 +228,10 @@ class Data(Base):
__tablename__ = 'data' __tablename__ = 'data'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
book = Column(Integer, ForeignKey('books.id')) book = Column(Integer, ForeignKey('books.id'), nullable=False)
format = Column(String) format = Column(String(collation='NOCASE'), nullable=False)
uncompressed_size = Column(Integer) uncompressed_size = Column(Integer, nullable=False)
name = Column(String) name = Column(String, nullable=False)
def __init__(self, book, book_format, uncompressed_size, name): def __init__(self, book, book_format, uncompressed_size, name):
self.book = book self.book = book
@ -247,17 +248,20 @@ class Books(Base):
DEFAULT_PUBDATE = "0101-01-01 00:00:00+00:00" DEFAULT_PUBDATE = "0101-01-01 00:00:00+00:00"
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String) title = Column(String(collation='NOCASE'), nullable=False, default='Unknown')
sort = Column(String) sort = Column(String(collation='NOCASE'))
author_sort = Column(String) author_sort = Column(String(collation='NOCASE'))
timestamp = Column(TIMESTAMP) timestamp = Column(TIMESTAMP, default=datetime.utcnow)
pubdate = Column(String) pubdate = Column(TIMESTAMP, default=datetime.utcnow)
series_index = Column(String) series_index = Column(REAL, nullable=False, default=1.0)
last_modified = Column(TIMESTAMP) last_modified = Column(TIMESTAMP, default=datetime.utcnow)
path = Column(String) path = Column(String, default="", nullable=False)
has_cover = Column(Integer) has_cover = Column(Integer, default=0)
uuid = Column(String) uuid = Column(String)
isbn = Column(String(collation='NOCASE'), default="")
# Iccn = Column(String(collation='NOCASE'), default="")
flags = Column(Integer, nullable=False, default=1)
authors = relationship('Authors', secondary=books_authors_link, backref='books') authors = relationship('Authors', secondary=books_authors_link, backref='books')
tags = relationship('Tags', secondary=books_tags_link, backref='books',order_by="Tags.name") tags = relationship('Tags', secondary=books_tags_link, backref='books',order_by="Tags.name")

View File

@ -30,6 +30,7 @@ from uuid import uuid4
from flask import Blueprint, request, flash, redirect, url_for, abort, Markup, Response from flask import Blueprint, request, flash, redirect, url_for, abort, Markup, Response
from flask_babel import gettext as _ from flask_babel import gettext as _
from flask_login import current_user, login_required from flask_login import current_user, login_required
from sqlalchemy import func
from . import constants, logger, isoLanguages, gdriveutils, uploader, helper from . import constants, logger, isoLanguages, gdriveutils, uploader, helper
from . import config, get_locale, db, ub, worker from . import config, get_locale, db, ub, worker
@ -680,10 +681,6 @@ def upload():
tags = meta.tags tags = meta.tags
series = meta.series series = meta.series
series_index = meta.series_id series_index = meta.series_id
title_dir = helper.get_valid_filename(title)
author_dir = helper.get_valid_filename(authr)
filepath = os.path.join(config.config_calibre_dir, author_dir, title_dir)
saved_filename = os.path.join(filepath, title_dir + meta.extension.lower())
if title != _(u'Unknown') and authr != _(u'Unknown'): if title != _(u'Unknown') and authr != _(u'Unknown'):
entry = helper.check_exists_book(authr, title) entry = helper.check_exists_book(authr, title)
@ -692,6 +689,11 @@ def upload():
flash(_(u"Uploaded book probably exists in the library, consider to change before upload new: ") flash(_(u"Uploaded book probably exists in the library, consider to change before upload new: ")
+ Markup(render_title_template('book_exists_flash.html', entry=entry)), category="warning") + Markup(render_title_template('book_exists_flash.html', entry=entry)), category="warning")
title_dir = helper.get_valid_filename(title)
author_dir = helper.get_valid_filename(authr)
filepath = os.path.join(config.config_calibre_dir, author_dir, title_dir)
saved_filename = os.path.join(filepath, title_dir + meta.extension.lower())
# check if file path exists, otherwise create it, copy file to calibre path and delete temp file # check if file path exists, otherwise create it, copy file to calibre path and delete temp file
if not os.path.exists(filepath): if not os.path.exists(filepath):
try: try:
@ -721,7 +723,7 @@ def upload():
has_cover = 1 has_cover = 1
# handle authors # handle authors
is_author = db.session.query(db.Authors).filter(db.Authors.name == authr).first() is_author = db.session.query(db.Authors).filter(db.Authors.name == func.binary(authr)).first()
if is_author: if is_author:
db_author = is_author db_author = is_author
else: else:

View File

@ -13,11 +13,14 @@
<th>{{_('E-mail Address')}}</th> <th>{{_('E-mail Address')}}</th>
<th>{{_('Send to Kindle E-mail Address')}}</th> <th>{{_('Send to Kindle E-mail Address')}}</th>
<th>{{_('Downloads')}}</th> <th>{{_('Downloads')}}</th>
<th class="hidden-xs">{{_('Admin')}}</th> <th class="hidden-xs ">{{_('Admin')}}</th>
<th class="hidden-xs">{{_('Download')}}</th> <th class="hidden-xs hidden-sm">{{_('Password')}}</th>
<th class="hidden-xs">{{_('View Books')}}</th> <th class="hidden-xs hidden-sm">{{_('Upload')}}</th>
<th class="hidden-xs">{{_('Upload')}}</th> <th class="hidden-xs hidden-sm">{{_('Download')}}</th>
<th class="hidden-xs">{{_('Edit')}}</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">{{_('Delete')}}</th>
<th class="hidden-xs hidden-sm hidden-md">{{_('Public Shelf')}}</th>
</tr> </tr>
{% for user in allUser %} {% for user in allUser %}
{% if not user.role_anonymous() or config.config_anonbrowse %} {% if not user.role_anonymous() or config.config_anonbrowse %}
@ -27,10 +30,13 @@
<td>{{user.kindle_mail}}</td> <td>{{user.kindle_mail}}</td>
<td>{{user.downloads.count()}}</td> <td>{{user.downloads.count()}}</td>
<td class="hidden-xs">{{ display_bool_setting(user.role_admin()) }}</td> <td class="hidden-xs">{{ display_bool_setting(user.role_admin()) }}</td>
<td class="hidden-xs">{{ display_bool_setting(user.role_download()) }}</td> <td class="hidden-xs hidden-sm">{{ display_bool_setting(user.role_passwd()) }}</td>
<td class="hidden-xs">{{ display_bool_setting(user.role_viewer()) }}</td> <td class="hidden-xs hidden-sm">{{ display_bool_setting(user.role_upload()) }}</td>
<td class="hidden-xs">{{ display_bool_setting(user.role_upload()) }}</td> <td class="hidden-xs hidden-sm">{{ display_bool_setting(user.role_download()) }}</td>
<td class="hidden-xs">{{ display_bool_setting(user.role_edit()) }}</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_delete_books()) }}</td>
<td class="hidden-xs hidden-sm hidden-md">{{ display_bool_setting(user.role_edit_shelfs()) }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% endfor %} {% endfor %}

View File

@ -3,7 +3,7 @@
<div class="discover"> <div class="discover">
<h2>{{title}}</h2> <h2>{{title}}</h2>
<form role="form" method="POST" autocomplete="off"> <form role="form" method="POST" autocomplete="off">
<div class="panel-group"> <div class="panel-group col-md-10 col-lg-6">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h4 class="panel-title"> <h4 class="panel-title">
@ -15,10 +15,13 @@
</div> </div>
<div id="collapseOne" class="panel-collapse collapse in"> <div id="collapseOne" class="panel-collapse collapse in">
<div class="panel-body"> <div class="panel-body">
<div class="form-group required"> <div class="form-group required input-group">
<label for="config_calibre_dir">{{_('Location of Calibre Database')}}</label> <label for="config_calibre_dir" class="sr-only">{{_('Location of Calibre Database')}}</label>
<input type="text" class="form-control" name="config_calibre_dir" id="config_calibre_dir" value="{% if config.config_calibre_dir != None %}{{ config.config_calibre_dir }}{% endif %}" autocomplete="off"> <input type="text" class="form-control" id="config_calibre_dir" name="config_calibre_dir" value="{% if config.config_calibre_dir != None %}{{ config.config_calibre_dir }}{% endif %}" autocomplete="off">
</div> <span class="input-group-btn">
<button type="button" id="library_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
</span>
</div>
{% if feature_support['gdrive'] %} {% if feature_support['gdrive'] %}
<div class="form-group required"> <div class="form-group required">
<input type="checkbox" id="config_use_google_drive" name="config_use_google_drive" data-control="gdrive_settings" {% if config.config_use_google_drive %}checked{% endif %} > <input type="checkbox" id="config_use_google_drive" name="config_use_google_drive" data-control="gdrive_settings" {% if config.config_use_google_drive %}checked{% endif %} >
@ -87,21 +90,25 @@
<label for="config_port">{{_('Server Port')}}</label> <label for="config_port">{{_('Server Port')}}</label>
<input type="number" min="1" max="65535" class="form-control" name="config_port" id="config_port" value="{% if config.config_port != None %}{{ config.config_port }}{% endif %}" autocomplete="off" required> <input type="number" min="1" max="65535" class="form-control" name="config_port" id="config_port" value="{% if config.config_port != None %}{{ config.config_port }}{% endif %}" autocomplete="off" required>
</div> </div>
<div class="form-group"> <div class="form-group input-group">
<label for="config_certfile">{{_('SSL certfile location (leave it empty for non-SSL Servers)')}}</label> <label for="config_certfile" class="sr-only">{{_('SSL certfile location (leave it empty for non-SSL Servers)')}}</label>
<input type="text" class="form-control" name="config_certfile" id="config_certfile" value="{% if config.config_certfile != None %}{{ config.config_certfile }}{% endif %}" autocomplete="off"> <input type="text" class="form-control" id="config_certfile" name="config_certfile" value="{% if config.config_certfile != None %}{{ config.config_certfile }}{% endif %}" autocomplete="off">
<span class="input-group-btn">
<button type="button" id="certfile_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
</span>
</div> </div>
<div class="form-group"> <div class="form-group input-group">
<label for="config_keyfile">{{_('SSL Keyfile location (leave it empty for non-SSL Servers)')}}</label> <label for="config_calibre_dir" class="sr-only">{{_('SSL Keyfile location (leave it empty for non-SSL Servers)')}}</label>
<input type="text" class="form-control" name="config_keyfile" id="config_keyfile" value="{% if config.config_keyfile != None %}{{ config.config_keyfile }}{% endif %}" autocomplete="off"> <input type="text" class="form-control" id="config_keyfile" name="config_keyfile" value="{% if config.config_keyfile != None %}{{ config.config_keyfile }}{% endif %}" autocomplete="off">
<span class="input-group-btn">
<button type="button" id="keyfile_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
</span>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="config_updatechannel">{{_('Update Channel')}}</label> <label for="config_updatechannel">{{_('Update Channel')}}</label>
<select name="config_updatechannel" id="config_updatechannel" class="form-control"> <select name="config_updatechannel" id="config_updatechannel" class="form-control">
<option value="0" {% if config.config_updatechannel == 0 %}selected{% endif %}>{{_('Stable')}}</option> <option value="0" {% if config.config_updatechannel == 0 %}selected{% endif %}>{{_('Stable')}}</option>
<!--option value="1" {% if config.config_updatechannel == 1 %}selected{% endif %}>{{_('Stable (Automatic)')}}</option--> <option value="2" {% if config.config_updatechannel == 2 %}selected{% endif %}>{{_('Nightly')}}</option>
<option value="2" {% if config.config_updatechannel == 2 %}selected{% endif %}>{{_('Nightly')}}</option>
<!--option-- value="3" {% if config.config_updatechannel == 3 %}selected{% endif %}>{{_('Nightly (Automatic)')}}</option-->
</select> </select>
</div> </div>
</div> </div>
@ -342,18 +349,27 @@
<label for="config_calibre">{{_('Calibre E-Book Converter Settings')}}</label> <label for="config_calibre">{{_('Calibre E-Book Converter Settings')}}</label>
<input type="text" class="form-control" id="config_calibre" name="config_calibre" value="{% if config.config_calibre != None %}{{ config.config_calibre }}{% endif %}" autocomplete="off"> <input type="text" class="form-control" id="config_calibre" name="config_calibre" value="{% if config.config_calibre != None %}{{ config.config_calibre }}{% endif %}" autocomplete="off">
</div> </div>
<div class="form-group"> <div class="form-group input-group">
<label for="config_converterpath">{{_('Path to Calibre E-Book Converter')}}</label> <label for="config_converterpath" class="sr-only">{{_('Path to Calibre E-Book Converter')}}</label>
<input type="text" class="form-control" id="config_converterpath" name="config_converterpath" value="{% if config.config_converterpath != None %}{{ config.config_converterpath }}{% endif %}" autocomplete="off"> <input type="text" class="form-control" id="config_converterpath" name="config_converterpath" value="{% if config.config_converterpath != None %}{{ config.config_converterpath }}{% endif %}" autocomplete="off">
<span class="input-group-btn">
<button type="button" id="converter_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
</span>
</div> </div>
<div class="form-group"> <div class="form-group input-group">
<label for="config_calibre">{{_('Path to Kepubify E-Book Converter')}}</label> <label for="config_kepubifypath" class="sr-only">{{_('Path to Kepubify E-Book Converter')}}</label>
<input type="text" class="form-control" id="config_kepubifypath" name="config_converterpath" value="{% if config.config_kepubifypath != None %}{{ config.config_kepubifypath }}{% endif %}" autocomplete="off"> <input type="text" class="form-control" id="config_kepubifypath" name="config_kepubifypath" value="{% if config.config_kepubifypath != None %}{{ config.config_kepubifypath }}{% endif %}" autocomplete="off">
<span class="input-group-btn">
<button type="button" id="kepubify_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
</span>
</div> </div>
{% if feature_support['rar'] %} {% if feature_support['rar'] %}
<div class="form-group"> <div class="form-group input-group">
<label for="config_rarfile_location">{{_('Location of Unrar binary')}}</label> <label for="config_rarfile_location" class="sr-only">{{_('Location of Unrar binary')}}</label>
<input type="text" class="form-control" name="config_rarfile_location" id="config_rarfile_location" value="{% if config.config_rarfile_location != None %}{{ config.config_rarfile_location }}{% endif %}" autocomplete="off"> <input type="text" class="form-control" id="config_rarfile_location" name="config_rarfile_location" value="{% if config.config_rarfile_location != None %}{{ config.config_rarfile_location }}{% endif %}" autocomplete="off">
<span class="input-group-btn">
<button type="button" id="unrar_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
</span>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -7,7 +7,7 @@
<div class="discover"> <div class="discover">
<h2>{{title}}</h2> <h2>{{title}}</h2>
<form role="form" method="POST" autocomplete="off"> <form role="form" method="POST" autocomplete="off">
<div class="panel-group"> <div class="panel-group col-md-10 col-lg-6">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h4 class="panel-title"> <h4 class="panel-title">

View File

@ -6,14 +6,14 @@
{% block body %} {% block body %}
<div class="discover"> <div class="discover">
<h1>{{title}}</h1> <h1>{{title}}</h1>
<form role="form" method="POST"> <form role="form" class="col-md-10 col-lg-6" method="POST">
<div class="form-group"> <div class="form-group">
<label for="mail_server">{{_('SMTP Hostname')}}</label> <label for="mail_server">{{_('SMTP Hostname')}}</label>
<input type="text" class="form-control" name="mail_server" id="mail_server" value="{{content.mail_server}}"> <input type="text" class="form-control" name="mail_server" id="mail_server" value="{{content.mail_server}}">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="mail_port">{{_('SMTP Port')}}</label> <label for="mail_port">{{_('SMTP Port')}}</label>
<input type="text" class="form-control" name="mail_port" id="mail_port" value="{{content.mail_port}}"> <input type="number" min="1" max="65535" class="form-control" name="mail_port" id="mail_port" value="{% if config.mail_port != None %}{{ config.mail_port }}{% endif %}" autocomplete="off">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="mail_use_ssl">{{_('Encryption')}}</label> <label for="mail_use_ssl">{{_('Encryption')}}</label>
@ -34,6 +34,13 @@
<div class="form-group"> <div class="form-group">
<label for="mail_from">{{_('From E-mail')}}</label> <label for="mail_from">{{_('From E-mail')}}</label>
<input type="text" class="form-control" name="mail_from" id="mail_from" value="{{content.mail_from}}"> <input type="text" class="form-control" name="mail_from" id="mail_from" value="{{content.mail_from}}">
</div>
<div class="form-group input-group">
<label for="mail_size" class="sr-only">{{_('Attachment Size Limit')}}</label>
<input type="number" min="1" max="600" class="form-control" name="attachment_size" id="mail_size" value="{% if config.mail_size != None %}{{ config.mail_size }}{% endif %}">
<span class="input-group-btn">
<button type="button" id="certfile_path" class="btn btn-default" disabled>MB</button>
</span>
</div> </div>
<button type="submit" name="submit" value="submit" class="btn btn-default">{{_('Save')}}</button> <button type="submit" name="submit" value="submit" class="btn btn-default">{{_('Save')}}</button>
<button type="submit" name="test" value="test" class="btn btn-default">{{_('Save and Send Test E-mail')}}</button> <button type="submit" name="test" value="test" class="btn btn-default">{{_('Save and Send Test E-mail')}}</button>

View File

@ -1,6 +1,6 @@
{% extends "layout.html" %} {% extends "layout.html" %}
{% block body %} {% block body %}
<div class="col-sm-8"> <div class="col-md-10 col-lg-6">
<form role="form" id="search" action="{{ url_for('web.advanced_search') }}" method="GET"> <form role="form" id="search" action="{{ url_for('web.advanced_search') }}" method="GET">
<div class="form-group"> <div class="form-group">
<label for="book_title">{{_('Book Title')}}</label> <label for="book_title">{{_('Book Title')}}</label>

View File

@ -3,6 +3,7 @@
<div class="discover"> <div class="discover">
<h1>{{title}}</h1> <h1>{{title}}</h1>
<form role="form" method="POST" autocomplete="off"> <form role="form" method="POST" autocomplete="off">
<div class="col-md-10 col-lg-8">
{% if new_user or ( g.user and content.nickname != "Guest" and g.user.role_admin() ) %} {% if new_user or ( g.user and content.nickname != "Guest" and g.user.role_admin() ) %}
<div class="form-group required"> <div class="form-group required">
<label for="nickname">{{_('Username')}}</label> <label for="nickname">{{_('Username')}}</label>
@ -65,6 +66,7 @@
<div class="btn btn-danger" id="config_delete_kobo_token" data-toggle="modal" data-target="#modalDeleteToken" data-remote="false" {% if not content.remote_auth_token.first() %} style="display: none;" {% endif %}>{{_('Delete')}}</div> <div class="btn btn-danger" id="config_delete_kobo_token" data-toggle="modal" data-target="#modalDeleteToken" data-remote="false" {% if not content.remote_auth_token.first() %} style="display: none;" {% endif %}>{{_('Delete')}}</div>
</div> </div>
{% endif %} {% endif %}
</div>
<div class="col-sm-6"> <div class="col-sm-6">
{% for element in sidebar %} {% for element in sidebar %}
{% if element['config_show'] %} {% if element['config_show'] %}