Commit 251a77c8 authored by Ozzie Isaacs's avatar Ozzie Isaacs

Merge branch 'master' into Development

Improved packaging support
parents 33a0a4c1 7b7494b8
......@@ -10,6 +10,7 @@ env/
venv/
eggs/
dist/
executable/
build/
vendor/
.eggs/
......
......@@ -48,6 +48,11 @@ try:
except ImportError:
flask_danceVersion = None
try:
from greenlet import __version__ as greenlet_Version
except ImportError:
greenlet_Version = None
from . import services
about = flask.Blueprint('about', __name__)
......@@ -77,7 +82,8 @@ _VERSIONS = OrderedDict(
python_LDAP = services.ldapVersion if bool(services.ldapVersion) else None,
Goodreads = u'installed' if bool(services.goodreads_support) else None,
jsonschema = services.SyncToken.__version__ if bool(services.SyncToken) else None,
flask_dance = flask_danceVersion
flask_dance = flask_danceVersion,
greenlet = greenlet_Version
)
_VERSIONS.update(uploader.get_versions())
......
......@@ -56,7 +56,8 @@ log = logger.create()
feature_support = {
'ldap': bool(services.ldap),
'goodreads': bool(services.goodreads_support),
'kobo': bool(services.kobo)
'kobo': bool(services.kobo),
'updater': constants.UPDATER_AVAILABLE
}
try:
......@@ -1335,8 +1336,11 @@ def download_debug():
@login_required
@admin_required
def get_update_status():
if feature_support['updater']:
log.info(u"Update status requested")
return updater_thread.get_available_updates(request.method, locale=get_locale())
else:
return ''
@admi.route("/get_updater_status", methods=['GET', 'POST'])
......@@ -1344,6 +1348,7 @@ def get_update_status():
@admin_required
def get_updater_status():
status = {}
if feature_support['updater']:
if request.method == "POST":
commit = request.form.to_dict()
if "start" in commit and commit['start'] == 'True':
......@@ -1373,6 +1378,7 @@ def get_updater_status():
except Exception:
status['status'] = 11
return json.dumps(status)
return ''
@admi.route('/import_ldap_users')
......
......@@ -23,6 +23,7 @@ from collections import namedtuple
# if installed via pip this variable is set to true
HOME_CONFIG = False
UPDATER_AVAILABLE = True
# Base dir is parent of current file, necessary if called from different folder
if sys.version_info < (3, 0):
......@@ -131,7 +132,7 @@ def selected_roles(dictionary):
BookMeta = namedtuple('BookMeta', 'file_path, extension, title, author, cover, description, tags, series, '
'series_id, languages')
STABLE_VERSION = {'version': '0.6.11 Beta'}
STABLE_VERSION = {'version': '0.6.12 Beta'}
NIGHTLY_VERSION = {}
NIGHTLY_VERSION[0] = '$Format:%H$'
......
......@@ -36,7 +36,7 @@ def get_sidebar_config(kwargs=None):
else:
content = 'conf' in kwargs
sidebar = list()
sidebar.append({"glyph": "glyphicon-book", "text": _('Recently Added'), "link": 'web.index', "id": "new",
sidebar.append({"glyph": "glyphicon-book", "text": _('Books'), "link": 'web.index', "id": "new",
"visibility": constants.SIDEBAR_RECENT, 'public': True, "page": "root",
"show_text": _('Show recent books'), "config_show":False})
sidebar.append({"glyph": "glyphicon-fire", "text": _('Hot Books'), "link": 'web.books_list', "id": "hot",
......
......@@ -22,6 +22,7 @@ import os
import errno
import signal
import socket
import subprocess
try:
from gevent.pywsgi import WSGIServer
......@@ -136,6 +137,64 @@ class WebServer(object):
return sock, _readable_listen_address(*address)
def _get_args_for_reloading(self):
"""Determine how the script was executed, and return the args needed
to execute it again in a new process.
Code from https://github.com/pyload/pyload. Author GammaC0de, voulter
"""
rv = [sys.executable]
py_script = sys.argv[0]
args = sys.argv[1:]
# Need to look at main module to determine how it was executed.
__main__ = sys.modules["__main__"]
# The value of __package__ indicates how Python was called. It may
# not exist if a setuptools script is installed as an egg. It may be
# set incorrectly for entry points created with pip on Windows.
if getattr(__main__, "__package__", None) is None or (
os.name == "nt"
and __main__.__package__ == ""
and not os.path.exists(py_script)
and os.path.exists(f"{py_script}.exe")
):
# Executed a file, like "python app.py".
py_script = os.path.abspath(py_script)
if os.name == "nt":
# Windows entry points have ".exe" extension and should be
# called directly.
if not os.path.exists(py_script) and os.path.exists(f"{py_script}.exe"):
py_script += ".exe"
if (
os.path.splitext(sys.executable)[1] == ".exe"
and os.path.splitext(py_script)[1] == ".exe"
):
rv.pop(0)
rv.append(py_script)
else:
# Executed a module, like "python -m module".
if sys.argv[0] == "-m":
args = sys.argv
else:
if os.path.isfile(py_script):
# Rewritten by Python from "-m script" to "/path/to/script.py".
py_module = __main__.__package__
name = os.path.splitext(os.path.basename(py_script))[0]
if name != "__main__":
py_module += f".{name}"
else:
# Incorrectly rewritten by pydevd debugger from "-m script" to "script".
py_module = py_script
rv.extend(("-m", py_module.lstrip(".")))
rv.extend(args)
return rv
def _start_gevent(self):
ssl_args = self.ssl_args or {}
......@@ -199,11 +258,8 @@ class WebServer(object):
return True
log.info("Performing restart of Calibre-Web")
arguments = list(sys.argv)
arguments.insert(0, sys.executable)
if os.name == 'nt':
arguments = ["\"%s\"" % a for a in arguments]
os.execv(sys.executable, arguments)
args = self._get_args_for_reloading()
subprocess.call(args, close_fds=True)
return True
def _killServer(self, __, ___):
......
......@@ -256,13 +256,11 @@ $(function() {
$("#h4").addClass("hidden");
});
function startTable(type, user_id) {
var pathname = document.getElementsByTagName("script"), src = pathname[pathname.length - 1].src;
var path = src.substring(0, src.lastIndexOf("/"));
$("#restrict-elements-table").bootstrapTable({
formatNoMatches: function () {
return "";
},
url: path + "/../../ajax/listrestriction/" + type + "/" + user_id,
url: getPath() + "/ajax/listrestriction/" + type + "/" + user_id,
rowStyle: function(row) {
// console.log('Reihe :' + row + " Index :" + index);
if (row.id.charAt(0) === "a") {
......@@ -276,13 +274,13 @@ $(function() {
$.ajax ({
type: "Post",
data: "id=" + row.id + "&type=" + row.type + "&Element=" + encodeURIComponent(row.Element),
url: path + "/../../ajax/deleterestriction/" + type + "/" + user_id,
url: getPath() + "/ajax/deleterestriction/" + type + "/" + user_id,
async: true,
timeout: 900,
success:function() {
$.ajax({
method:"get",
url: path + "/../../ajax/listrestriction/" + type + "/" + user_id,
url: getPath() + "/ajax/listrestriction/" + type + "/" + user_id,
async: true,
timeout: 900,
success:function(data) {
......@@ -298,7 +296,7 @@ $(function() {
$("#restrict-elements-table").removeClass("table-hover");
$("#restrict-elements-table").on("editable-save.bs.table", function (e, field, row) {
$.ajax({
url: path + "/../../ajax/editrestriction/" + type + "/" + user_id,
url: getPath() + "/ajax/editrestriction/" + type + "/" + user_id,
type: "Post",
data: row
});
......@@ -306,13 +304,13 @@ $(function() {
$("[id^=submit_]").click(function() {
$(this)[0].blur();
$.ajax({
url: path + "/../../ajax/addrestriction/" + type + "/" + user_id,
url: getPath() + "/ajax/addrestriction/" + type + "/" + user_id,
type: "Post",
data: $(this).closest("form").serialize() + "&" + $(this)[0].name + "=",
success: function () {
$.ajax ({
method:"get",
url: path + "/../../ajax/listrestriction/" + type + "/" + user_id,
url: getPath() + "/ajax/listrestriction/" + type + "/" + user_id,
async: true,
timeout: 900,
success:function(data) {
......
......@@ -171,9 +171,11 @@
</tbody>
</table>
{% if feature_support['updater'] %}
<div class="hidden" id="update_error"> <span>{{update_error}}</span></div>
<div class="btn btn-primary" id="check_for_update">{{_('Check for Update')}}</div>
<div class="btn btn-primary hidden" id="perform_update" data-toggle="modal" data-target="#StatusDialog">{{_('Perform Update')}}</div>
{% endif %}
</div>
</div>
</div>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -264,7 +264,7 @@ class Updater(threading.Thread):
# log_from_thread("Delete file " + item_path)
os.remove(item_path)
except OSError:
logger.debug("Could not remove: %s", item_path)
log.debug("Could not remove: %s", item_path)
shutil.rmtree(source, ignore_errors=True)
def is_venv(self):
......
This diff is collapsed.
# GDrive Integration
google-api-python-client>=1.7.11,<1.8.0
gevent>=1.2.1,<20.6.0
greenlet>=0.4.12,<0.4.17
google-api-python-client>=1.7.11,<1.13.0
gevent>20.6.0,<21.2.0
greenlet>=0.4.17,<1.1.0
httplib2>=0.9.2,<0.18.0
oauth2client>=4.0.0,<4.1.4
uritemplate>=3.0.0,<3.1.0
......@@ -17,7 +17,7 @@ goodreads>=0.3.2,<0.4.0
python-Levenshtein>=0.12.0,<0.13.0
# ldap login
python-ldap>=3.0.0,<3.3.0
python-ldap>=3.0.0,<3.4.0
Flask-SimpleLDAP>=1.4.0,<1.5.0
#oauth
......@@ -25,7 +25,7 @@ Flask-Dance>=1.4.0,<3.1.0
SQLAlchemy-Utils>=0.33.5,<0.37.0
# extracting metadata
lxml>=3.8.0,<4.6.0
lxml>=3.8.0,<4.7.0
rarfile>=2.7
# other
......
......@@ -37,20 +37,20 @@
<div class="row">
<div class="col-xs-6 col-md-6 col-sm-offset-3" style="margin-top:50px;">
<p class='text-justify attribute'><strong>Start Time: </strong>2021-01-30 17:56:37</p>
<p class='text-justify attribute'><strong>Start Time: </strong>2021-02-01 19:02:39</p>
</div>
</div>
<div class="row">
<div class="col-xs-6 col-md-6 col-sm-offset-3">
<p class='text-justify attribute'><strong>Stop Time: </strong>2021-01-30 20:23:25</p>
<p class='text-justify attribute'><strong>Stop Time: </strong>2021-02-01 21:32:03</p>
</div>
</div>
<div class="row">
<div class="col-xs-6 col-md-6 col-sm-offset-3">
<p class='text-justify attribute'><strong>Duration: </strong>1h 59 min</p>
<p class='text-justify attribute'><strong>Duration: </strong>2h 0 min</p>
</div>
</div>
</div>
......@@ -802,11 +802,11 @@
<tr id="su" class="failClass">
<tr id="su" class="skipClass">
<td>TestEditBooks</td>
<td class="text-center">33</td>
<td class="text-center">30</td>
<td class="text-center">1</td>
<td class="text-center">31</td>
<td class="text-center">0</td>
<td class="text-center">0</td>
<td class="text-center">2</td>
<td class="text-center">
......@@ -977,33 +977,11 @@
<tr id="ft10.17" class="none bg-danger">
<tr id='pt10.17' class='hiddenRow bg-success'>
<td>
<div class='testcase'>TestEditBooks - test_edit_title</div>
</td>
<td colspan='6'>
<div class="text-center">
<a class="popup_link text-center" onfocus='blur()' onclick="showTestDetail('div_ft10.17')">FAIL</a>
</div>
<!--css div popup start-->
<div id="div_ft10.17" class="popup_window test_output" style="display:none;">
<div class='close_button pull-right'>
<button type="button" class="close" aria-label="Close" onfocus='this.blur();'
onclick='document.getElementById('div_ft10.17').style.display='none'"><span
aria-hidden="true">&times;</span></button>
</div>
<div class="text-left pull-left">
<pre class="text-left">Traceback (most recent call last):
File "/home/ozzie/Development/calibre-web-test/test/test_edit_books.py", line 131, in test_edit_title
self.assertEqual(ele.text, u'Very long extra super turbo cool title without any issue of ...')
AssertionError: 'Very[33 chars]e without any issue of displaying including ö utf-8 characters' != 'Very[33 chars]e without any issue of ...'
- Very long extra super turbo cool title without any issue of displaying including ö utf-8 characters
+ Very long extra super turbo cool title without any issue of ...</pre>
</div>
<div class="clearfix"></div>
</div>
<!--css div popup end-->
</td>
<td colspan='6' align='center'>PASS</td>
</tr>
......@@ -1215,8 +1193,8 @@ AssertionError: 'Very[33 chars]e without any issue of displaying including ö ut
<tr id="su" class="failClass">
<td>TestEditBooksOnGdrive</td>
<td class="text-center">20</td>
<td class="text-center">18</td>
<td class="text-center">2</td>
<td class="text-center">19</td>
<td class="text-center">1</td>
<td class="text-center">0</td>
<td class="text-center">0</td>
<td class="text-center">
......@@ -1361,33 +1339,11 @@ AssertionError: 'Very[33 chars]e without any issue of displaying including ö ut
<tr id="ft12.16" class="none bg-danger">
<tr id='pt12.16' class='hiddenRow bg-success'>
<td>
<div class='testcase'>TestEditBooksOnGdrive - test_edit_title</div>
</td>
<td colspan='6'>
<div class="text-center">
<a class="popup_link text-center" onfocus='blur()' onclick="showTestDetail('div_ft12.16')">FAIL</a>
</div>
<!--css div popup start-->
<div id="div_ft12.16" class="popup_window test_output" style="display:none;">
<div class='close_button pull-right'>
<button type="button" class="close" aria-label="Close" onfocus='this.blur();'
onclick='document.getElementById('div_ft12.16').style.display='none'"><span
aria-hidden="true">&times;</span></button>
</div>
<div class="text-left pull-left">
<pre class="text-left">Traceback (most recent call last):
File "/home/ozzie/Development/calibre-web-test/test/test_edit_ebooks_gdrive.py", line 227, in test_edit_title
self.assertEqual(ele.text, u'Very long extra super turbo cool title without any issue of ...')
AssertionError: 'Very[33 chars]e without any issue of displaying including ö utf-8 characters' != 'Very[33 chars]e without any issue of ...'
- Very long extra super turbo cool title without any issue of displaying including ö utf-8 characters
+ Very long extra super turbo cool title without any issue of ...</pre>
</div>
<div class="clearfix"></div>
</div>
<!--css div popup end-->
</td>
<td colspan='6' align='center'>PASS</td>
</tr>
......@@ -1438,7 +1394,7 @@ AssertionError: 'Very[33 chars]e without any issue of displaying including ö ut
<pre class="text-left">Traceback (most recent call last):
File "/home/ozzie/Development/calibre-web-test/test/test_edit_ebooks_gdrive.py", line 847, in test_watch_metadata
self.assertNotIn('series', book)
AssertionError: 'series' unexpectedly found in {'reader': ['epub'], 'title': 'testbook', 'author': ['John Döe'], 'rating': 0, 'languages': ['English'], 'identifier': [], 'cover': '/cover/5?edit=f84d9deb-4c69-48d6-9f16-94ad43b3e3fa', 'tag': [], 'publisher': ['Randomhäus'], 'comment': '\n', 'add_shelf': [], 'del_shelf': [], 'edit_enable': True, 'kindle': None, 'kindlebtn': None, 'download': ['EPUB (6.7 kB)'], 'read': False, 'archived': False, 'series_all': 'Book 1.0 of test', 'series_index': '1.0', 'series': 'test', 'cust_columns': []}</pre>
AssertionError: 'series' unexpectedly found in {'reader': ['epub'], 'title': 'testbook', 'author': ['John Döe'], 'rating': 0, 'languages': ['English'], 'identifier': [], 'cover': '/cover/5?edit=175d2a21-2733-49b6-9fcf-3ef9aee1670b', 'tag': [], 'publisher': ['Randomhäus'], 'comment': '\n', 'add_shelf': [], 'del_shelf': [], 'edit_enable': True, 'kindle': None, 'kindlebtn': None, 'download': ['EPUB (6.7 kB)'], 'read': False, 'archived': False, 'series_all': 'Book 1.0 of test', 'series_index': '1.0', 'series': 'test', 'cust_columns': []}</pre>
</div>
<div class="clearfix"></div>
</div>
......@@ -3443,8 +3399,8 @@ AssertionError: 'series' unexpectedly found in {'reader': ['epub'], 'title': 'te
<tr id='total_row' class="text-center bg-grey">
<td>Total</td>
<td>299</td>
<td>289</td>
<td>3</td>
<td>291</td>
<td>1</td>
<td>0</td>
<td>7</td>
<td>&nbsp;</td>
......@@ -3528,7 +3484,7 @@ AssertionError: 'series' unexpectedly found in {'reader': ['epub'], 'title': 'te
<tr>
<th>Jinja2</th>
<td>2.11.2</td>
<td>2.11.3</td>
<td>Basic</td>
</tr>
......@@ -3540,7 +3496,7 @@ AssertionError: 'series' unexpectedly found in {'reader': ['epub'], 'title': 'te
<tr>
<th>pytz</th>
<td>2020.5</td>
<td>2021.1</td>
<td>Basic</td>
</tr>
......@@ -3804,7 +3760,7 @@ AssertionError: 'series' unexpectedly found in {'reader': ['epub'], 'title': 'te
</div>
<script>
drawCircle(289, 3, 0, 7);
drawCircle(291, 1, 0, 7);
</script>
</div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment