From b4122e985882c19517cf1e4d4d665615e72464c8 Mon Sep 17 00:00:00 2001 From: bodybybuddha Date: Wed, 19 Sep 2018 11:26:52 -0400 Subject: [PATCH 1/2] Partial fix to #617. Local status messages now work. --- cps/helper.py | 21 +++++++++++++++++++++ cps/web.py | 13 +++++++++++-- cps/worker.py | 12 ++++++------ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/cps/helper.py b/cps/helper.py index 722a6245..ca404384 100755 --- a/cps/helper.py +++ b/cps/helper.py @@ -567,3 +567,24 @@ def get_current_version_info(): if is_sha1(content[0]) and len(content[1]) > 0: return {'hash': content[0], 'datetime': content[1]} return False + +def render_task_status(tasklist): + #helper function to apply localize status information in tasklist entries + renderedtasklist=list() + + for task in tasklist: + if isinstance( task['status'], int ): + if task['status'] == worker.STAT_WAITING: + task['status'] = _('Waiting') + elif task['status'] == worker.STAT_FAIL: + task['status'] = _('Failed') + elif task['status'] == worker.STAT_STARTED: + task['status'] = _('Started') + elif task['status'] == worker.STAT_FINISH_SUCCESS: + task['status'] = _('Finished') + else: + task['status'] = _('Unknown Status') + renderedtasklist.append(task) + + return renderedtasklist + \ No newline at end of file diff --git a/cps/web.py b/cps/web.py index 2de1bbd3..559f8d4a 100644 --- a/cps/web.py +++ b/cps/web.py @@ -85,6 +85,7 @@ import hashlib from redirect import redirect_back import time import server +import copy try: import cPickle except ImportError: @@ -873,6 +874,7 @@ def get_metadata_calibre_companion(uuid): @login_required def get_email_status_json(): answer=list() + UIanswer = list() tasks=helper.global_WorkerThread.get_taskstatus() if not current_user.role_admin(): for task in tasks: @@ -893,7 +895,11 @@ def get_email_status_json(): if 'starttime' not in task: task['starttime'] = "" answer = tasks - js=json.dumps(answer) + + UIanswer = copy.deepcopy(answer) + UIanswer = helper.render_task_status(UIanswer) + + js=json.dumps(UIanswer) response = make_response(js) response.headers["Content-Type"] = "application/json; charset=utf-8" return response @@ -1626,6 +1632,7 @@ def bookmark(book_id, book_format): def get_tasks_status(): # if current user admin, show all email, otherwise only own emails answer=list() + UIanswer=list() tasks=helper.global_WorkerThread.get_taskstatus() if not current_user.role_admin(): for task in tasks: @@ -1647,8 +1654,10 @@ def get_tasks_status(): task['starttime'] = "" answer = tasks + UIanswer = copy.deepcopy(answer) + UIanswer = helper.render_task_status(UIanswer) # foreach row format row - return render_title_template('tasks.html', entries=answer, title=_(u"Tasks")) + return render_title_template('tasks.html', entries=UIanswer, title=_(u"Tasks")) @app.route("/admin") diff --git a/cps/worker.py b/cps/worker.py index 0eca51c1..5fff893e 100644 --- a/cps/worker.py +++ b/cps/worker.py @@ -212,7 +212,7 @@ class WorkerThread(threading.Thread): def convert_any_format(self): # convert book, and upload in case of google drive self.queue[self.current]['status'] = STAT_STARTED - self.UIqueue[self.current]['status'] = _('Started') + self.UIqueue[self.current]['status'] = STAT_STARTED self.queue[self.current]['starttime'] = datetime.now() self.UIqueue[self.current]['formStarttime'] = self.queue[self.current]['starttime'] curr_task = self.queue[self.current]['typ'] @@ -352,7 +352,7 @@ class WorkerThread(threading.Thread): self.queue.append({'file_path':file_path, 'bookid':bookid, 'starttime': 0, 'kindle': kindle_mail, 'status': STAT_WAITING, 'typ': task, 'settings':settings}) self.UIqueue.append({'user': user_name, 'formStarttime': '', 'progress': " 0 %", 'type': typ, - 'runtime': '0 s', 'status': _('Waiting'),'id': self.id } ) + 'runtime': '0 s', 'status': STAT_WAITING,'id': self.id } ) self.last=len(self.queue) addLock.release() @@ -371,7 +371,7 @@ class WorkerThread(threading.Thread): 'settings':settings, 'recipent':recipient, 'starttime': 0, 'status': STAT_WAITING, 'typ': TASK_EMAIL, 'text':text}) self.UIqueue.append({'user': user_name, 'formStarttime': '', 'progress': " 0 %", 'type': typ, - 'runtime': '0 s', 'status': _('Waiting'),'id': self.id }) + 'runtime': '0 s', 'status': STAT_WAITING,'id': self.id }) self.last=len(self.queue) addLock.release() @@ -395,7 +395,7 @@ class WorkerThread(threading.Thread): self.queue[self.current]['starttime'] = datetime.now() self.UIqueue[self.current]['formStarttime'] = self.queue[self.current]['starttime'] self.queue[self.current]['status'] = STAT_STARTED - self.UIqueue[self.current]['status'] = _('Started') + self.UIqueue[self.current]['status'] = STAT_STARTED obj=self.queue[self.current] # create MIME message msg = MIMEMultipart() @@ -473,7 +473,7 @@ class WorkerThread(threading.Thread): def _handleError(self, error_message): web.app.logger.error(error_message) self.queue[self.current]['status'] = STAT_FAIL - self.UIqueue[self.current]['status'] = _('Failed') + self.UIqueue[self.current]['status'] = STAT_FAIL self.UIqueue[self.current]['progress'] = "100 %" self.UIqueue[self.current]['runtime'] = self._formatRuntime( datetime.now() - self.queue[self.current]['starttime']) @@ -481,7 +481,7 @@ class WorkerThread(threading.Thread): def _handleSuccess(self): self.queue[self.current]['status'] = STAT_FINISH_SUCCESS - self.UIqueue[self.current]['status'] = _('Finished') + self.UIqueue[self.current]['status'] = STAT_FINISH_SUCCESS self.UIqueue[self.current]['progress'] = "100 %" self.UIqueue[self.current]['runtime'] = self._formatRuntime( datetime.now() - self.queue[self.current]['starttime']) From ee686b5379e00402b9d538404d1da2c6e5cf58b1 Mon Sep 17 00:00:00 2001 From: bodybybuddha Date: Wed, 3 Oct 2018 15:58:37 -0400 Subject: [PATCH 2/2] Fix for #617 Task table: Status column and task messages have been localized Cleaned up the use of the task fields 'typ' and 'type' to be taskType and taskMessage --- cps/helper.py | 25 ++++++++++++++++---- cps/templates/tasks.html | 2 +- cps/web.py | 32 +++++++++++++------------- cps/worker.py | 49 ++++++++++++++++++++-------------------- 4 files changed, 62 insertions(+), 46 deletions(-) diff --git a/cps/helper.py b/cps/helper.py index bf1bcbef..0e214a06 100755 --- a/cps/helper.py +++ b/cps/helper.py @@ -73,10 +73,10 @@ def convert_book_format(book_id, calibrepath, old_book_format, new_book_format, # read settings and append converter task to queue if kindle_mail: settings = ub.get_mail_settings() - text = _(u"Convert: %(book)s" , book=book.title) + text = _(u"%(format)s: %(book)s", format=new_book_format, book=book.title) else: settings = dict() - text = _(u"Convert to %(format)s: %(book)s", format=new_book_format, book=book.title) + text = _(u"%(format)s: %(book)s", format=new_book_format, book=book.title) settings['old_book_format'] = old_book_format settings['new_book_format'] = new_book_format global_WorkerThread.add_convert(file_path, book.id, user_id, text, settings, kindle_mail) @@ -523,7 +523,7 @@ class Updater(threading.Thread): logging.getLogger('cps.web').debug("Could not remove:" + item_path) shutil.rmtree(source, ignore_errors=True) - + def check_unrar(unrarLocation): error = False if os.path.exists(unrarLocation): @@ -568,11 +568,13 @@ def get_current_version_info(): return {'hash': content[0], 'datetime': content[1]} return False + def render_task_status(tasklist): #helper function to apply localize status information in tasklist entries renderedtasklist=list() for task in tasklist: + # localize the task status if isinstance( task['status'], int ): if task['status'] == worker.STAT_WAITING: task['status'] = _('Waiting') @@ -583,8 +585,21 @@ def render_task_status(tasklist): elif task['status'] == worker.STAT_FINISH_SUCCESS: task['status'] = _('Finished') else: - task['status'] = _('Unknown Status') + task['status'] = _('Unknown Status') + + # localize the task type + if isinstance( task['taskType'], int ): + if task['taskType'] == worker.TASK_EMAIL: + task['taskMessage'] = _('EMAIL: ') + task['taskMessage'] + elif task['taskType'] == worker.TASK_CONVERT: + task['taskMessage'] = _('CONVERT: ') + task['taskMessage'] + elif task['taskType'] == worker.TASK_UPLOAD: + task['taskMessage'] = _('UPLOAD: ') + task['taskMessage'] + elif task['taskType'] == worker.TASK_CONVERT_ANY: + task['taskMessage'] = _('CONVERT: ') + task['taskMessage'] + else: + task['taskMessage'] = _('Unknown Task: ') + task['taskMessage'] + renderedtasklist.append(task) return renderedtasklist - \ No newline at end of file diff --git a/cps/templates/tasks.html b/cps/templates/tasks.html index d4f72829..4cf13c95 100644 --- a/cps/templates/tasks.html +++ b/cps/templates/tasks.html @@ -11,7 +11,7 @@ {% if g.user.role_admin() %} {{_('User')}} {% endif %} - {{_('Task')}} + {{_('Task')}} {{_('Status')}} {{_('Progress')}} {{_('Runtime')}} diff --git a/cps/web.py b/cps/web.py index 421bb44b..37439bd9 100644 --- a/cps/web.py +++ b/cps/web.py @@ -894,10 +894,10 @@ def get_email_status_json(): if 'starttime' not in task: task['starttime'] = "" answer = tasks - + UIanswer = copy.deepcopy(answer) UIanswer = helper.render_task_status(UIanswer) - + js=json.dumps(UIanswer) response = make_response(js) response.headers["Content-Type"] = "application/json; charset=utf-8" @@ -905,7 +905,7 @@ def get_email_status_json(): # checks if domain is in database (including wildcards) -# example SELECT * FROM @TABLE WHERE 'abcdefg' LIKE Name; +# example SELECT * FROM @TABLE WHERE 'abcdefg' LIKE Name; # from https://code.luasoftware.com/tutorials/flask/execute-raw-sql-in-flask-sqlalchemy/ def check_valid_domain(domain_text): # result = session.query(Notification).from_statement(text(sql)).params(id=5).all() @@ -926,7 +926,7 @@ def check_valid_domain(domain_text): def edit_domain(): vals = request.form.to_dict() answer = ub.session.query(ub.Registration).filter(ub.Registration.id == vals['pk']).first() - # domain_name = request.args.get('domain') + # domain_name = request.args.get('domain') answer.domain = vals['value'].replace('*','%').replace('?','_').lower() ub.session.commit() return "" @@ -2265,7 +2265,7 @@ def register(): content.nickname = to_save["nickname"] content.email = to_save["email"] password = helper.generate_random_password() - content.password = generate_password_hash(password) + content.password = generate_password_hash(password) content.role = config.config_default_role content.sidebar_view = config.config_default_show try: @@ -2528,9 +2528,9 @@ def search_to_shelf(shelf_id): flash(_(u"Books have been added to shelf: %(sname)s", sname=shelf.name), category="success") else: flash(_(u"Could not add books to shelf: %(sname)s", sname=shelf.name), category="error") - return redirect(url_for('index')) + return redirect(url_for('index')) + - @app.route("/shelf/remove//") @login_required def remove_from_shelf(shelf_id, book_id): @@ -2741,7 +2741,7 @@ def profile(): if config.config_public_reg and not check_valid_domain(to_save["email"]): flash(_(u"E-mail is not from valid domain"), category="error") return render_title_template("user_edit.html", content=content, downloads=downloads, - title=_(u"%(name)s's profile", name=current_user.nickname)) + title=_(u"%(name)s's profile", name=current_user.nickname)) content.email = to_save["email"] if "show_random" in to_save and to_save["show_random"] == "on": content.random_books = 1 @@ -3721,7 +3721,7 @@ def upload(): # create the function for sorting... db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort) db.session.connection().connection.connection.create_function('uuid4', 0, lambda: str(uuid4())) - + # check if file extension is correct if '.' in requested_file.filename: file_ext = requested_file.filename.rsplit('.', 1)[-1].lower() @@ -3733,7 +3733,7 @@ def upload(): else: flash(_('File to be uploaded must have an extension'), category="error") return redirect(url_for('index')) - + # extract metadata from file meta = uploader.upload(requested_file) title = meta.title @@ -3777,7 +3777,7 @@ def upload(): else: db_author = db.Authors(authr, helper.get_sorted_author(authr), "") db.session.add(db_author) - + # handle series db_series = None is_series = db.session.query(db.Series).filter(db.Series.name == series).first() @@ -3798,7 +3798,7 @@ def upload(): else: db_language = db.Languages(input_language) db.session.add(db_language) - + # combine path and normalize path from windows systems path = os.path.join(author_dir, title_dir).replace('\\', '/') db_book = db.Books(title, "", db_author.sort, datetime.datetime.now(), datetime.datetime(101, 1, 1), @@ -3810,13 +3810,13 @@ def upload(): db_book.languages.append(db_language) file_size = os.path.getsize(saved_filename) db_data = db.Data(db_book, meta.extension.upper()[1:], file_size, title_dir) - + # handle tags input_tags = tags.split(',') input_tags = list(map(lambda it: it.strip(), input_tags)) if input_tags[0] !="": modify_database_object(input_tags, db_book.tags, db.Tags, db.session, 'tags') - + # flush content, get db_book.id available db_book.data.append(db_data) db.session.add(db_book) @@ -3827,7 +3827,7 @@ def upload(): upload_comment = Markup(meta.description).unescape() if upload_comment != "": db.session.add(db.Comments(upload_comment, book_id)) - + # save data to database, reread data db.session.commit() db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort) @@ -3844,7 +3844,7 @@ def upload(): if error: flash(error, category="error") uploadText=_(u"File %(file)s uploaded", file=book.title) - helper.global_WorkerThread.add_upload(current_user.nickname, + helper.global_WorkerThread.add_upload(current_user.nickname, "" + uploadText + "") # create data for displaying display Full language name instead of iso639.part3language diff --git a/cps/worker.py b/cps/worker.py index c01d584e..de891916 100644 --- a/cps/worker.py +++ b/cps/worker.py @@ -33,12 +33,12 @@ from email.utils import formatdate from email.utils import make_msgid chunksize = 8192 - +# task 'status' consts STAT_WAITING = 0 STAT_FAIL = 1 STAT_STARTED = 2 STAT_FINISH_SUCCESS = 3 - +#taskType consts TASK_EMAIL = 1 TASK_CONVERT = 2 TASK_UPLOAD = 3 @@ -169,11 +169,11 @@ class WorkerThread(threading.Thread): doLock.acquire() if self.current != self.last: doLock.release() - if self.queue[self.current]['typ'] == TASK_EMAIL: + if self.queue[self.current]['taskType'] == TASK_EMAIL: self.send_raw_email() - if self.queue[self.current]['typ'] == TASK_CONVERT: + if self.queue[self.current]['taskType'] == TASK_CONVERT: self.convert_any_format() - if self.queue[self.current]['typ'] == TASK_CONVERT_ANY: + if self.queue[self.current]['taskType'] == TASK_CONVERT_ANY: self.convert_any_format() # TASK_UPLOAD is handled implicitly self.current += 1 @@ -203,7 +203,7 @@ class WorkerThread(threading.Thread): def get_taskstatus(self): if self.current < len(self.queue): if self.queue[self.current]['status'] == STAT_STARTED: - if self.queue[self.current]['typ'] == TASK_EMAIL: + if self.queue[self.current]['taskType'] == TASK_EMAIL: self.UIqueue[self.current]['progress'] = self.get_send_status() self.UIqueue[self.current]['runtime'] = self._formatRuntime( datetime.now() - self.queue[self.current]['starttime']) @@ -215,7 +215,7 @@ class WorkerThread(threading.Thread): self.UIqueue[self.current]['status'] = STAT_STARTED self.queue[self.current]['starttime'] = datetime.now() self.UIqueue[self.current]['formStarttime'] = self.queue[self.current]['starttime'] - curr_task = self.queue[self.current]['typ'] + curr_task = self.queue[self.current]['taskType'] filename = self.convert_ebook_format() if filename: if web.ub.config.config_use_google_drive: @@ -223,7 +223,7 @@ class WorkerThread(threading.Thread): if curr_task == TASK_CONVERT: self.add_email(_(u'Send to Kindle'), self.queue[self.current]['path'], filename, self.queue[self.current]['settings'], self.queue[self.current]['kindle'], - self.UIqueue[self.current]['user'], _(u"E-mail: %(book)s", book=self.queue[self.current]['title'])) + self.UIqueue[self.current]['user'], _(u"%(book)s", book=self.queue[self.current]['title'])) def convert_ebook_format(self): @@ -232,7 +232,7 @@ class WorkerThread(threading.Thread): bookid = self.queue[self.current]['bookid'] format_old_ext = u'.' + self.queue[self.current]['settings']['old_book_format'].lower() format_new_ext = u'.' + self.queue[self.current]['settings']['new_book_format'].lower() - + # check to see if destination format already exists - # if it does - mark the conversion task as complete and return a success # this will allow send to kindle workflow to continue to work @@ -245,12 +245,12 @@ class WorkerThread(threading.Thread): return file_path + format_new_ext else: web.app.logger.info("Book id %d - target format of %s does not existing. Moving forward with convert.", bookid, format_new_ext) - + # check if converter-executable is existing if not os.path.exists(web.ub.config.config_converterpath): self._handleError(_(u"Convertertool %(converter)s not found", converter=web.ub.config.config_converterpath)) return - + try: # check which converter to use kindlegen is "1" if format_old_ext == '.epub' and format_new_ext == '.mobi': @@ -339,7 +339,7 @@ class WorkerThread(threading.Thread): return - def add_convert(self, file_path, bookid, user_name, typ, settings, kindle_mail=None): + def add_convert(self, file_path, bookid, user_name, taskMessage, settings, kindle_mail=None): addLock = threading.Lock() addLock.acquire() if self.last >= 20: @@ -350,15 +350,15 @@ class WorkerThread(threading.Thread): if kindle_mail: task = TASK_CONVERT self.queue.append({'file_path':file_path, 'bookid':bookid, 'starttime': 0, 'kindle': kindle_mail, - 'status': STAT_WAITING, 'typ': task, 'settings':settings}) - self.UIqueue.append({'user': user_name, 'formStarttime': '', 'progress': " 0 %", 'type': typ, - 'runtime': '0 s', 'status': STAT_WAITING,'id': self.id } ) + 'status': STAT_WAITING, 'taskType': task, 'settings':settings}) + self.UIqueue.append({'user': user_name, 'formStarttime': '', 'progress': " 0 %", 'taskMessage': taskMessage, + 'runtime': '0 s', 'status': STAT_WAITING,'id': self.id, 'taskType': task } ) self.last=len(self.queue) addLock.release() - def add_email(self, subject, filepath, attachment, settings, recipient, user_name, typ, + def add_email(self, subject, filepath, attachment, settings, recipient, user_name, taskMessage, text=_(u'This e-mail has been sent via Calibre-Web.')): # if more than 20 entries in the list, clean the list addLock = threading.Lock() @@ -369,13 +369,13 @@ class WorkerThread(threading.Thread): self.id += 1 self.queue.append({'subject':subject, 'attachment':attachment, 'filepath':filepath, 'settings':settings, 'recipent':recipient, 'starttime': 0, - 'status': STAT_WAITING, 'typ': TASK_EMAIL, 'text':text}) - self.UIqueue.append({'user': user_name, 'formStarttime': '', 'progress': " 0 %", 'type': typ, - 'runtime': '0 s', 'status': STAT_WAITING,'id': self.id }) + 'status': STAT_WAITING, 'taskType': TASK_EMAIL, 'text':text}) + self.UIqueue.append({'user': user_name, 'formStarttime': '', 'progress': " 0 %", 'taskMessage': taskMessage, + 'runtime': '0 s', 'status': STAT_WAITING,'id': self.id, 'taskType': TASK_EMAIL }) self.last=len(self.queue) addLock.release() - def add_upload(self, user_name, typ): + def add_upload(self, user_name, taskMessage): # if more than 20 entries in the list, clean the list addLock = threading.Lock() addLock.acquire() @@ -383,9 +383,9 @@ class WorkerThread(threading.Thread): self.delete_completed_tasks() # progress=100%, runtime=0, and status finished self.id += 1 - self.queue.append({'starttime': datetime.now(), 'status': STAT_FINISH_SUCCESS, 'typ': TASK_UPLOAD}) - self.UIqueue.append({'user': user_name, 'formStarttime': '', 'progress': "100 %", 'type': typ, - 'runtime': '0 s', 'status': _('Finished'),'id': self.id }) + self.queue.append({'starttime': datetime.now(), 'status': STAT_FINISH_SUCCESS, 'taskType': TASK_UPLOAD}) + self.UIqueue.append({'user': user_name, 'formStarttime': '', 'progress': "100 %", 'taskMessage': taskMessage, + 'runtime': '0 s', 'status': _('Finished'),'id': self.id, 'taskType': TASK_UPLOAD}) self.UIqueue[self.current]['formStarttime'] = self.queue[self.current]['starttime'] self.last=len(self.queue) addLock.release() @@ -469,7 +469,7 @@ class WorkerThread(threading.Thread): if retVal == ' s': retVal = '0 s' return retVal - + def _handleError(self, error_message): web.app.logger.error(error_message) self.queue[self.current]['status'] = STAT_FAIL @@ -502,3 +502,4 @@ class StderrLogger(object): self.buffer = '' else: self.buffer += message +