diff --git a/cps/__init__.py b/cps/__init__.py
index 6c241d4f..1791098f 100755
--- a/cps/__init__.py
+++ b/cps/__init__.py
@@ -134,6 +134,4 @@ def get_timezone():
from .updater import Updater
updater_thread = Updater()
-
-
-__all__ = ['app']
+updater_thread.start()
diff --git a/cps/admin.py b/cps/admin.py
index 8e4f7df2..fa5b1caf 100644
--- a/cps/admin.py
+++ b/cps/admin.py
@@ -604,8 +604,8 @@ def _configuration_update_helper():
{"active":0})
element["active"] = 0
- _config_int("config_log_level")
- _config_string("config_logfile")
+ reboot_required |= _config_int("config_log_level")
+ reboot_required |= _config_string("config_logfile")
if not logger.is_valid_logfile(config.config_logfile):
return _configuration_result('Logfile location is not valid, please enter correct path', gdriveError)
@@ -968,7 +968,7 @@ def get_updater_status():
}
status['text'] = text
updater_thread.status = 0
- updater_thread.start()
+ updater_thread.resume()
status['status'] = updater_thread.get_update_status()
elif request.method == "GET":
try:
diff --git a/cps/helper.py b/cps/helper.py
index f82564b8..6187ffa6 100644
--- a/cps/helper.py
+++ b/cps/helper.py
@@ -492,7 +492,7 @@ def get_book_cover_internal(book,
# saves book cover from url
def save_cover_from_url(url, book_path):
- img = requests.get(url)
+ img = requests.get(url, timeout=10) # ToDo: Error Handling
return save_cover(img, book_path)
diff --git a/cps/server.py b/cps/server.py
index 74c591ec..a59d7a38 100755
--- a/cps/server.py
+++ b/cps/server.py
@@ -24,7 +24,7 @@ import signal
import socket
try:
- from gevent.pywsgi import WSGIServer
+ from gevent.pyewsgi import WSGIServer
from gevent.pool import Pool
from gevent import __version__ as _version
VERSION = 'Gevent ' + _version
@@ -193,6 +193,9 @@ class WebServer(object):
self.stop()
def stop(self, restart=False):
+ from . import updater_thread
+ updater_thread.stop()
+
log.info("webserver stop (restart=%s)", restart)
self.restart = restart
if self.wsgiserver:
diff --git a/cps/static/js/logviewer.js b/cps/static/js/logviewer.js
index aa86d09e..7b93f30f 100644
--- a/cps/static/js/logviewer.js
+++ b/cps/static/js/logviewer.js
@@ -17,8 +17,7 @@
// Upon loading load the logfile for the first option (event log)
$(function() {
- if ($("#log_group input").length)
- {
+ if ($("#log_group input").length) {
var element = $("#log_group input[type='radio']:checked").val();
init(element);
}
diff --git a/cps/static/js/main.js b/cps/static/js/main.js
index 8f54ba45..bd8d04f9 100644
--- a/cps/static/js/main.js
+++ b/cps/static/js/main.js
@@ -61,6 +61,20 @@ $(function() {
$("#RestartDialog").modal("hide");
}
+ function cleanUp() {
+ clearInterval(updateTimerID);
+ $("#spinner2").hide();
+ $("#updateFinished").removeClass("hidden");
+ $("#check_for_update").removeClass("hidden");
+ $("#perform_update").addClass("hidden");
+ $("#message").alert("close");
+ $("#update_table > tbody > tr").each(function () {
+ if ($(this).attr("id") !== "current_version") {
+ $(this).closest("tr").remove();
+ }
+ });
+ }
+
function updateTimer() {
$.ajax({
dataType: "json",
@@ -69,21 +83,12 @@ $(function() {
// console.log(data.status);
$("#Updatecontent").html(updateText[data.status]);
if (data.status > 6) {
- clearInterval(updateTimerID);
- $("#spinner2").hide();
- $("#updateFinished").removeClass("hidden");
- $("#check_for_update").removeClass("hidden");
- $("#perform_update").addClass("hidden");
+ cleanUp();
}
},
error: function error() {
- // console.log('Done');
- clearInterval(updateTimerID);
- $("#spinner2").hide();
$("#Updatecontent").html(updateText[7]);
- $("#updateFinished").removeClass("hidden");
- $("#check_for_update").removeClass("hidden");
- $("#perform_update").addClass("hidden");
+ cleanUp();
},
timeout: 2000
});
@@ -141,6 +146,8 @@ $(function() {
var $this = $(this);
var buttonText = $this.html();
$this.html("...");
+ $("#Updatecontent").html("");
+ $("#updateFinished").addClass("hidden");
$("#update_error").addClass("hidden");
if ($("#message").length) {
$("#message").alert("close");
@@ -246,13 +253,13 @@ $(function() {
})
.on("hidden.bs.modal", function() {
$(this).find(".modal-body").html("...");
- $("#config_delete_kobo_token").show();
+ $("#config_delete_kobo_token").show();
});
$("#btndeletetoken").click(function() {
//get data-id attribute of the clicked element
- var pathname = document.getElementsByTagName("script"), src = pathname[pathname.length-1].src;
- var path = src.substring(0,src.lastIndexOf("/"));
+ var pathname = document.getElementsByTagName("script"), src = pathname[pathname.length - 1].src;
+ var path = src.substring(0, src.lastIndexOf("/"));
// var domainId = $(this).value("domainId");
$.ajax({
method:"get",
diff --git a/cps/static/js/table.js b/cps/static/js/table.js
index de570ed8..1478a519 100644
--- a/cps/static/js/table.js
+++ b/cps/static/js/table.js
@@ -15,7 +15,7 @@
* along with this program. If not, see .
*/
-/* exported TableActions */
+/* exported TableActions, RestrictionActions*/
$(function() {
@@ -94,46 +94,44 @@ $(function() {
$(e.currentTarget).find("#btndeletedomain").data("domainId", domainId);
});
- $('#restrictModal').on('hidden.bs.modal', function () {
+ $("#restrictModal").on("hidden.bs.modal", function () {
// Destroy table and remove hooks for buttons
$("#restrict-elements-table").unbind();
- $('#restrict-elements-table').bootstrapTable('destroy');
+ $("#restrict-elements-table").bootstrapTable("destroy");
$("[id^=submit_]").unbind();
- $('#h1').addClass('hidden');
- $('#h2').addClass('hidden');
- $('#h3').addClass('hidden');
- $('#h4').addClass('hidden');
+ $("#h1").addClass("hidden");
+ $("#h2").addClass("hidden");
+ $("#h3").addClass("hidden");
+ $("#h4").addClass("hidden");
});
- function startTable(type){
- var pathname = document.getElementsByTagName("script"), src = pathname[pathname.length-1].src;
- var path = src.substring(0,src.lastIndexOf("/"));
+ function startTable(type) {
+ 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,
rowStyle: function(row, index) {
- console.log('Reihe :' + row + ' Index :'+ index);
- if (row.id.charAt(0) == 'a') {
- return {classes: 'bg-primary'}
- }
- else {
- return {classes: 'bg-dark-danger'}
+ // console.log('Reihe :' + row + " Index :" + index);
+ if (row.id.charAt(0) === "a") {
+ return {classes: "bg-primary"};
+ } else {
+ return {classes: "bg-dark-danger"};
}
},
onClickCell: function (field, value, row, $element) {
- if(field == 3){
- console.log("element")
+ if (field == 3) {
$.ajax ({
- type: 'Post',
- data: 'id=' + row.id + '&type=' + row.type + "&Element=" + row.Element,
+ type: "Post",
+ data: "id=" + row.id + "&type=" + row.type + "&Element=" + row.Element,
url: path + "/../../ajax/deleterestriction/" + type,
async: true,
timeout: 900,
success:function(data) {
$.ajax({
method:"get",
- url: path + "/../../ajax/listrestriction/"+type,
+ url: path + "/../../ajax/listrestriction/" + type,
async: true,
timeout: 900,
success:function(data) {
@@ -146,12 +144,11 @@ $(function() {
},
striped: false
});
- $("#restrict-elements-table").removeClass('table-hover');
- $("#restrict-elements-table").on('editable-save.bs.table', function (e, field, row, old, $el) {
- console.log("Hallo");
+ $("#restrict-elements-table").removeClass("table-hover");
+ $("#restrict-elements-table").on("editable-save.bs.table", function (e, field, row, old, $el) {
$.ajax({
- url: path + "/../../ajax/editrestriction/"+type,
- type: 'Post',
+ url: path + "/../../ajax/editrestriction/" + type,
+ type: "Post",
data: row //$(this).closest("form").serialize() + "&" + $(this)[0].name + "=",
});
});
@@ -159,48 +156,43 @@ $(function() {
// event.stopPropagation();
// event.preventDefault();
$(this)[0].blur();
- console.log($(this)[0].name);
$.ajax({
- url: path + "/../../ajax/addrestriction/"+type,
- type: 'Post',
+ url: path + "/../../ajax/addrestriction/" + type,
+ type: "Post",
data: $(this).closest("form").serialize() + "&" + $(this)[0].name + "=",
success: function () {
- $.ajax ({
- method:"get",
- url: path + "/../../ajax/listrestriction/"+type,
- async: true,
- timeout: 900,
- success:function(data) {
- $("#restrict-elements-table").bootstrapTable("load", data);
- }
+ $.ajax ({
+ method:"get",
+ url: path + "/../../ajax/listrestriction/" + type,
+ async: true,
+ timeout: 900,
+ success:function(data) {
+ $("#restrict-elements-table").bootstrapTable("load", data);
+ }
});
}
});
return;
});
}
- $('#get_column_values').on('click',function()
- {
+ $("#get_column_values").on("click", function() {
startTable(1);
- $('#h2').removeClass('hidden');
+ $("#h2").removeClass("hidden");
});
- $('#get_tags').on('click',function()
- {
+ $("#get_tags").on("click", function() {
startTable(0);
- $('#h1').removeClass('hidden');
+ $("#h1").removeClass("hidden");
});
- $('#get_user_column_values').on('click',function()
- {
+ $("#get_user_column_values").on("click", function() {
startTable(3);
- $('#h4').removeClass('hidden');
+ $("#h4").removeClass("hidden");
});
- $('#get_user_tags').on('click',function()
- {
+ $("#get_user_tags").on("click", function() {
startTable(2);
$(this)[0].blur();
- $('#h3').removeClass('hidden');
+ $("#h3").removeClass("hidden");
});
});
diff --git a/cps/updater.py b/cps/updater.py
index 7af8649c..34f3ceef 100644
--- a/cps/updater.py
+++ b/cps/updater.py
@@ -53,8 +53,13 @@ class Updater(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
+ self.paused = False
+ # self.pause_cond = threading.Condition(threading.Lock())
+ self.can_run = threading.Event()
+ self.pause()
self.status = -1
self.updateIndex = None
+ # self.run()
def get_current_version_info(self):
if config.config_updatechannel == constants.UPDATE_STABLE:
@@ -66,12 +71,12 @@ class Updater(threading.Thread):
return self._stable_available_updates(request_method)
return self._nightly_available_updates(request_method,locale)
- def run(self):
+ def do_work(self):
try:
self.status = 1
log.debug(u'Download update file')
headers = {'Accept': 'application/vnd.github.v3+json'}
- r = requests.get(self._get_request_path(), stream=True, headers=headers)
+ r = requests.get(self._get_request_path(), stream=True, headers=headers, timeout=(10, 600))
r.raise_for_status()
self.status = 2
@@ -85,7 +90,8 @@ class Updater(threading.Thread):
if not os.path.isdir(foldername):
self.status = 11
log.info(u'Extracted contents of zipfile not found in temp folder')
- return
+ self.pause()
+ return False
self.status = 4
log.debug(u'Replacing files')
self.update_source(foldername, constants.BASE_DIR)
@@ -95,6 +101,7 @@ class Updater(threading.Thread):
web_server.stop(True)
self.status = 7
time.sleep(2)
+ return True
except requests.exceptions.HTTPError as ex:
log.info(u'HTTP Error %s', ex)
self.status = 8
@@ -104,9 +111,31 @@ class Updater(threading.Thread):
except requests.exceptions.Timeout:
log.info(u'Timeout while establishing connection')
self.status = 10
- except requests.exceptions.RequestException:
+ except (requests.exceptions.RequestException, zipfile.BadZipFile):
self.status = 11
log.info(u'General error')
+ self.pause()
+ return False
+
+ def run(self):
+ while True:
+ self.can_run.wait()
+ if self.status > -1:
+ if self.do_work():
+ break # stop loop and end thread for restart
+ else:
+ break
+
+ def pause(self):
+ self.can_run.clear()
+
+ #should just resume the thread
+ def resume(self):
+ self.can_run.set()
+
+ def stop(self):
+ self.status = -2
+ self.can_run.set()
def get_update_status(self):
return self.status
@@ -258,16 +287,19 @@ class Updater(threading.Thread):
parents = []
if status['message'] != '':
return json.dumps(status)
- if 'object' not in commit:
+ if 'object' not in commit or 'url' not in commit['object']:
status['message'] = _(u'Unexpected data while reading update information')
return json.dumps(status)
-
- if commit['object']['sha'] == status['current_commit_hash']:
- status.update({
- 'update': False,
- 'success': True,
- 'message': _(u'No update available. You already have the latest version installed')
- })
+ try:
+ if commit['object']['sha'] == status['current_commit_hash']:
+ status.update({
+ 'update': False,
+ 'success': True,
+ 'message': _(u'No update available. You already have the latest version installed')
+ })
+ return json.dumps(status)
+ except (TypeError, KeyError):
+ status['message'] = _(u'Unexpected data while reading update information')
return json.dumps(status)
# a new update is available
@@ -275,22 +307,25 @@ class Updater(threading.Thread):
try:
headers = {'Accept': 'application/vnd.github.v3+json'}
- r = requests.get(repository_url + '/git/commits/' + commit['object']['sha'], headers=headers)
+ r = requests.get(repository_url + '/git/commits/' + commit['object']['sha'],
+ headers=headers,
+ timeout=10)
r.raise_for_status()
update_data = r.json()
except requests.exceptions.HTTPError as e:
- status['error'] = _(u'HTTP Error') + ' ' + str(e)
+ status['message'] = _(u'HTTP Error') + ' ' + str(e)
except requests.exceptions.ConnectionError:
- status['error'] = _(u'Connection error')
+ status['message'] = _(u'Connection error')
except requests.exceptions.Timeout:
- status['error'] = _(u'Timeout while establishing connection')
- except requests.exceptions.RequestException:
- status['error'] = _(u'General error')
+ status['message'] = _(u'Timeout while establishing connection')
+ except (requests.exceptions.RequestException, ValueError):
+ status['message'] = _(u'General error')
if status['message'] != '':
return json.dumps(status)
- if 'committer' in update_data and 'message' in update_data:
+ # if 'committer' in update_data and 'message' in update_data:
+ try:
status['success'] = True
status['message'] = _(
u'A new update is available. Click on the button below to update to the latest version.')
@@ -304,14 +339,13 @@ class Updater(threading.Thread):
update_data['sha']
]
)
-
# it only makes sense to analyze the parents if we know the current commit hash
if status['current_commit_hash'] != '':
try:
parent_commit = update_data['parents'][0]
# limit the maximum search depth
remaining_parents_cnt = 10
- except IndexError:
+ except (IndexError, KeyError):
remaining_parents_cnt = None
if remaining_parents_cnt is not None:
@@ -323,7 +357,7 @@ class Updater(threading.Thread):
if parent_commit['sha'] != status['current_commit_hash']:
try:
headers = {'Accept': 'application/vnd.github.v3+json'}
- r = requests.get(parent_commit['url'], headers=headers)
+ r = requests.get(parent_commit['url'], headers=headers, timeout=10)
r.raise_for_status()
parent_data = r.json()
@@ -343,7 +377,7 @@ class Updater(threading.Thread):
# parent is our current version
break
status['history'] = parents[::-1]
- else:
+ except (IndexError, KeyError):
status['success'] = False
status['message'] = _(u'Could not fetch update information')
return json.dumps(status)
@@ -377,8 +411,9 @@ class Updater(threading.Thread):
return json.dumps(status)
i = len(commit) - 1
+ newer = False
while i >= 0:
- if 'tag_name' not in commit[i] or 'body' not in commit[i]:
+ if 'tag_name' not in commit[i] or 'body' not in commit[i] or 'zipball_url' not in commit[i]:
status['message'] = _(u'Unexpected data while reading update information')
return json.dumps(status)
major_version_update = int(commit[i]['tag_name'].split('.')[0])
@@ -392,12 +427,13 @@ class Updater(threading.Thread):
except ValueError:
current_version[2] = int(current_version[2].split(' ')[0])-1
- # Check if major versions are identical search for newest nonenqual commit and update to this one
+ # Check if major versions are identical search for newest non equal commit and update to this one
if major_version_update == current_version[0]:
if (minor_version_update == current_version[1] and
patch_version_update > current_version[2]) or \
minor_version_update > current_version[1]:
parents.append([commit[i]['tag_name'], commit[i]['body'].replace('\r\n', '
')])
+ newer=True
i -= 1
continue
if major_version_update < current_version[0]:
@@ -406,7 +442,9 @@ class Updater(threading.Thread):
if major_version_update > current_version[0]:
# found update update to last version before major update, unless current version is on last version
# before major update
- if commit[i+1]['tag_name'].split('.')[1] == current_version[1]:
+ if i == (len(commit) - 1):
+ i -= 1
+ if int(commit[i+1]['tag_name'].split('.')[1]) == current_version[1]:
parents.append([commit[i]['tag_name'],
commit[i]['body'].replace('\r\n', '
').replace('\n', '
')])
status.update({
@@ -418,16 +456,18 @@ class Updater(threading.Thread):
})
self.updateFile = commit[i]['zipball_url']
else:
+ parents.append([commit[i+1]['tag_name'],
+ commit[i+1]['body'].replace('\r\n', '
').replace('\n', '
')])
status.update({
'update': True,
'success': True,
'message': _(u'A new update is available. Click on the button below to '
- u'update to version: %(version)s', version=commit[i]['tag_name']),
+ u'update to version: %(version)s', version=commit[i+1]['tag_name']),
'history': parents
})
self.updateFile = commit[i+1]['zipball_url']
break
- if i == -1:
+ if i == -1 and newer == False:
status.update({
'update': True,
'success': True,
@@ -436,6 +476,16 @@ class Updater(threading.Thread):
'history': parents
})
self.updateFile = commit[0]['zipball_url']
+ elif i == -1 and newer == True:
+ status.update({
+ 'update': True,
+ 'success': True,
+ 'message': _(u'A new update is available. Click on the button below to '
+ u'update to version: %(version)s', version=commit[0]['tag_name']),
+ 'history': parents
+ })
+ self.updateFile = commit[0]['zipball_url']
+
return json.dumps(status)
def _get_request_path(self):
@@ -458,7 +508,7 @@ class Updater(threading.Thread):
status['current_commit_hash'] = version['version']
try:
headers = {'Accept': 'application/vnd.github.v3+json'}
- r = requests.get(repository_url, headers=headers)
+ r = requests.get(repository_url, headers=headers, timeout=10)
commit = r.json()
r.raise_for_status()
except requests.exceptions.HTTPError as e:
@@ -471,7 +521,7 @@ class Updater(threading.Thread):
status['message'] = _(u'Connection error')
except requests.exceptions.Timeout:
status['message'] = _(u'Timeout while establishing connection')
- except requests.exceptions.RequestException:
+ except (requests.exceptions.RequestException, ValueError):
status['message'] = _(u'General error')
-
+ log.debug('Updater status: %s', status['message'])
return status, commit