diff --git a/cps/admin.py b/cps/admin.py index 767aece3..b932bd8e 100644 --- a/cps/admin.py +++ b/cps/admin.py @@ -61,6 +61,7 @@ feature_support = { } try: + # pylint: disable=unused-import import rarfile feature_support['rar'] = True except (ImportError, SyntaxError): @@ -184,10 +185,10 @@ def admin(): else: commit = version['version'] - allUser = ub.session.query(ub.User).all() + all_user = ub.session.query(ub.User).all() email_settings = config.get_mail_settings() kobo_support = feature_support['kobo'] and config.config_kobo_sync - return render_title_template("admin.html", allUser=allUser, email=email_settings, config=config, commit=commit, + return render_title_template("admin.html", allUser=all_user, email=email_settings, config=config, commit=commit, feature_support=feature_support, kobo_support=kobo_support, title=_(u"Admin page"), page="admin") @@ -729,35 +730,13 @@ def _configuration_logfile_helper(to_save, gdrive_error): return reboot_required, None -def _configuration_ldap_helper(to_save, gdrive_error): - reboot_required = False - reboot_required |= _config_string(to_save, "config_ldap_provider_url") - reboot_required |= _config_int(to_save, "config_ldap_port") - reboot_required |= _config_int(to_save, "config_ldap_authentication") - reboot_required |= _config_string(to_save, "config_ldap_dn") - reboot_required |= _config_string(to_save, "config_ldap_serv_username") - reboot_required |= _config_string(to_save, "config_ldap_user_object") - reboot_required |= _config_string(to_save, "config_ldap_group_object_filter") - reboot_required |= _config_string(to_save, "config_ldap_group_members_field") - reboot_required |= _config_string(to_save, "config_ldap_member_user_object") - reboot_required |= _config_checkbox(to_save, "config_ldap_openldap") - reboot_required |= _config_int(to_save, "config_ldap_encryption") - reboot_required |= _config_string(to_save, "config_ldap_cacert_path") - reboot_required |= _config_string(to_save, "config_ldap_cert_path") - reboot_required |= _config_string(to_save, "config_ldap_key_path") - _config_string(to_save, "config_ldap_group_name") - if "config_ldap_serv_password" in to_save and to_save["config_ldap_serv_password"] != "": - reboot_required |= 1 - config.set_from_dictionary(to_save, "config_ldap_serv_password", base64.b64encode, encode='UTF-8') - config.save() - +def _configuration_ldap_check(reboot_required, to_save, gdrive_error): if not config.config_ldap_provider_url \ - or not config.config_ldap_port \ - or not config.config_ldap_dn \ - or not config.config_ldap_user_object: + or not config.config_ldap_port \ + or not config.config_ldap_dn \ + or not config.config_ldap_user_object: return reboot_required, _configuration_result(_('Please Enter a LDAP Provider, ' 'Port, DN and User Object Identifier'), gdrive_error) - if config.config_ldap_authentication > constants.LDAP_AUTH_ANONYMOUS: if config.config_ldap_authentication > constants.LDAP_AUTH_UNAUTHENTICATE: if not config.config_ldap_serv_username or not bool(config.config_ldap_serv_password): @@ -767,6 +746,14 @@ def _configuration_ldap_helper(to_save, gdrive_error): if not config.config_ldap_serv_username: return reboot_required, _configuration_result('Please Enter a LDAP Service Account', gdrive_error) + if config.config_ldap_group_object_filter: + if config.config_ldap_group_object_filter.count("%s") != 1: + return reboot_required, \ + _configuration_result(_('LDAP Group Object Filter Needs to Have One "%s" Format Identifier'), + gdrive_error) + if config.config_ldap_group_object_filter.count("(") != config.config_ldap_group_object_filter.count(")"): + return reboot_required, _configuration_result(_('LDAP Group Object Filter Has Unmatched Parenthesis'), + gdrive_error) if config.config_ldap_group_object_filter: if config.config_ldap_group_object_filter.count("%s") != 1: return reboot_required, \ @@ -806,6 +793,31 @@ def _configuration_ldap_helper(to_save, gdrive_error): return reboot_required, None +def _configuration_ldap_helper(to_save, gdrive_error): + reboot_required = False + reboot_required |= _config_string(to_save, "config_ldap_provider_url") + reboot_required |= _config_int(to_save, "config_ldap_port") + reboot_required |= _config_int(to_save, "config_ldap_authentication") + reboot_required |= _config_string(to_save, "config_ldap_dn") + reboot_required |= _config_string(to_save, "config_ldap_serv_username") + reboot_required |= _config_string(to_save, "config_ldap_user_object") + reboot_required |= _config_string(to_save, "config_ldap_group_object_filter") + reboot_required |= _config_string(to_save, "config_ldap_group_members_field") + reboot_required |= _config_string(to_save, "config_ldap_member_user_object") + reboot_required |= _config_checkbox(to_save, "config_ldap_openldap") + reboot_required |= _config_int(to_save, "config_ldap_encryption") + reboot_required |= _config_string(to_save, "config_ldap_cacert_path") + reboot_required |= _config_string(to_save, "config_ldap_cert_path") + reboot_required |= _config_string(to_save, "config_ldap_key_path") + _config_string(to_save, "config_ldap_group_name") + if "config_ldap_serv_password" in to_save and to_save["config_ldap_serv_password"] != "": + reboot_required |= 1 + config.set_from_dictionary(to_save, "config_ldap_serv_password", base64.b64encode, encode='UTF-8') + config.save() + + return _configuration_ldap_check(reboot_required, to_save, gdrive_error) + + def _configuration_update_helper(configured): reboot_required = False db_change = False @@ -1011,18 +1023,33 @@ def _handle_new_user(to_save, content, languages, translations, kobo_support): ub.session.rollback() flash(_(u"Settings DB is not Writeable"), category="error") +def delete_user(content): + if ub.session.query(ub.User).filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN, + ub.User.id != content.id).count(): + ub.session.query(ub.User).filter(ub.User.id == content.id).delete() + ub.session_commit() + flash(_(u"User '%(nick)s' deleted", nick=content.nickname), category="success") + return redirect(url_for('admin.admin')) + else: + flash(_(u"No admin user remaining, can't delete user", nick=content.nickname), category="error") + return redirect(url_for('admin.admin')) + + +def save_edited_user(content): + try: + ub.session_commit() + flash(_(u"User '%(nick)s' updated", nick=content.nickname), category="success") + except IntegrityError: + ub.session.rollback() + flash(_(u"An unknown error occured."), category="error") + except OperationalError: + ub.session.rollback() + flash(_(u"Settings DB is not Writeable"), category="error") + def _handle_edit_user(to_save, content, languages, translations, kobo_support): if "delete" in to_save: - if ub.session.query(ub.User).filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN, - ub.User.id != content.id).count(): - ub.session.query(ub.User).filter(ub.User.id == content.id).delete() - ub.session_commit() - flash(_(u"User '%(nick)s' deleted", nick=content.nickname), category="success") - return redirect(url_for('admin.admin')) - else: - flash(_(u"No admin user remaining, can't delete user", nick=content.nickname), category="error") - return redirect(url_for('admin.admin')) + return delete_user(content) else: if not ub.session.query(ub.User).filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN, ub.User.id != content.id).count() and 'admin_role' not in to_save: @@ -1090,15 +1117,7 @@ def _handle_edit_user(to_save, content, languages, translations, kobo_support): if "kindle_mail" in to_save and to_save["kindle_mail"] != content.kindle_mail: content.kindle_mail = to_save["kindle_mail"] - try: - ub.session_commit() - flash(_(u"User '%(nick)s' updated", nick=content.nickname), category="success") - except IntegrityError: - ub.session.rollback() - flash(_(u"An unknown error occured."), category="error") - except OperationalError: - ub.session.rollback() - flash(_(u"Settings DB is not Writeable"), category="error") + return save_edited_user(content) @admi.route("/admin/user/new", methods=["GET", "POST"]) @@ -1310,6 +1329,55 @@ def get_updater_status(): return '' +def create_ldap_user(user, user_data, config): + imported = 0 + showtext = None + + user_login_field = extract_dynamic_field_from_filter(user, config.config_ldap_user_object) + + username = user_data[user_login_field][0].decode('utf-8') + # check for duplicate username + if ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == username.lower()).first(): + # if ub.session.query(ub.User).filter(ub.User.nickname == username).first(): + log.warning("LDAP User %s Already in Database", user_data) + return imported, showtext + + kindlemail = '' + if 'mail' in user_data: + useremail = user_data['mail'][0].decode('utf-8') + if len(user_data['mail']) > 1: + kindlemail = user_data['mail'][1].decode('utf-8') + + else: + log.debug('No Mail Field Found in LDAP Response') + useremail = username + '@email.com' + # check for duplicate email + if ub.session.query(ub.User).filter(func.lower(ub.User.email) == useremail.lower()).first(): + log.warning("LDAP Email %s Already in Database", user_data) + return imported, showtext + + content = ub.User() + content.nickname = username + content.password = '' # dummy password which will be replaced by ldap one + content.email = useremail + content.kindle_mail = kindlemail + content.role = config.config_default_role + content.sidebar_view = config.config_default_show + content.allowed_tags = config.config_allowed_tags + content.denied_tags = config.config_denied_tags + content.allowed_column_value = config.config_allowed_column_value + content.denied_column_value = config.config_denied_column_value + ub.session.add(content) + try: + ub.session.commit() + imported = 1 + except Exception as e: + log.warning("Failed to create LDAP user: %s - %s", user, e) + ub.session.rollback() + showtext = _(u'Failed to Create at Least One LDAP User') + return imported, showtext + + @admi.route('/import_ldap_users') @login_required @admin_required @@ -1349,47 +1417,11 @@ def import_ldap_users(): log.debug_or_exception(e) continue if user_data: - user_login_field = extract_dynamic_field_from_filter(user, config.config_ldap_user_object) - - username = user_data[user_login_field][0].decode('utf-8') - # check for duplicate username - if ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == username.lower()).first(): - # if ub.session.query(ub.User).filter(ub.User.nickname == username).first(): - log.warning("LDAP User %s Already in Database", user_data) - continue - - kindlemail = '' - if 'mail' in user_data: - useremail = user_data['mail'][0].decode('utf-8') - if len(user_data['mail']) > 1: - kindlemail = user_data['mail'][1].decode('utf-8') - - else: - log.debug('No Mail Field Found in LDAP Response') - useremail = username + '@email.com' - # check for duplicate email - if ub.session.query(ub.User).filter(func.lower(ub.User.email) == useremail.lower()).first(): - log.warning("LDAP Email %s Already in Database", user_data) - continue - content = ub.User() - content.nickname = username - content.password = '' # dummy password which will be replaced by ldap one - content.email = useremail - content.kindle_mail = kindlemail - content.role = config.config_default_role - content.sidebar_view = config.config_default_show - content.allowed_tags = config.config_allowed_tags - content.denied_tags = config.config_denied_tags - content.allowed_column_value = config.config_allowed_column_value - content.denied_column_value = config.config_denied_column_value - ub.session.add(content) - try: - ub.session.commit() - imported += 1 - except Exception as e: - log.warning("Failed to create LDAP user: %s - %s", user, e) - ub.session.rollback() - showtext['text'] = _(u'Failed to Create at Least One LDAP User') + success, txt = create_ldap_user(user, user_data, config) + # In case of error store text for showing it + if txt: + showtext['text'] = txt + imported += success else: log.warning("LDAP User: %s Not Found", user) showtext['text'] = _(u'At Least One LDAP User Not Found in Database') diff --git a/cps/comic.py b/cps/comic.py index a25f9a51..c2b30197 100644 --- a/cps/comic.py +++ b/cps/comic.py @@ -74,6 +74,41 @@ def _cover_processing(tmp_file_name, img, extension): return tmp_cover_name +def _extract_Cover_from_archive(original_file_extension, tmp_file_name, rarExecutable): + cover_data = None + if original_file_extension.upper() == '.CBZ': + cf = zipfile.ZipFile(tmp_file_name) + for name in cf.namelist(): + ext = os.path.splitext(name) + if len(ext) > 1: + extension = ext[1].lower() + if extension in COVER_EXTENSIONS: + cover_data = cf.read(name) + break + elif original_file_extension.upper() == '.CBT': + cf = tarfile.TarFile(tmp_file_name) + for name in cf.getnames(): + ext = os.path.splitext(name) + if len(ext) > 1: + extension = ext[1].lower() + if extension in COVER_EXTENSIONS: + cover_data = cf.extractfile(name).read() + break + elif original_file_extension.upper() == '.CBR' and use_rarfile: + try: + rarfile.UNRAR_TOOL = rarExecutable + cf = rarfile.RarFile(tmp_file_name) + for name in cf.getnames(): + ext = os.path.splitext(name) + if len(ext) > 1: + extension = ext[1].lower() + if extension in COVER_EXTENSIONS: + cover_data = cf.read(name) + break + except Exception as e: + log.debug('Rarfile failed with error: %s', e) + return cover_data + def _extractCover(tmp_file_name, original_file_extension, rarExecutable): cover_data = extension = None @@ -87,37 +122,7 @@ def _extractCover(tmp_file_name, original_file_extension, rarExecutable): cover_data = archive.getPage(index) break else: - if original_file_extension.upper() == '.CBZ': - cf = zipfile.ZipFile(tmp_file_name) - for name in cf.namelist(): - ext = os.path.splitext(name) - if len(ext) > 1: - extension = ext[1].lower() - if extension in COVER_EXTENSIONS: - cover_data = cf.read(name) - break - elif original_file_extension.upper() == '.CBT': - cf = tarfile.TarFile(tmp_file_name) - for name in cf.getnames(): - ext = os.path.splitext(name) - if len(ext) > 1: - extension = ext[1].lower() - if extension in COVER_EXTENSIONS: - cover_data = cf.extractfile(name).read() - break - elif original_file_extension.upper() == '.CBR' and use_rarfile: - try: - rarfile.UNRAR_TOOL = rarExecutable - cf = rarfile.RarFile(tmp_file_name) - for name in cf.getnames(): - ext = os.path.splitext(name) - if len(ext) > 1: - extension = ext[1].lower() - if extension in COVER_EXTENSIONS: - cover_data = cf.read(name) - break - except Exception as e: - log.debug('Rarfile failed with error: %s', e) + cover_data = _extract_Cover_from_archive(original_file_extension, tmp_file_name, rarExecutable) return _cover_processing(tmp_file_name, cover_data, extension) @@ -142,7 +147,8 @@ def get_comic_info(tmp_file_path, original_file_name, original_file_extension, r file_path=tmp_file_path, extension=original_file_extension, title=loadedMetadata.title or original_file_name, - author=" & ".join([credit["person"] for credit in loadedMetadata.credits if credit["role"] == "Writer"]) or u'Unknown', + author=" & ".join([credit["person"] + for credit in loadedMetadata.credits if credit["role"] == "Writer"]) or u'Unknown', cover=_extractCover(tmp_file_path, original_file_extension, rarExecutable), description=loadedMetadata.comments or "", tags="", diff --git a/cps/config_sql.py b/cps/config_sql.py index f7b300c0..60e17eb3 100644 --- a/cps/config_sql.py +++ b/cps/config_sql.py @@ -146,15 +146,16 @@ class _ConfigSQL(object): self.load() change = False - if self.config_converterpath == None: + if self.config_converterpath == None: # pylint: disable=access-member-before-definition change = True self.config_converterpath = autodetect_calibre_binary() - if self.config_kepubifypath == None: + if self.config_kepubifypath == None: # pylint: disable=access-member-before-definition + change = True self.config_kepubifypath = autodetect_kepubify_binary() - if self.config_rarfile_location == None: + if self.config_rarfile_location == None: # pylint: disable=access-member-before-definition change = True self.config_rarfile_location = autodetect_unrar_binary() if change: @@ -181,7 +182,8 @@ class _ConfigSQL(object): return None return self.config_keyfile - def get_config_ipaddress(self): + @staticmethod + def get_config_ipaddress(): return cli.ipadress or "" def _has_role(self, role_flag): @@ -299,6 +301,7 @@ class _ConfigSQL(object): have_metadata_db = os.path.isfile(db_file) self.db_configured = have_metadata_db constants.EXTENSIONS_UPLOAD = [x.lstrip().rstrip().lower() for x in self.config_upload_formats.split(',')] + # pylint: disable=access-member-before-definition logfile = logger.setup(self.config_logfile, self.config_log_level) if logfile != self.config_logfile: log.warning("Log path %s not valid, falling back to default", self.config_logfile) diff --git a/cps/constants.py b/cps/constants.py index ac48a5b8..200bec8d 100644 --- a/cps/constants.py +++ b/cps/constants.py @@ -104,7 +104,7 @@ LDAP_AUTH_SIMPLE = 0 DEFAULT_MAIL_SERVER = "mail.example.org" -DEFAULT_PASSWORD = "admin123" +DEFAULT_PASSWORD = "admin123" # nosec # noqa DEFAULT_PORT = 8083 env_CALIBRE_PORT = os.environ.get("CALIBRE_PORT", DEFAULT_PORT) try: diff --git a/cps/db.py b/cps/db.py index 2bc0fc51..3eec6454 100644 --- a/cps/db.py +++ b/cps/db.py @@ -156,10 +156,8 @@ class Identifiers(Base): return u"https://portal.issn.org/resource/ISSN/{0}".format(self.val) elif format_type == "isfdb": return u"http://www.isfdb.org/cgi-bin/pl.cgi?{0}".format(self.val) - elif format_type == "url": - return u"{0}".format(self.val) else: - return u"" + return u"{0}".format(self.val) class Comments(Base): @@ -386,14 +384,14 @@ class Custom_Columns(Base): class AlchemyEncoder(json.JSONEncoder): - def default(self, obj): - if isinstance(obj.__class__, DeclarativeMeta): + def default(self, o): + if isinstance(o.__class__, DeclarativeMeta): # an SQLAlchemy class fields = {} - for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']: + for field in [x for x in dir(o) if not x.startswith('_') and x != 'metadata']: if field == 'books': continue - data = obj.__getattribute__(field) + data = o.__getattribute__(field) try: if isinstance(data, str): data = data.replace("'", "\'") @@ -413,12 +411,12 @@ class AlchemyEncoder(json.JSONEncoder): else: json.dumps(data) fields[field] = data - except: + except Exception: fields[field] = "" # a json-encodable dict return fields - return json.JSONEncoder.default(self, obj) + return json.JSONEncoder.default(self, o) class CalibreDB(): @@ -565,8 +563,8 @@ class CalibreDB(): def get_book_by_uuid(self, book_uuid): return self.session.query(Books).filter(Books.uuid == book_uuid).first() - def get_book_format(self, book_id, format): - return self.session.query(Data).filter(Data.book == book_id).filter(Data.format == format).first() + def get_book_format(self, book_id, file_format): + return self.session.query(Data).filter(Data.book == book_id).filter(Data.format == file_format).first() # Language and content filters for displaying in the UI def common_filters(self, allow_show_archived=False): @@ -744,7 +742,7 @@ class CalibreDB(): if old_session: try: old_session.close() - except: + except Exception: pass if old_session.bind: try: diff --git a/cps/gdrive.py b/cps/gdrive.py index b1896bbb..950f3ce2 100644 --- a/cps/gdrive.py +++ b/cps/gdrive.py @@ -47,7 +47,7 @@ except ImportError as err: current_milli_time = lambda: int(round(time() * 1000)) -gdrive_watch_callback_token = 'target=calibreweb-watch_files' +gdrive_watch_callback_token = 'target=calibreweb-watch_files' #nosec @gdrive.route("/authenticate") diff --git a/cps/helper.py b/cps/helper.py index 92cdb2fb..88c0550b 100644 --- a/cps/helper.py +++ b/cps/helper.py @@ -134,63 +134,71 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False): taskMessage=_(u"Registration e-mail for user: %(name)s", name=user_name), text=txt )) - return +def check_send_to_kindle_without_converter(entry): + bookformats = list() + # no converter - only for mobi and pdf formats + for ele in iter(entry.data): + if ele.uncompressed_size < config.mail_size: + if 'MOBI' in ele.format: + bookformats.append({'format': 'Mobi', + 'convert': 0, + 'text': _('Send %(format)s to Kindle', format='Mobi')}) + if 'PDF' in ele.format: + bookformats.append({'format': 'Pdf', + 'convert': 0, + 'text': _('Send %(format)s to Kindle', format='Pdf')}) + if 'AZW' in ele.format: + bookformats.append({'format': 'Azw', + 'convert': 0, + 'text': _('Send %(format)s to Kindle', format='Azw')}) + return bookformats + +def check_send_to_kindle_with_converter(entry): + bookformats = list() + formats = list() + for ele in iter(entry.data): + if ele.uncompressed_size < config.mail_size: + formats.append(ele.format) + if 'MOBI' in formats: + bookformats.append({'format': 'Mobi', + 'convert': 0, + 'text': _('Send %(format)s to Kindle', format='Mobi')}) + if 'AZW' in formats: + bookformats.append({'format': 'Azw', + 'convert': 0, + 'text': _('Send %(format)s to Kindle', format='Azw')}) + if 'PDF' in formats: + bookformats.append({'format': 'Pdf', + 'convert': 0, + 'text': _('Send %(format)s to Kindle', format='Pdf')}) + if 'EPUB' in formats and 'MOBI' not in formats: + bookformats.append({'format': 'Mobi', + 'convert': 1, + 'text': _('Convert %(orig)s to %(format)s and send to Kindle', + orig='Epub', + format='Mobi')}) + if 'AZW3' in formats and not 'MOBI' in formats: + bookformats.append({'format': 'Mobi', + 'convert': 2, + 'text': _('Convert %(orig)s to %(format)s and send to Kindle', + orig='Azw3', + format='Mobi')}) + return bookformats + + def check_send_to_kindle(entry): """ returns all available book formats for sending to Kindle """ if len(entry.data): - bookformats = list() if not config.config_converterpath: - # no converter - only for mobi and pdf formats - for ele in iter(entry.data): - if ele.uncompressed_size < config.mail_size: - if 'MOBI' in ele.format: - bookformats.append({'format': 'Mobi', - 'convert': 0, - 'text': _('Send %(format)s to Kindle', format='Mobi')}) - if 'PDF' in ele.format: - bookformats.append({'format': 'Pdf', - 'convert': 0, - 'text': _('Send %(format)s to Kindle', format='Pdf')}) - if 'AZW' in ele.format: - bookformats.append({'format': 'Azw', - 'convert': 0, - 'text': _('Send %(format)s to Kindle', format='Azw')}) + book_formats = check_send_to_kindle_with_converter(entry) else: - formats = list() - for ele in iter(entry.data): - if ele.uncompressed_size < config.mail_size: - formats.append(ele.format) - if 'MOBI' in formats: - bookformats.append({'format': 'Mobi', - 'convert': 0, - 'text': _('Send %(format)s to Kindle', format='Mobi')}) - if 'AZW' in formats: - bookformats.append({'format': 'Azw', - 'convert': 0, - 'text': _('Send %(format)s to Kindle', format='Azw')}) - if 'PDF' in formats: - bookformats.append({'format': 'Pdf', - 'convert': 0, - 'text': _('Send %(format)s to Kindle', format='Pdf')}) - if config.config_converterpath: - if 'EPUB' in formats and 'MOBI' not in formats: - bookformats.append({'format': 'Mobi', - 'convert':1, - 'text': _('Convert %(orig)s to %(format)s and send to Kindle', - orig='Epub', - format='Mobi')}) - if 'AZW3' in formats and not 'MOBI' in formats: - bookformats.append({'format': 'Mobi', - 'convert': 2, - 'text': _('Convert %(orig)s to %(format)s and send to Kindle', - orig='Azw3', - format='Mobi')}) - return bookformats + book_formats = check_send_to_kindle_with_converter(entry) + return book_formats else: log.error(u'Cannot find book entry %d', entry.id) return None @@ -742,7 +750,7 @@ def format_runtime(runtime): # helper function to apply localize status information in tasklist entries def render_task_status(tasklist): renderedtasklist = list() - for num, user, added, task in tasklist: + for __, user, added, task in tasklist: if user == current_user.nickname or current_user.role_admin(): ret = {} if task.start_time: diff --git a/cps/isoLanguages.py b/cps/isoLanguages.py index 4c0aefc3..896d4faf 100644 --- a/cps/isoLanguages.py +++ b/cps/isoLanguages.py @@ -71,7 +71,7 @@ def get_valid_language_codes(locale, language_names, remainder=None): languages = list() if "" in language_names: language_names.remove("") - for k, v in get_language_names(locale).items(): + for k, __ in get_language_names(locale).items(): if k in language_names: languages.append(k) language_names.remove(k) diff --git a/cps/kobo.py b/cps/kobo.py index d019e918..b5d5397b 100644 --- a/cps/kobo.py +++ b/cps/kobo.py @@ -42,8 +42,7 @@ from flask import ( from flask_login import current_user from werkzeug.datastructures import Headers from sqlalchemy import func -from sqlalchemy.sql.expression import and_, or_ -from sqlalchemy.orm import load_only +from sqlalchemy.sql.expression import and_ from sqlalchemy.exc import StatementError import requests @@ -893,17 +892,6 @@ def HandleProductsRequest(dummy=None): return redirect_or_proxy_request() -'''@kobo.errorhandler(404) -def handle_404(err): - # This handler acts as a catch-all for endpoints that we don't have an interest in - # implementing (e.g: v1/analytics/gettests, v1/user/recommendations, etc) - if err: - print('404') - return jsonify(error=str(err)), 404 - log.debug("Unknown Request received: %s, method: %s, data: %s", request.base_url, request.method, request.data) - return redirect_or_proxy_request()''' - - def make_calibre_web_auth_response(): # As described in kobo_auth.py, CalibreWeb doesn't make use practical use of this auth/device API call for # authentation (nor for authorization). We return a dummy response just to keep the device happy. @@ -947,7 +935,7 @@ def HandleInitRequest(): store_response_json = store_response.json() if "Resources" in store_response_json: kobo_resources = store_response_json["Resources"] - except: + except Exception: log.error("Failed to receive or parse response from Kobo's init endpoint. Falling back to un-proxied mode.") if not kobo_resources: kobo_resources = NATIVE_KOBO_RESOURCES() diff --git a/cps/oauth.py b/cps/oauth.py index 67ef2703..a8995180 100644 --- a/cps/oauth.py +++ b/cps/oauth.py @@ -19,7 +19,6 @@ from __future__ import division, print_function, unicode_literals from flask import session - try: from flask_dance.consumer.backend.sqla import SQLAlchemyBackend, first, _get_real_user from sqlalchemy.orm.exc import NoResultFound @@ -34,134 +33,131 @@ except ImportError: except ImportError: pass -try: - class OAuthBackend(SQLAlchemyBackend): - """ - Stores and retrieves OAuth tokens using a relational database through - the `SQLAlchemy`_ ORM. - .. _SQLAlchemy: https://www.sqlalchemy.org/ - """ - def __init__(self, model, session, provider_id, - user=None, user_id=None, user_required=None, anon_user=None, - cache=None): - self.provider_id = provider_id - super(OAuthBackend, self).__init__(model, session, user, user_id, user_required, anon_user, cache) +class OAuthBackend(SQLAlchemyBackend): + """ + Stores and retrieves OAuth tokens using a relational database through + the `SQLAlchemy`_ ORM. - def get(self, blueprint, user=None, user_id=None): - if self.provider_id + '_oauth_token' in session and session[self.provider_id + '_oauth_token'] != '': - return session[self.provider_id + '_oauth_token'] - # check cache - cache_key = self.make_cache_key(blueprint=blueprint, user=user, user_id=user_id) - token = self.cache.get(cache_key) - if token: - return token - - # if not cached, make database queries - query = ( - self.session.query(self.model) - .filter_by(provider=self.provider_id) - ) - uid = first([user_id, self.user_id, blueprint.config.get("user_id")]) - u = first(_get_real_user(ref, self.anon_user) - for ref in (user, self.user, blueprint.config.get("user"))) - - use_provider_user_id = False - if self.provider_id + '_oauth_user_id' in session and session[self.provider_id + '_oauth_user_id'] != '': - query = query.filter_by(provider_user_id=session[self.provider_id + '_oauth_user_id']) - use_provider_user_id = True - - if self.user_required and not u and not uid and not use_provider_user_id: - # raise ValueError("Cannot get OAuth token without an associated user") - return None - # check for user ID - if hasattr(self.model, "user_id") and uid: - query = query.filter_by(user_id=uid) - # check for user (relationship property) - elif hasattr(self.model, "user") and u: - query = query.filter_by(user=u) - # if we have the property, but not value, filter by None - elif hasattr(self.model, "user_id"): - query = query.filter_by(user_id=None) - # run query - try: - token = query.one().token - except NoResultFound: - token = None - - # cache the result - self.cache.set(cache_key, token) + .. _SQLAlchemy: https://www.sqlalchemy.org/ + """ + def __init__(self, model, session, provider_id, + user=None, user_id=None, user_required=None, anon_user=None, + cache=None): + self.provider_id = provider_id + super(OAuthBackend, self).__init__(model, session, user, user_id, user_required, anon_user, cache) + def get(self, blueprint, user=None, user_id=None): + if self.provider_id + '_oauth_token' in session and session[self.provider_id + '_oauth_token'] != '': + return session[self.provider_id + '_oauth_token'] + # check cache + cache_key = self.make_cache_key(blueprint=blueprint, user=user, user_id=user_id) + token = self.cache.get(cache_key) + if token: return token - def set(self, blueprint, token, user=None, user_id=None): - uid = first([user_id, self.user_id, blueprint.config.get("user_id")]) - u = first(_get_real_user(ref, self.anon_user) - for ref in (user, self.user, blueprint.config.get("user"))) + # if not cached, make database queries + query = ( + self.session.query(self.model) + .filter_by(provider=self.provider_id) + ) + uid = first([user_id, self.user_id, blueprint.config.get("user_id")]) + u = first(_get_real_user(ref, self.anon_user) + for ref in (user, self.user, blueprint.config.get("user"))) - if self.user_required and not u and not uid: - raise ValueError("Cannot set OAuth token without an associated user") + use_provider_user_id = False + if self.provider_id + '_oauth_user_id' in session and session[self.provider_id + '_oauth_user_id'] != '': + query = query.filter_by(provider_user_id=session[self.provider_id + '_oauth_user_id']) + use_provider_user_id = True - # if there was an existing model, delete it - existing_query = ( - self.session.query(self.model) - .filter_by(provider=self.provider_id) - ) - # check for user ID - has_user_id = hasattr(self.model, "user_id") - if has_user_id and uid: - existing_query = existing_query.filter_by(user_id=uid) - # check for user (relationship property) - has_user = hasattr(self.model, "user") - if has_user and u: - existing_query = existing_query.filter_by(user=u) - # queue up delete query -- won't be run until commit() - existing_query.delete() - # create a new model for this token - kwargs = { - "provider": self.provider_id, - "token": token, - } - if has_user_id and uid: - kwargs["user_id"] = uid - if has_user and u: - kwargs["user"] = u - self.session.add(self.model(**kwargs)) - # commit to delete and add simultaneously - self.session.commit() - # invalidate cache - self.cache.delete(self.make_cache_key( - blueprint=blueprint, user=user, user_id=user_id - )) + if self.user_required and not u and not uid and not use_provider_user_id: + # raise ValueError("Cannot get OAuth token without an associated user") + return None + # check for user ID + if hasattr(self.model, "user_id") and uid: + query = query.filter_by(user_id=uid) + # check for user (relationship property) + elif hasattr(self.model, "user") and u: + query = query.filter_by(user=u) + # if we have the property, but not value, filter by None + elif hasattr(self.model, "user_id"): + query = query.filter_by(user_id=None) + # run query + try: + token = query.one().token + except NoResultFound: + token = None - def delete(self, blueprint, user=None, user_id=None): - query = ( - self.session.query(self.model) - .filter_by(provider=self.provider_id) - ) - uid = first([user_id, self.user_id, blueprint.config.get("user_id")]) - u = first(_get_real_user(ref, self.anon_user) - for ref in (user, self.user, blueprint.config.get("user"))) + # cache the result + self.cache.set(cache_key, token) - if self.user_required and not u and not uid: - raise ValueError("Cannot delete OAuth token without an associated user") + return token - # check for user ID - if hasattr(self.model, "user_id") and uid: - query = query.filter_by(user_id=uid) - # check for user (relationship property) - elif hasattr(self.model, "user") and u: - query = query.filter_by(user=u) - # if we have the property, but not value, filter by None - elif hasattr(self.model, "user_id"): - query = query.filter_by(user_id=None) - # run query - query.delete() - self.session.commit() - # invalidate cache - self.cache.delete(self.make_cache_key( - blueprint=blueprint, user=user, user_id=user_id, - )) + def set(self, blueprint, token, user=None, user_id=None): + uid = first([user_id, self.user_id, blueprint.config.get("user_id")]) + u = first(_get_real_user(ref, self.anon_user) + for ref in (user, self.user, blueprint.config.get("user"))) -except Exception: - pass + if self.user_required and not u and not uid: + raise ValueError("Cannot set OAuth token without an associated user") + + # if there was an existing model, delete it + existing_query = ( + self.session.query(self.model) + .filter_by(provider=self.provider_id) + ) + # check for user ID + has_user_id = hasattr(self.model, "user_id") + if has_user_id and uid: + existing_query = existing_query.filter_by(user_id=uid) + # check for user (relationship property) + has_user = hasattr(self.model, "user") + if has_user and u: + existing_query = existing_query.filter_by(user=u) + # queue up delete query -- won't be run until commit() + existing_query.delete() + # create a new model for this token + kwargs = { + "provider": self.provider_id, + "token": token, + } + if has_user_id and uid: + kwargs["user_id"] = uid + if has_user and u: + kwargs["user"] = u + self.session.add(self.model(**kwargs)) + # commit to delete and add simultaneously + self.session.commit() + # invalidate cache + self.cache.delete(self.make_cache_key( + blueprint=blueprint, user=user, user_id=user_id + )) + + def delete(self, blueprint, user=None, user_id=None): + query = ( + self.session.query(self.model) + .filter_by(provider=self.provider_id) + ) + uid = first([user_id, self.user_id, blueprint.config.get("user_id")]) + u = first(_get_real_user(ref, self.anon_user) + for ref in (user, self.user, blueprint.config.get("user"))) + + if self.user_required and not u and not uid: + raise ValueError("Cannot delete OAuth token without an associated user") + + # check for user ID + if hasattr(self.model, "user_id") and uid: + query = query.filter_by(user_id=uid) + # check for user (relationship property) + elif hasattr(self.model, "user") and u: + query = query.filter_by(user=u) + # if we have the property, but not value, filter by None + elif hasattr(self.model, "user_id"): + query = query.filter_by(user_id=None) + # run query + query.delete() + self.session.commit() + # invalidate cache + self.cache.delete(self.make_cache_key( + blueprint=blueprint, user=user, user_id=user_id, + )) diff --git a/cps/oauth_bb.py b/cps/oauth_bb.py index b17d38c7..3fee2e04 100644 --- a/cps/oauth_bb.py +++ b/cps/oauth_bb.py @@ -35,7 +35,10 @@ from sqlalchemy.orm.exc import NoResultFound from . import constants, logger, config, app, ub -from .oauth import OAuthBackend, backend_resultcode +try: + from .oauth import OAuthBackend, backend_resultcode +except NameError: + pass oauth_check = {} diff --git a/cps/server.py b/cps/server.py index bf564108..ac821b31 100644 --- a/cps/server.py +++ b/cps/server.py @@ -137,8 +137,8 @@ class WebServer(object): return sock, _readable_listen_address(*address) - - def _get_args_for_reloading(self): + @staticmethod + def _get_args_for_reloading(): """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 diff --git a/cps/services/SyncToken.py b/cps/services/SyncToken.py index 26eb396c..da5d93a3 100644 --- a/cps/services/SyncToken.py +++ b/cps/services/SyncToken.py @@ -64,7 +64,7 @@ class SyncToken: books_last_modified: Datetime representing the last modified book that the device knows about. """ - SYNC_TOKEN_HEADER = "x-kobo-synctoken" + SYNC_TOKEN_HEADER = "x-kobo-synctoken" # nosec VERSION = "1-1-0" LAST_MODIFIED_ADDED_VERSION = "1-1-0" MIN_VERSION = "1-0-0" @@ -91,7 +91,7 @@ class SyncToken: def __init__( self, - raw_kobo_store_token="", + raw_kobo_store_token="", # nosec books_last_created=datetime.min, books_last_modified=datetime.min, archive_last_modified=datetime.min, @@ -110,7 +110,7 @@ class SyncToken: @staticmethod def from_headers(headers): sync_token_header = headers.get(SyncToken.SYNC_TOKEN_HEADER, "") - if sync_token_header == "": + if sync_token_header == "": # nosec return SyncToken() # On the first sync from a Kobo device, we may receive the SyncToken diff --git a/cps/static/css/caliBlur_override.css b/cps/static/css/caliBlur_override.css index 00ba3cca..4c8b6cb0 100644 --- a/cps/static/css/caliBlur_override.css +++ b/cps/static/css/caliBlur_override.css @@ -1,22 +1,24 @@ -body.serieslist.grid-view div.container-fluid>div>div.col-sm-10:before{ - display: none; -} -.cover .badge{ - position: absolute; - top: 0; - left: 0; - color: #fff; - background-color: #cc7b19; - border-radius: 0; - padding: 0 8px; - box-shadow: 0 0 4px rgba(0,0,0,.6); - line-height: 24px; -} -.cover{ - box-shadow: 0 0 4px rgba(0,0,0,.6); +body.serieslist.grid-view div.container-fluid > div > div.col-sm-10::before { + display: none; } -.cover .read{ - padding: 0 0px; - line-height: 15px; +.cover .badge { + position: absolute; + top: 0; + left: 0; + color: #fff; + background-color: #cc7b19; + border-radius: 0; + padding: 0 8px; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.6); + line-height: 24px; +} + +.cover { + box-shadow: 0 0 4px rgba(0, 0, 0, 0.6); +} + +.cover .read { + padding: 0 0; + line-height: 15px; } diff --git a/cps/static/css/kthoom.css b/cps/static/css/kthoom.css index cc38740b..233cfe94 100644 --- a/cps/static/css/kthoom.css +++ b/cps/static/css/kthoom.css @@ -33,7 +33,6 @@ body { position: relative; cursor: pointer; padding: 4px; - transition: all 0.2s ease; } @@ -45,7 +44,7 @@ body { #sidebar a.active, #sidebar a.active img + span { - background-color: #45B29D; + background-color: #45b29d; } #sidebar li img { @@ -99,7 +98,7 @@ body { background-color: #ccc; } -#progress .bar-read { +#progress .bar-read { color: #fff; background-color: #45b29d; } diff --git a/cps/static/css/listen.css b/cps/static/css/listen.css index a69af72e..9e1d3bb4 100644 --- a/cps/static/css/listen.css +++ b/cps/static/css/listen.css @@ -66,19 +66,12 @@ body { right: 40px; } -xmp, -pre, -plaintext { - display: block; - font-family: -moz-fixed; - white-space: pre; - margin: 1em 0; -} - pre { + display: block; + margin: 1em 0; white-space: pre-wrap; word-wrap: break-word; - font-family: -moz-fixed; + font-family: -moz-fixed, sans-serif; column-count: 2; -webkit-columns: 2; -moz-columns: 2; diff --git a/cps/static/css/main.css b/cps/static/css/main.css index 2831a0fd..e97497de 100644 --- a/cps/static/css/main.css +++ b/cps/static/css/main.css @@ -35,7 +35,6 @@ body { height: 8%; min-height: 20px; padding: 10px; - /* margin: 0 50px 0 50px; */ position: relative; color: #4f4f4f; font-weight: 100; @@ -73,6 +72,16 @@ body { padding: 3px; } +#panels a { + visibility: hidden; + width: 18px; + height: 20px; + overflow: hidden; + display: inline-block; + color: #ccc; + margin-left: 6px; +} + #titlebar a:active { opacity: 1; color: rgba(0, 0, 0, 0.6); @@ -114,7 +123,7 @@ body { top: 50%; margin-top: -192px; font-size: 64px; - color: #E2E2E2; + color: #e2e2e2; font-family: arial, sans-serif; font-weight: bold; cursor: pointer; @@ -148,12 +157,6 @@ body { overflow: hidden; } -#sidebar.open { - /* left: 0; */ - /* -webkit-transform: translate(0, 0); - -moz-transform: translate(0, 0); */ -} - #main.closed { /* left: 300px; */ -webkit-transform: translate(300px, 0); @@ -196,19 +199,24 @@ body { #title-controls { float: right; } -#panels a { - visibility: hidden; - width: 18px; - height: 20px; - overflow: hidden; - display: inline-block; - color: #ccc; - margin-left: 6px; -} - #panels a::before { visibility: visible; } #panels a:hover { color: #aaa; } +.list_item.currentChapter > a, +.list_item a:hover { + color: #f1f1f1; +} + +.list_item a { + color: #aaa; + text-decoration: none; +} + +#searchResults a { + color: #aaa; + text-decoration: none; +} + #panels a:active { color: #aaa; margin: 1px 0 -1px 6px; @@ -238,7 +246,7 @@ input:-moz-placeholder { color: #454545; } left: 50%; margin-left: -1px; top: 10%; - opacity: .15; + opacity: 0.15; box-shadow: -2px 0 15px rgba(0, 0, 0, 1); display: none; } @@ -281,6 +289,17 @@ input:-moz-placeholder { color: #454545; } display: block; } +.list_item ul { + padding-left: 10px; + margin-top: 8px; + display: none; +} + +.list_item.currentChapter > ul, +.list_item.openChapter > ul { + display: block; +} + #tocView > ul, #bookmarksView > ul { margin-top: 15px; @@ -291,22 +310,41 @@ input:-moz-placeholder { color: #454545; } #tocView li, #bookmarksView li { - margin-bottom:10px; + margin-bottom: 10px; width: 225px; font-family: Georgia, "Times New Roman", Times, serif; list-style: none; text-transform: capitalize; } -#tocView li:active, -#tocView li.currentChapter -{ +.md-content > div ul li { + padding: 5px 0; +} + +#settingsPanel li { + font-size: 1em; + color: #f1f1f1; +} + +#searchResults li { + margin-bottom: 10px; + width: 225px; + font-family: Georgia, "Times New Roman", Times, serif; list-style: none; } -.list_item a { - color: #aaa; - text-decoration: none; +#notes li { + color: #eee; + font-size: 12px; + width: 240px; + border-top: 1px #fff solid; + padding-top: 6px; + margin-bottom: 6px; +} + +#tocView li:active, +#tocView li.currentChapter { + list-style: none; } .list_item a.chapter { @@ -317,27 +355,11 @@ input:-moz-placeholder { color: #454545; } font-size: 0.8em; } -.list_item.currentChapter > a, -.list_item a:hover { - color: #f1f1f1 -} - /* #tocView li.openChapter > a, */ .list_item a:hover { color: #e2e2e2; } -.list_item ul { - padding-left:10px; - margin-top: 8px; - display: none; -} - -.list_item.currentChapter > ul, -.list_item.openChapter > ul { - display: block; -} - #tocView.hidden { display: none; } @@ -352,14 +374,14 @@ input:-moz-placeholder { color: #454545; } user-select: none; } -.toc_toggle:before { +.toc_toggle::before { content: '▸'; color: #fff; margin-right: -4px; } -.currentChapter > .toc_toggle:before, -.openChapter > .toc_toggle:before { +.currentChapter > .toc_toggle::before, +.openChapter > .toc_toggle::before { content: '▾'; } @@ -377,18 +399,6 @@ input:-moz-placeholder { color: #454545; } display: block; } -#searchResults li { - margin-bottom:10px; - width: 225px; - font-family: Georgia, "Times New Roman", Times, serif; - list-style: none; -} - -#searchResults a { - color: #aaa; - text-decoration: none; -} - #searchResults p { text-decoration: none; font-size: 12px; @@ -400,10 +410,21 @@ input:-moz-placeholder { color: #454545; } color: #000; } +.md-content > div p { + margin: 0; + padding: 10px 0; +} + #searchResults li > p { color: #aaa; } +#notes li a { + color: #fff; + display: inline-block; + margin-left: 6px; +} + #searchResults li a:hover { color: #e2e2e2; } @@ -414,22 +435,7 @@ input:-moz-placeholder { color: #454545; } } #notes { - padding: 0 0 0 34px; -} - -#notes li { - color: #eee; - font-size: 12px; - width: 240px; - border-top: 1px #fff solid; - padding-top: 6px; - margin-bottom: 6px; -} - -#notes li a { - color: #fff; - display: inline-block; - margin-left: 6px; + padding: 0 0 0 34px; } #notes li a:hover { @@ -449,8 +455,9 @@ input:-moz-placeholder { color: #454545; } border-radius: 5px; } -#note-text[disabled], #note-text[disabled="disabled"]{ - opacity: 0.5; +#note-text[disabled], +#note-text[disabled="disabled"] { + opacity: 0.5; } #note-anchor { @@ -462,6 +469,22 @@ input:-moz-placeholder { color: #454545; } display: none; } +.md-content h3 { + margin: 0; + padding: 6px; + text-align: center; + font-size: 22px; + font-weight: 300; + opacity: 0.8; + background: rgba(0, 0, 0, 0.1); + border-radius: 3px 3px 0 0; +} + +.md-content > div ul { + margin: 0; + padding: 0 0 30px 20px; +} + #settingsPanel h3 { color: #f1f1f1; font-family: Georgia, "Times New Roman", Times, serif; @@ -473,31 +496,24 @@ input:-moz-placeholder { color: #454545; } list-style-type: none; } -#settingsPanel li { - font-size: 1em; - color: #f1f1f1; -} +#settingsPanel .xsmall { font-size: x-small; } +#settingsPanel .small { font-size: small; } +#settingsPanel .medium { font-size: medium; } +#settingsPanel .large { font-size: large; } +#settingsPanel .xlarge { font-size: x-large; } -#settingsPanel .xsmall { font-size: x-small; } -#settingsPanel .small { font-size: small; } -#settingsPanel .medium { font-size: medium; } -#settingsPanel .large { font-size: large; } -#settingsPanel .xlarge { font-size: x-large; } - -.highlight { background-color: yellow } +.highlight { background-color: yellow; } .modal { position: fixed; top: 50%; left: 50%; - // width: 50%; width: 630px; height: auto; z-index: 2000; visibility: hidden; margin-left: -320px; margin-top: -160px; - } .overlay { @@ -516,12 +532,12 @@ input:-moz-placeholder { color: #454545; } } .md-show { - visibility: visible; + visibility: visible; } .md-show ~ .overlay { - opacity: 1; - visibility: visible; + opacity: 1; + visibility: visible; } /* Content styles */ @@ -534,17 +550,6 @@ input:-moz-placeholder { color: #454545; } height: 320px; } -.md-content h3 { - margin: 0; - padding: 6px; - text-align: center; - font-size: 22px; - font-weight: 300; - opacity: 0.8; - background: rgba(0, 0, 0, 0.1); - border-radius: 3px 3px 0 0; -} - .md-content > div { padding: 15px 40px 30px; margin: 0; @@ -552,20 +557,6 @@ input:-moz-placeholder { color: #454545; } font-size: 14px; } -.md-content > div p { - margin: 0; - padding: 10px 0; -} - -.md-content > div ul { - margin: 0; - padding: 0 0 30px 20px; -} - -.md-content > div ul li { - padding: 5px 0; -} - .md-content button { display: block; margin: 0 auto; @@ -593,7 +584,6 @@ input:-moz-placeholder { color: #454545; } } .md-content > .closer { - //font-size: 18px; position: absolute; right: 0; top: 0; @@ -602,7 +592,7 @@ input:-moz-placeholder { color: #454545; } } @media only screen and (max-width: 1040px) and (orientation: portrait) { - #viewer{ + #viewer { width: 80%; margin-left: 10%; } @@ -614,7 +604,7 @@ input:-moz-placeholder { color: #454545; } } @media only screen and (max-width: 900px) { - #viewer{ + #viewer { width: 60%; margin-left: 20%; } @@ -629,7 +619,7 @@ input:-moz-placeholder { color: #454545; } } @media only screen and (max-width: 550px) { - #viewer{ + #viewer { width: 80%; margin-left: 10%; } @@ -653,9 +643,9 @@ input:-moz-placeholder { color: #454545; } -webkit-transform: translate(0, 0); -moz-transform: translate(0, 0); -ms-transform: translate(0, 0); - -webkit-transition: -webkit-transform .3s; - -moz-transition: -moz-transform .3s; - transition: -moz-transform .3s; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + transition: -moz-transform 0.3s; } #main.closed { @@ -664,11 +654,6 @@ input:-moz-placeholder { color: #454545; } -ms-transform: translate(260px, 0); } - #titlebar { - /* font-size: 16px; */ - /* margin: 0 50px 0 50px; */ - } - #metainfo { font-size: 10px; } @@ -681,130 +666,129 @@ input:-moz-placeholder { color: #454545; } font-size: 12px; } - #tocView > ul{ + #tocView > ul { padding-left: 10px; } } - /* For iPad portrait layouts only */ @media only screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation: portrait) { - #viewer iframe { - width: 460px; - height: 740px; - } + #viewer iframe { + width: 460px; + height: 740px; + } } - /*For iPad landscape layouts only *//* -@media only screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation: landscape) { - #viewer iframe { - width: 460px; - height: 415px; - } -}*/ @media only screen -and (min-device-width : 768px) -and (max-device-width : 1024px) -and (orientation : landscape) -/*and (-webkit-min-device-pixel-ratio: 2)*/ { - #viewer{ + and (min-device-width: 768px) + and (max-device-width: 1024px) + and (orientation: landscape) + /* and (-webkit-min-device-pixel-ratio: 2)*/ { + #viewer { width: 80%; margin-left: 10%; } + #divider, #divider.show { display: none; } } - /*For iPad landscape layouts only */ +/* For iPad landscape layouts only */ @media only screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation: landscape) { - #viewer iframe { - width: 960px; - height: 515px; - } + #viewer iframe { + width: 960px; + height: 515px; + } } /* For iPhone 6\6s portrait layouts only */ -@media only screen and (min-device-width : 375px) and (max-device-width : 667px) and (orientation: portrait) { - #viewer { - width: 300px; - height: 480px; - } - #viewer iframe { - width: 300px; - height: 480px; - } +@media only screen and (min-device-width: 375px) and (max-device-width: 667px) and (orientation: portrait) { + #viewer { + width: 300px; + height: 480px; + } + + #viewer iframe { + width: 300px; + height: 480px; + } } /* For iPhone 6\6s landscape layouts only */ -@media only screen and (min-device-width : 375px) and (max-device-width : 667px) and (orientation: landscape) { - #viewer { - width: 450px; - height: 300px; - } - #viewer iframe { - width: 450px; - height: 300px; - } +@media only screen and (min-device-width: 375px) and (max-device-width: 667px) and (orientation: landscape) { + #viewer { + width: 450px; + height: 300px; + } + + #viewer iframe { + width: 450px; + height: 300px; + } } /* For iPhone portrait layouts only */ @media only screen and (max-device-width: 374px) and (orientation: portrait) { - #viewer { - width: 256px; - height: 432px; - } - #viewer iframe { - width: 256px; - height: 432px; - } + #viewer { + width: 256px; + height: 432px; + } + + #viewer iframe { + width: 256px; + height: 432px; + } } /* For iPhone landscape layouts only */ @media only screen and (max-device-width: 374px) and (orientation: landscape) { - #viewer iframe { - width: 256px; - height: 124px; - } + #viewer iframe { + width: 256px; + height: 124px; + } } -[class^="icon-"]:before, [class*=" icon-"]:before { - font-family: "fontello", serif; - font-style: normal; - font-weight: normal; - speak: none; - display: inline-block; - text-decoration: inherit; - width: 1em; - margin-right: 0.2em; - text-align: center; - /* For safety - reset parent styles, that can break glyph codes*/ - font-variant: normal; - text-transform: none; - /* you can be more comfortable with increased icons size */ - font-size: 112%; +[class^="icon-"]::before, +[class*=" icon-"]::before { + font-family: "fontello", serif; + font-style: normal; + font-weight: normal; + speak: none; + display: inline-block; + text-decoration: inherit; + width: 1em; + margin-right: 0.2em; + text-align: center; + + /* For safety - reset parent styles, that can break glyph codes */ + font-variant: normal; + text-transform: none; + + /* you can be more comfortable with increased icons size */ + font-size: 112%; } -.icon-search:before { content: '\e807'; } /* '' */ -.icon-resize-full-1:before { content: '\e804'; } /* '' */ -.icon-cancel-circled2:before { content: '\e80f'; } /* '' */ -.icon-link:before { content: '\e80d'; } /* '' */ -.icon-bookmark:before { content: '\e805'; } /* '' */ -.icon-bookmark-empty:before { content: '\e806'; } /* '' */ -.icon-download-cloud:before { content: '\e811'; } /* '' */ -.icon-edit:before { content: '\e814'; } /* '' */ -.icon-menu:before { content: '\e802'; } /* '' */ -.icon-cog:before { content: '\e813'; } /* '' */ -.icon-resize-full:before { content: '\e812'; } /* '' */ -.icon-cancel-circled:before { content: '\e80e'; } /* '' */ -.icon-up-dir:before { content: '\e80c'; } /* '' */ -.icon-right-dir:before { content: '\e80b'; } /* '' */ -.icon-angle-right:before { content: '\e809'; } /* '' */ -.icon-angle-down:before { content: '\e80a'; } /* '' */ -.icon-right:before { content: '\e815'; } /* '' */ -.icon-list-1:before { content: '\e803'; } /* '' */ -.icon-list-numbered:before { content: '\e801'; } /* '' */ -.icon-columns:before { content: '\e810'; } /* '' */ -.icon-list:before { content: '\e800'; } /* '' */ -.icon-resize-small:before { content: '\e808'; } /* '' */ +.icon-search::before { content: '\e807'; } /* '' */ +.icon-resize-full-1::before { content: '\e804'; } /* '' */ +.icon-cancel-circled2::before { content: '\e80f'; } /* '' */ +.icon-link::before { content: '\e80d'; } /* '' */ +.icon-bookmark::before { content: '\e805'; } /* '' */ +.icon-bookmark-empty::before { content: '\e806'; } /* '' */ +.icon-download-cloud::before { content: '\e811'; } /* '' */ +.icon-edit::before { content: '\e814'; } /* '' */ +.icon-menu::before { content: '\e802'; } /* '' */ +.icon-cog::before { content: '\e813'; } /* '' */ +.icon-resize-full::before { content: '\e812'; } /* '' */ +.icon-cancel-circled::before { content: '\e80e'; } /* '' */ +.icon-up-dir::before { content: '\e80c'; } /* '' */ +.icon-right-dir::before { content: '\e80b'; } /* '' */ +.icon-angle-right::before { content: '\e809'; } /* '' */ +.icon-angle-down::before { content: '\e80a'; } /* '' */ +.icon-right::before { content: '\e815'; } /* '' */ +.icon-list-1::before { content: '\e803'; } /* '' */ +.icon-list-numbered::before { content: '\e801'; } /* '' */ +.icon-columns::before { content: '\e810'; } /* '' */ +.icon-list::before { content: '\e800'; } /* '' */ +.icon-resize-small::before { content: '\e808'; } /* '' */ diff --git a/cps/static/css/style.css b/cps/static/css/style.css index 8c99aaa0..02658771 100644 --- a/cps/static/css/style.css +++ b/cps/static/css/style.css @@ -1,7 +1,7 @@ .tooltip.bottom .tooltip-inner { font-size: 13px; - font-family: Open Sans Semibold,Helvetica Neue,Helvetica,Arial,sans-serif; + font-family: Open Sans Semibold, Helvetica Neue, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; padding: 3px 10px; @@ -28,6 +28,11 @@ html.http-error { height: 100%; } +body { + background: #f2f2f2; + margin-bottom: 40px; +} + .http-error body { margin: 0; height: 100%; @@ -41,32 +46,39 @@ html.http-error { text-align: center; } -body { - background: #f2f2f2; - margin-bottom: 40px; -} - body h2 { font-weight: normal; - color:#444; + color: #444; } -a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d; } - -.book-remove:hover { color: #23527c; } - +a, +.danger, +.book-remove, +.editable-empty, +.editable-empty:hover { color: #45b29d; } +.user-remove:hover { color: #23527c; } .btn-default a { color: #444; } +.panel-title > a { text-decoration: none; } + +.navigation li a { + color: #444; + text-decoration: none; + display: block; + padding: 10px; +} .btn-default a:hover { - color: #45b29d; - text-decoration: None; + color: #45b29d; + text-decoration: None; } .btn-default:hover { - color: #45b29d; + color: #45b29d; } -.editable-click, a.editable-click, a.editable-click:hover { border-bottom: None; } +.editable-click, +a.editable-click, +a.editable-click:hover { border-bottom: None; } .navigation .nav-head { text-transform: uppercase; @@ -79,11 +91,17 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d padding-top: 20px; } -.navigation li a { - color: #444; +.book-meta .tags a { display: inline; } +table .bg-primary a { color: #fff; } +table .bg-dark-danger a { color: #fff; } +.book-meta .identifiers a { display: inline; } + +.navigation .create-shelf a { + color: #fff; + background: #45b29d; + padding: 10px 20px; + border-radius: 5px; text-decoration: none; - display: block; - padding: 10px; } .navigation li a:hover { @@ -99,14 +117,6 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d text-align: center; } -.navigation .create-shelf a { - color: #fff; - background: #45b29d; - padding: 10px 20px; - border-radius: 5px; - text-decoration: none; -} - .row.display-flex { display: flex; flex-wrap: wrap; @@ -119,25 +129,41 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d max-height: 100%; } -.container-fluid .discover{ margin-bottom: 50px; } +.container-fluid .discover { margin-bottom: 50px; } .container-fluid .new-books { border-top: 1px solid #ccc; } .container-fluid .new-books h2 { margin: 50px 0 0 0; } + .container-fluid .book { margin-top: 20px; display: flex; flex-direction: column; } +.cover { margin-bottom: 10px; } .container-fluid .book .cover { height: 225px; position: relative; } +.author-link img { + display: block; + height: 100%; +} + .container-fluid .book .cover span.img { bottom: 0; height: 100%; position: absolute; } +.author-bio img { margin: 0 1em 1em 0; } + +.container-fluid .single .cover img { + border: 1px solid #fff; + box-sizing: border-box; + -webkit-box-shadow: 0 5px 8px -6px #777; + -moz-box-shadow: 0 5px 8px -6px #777; + box-shadow: 0 5px 8px -6px #777; +} .container-fluid .book .cover span img { position: relative; @@ -152,6 +178,7 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d } .container-fluid .book .meta { margin-top: 10px; } +.media-body p { text-align: justify; } .container-fluid .book .meta p { margin: 0; } .container-fluid .book .meta .title { @@ -174,9 +201,10 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d .container-fluid .book .meta .rating { margin-top: 5px; } .rating .glyphicon-star-empty { color: #444; } .rating .glyphicon-star.good { color: #444; } -.rating-clear .glyphicon-remove { color: #333 } +.rating-clear .glyphicon-remove { color: #333; } -.container-fluid .author .author-hidden, .container-fluid .author .author-hidden-divider { display: none; } +.container-fluid .author .author-hidden, +.container-fluid .author .author-hidden-divider { display: none; } .navbar-brand { font-family: 'Grand Hotel', cursive; @@ -190,7 +218,7 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d border-top: 1px solid #ccc; } -.more-stuff>li { margin-bottom: 10px; } +.more-stuff > li { margin-bottom: 10px; } .navbar-collapse.in .navbar-nav { margin: 0; } span.glyphicon.glyphicon-tags { @@ -200,30 +228,20 @@ span.glyphicon.glyphicon-tags { } .book-meta { padding-bottom: 20px; } -.book-meta .tags a { display: inline; } -.book-meta .identifiers a { display: inline; } -.container-fluid .single .cover img { - border: 1px solid #fff; - box-sizing: border-box; - -webkit-box-shadow: 0 5px 8px -6px #777; - -moz-box-shadow: 0 5px 8px -6px #777; - box-shadow: 0 5px 8px -6px #777; +.navbar-default .navbar-toggle .icon-bar { background-color: #000; } +.navbar-default .navbar-toggle { border-color: #000; } + +.cover .badge { + position: absolute; + top: 2px; + left: 2px; + color: #000; + border-radius: 10px; + background-color: #fff; } -.navbar-default .navbar-toggle .icon-bar {background-color: #000; } -.navbar-default .navbar-toggle {border-color: #000; } -.cover { margin-bottom: 10px; } - -.cover .badge{ - position: absolute; - top: 2px; - left: 2px; - color: #000; - border-radius: 10px; - background-color: #fff; -} -.cover .read{ +.cover .read { left: auto; right: 2px; width: 17px; @@ -231,14 +249,17 @@ span.glyphicon.glyphicon-tags { display: inline-block; padding: 2px; } -.cover-height { max-height: 100px;} +.cover-height { max-height: 100px; } .col-sm-2 a .cover-small { margin: 5px; max-height: 200px; } -.btn-file {position: relative; overflow: hidden;} +.btn-file { + position: relative; + overflow: hidden; +} .btn-file input[type=file] { position: absolute; @@ -256,24 +277,60 @@ span.glyphicon.glyphicon-tags { display: block; } -.btn-toolbar .btn,.discover .btn { margin-bottom: 5px; } -.button-link {color: #fff; } -.btn-primary:hover, .btn-primary:focus, .btn-primary:active, .btn-primary.active, .open .dropdown-toggle.btn-primary{ background-color: #1C5484; } -.btn-primary.disabled, .btn-primary[disabled], fieldset[disabled] .btn-primary, .btn-primary.disabled:hover, .btn-primary[disabled]:hover, fieldset[disabled] .btn-primary:hover, .btn-primary.disabled:focus, .btn-primary[disabled]:focus, fieldset[disabled] .btn-primary:focus, .btn-primary.disabled:active, .btn-primary[disabled]:active, fieldset[disabled] .btn-primary:active, .btn-primary.disabled.active, .btn-primary[disabled].active, fieldset[disabled] .btn-primary.active { background-color: #89B9E2; } -.btn-toolbar>.btn+.btn, .btn-toolbar>.btn-group+.btn, .btn-toolbar>.btn+.btn-group, .btn-toolbar>.btn-group+.btn-group { margin-left: 0; } -.panel-body {background-color: #f5f5f5; } -.spinner {margin: 0 41%; } -.spinner2 {margin: 0 41%; } -.intend-form { margin-left:20px; } -table .bg-dark-danger {background-color: #d9534f; color: #fff; } -table .bg-dark-danger a {color: #fff; } -table .bg-dark-danger:hover {background-color: #c9302c; } -table .bg-primary:hover {background-color: #1C5484; } -table .bg-primary a {color: #fff; } -.block-label {display: block;} -.fake-input {position: absolute; pointer-events: none; top: 0; } +.btn-toolbar .btn, +.discover .btn { margin-bottom: 5px; } +.button-link { color: #fff; } -input.pill { position: absolute; opacity: 0; } +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { background-color: #1c5484; } + +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { background-color: #89b9e2; } + +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group, +.btn-toolbar > .btn-group + .btn-group { margin-left: 0; } + +.panel-body { background-color: #f5f5f5; } +.spinner { margin: 0 41%; } +.spinner2 { margin: 0 41%; } +.intend-form { margin-left: 20px; } + +table .bg-dark-danger { + background-color: #d9534f; + color: #fff; +} +table .bg-dark-danger:hover { background-color: #c9302c; } +table .bg-primary:hover { background-color: #1c5484; } +.block-label { display: block; } + +.fake-input { + position: absolute; + pointer-events: none; + top: 0; +} + +input.pill { + position: absolute; + opacity: 0; +} input.pill + label { border: 2px solid #45b29d; @@ -295,12 +352,18 @@ input.pill:checked + label { input.pill:not(:checked) + label .glyphicon { display: none; } -.author-bio img { margin: 0 1em 1em 0; } -.author-link { display: inline-block; margin-top: 10px; width: 100px; } -.author-link img { display: block; height: 100%; } -#remove-from-shelves .btn, #shelf-action-errors { margin-left: 5px; } +.author-link { + display: inline-block; + margin-top: 10px; + width: 100px; +} -.tags_click, .serie_click, .language_click { margin-right: 5px; } +#remove-from-shelves .btn, +#shelf-action-errors { margin-left: 5px; } + +.tags_click, +.serie_click, +.language_click { margin-right: 5px; } #meta-info { height: 600px; @@ -308,7 +371,6 @@ input.pill:not(:checked) + label .glyphicon { display: none; } } .media-list { padding-right: 15px; } -.media-body p { text-align: justify; } #meta-info img { max-height: 150px; @@ -321,13 +383,13 @@ input.pill:not(:checked) + label .glyphicon { display: none; } #btn-upload-format { display: none; } .upload-cover-input-text { display: initial; } #btn-upload-cover { display: none; } -.panel-title > a { text-decoration: none; } + .editable-buttons { - display:inline-block; + display: inline-block; margin-left: 7px; } -.editable-input { display:inline-block; } +.editable-input { display: inline-block; } .editable-cancel { margin-bottom: 0 !important; @@ -354,4 +416,3 @@ div.log { white-space: nowrap; padding: 0.5em; } - diff --git a/cps/static/js/caliBlur.js b/cps/static/js/caliBlur.js index d4c43bcc..45166834 100644 --- a/cps/static/js/caliBlur.js +++ b/cps/static/js/caliBlur.js @@ -710,7 +710,7 @@ $(".navbar-collapse.collapse.in").before('
') // Get rid of leading white space recentlyAdded = $("#nav_new a:contains('Recently')").text().trim(); $("#nav_new a:contains('Recently')").contents().filter(function () { - return this.nodeType == 3 + return this.nodeType === 3 }).each(function () { this.textContent = this.textContent.replace(" Recently Added", recentlyAdded); }); diff --git a/cps/static/js/edit_books.js b/cps/static/js/edit_books.js index b7890764..8cedf688 100644 --- a/cps/static/js/edit_books.js +++ b/cps/static/js/edit_books.js @@ -1,7 +1,7 @@ /** * Created by SpeedProg on 05.04.2015. */ -/* global Bloodhound, language, Modernizr, tinymce */ +/* global Bloodhound, language, Modernizr, tinymce, getPath */ if ($("#description").length) { tinymce.init({ @@ -250,14 +250,14 @@ promisePublishers.done(function() { }); $("#search").on("change input.typeahead:selected", function(event) { - if (event.target.type == "search" && event.target.tagName == "INPUT") { + if (event.target.type === "search" && event.target.tagName === "INPUT") { return; } var form = $("form").serialize(); $.getJSON( getPath() + "/get_matching_tags", form, function( data ) { $(".tags_click").each(function() { if ($.inArray(parseInt($(this).val(), 10), data.tags) === -1) { - if(!$(this).prop("selected")) { + if (!$(this).prop("selected")) { $(this).prop("disabled", true); } } else { @@ -265,10 +265,10 @@ $("#search").on("change input.typeahead:selected", function(event) { } }); $("#include_tag option:selected").each(function () { - $("#exclude_tag").find("[value="+$(this).val()+"]").prop("disabled", true); + $("#exclude_tag").find("[value=" + $(this).val() + "]").prop("disabled", true); }); - $('#include_tag').selectpicker("refresh"); - $('#exclude_tag').selectpicker("refresh"); + $("#include_tag").selectpicker("refresh"); + $("#exclude_tag").selectpicker("refresh"); }); }); diff --git a/cps/static/js/filter_grid.js b/cps/static/js/filter_grid.js index 362c6bfa..d57d155f 100644 --- a/cps/static/js/filter_grid.js +++ b/cps/static/js/filter_grid.js @@ -36,7 +36,6 @@ $("#desc").click(function() { sortBy: "name", sortAscending: true }); - return; }); $("#asc").click(function() { @@ -52,19 +51,20 @@ $("#asc").click(function() { sortBy: "name", sortAscending: false }); - return; }); $("#all").click(function() { // go through all elements and make them visible $list.isotope({ filter: function() { return true; - } }) + } + }); }); $(".char").click(function() { var character = this.innerText; $list.isotope({ filter: function() { - return this.attributes["data-id"].value.charAt(0).toUpperCase() == character; - } }) + return this.attributes["data-id"].value.charAt(0).toUpperCase() === character; + } + }); }); diff --git a/cps/static/js/filter_list.js b/cps/static/js/filter_list.js index 679c5359..ef7639fa 100644 --- a/cps/static/js/filter_list.js +++ b/cps/static/js/filter_list.js @@ -88,7 +88,7 @@ $("#desc").click(function() { // Find count of middle element var count = $(".row:visible").length; if (count > 20) { - middle = parseInt(count / 2) + (count % 2); + middle = parseInt(count / 2, 10) + (count % 2); //var middle = parseInt(count / 2) + (count % 2); // search for the middle of all visible elements @@ -135,7 +135,7 @@ $("#asc").click(function() { // Find count of middle element var count = $(".row:visible").length; if (count > 20) { - var middle = parseInt(count / 2) + (count % 2); + var middle = parseInt(count / 2, 10) + (count % 2); //var middle = parseInt(count / 2) + (count % 2); // search for the middle of all visible elements diff --git a/cps/static/js/get_meta.js b/cps/static/js/get_meta.js index d3e0eb46..04c1d270 100644 --- a/cps/static/js/get_meta.js +++ b/cps/static/js/get_meta.js @@ -138,8 +138,8 @@ $(function () { seriesTitle = result.series.title; } var dateFomers = result.pubdate.split("-"); - var publishedYear = parseInt(dateFomers[0]); - var publishedMonth = parseInt(dateFomers[1]); + var publishedYear = parseInt(dateFomers[0], 10); + var publishedMonth = parseInt(dateFomers[1], 10); var publishedDate = new Date(publishedYear, publishedMonth - 1, 1); publishedDate = formatDate(publishedDate); @@ -194,8 +194,8 @@ $(function () { } else { dateFomers = result.date_added.split("-"); } - var publishedYear = parseInt(dateFomers[0]); - var publishedMonth = parseInt(dateFomers[1]); + var publishedYear = parseInt(dateFomers[0], 10); + var publishedMonth = parseInt(dateFomers[1], 10); var publishedDate = new Date(publishedYear, publishedMonth - 1, 1); publishedDate = formatDate(publishedDate); diff --git a/cps/static/js/main.js b/cps/static/js/main.js index e0f2dfe7..fea85990 100644 --- a/cps/static/js/main.js +++ b/cps/static/js/main.js @@ -38,10 +38,10 @@ $(document).on("change", "input[type=\"checkbox\"][data-control]", function () { $(document).on("change", "select[data-control]", function() { var $this = $(this); var name = $this.data("control"); - var showOrHide = parseInt($this.val()); + var showOrHide = parseInt($this.val(), 10); // var showOrHideLast = $("#" + name + " option:last").val() for (var i = 0; i < $(this)[0].length; i++) { - var element = parseInt($(this)[0][i].value); + var element = parseInt($(this)[0][i].value, 10); if (element === showOrHide) { $("[data-related^=" + name + "][data-related*=-" + element + "]").show(); } else { @@ -55,7 +55,7 @@ $(document).on("change", "select[data-control]", function() { $(document).on("change", "select[data-controlall]", function() { var $this = $(this); var name = $this.data("controlall"); - var showOrHide = parseInt($this.val()); + var showOrHide = parseInt($this.val(), 10); if (showOrHide) { $("[data-related=" + name + "]").show(); } else { @@ -114,7 +114,7 @@ $(document).ready(function() { } }); -function ConfirmDialog(id, dataValue, yesFn, noFn) { +function confirmDialog(id, dataValue, yesFn, noFn) { var $confirm = $("#GeneralDeleteModal"); // var dataValue= e.data('value'); // target.data('value'); $confirm.modal('show'); @@ -481,7 +481,7 @@ $(function() { }); $("#config_delete_kobo_token").click(function() { - ConfirmDialog( + confirmDialog( $(this).attr('id'), $(this).data('value'), function (value) { @@ -509,7 +509,7 @@ $(function() { }); $("#btndeluser").click(function() { - ConfirmDialog( + confirmDialog( $(this).attr('id'), $(this).data('value'), function(value){ @@ -527,7 +527,7 @@ $(function() { }); $("#delete_shelf").click(function() { - ConfirmDialog( + confirmDialog( $(this).attr('id'), $(this).data('value'), function(value){ diff --git a/cps/static/js/table.js b/cps/static/js/table.js index 2cf4c6a2..a27b998e 100644 --- a/cps/static/js/table.js +++ b/cps/static/js/table.js @@ -16,6 +16,7 @@ */ /* exported TableActions, RestrictionActions, EbookActions, responseHandler */ +/* global getPath, confirmDialog */ var selections = []; @@ -209,7 +210,7 @@ $(function() { striped: false }); - function domain_handle(domainId) { + function domainHandle(domainId) { $.ajax({ method:"post", url: window.location.pathname + "/../../ajax/deletedomain", @@ -236,12 +237,12 @@ $(function() { } $("#domain-allow-table").on("click-cell.bs.table", function (field, value, row, $element) { if (value === 2) { - ConfirmDialog("btndeletedomain", $element.id, domain_handle); + confirmDialog("btndeletedomain", $element.id, domainHandle); } }); $("#domain-deny-table").on("click-cell.bs.table", function (field, value, row, $element) { if (value === 2) { - ConfirmDialog("btndeletedomain", $element.id, domain_handle); + confirmDialog("btndeletedomain", $element.id, domainHandle); } }); @@ -255,12 +256,12 @@ $(function() { $("#h3").addClass("hidden"); $("#h4").addClass("hidden"); }); - function startTable(type, user_id) { + function startTable(type, userId) { $("#restrict-elements-table").bootstrapTable({ formatNoMatches: function () { return ""; }, - url: getPath() + "/ajax/listrestriction/" + type + "/" + user_id, + url: getPath() + "/ajax/listrestriction/" + type + "/" + userId, rowStyle: function(row) { // console.log('Reihe :' + row + " Index :" + index); if (row.id.charAt(0) === "a") { @@ -274,13 +275,13 @@ $(function() { $.ajax ({ type: "Post", data: "id=" + row.id + "&type=" + row.type + "&Element=" + encodeURIComponent(row.Element), - url: getPath() + "/ajax/deleterestriction/" + type + "/" + user_id, + url: getPath() + "/ajax/deleterestriction/" + type + "/" + userId, async: true, timeout: 900, success:function() { $.ajax({ method:"get", - url: getPath() + "/ajax/listrestriction/" + type + "/" + user_id, + url: getPath() + "/ajax/listrestriction/" + type + "/" + userId, async: true, timeout: 900, success:function(data) { @@ -296,7 +297,7 @@ $(function() { $("#restrict-elements-table").removeClass("table-hover"); $("#restrict-elements-table").on("editable-save.bs.table", function (e, field, row) { $.ajax({ - url: getPath() + "/ajax/editrestriction/" + type + "/" + user_id, + url: getPath() + "/ajax/editrestriction/" + type + "/" + userId, type: "Post", data: row }); @@ -304,13 +305,13 @@ $(function() { $("[id^=submit_]").click(function() { $(this)[0].blur(); $.ajax({ - url: getPath() + "/ajax/addrestriction/" + type + "/" + user_id, + url: getPath() + "/ajax/addrestriction/" + type + "/" + userId, type: "Post", data: $(this).closest("form").serialize() + "&" + $(this)[0].name + "=", success: function () { $.ajax ({ method:"get", - url: getPath() + "/ajax/listrestriction/" + type + "/" + user_id, + url: getPath() + "/ajax/listrestriction/" + type + "/" + userId, async: true, timeout: 900, success:function(data) { @@ -332,12 +333,12 @@ $(function() { $("#h1").removeClass("hidden"); }); $("#get_user_column_values").on("click", function() { - startTable(3, $(this).data('id')); + startTable(3, $(this).data("id")); $("#h4").removeClass("hidden"); }); $("#get_user_tags").on("click", function() { - startTable(2, $(this).data('id')); + startTable(2, $(this).data("id")); $(this)[0].blur(); $("#h3").removeClass("hidden"); }); diff --git a/cps/tasks/upload.py b/cps/tasks/upload.py index ce2cb07b..d7ef34c2 100644 --- a/cps/tasks/upload.py +++ b/cps/tasks/upload.py @@ -12,7 +12,6 @@ class TaskUpload(CalibreTask): def run(self, worker_thread): """Upload task doesn't have anything to do, it's simply a way to add information to the task list""" - pass @property def name(self): diff --git a/cps/ub.py b/cps/ub.py index 1969ef53..967ac0c5 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -138,15 +138,15 @@ class UserBase: mct = self.allowed_column_value or "" return [t.strip() for t in mct.split(",")] - def get_view_property(self, page, property): + def get_view_property(self, page, prop): if not self.view_settings.get(page): return None - return self.view_settings[page].get(property) + return self.view_settings[page].get(prop) - def set_view_property(self, page, property, value): + def set_view_property(self, page, prop, value): if not self.view_settings.get(page): self.view_settings[page] = dict() - self.view_settings[page][property] = value + self.view_settings[page][prop] = value try: flag_modified(self, "view_settings") except AttributeError: @@ -437,11 +437,8 @@ class RemoteAuthToken(Base): return '