{% endif %}
{% if g.user.is_authenticated %}
{% if (g.user.role_edit_shelfs() and shelf.is_public ) or not shelf.is_public %}
@@ -17,21 +17,21 @@
{% for entry in entries %}
diff --git a/cps/templates/shelf_edit.html b/cps/templates/shelf_edit.html
index e9bc1523..d7f32dc4 100644
--- a/cps/templates/shelf_edit.html
+++ b/cps/templates/shelf_edit.html
@@ -16,7 +16,7 @@
{% endif %}
{{_('Submit')}}
{% if shelf.id != None %}
-
{{_('Back')}}
+
{{_('Back')}}
{% endif %}
diff --git a/cps/ub.py b/cps/ub.py
index 177f9ce9..ba69c4ec 100644
--- a/cps/ub.py
+++ b/cps/ub.py
@@ -35,6 +35,8 @@ import cli
engine = create_engine('sqlite:///{0}'.format(cli.settingspath), echo=False)
Base = declarative_base()
+session = None
+
ROLE_USER = 0
ROLE_ADMIN = 1
ROLE_DOWNLOAD = 2
@@ -849,22 +851,23 @@ def create_admin_user():
except Exception:
session.rollback()
-
-# Open session for database connection
-Session = sessionmaker()
-Session.configure(bind=engine)
-session = Session()
-
-
-if not os.path.exists(cli.settingspath):
- try:
+def init_db():
+ # Open session for database connection
+ global session
+ Session = sessionmaker()
+ Session.configure(bind=engine)
+ session = Session()
+
+
+ if not os.path.exists(cli.settingspath):
+ try:
+ Base.metadata.create_all(engine)
+ create_default_config()
+ create_admin_user()
+ create_anonymous_user()
+ except Exception:
+ raise
+ else:
Base.metadata.create_all(engine)
- create_default_config()
- create_admin_user()
- create_anonymous_user()
- except Exception:
- raise
-else:
- Base.metadata.create_all(engine)
- migrate_Database()
- clean_database()
+ migrate_Database()
+ clean_database()
diff --git a/cps/updater.py b/cps/updater.py
index 91d86660..b01646a0 100644
--- a/cps/updater.py
+++ b/cps/updater.py
@@ -17,26 +17,25 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see
.
+
+from cps import config, get_locale
import threading
import zipfile
import requests
-import re
import logging
-import server
import time
from io import BytesIO
import os
import sys
import shutil
-from cps import config
from ub import UPDATE_STABLE
from tempfile import gettempdir
import datetime
import json
from flask_babel import gettext as _
from babel.dates import format_datetime
-import web
+import server
def is_sha1(sha1):
if len(sha1) != 40:
@@ -288,7 +287,7 @@ class Updater(threading.Thread):
update_data['committer']['date'], '%Y-%m-%dT%H:%M:%SZ') - tz
parents.append(
[
- format_datetime(new_commit_date, format='short', locale=web.get_locale()),
+ format_datetime(new_commit_date, format='short', locale=get_locale()),
update_data['message'],
update_data['sha']
]
@@ -318,7 +317,7 @@ class Updater(threading.Thread):
parent_commit_date = datetime.datetime.strptime(
parent_data['committer']['date'], '%Y-%m-%dT%H:%M:%SZ') - tz
parent_commit_date = format_datetime(
- parent_commit_date, format='short', locale=web.get_locale())
+ parent_commit_date, format='short', locale=get_locale())
parents.append([parent_commit_date,
parent_data['message'].replace('\r\n','
').replace('\n','
')])
@@ -346,7 +345,7 @@ class Updater(threading.Thread):
commit['committer']['date'], '%Y-%m-%dT%H:%M:%SZ') - tz
parents.append(
[
- format_datetime(new_commit_date, format='short', locale=web.get_locale()),
+ format_datetime(new_commit_date, format='short', locale=get_locale()),
commit['message'],
commit['sha']
]
@@ -376,7 +375,7 @@ class Updater(threading.Thread):
parent_commit_date = datetime.datetime.strptime(
parent_data['committer']['date'], '%Y-%m-%dT%H:%M:%SZ') - tz
parent_commit_date = format_datetime(
- parent_commit_date, format='short', locale=web.get_locale())
+ parent_commit_date, format='short', locale=get_locale())
parents.append([parent_commit_date, parent_data['message'], parent_data['sha']])
parent_commit = parent_data['parents'][0]
@@ -510,6 +509,3 @@ class Updater(threading.Thread):
status['message'] = _(u'General error')
return status, commit
-
-
-updater_thread = Updater()
diff --git a/cps/uploader.py b/cps/uploader.py
index 8d9b74a4..df516d24 100644
--- a/cps/uploader.py
+++ b/cps/uploader.py
@@ -17,11 +17,14 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-import os
+# import os
from tempfile import gettempdir
import hashlib
from collections import namedtuple
-import book_formats
+import logging
+import os
+from flask_babel import gettext as _
+import comic
BookMeta = namedtuple('BookMeta', 'file_path, extension, title, author, cover, description, tags, series, series_id, languages')
@@ -29,6 +32,158 @@ BookMeta = namedtuple('BookMeta', 'file_path, extension, title, author, cover, d
:rtype: BookMeta
"""
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
+# Copyright (C) 2016-2019 lemmsh cervinko Kennyl matthazinski OzzieIsaacs
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+try:
+ from lxml.etree import LXML_VERSION as lxmlversion
+except ImportError:
+ lxmlversion = None
+
+__author__ = 'lemmsh'
+
+logger = logging.getLogger("book_formats")
+
+try:
+ from wand.image import Image
+ from wand import version as ImageVersion
+ use_generic_pdf_cover = False
+except (ImportError, RuntimeError) as e:
+ logger.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e)
+ use_generic_pdf_cover = True
+try:
+ from PyPDF2 import PdfFileReader
+ from PyPDF2 import __version__ as PyPdfVersion
+ use_pdf_meta = True
+except ImportError as e:
+ logger.warning('cannot import PyPDF2, extracting pdf metadata will not work: %s', e)
+ use_pdf_meta = False
+
+try:
+ import epub
+ use_epub_meta = True
+except ImportError as e:
+ logger.warning('cannot import epub, extracting epub metadata will not work: %s', e)
+ use_epub_meta = False
+
+try:
+ import fb2
+ use_fb2_meta = True
+except ImportError as e:
+ logger.warning('cannot import fb2, extracting fb2 metadata will not work: %s', e)
+ use_fb2_meta = False
+
+
+def process(tmp_file_path, original_file_name, original_file_extension):
+ meta = None
+ try:
+ if ".PDF" == original_file_extension.upper():
+ meta = pdf_meta(tmp_file_path, original_file_name, original_file_extension)
+ if ".EPUB" == original_file_extension.upper() and use_epub_meta is True:
+ meta = epub.get_epub_info(tmp_file_path, original_file_name, original_file_extension)
+ if ".FB2" == original_file_extension.upper() and use_fb2_meta is True:
+ meta = fb2.get_fb2_info(tmp_file_path, original_file_extension)
+ if original_file_extension.upper() in ['.CBZ', '.CBT']:
+ meta = comic.get_comic_info(tmp_file_path, original_file_name, original_file_extension)
+
+ except Exception as ex:
+ logger.warning('cannot parse metadata, using default: %s', ex)
+
+ if meta and meta.title.strip() and meta.author.strip():
+ return meta
+ else:
+ return default_meta(tmp_file_path, original_file_name, original_file_extension)
+
+
+def default_meta(tmp_file_path, original_file_name, original_file_extension):
+ return BookMeta(
+ file_path=tmp_file_path,
+ extension=original_file_extension,
+ title=original_file_name,
+ author=u"Unknown",
+ cover=None,
+ description="",
+ tags="",
+ series="",
+ series_id="",
+ languages="")
+
+
+def pdf_meta(tmp_file_path, original_file_name, original_file_extension):
+
+ if use_pdf_meta:
+ pdf = PdfFileReader(open(tmp_file_path, 'rb'))
+ doc_info = pdf.getDocumentInfo()
+ else:
+ doc_info = None
+
+ if doc_info is not None:
+ author = doc_info.author if doc_info.author else u"Unknown"
+ title = doc_info.title if doc_info.title else original_file_name
+ subject = doc_info.subject
+ else:
+ author = u"Unknown"
+ title = original_file_name
+ subject = ""
+ return BookMeta(
+ file_path=tmp_file_path,
+ extension=original_file_extension,
+ title=title,
+ author=author,
+ cover=pdf_preview(tmp_file_path, original_file_name),
+ description=subject,
+ tags="",
+ series="",
+ series_id="",
+ languages="")
+
+
+def pdf_preview(tmp_file_path, tmp_dir):
+ if use_generic_pdf_cover:
+ return None
+ else:
+ cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg"
+ with Image(filename=tmp_file_path + "[0]", resolution=150) as img:
+ img.compression_quality = 88
+ img.save(filename=os.path.join(tmp_dir, cover_file_name))
+ return cover_file_name
+
+
+def get_versions():
+ if not use_generic_pdf_cover:
+ IVersion = ImageVersion.MAGICK_VERSION
+ WVersion = ImageVersion.VERSION
+ else:
+ IVersion = _(u'not installed')
+ WVersion = _(u'not installed')
+ if use_pdf_meta:
+ PVersion='v'+PyPdfVersion
+ else:
+ PVersion=_(u'not installed')
+ if lxmlversion:
+ XVersion = 'v'+'.'.join(map(str, lxmlversion))
+ else:
+ XVersion = _(u'not installed')
+ return {'Image Magick': IVersion, 'PyPdf': PVersion, 'lxml':XVersion, 'Wand Version': WVersion}
+
def upload(uploadfile):
tmp_dir = os.path.join(gettempdir(), 'calibre_web')
diff --git a/cps/web.py b/cps/web.py
index 36728b7c..346cb005 100644
--- a/cps/web.py
+++ b/cps/web.py
@@ -21,33 +21,21 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-import mimetypes
-import logging
-from flask import (Flask, session, render_template, request, Response, redirect,
- url_for, send_from_directory, make_response, g, flash,
- abort, Markup)
-from flask import __version__ as flaskVersion
-from werkzeug import __version__ as werkzeugVersion
+from cps import mimetypes, global_WorkerThread, searched_ids
+from flask import render_template, request, redirect, url_for, send_from_directory, make_response, g, flash, abort
# from werkzeug.exceptions import default_exceptions
-
-from jinja2 import __version__ as jinja2Version
import helper
import os
# from sqlalchemy.sql.expression import func
# from sqlalchemy.sql.expression import false
from sqlalchemy.exc import IntegrityError
-from sqlalchemy import __version__ as sqlalchemyVersion
-from flask_login import (login_user, logout_user,
- login_required, current_user)
-from flask_principal import __version__ as flask_principalVersion
+from flask_login import login_user, logout_user, login_required, current_user
from flask_babel import gettext as _
-import requests
+
from werkzeug.security import generate_password_hash, check_password_hash
from werkzeug.datastructures import Headers
from babel import Locale as LC
-from babel import negotiate_locale
-from babel import __version__ as babelVersion
-from babel.dates import format_date, format_datetime
+from babel.dates import format_date
from babel.core import UnknownLocaleError
from functools import wraps
import base64
@@ -55,30 +43,14 @@ from sqlalchemy.sql import *
import json
import datetime
from iso639 import languages as isoLanguages
-from iso639 import __version__ as iso639Version
-from pytz import __version__ as pytzVersion
-from uuid import uuid4
import os.path
-import sys
import re
import db
-from shutil import move, copyfile
import gdriveutils
-import converter
-import tempfile
from redirect import redirect_back
-import time
-import server
-from updater import updater_thread
-#from flask_dance.contrib.github import make_github_blueprint, github
-#from flask_dance.contrib.google import make_google_blueprint, google
-#from flask_dance.consumer import oauth_authorized, oauth_error
-#from sqlalchemy.orm.exc import NoResultFound
-# from oauth import OAuthBackend
-import hashlib
-from cps import lm, babel, ub_session, config, Server
-import ub
+from cps import lm, babel, ub, config, get_locale, language_table, app
from pagination import Pagination
+# from oauth_bb import oauth_check, register_user_with_oauth
try:
from googleapiclient.errors import HttpError
@@ -111,12 +83,7 @@ except ImportError:
try:
from natsort import natsorted as sort
except ImportError:
- sort=sorted # Just use regular sort then
- # may cause issues with badly named pages in cbz/cbr files
-try:
- import cPickle
-except ImportError:
- import pickle as cPickle
+ sort = sorted # Just use regular sort then, may cause issues with badly named pages in cbz/cbr files
try:
from urllib.parse import quote
@@ -124,48 +91,15 @@ try:
except ImportError:
from urllib import quote
-try:
- from flask_login import __version__ as flask_loginVersion
-except ImportError:
- from flask_login.__about__ import __version__ as flask_loginVersion
+from flask import Blueprint
# Global variables
-current_milli_time = lambda: int(round(time.time() * 1000))
-gdrive_watch_callback_token = 'target=calibreweb-watch_files'
-# ToDo: Somehow caused by circular import under python3 refactor
-EXTENSIONS_UPLOAD = {'txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx',
- 'fb2', 'html', 'rtf', 'odt', 'mp3', 'm4a', 'm4b'}
-EXTENSIONS_CONVERT = {'pdf', 'epub', 'mobi', 'azw3', 'docx', 'rtf', 'fb2', 'lit', 'lrf', 'txt', 'html', 'rtf', 'odt'}
+
EXTENSIONS_AUDIO = {'mp3', 'm4a', 'm4b'}
# EXTENSIONS_READER = set(['txt', 'pdf', 'epub', 'zip', 'cbz', 'tar', 'cbt'] + (['rar','cbr'] if rar_support else []))
-oauth_check = {}
-
-
-
-# Main code
-mimetypes.init()
-mimetypes.add_type('application/xhtml+xml', '.xhtml')
-mimetypes.add_type('application/epub+zip', '.epub')
-mimetypes.add_type('application/fb2+zip', '.fb2')
-mimetypes.add_type('application/x-mobipocket-ebook', '.mobi')
-mimetypes.add_type('application/x-mobipocket-ebook', '.prc')
-mimetypes.add_type('application/vnd.amazon.ebook', '.azw')
-mimetypes.add_type('application/x-cbr', '.cbr')
-mimetypes.add_type('application/x-cbz', '.cbz')
-mimetypes.add_type('application/x-cbt', '.cbt')
-mimetypes.add_type('image/vnd.djvu', '.djvu')
-mimetypes.add_type('application/mpeg', '.mpeg')
-mimetypes.add_type('application/mpeg', '.mp3')
-mimetypes.add_type('application/mp4', '.m4a')
-mimetypes.add_type('application/mp4', '.m4b')
-mimetypes.add_type('application/ogg', '.ogg')
-mimetypes.add_type('application/ogg', '.oga')
-
-
-app = (Flask(__name__))
''''# custom error page
def error_http(error):
@@ -181,55 +115,19 @@ for ex in default_exceptions:
if ex < 500:
app.register_error_handler(ex, error_http)
-
-
-# import uploader
-
'''
-from flask import Blueprint
-
web = Blueprint('web', __name__)
-def is_gdrive_ready():
- return os.path.exists(os.path.join(config.get_main_dir, 'settings.yaml')) and \
- os.path.exists(os.path.join(config.get_main_dir, 'gdrive_credentials'))
-
-
-
-@babel.localeselector
-def get_locale():
- # if a user is logged in, use the locale from the user settings
- user = getattr(g, 'user', None)
- if user is not None and hasattr(user, "locale"):
- if user.nickname != 'Guest': # if the account is the guest account bypass the config lang settings
- return user.locale
- translations = [str(item) for item in babel.list_translations()] + ['en']
- preferred = list()
- for x in request.accept_languages.values():
- try:
- preferred.append(str(LC.parse(x.replace('-', '_'))))
- except (UnknownLocaleError, ValueError) as e:
- app.logger.debug("Could not parse locale: %s", e)
- preferred.append('en')
- return negotiate_locale(preferred, translations)
-
-
-@babel.timezoneselector
-def get_timezone():
- user = getattr(g, 'user', None)
- if user is not None:
- return user.timezone
-
-
@lm.user_loader
def load_user(user_id):
try:
- return ub_session.query(ub.User).filter(ub.User.id == int(user_id)).first()
+ return ub.session.query(ub.User).filter(ub.User.id == int(user_id)).first()
except Exception as e:
print(e)
+
@lm.header_loader
def load_user_from_header(header_val):
if header_val.startswith('Basic '):
@@ -247,30 +145,6 @@ def load_user_from_header(header_val):
return
-def check_auth(username, password):
- user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == username.lower()).first()
- return bool(user and check_password_hash(user.password, password))
-
-
-def authenticate():
- return Response(
- 'Could not verify your access level for that URL.\n'
- 'You have to login with proper credentials', 401,
- {'WWW-Authenticate': 'Basic realm="Login Required"'})
-
-
-def requires_basic_auth_if_no_ano(f):
- @wraps(f)
- def decorated(*args, **kwargs):
- auth = request.authorization
- if config.config_anonbrowse != 1:
- if not auth or not check_auth(auth.username, auth.password):
- return authenticate()
- return f(*args, **kwargs)
-
- return decorated
-
-
def login_required_if_no_ano(func):
@wraps(func)
def decorated_view(*args, **kwargs):
@@ -324,85 +198,6 @@ def google_oauth_required(f):
return inner
-# custom jinja filters
-
-# pagination links in jinja
-@web.app_template_filter('url_for_other_page')
-def url_for_other_page(page):
- args = request.view_args.copy()
- args['page'] = page
- return url_for(request.endpoint, **args)
-
-
-# shortentitles to at longest nchar, shorten longer words if necessary
-@web.app_template_filter('shortentitle')
-def shortentitle_filter(s, nchar=20):
- text = s.split()
- res = "" # result
- suml = 0 # overall length
- for line in text:
- if suml >= 60:
- res += '...'
- break
- # if word longer than 20 chars truncate line and append '...', otherwise add whole word to result
- # string, and summarize total length to stop at chars given by nchar
- if len(line) > nchar:
- res += line[:(nchar-3)] + '[..] '
- suml += nchar+3
- else:
- res += line + ' '
- suml += len(line) + 1
- return res.strip()
-
-
-@web.app_template_filter('mimetype')
-def mimetype_filter(val):
- try:
- s = mimetypes.types_map['.' + val]
- except Exception:
- s = 'application/octet-stream'
- return s
-
-
-@web.app_template_filter('formatdate')
-def formatdate_filter(val):
- conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))", '', val)
- formatdate = datetime.datetime.strptime(conformed_timestamp[:15], "%Y%m%d %H%M%S")
- return format_date(formatdate, format='medium', locale=get_locale())
-
-
-@web.app_template_filter('formatdateinput')
-def format_date_input(val):
- conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))", '', val)
- date_obj = datetime.datetime.strptime(conformed_timestamp[:15], "%Y%m%d %H%M%S")
- input_date = date_obj.isoformat().split('T', 1)[0] # Hack to support dates <1900
- return '' if input_date == "0101-01-01" else input_date
-
-
-@web.app_template_filter('strftime')
-def timestamptodate(date, fmt=None):
- date = datetime.datetime.fromtimestamp(
- int(date)/1000
- )
- native = date.replace(tzinfo=None)
- if fmt:
- time_format = fmt
- else:
- time_format = '%d %m %Y - %H:%S'
- return native.strftime(time_format)
-
-
-@web.app_template_filter('yesno')
-def yesno(value, yes, no):
- return yes if value else no
-
-
-'''@web.app_template_filter('canread')
-def canread(ext):
- if isinstance(ext, db.Data):
- ext = ext.format
- return ext.lower() in EXTENSIONS_READER'''
-
def admin_required(f):
"""
@@ -485,6 +280,7 @@ def speaking_language(languages=None):
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
return languages
+
# Orders all Authors in the list according to authors sort
def order_authors(entry):
sort_authors = entry.author_sort.split('&')
@@ -501,6 +297,7 @@ def order_authors(entry):
entry.authors = authors_ordered
return entry
+
# Fill indexpage with all requested data from database
def fill_indexpage(page, database, db_filter, order, *join):
if current_user.show_detail_random():
@@ -510,121 +307,14 @@ def fill_indexpage(page, database, db_filter, order, *join):
randm = false()
off = int(int(config.config_books_per_page) * (page - 1))
pagination = Pagination(page, config.config_books_per_page,
- len(db.session.query(database)
- .filter(db_filter).filter(common_filters()).all()))
- entries = db.session.query(database).join(*join,isouter=True).filter(db_filter)\
- .filter(common_filters()).order_by(*order).offset(off).limit(config.config_books_per_page).all()
+ len(db.session.query(database).filter(db_filter).filter(common_filters()).all()))
+ entries = db.session.query(database).join(*join, isouter=True).filter(db_filter).filter(common_filters()).\
+ order_by(*order).offset(off).limit(config.config_books_per_page).all()
for book in entries:
book = order_authors(book)
return entries, randm, pagination
-# Modifies different Database objects, first check if elements have to be added to database, than check
-# if elements have to be deleted, because they are no longer used
-def modify_database_object(input_elements, db_book_object, db_object, db_session, db_type):
- # passing input_elements not as a list may lead to undesired results
- if not isinstance(input_elements, list):
- raise TypeError(str(input_elements) + " should be passed as a list")
-
- input_elements = [x for x in input_elements if x != '']
- # we have all input element (authors, series, tags) names now
- # 1. search for elements to remove
- del_elements = []
- for c_elements in db_book_object:
- found = False
- if db_type == 'languages':
- type_elements = c_elements.lang_code
- elif db_type == 'custom':
- type_elements = c_elements.value
- else:
- type_elements = c_elements.name
- for inp_element in input_elements:
- if inp_element.lower() == type_elements.lower():
- # if inp_element == type_elements:
- found = True
- break
- # if the element was not found in the new list, add it to remove list
- if not found:
- del_elements.append(c_elements)
- # 2. search for elements that need to be added
- add_elements = []
- for inp_element in input_elements:
- found = False
- for c_elements in db_book_object:
- if db_type == 'languages':
- type_elements = c_elements.lang_code
- elif db_type == 'custom':
- type_elements = c_elements.value
- else:
- type_elements = c_elements.name
- if inp_element == type_elements:
- found = True
- break
- if not found:
- add_elements.append(inp_element)
- # if there are elements to remove, we remove them now
- if len(del_elements) > 0:
- for del_element in del_elements:
- db_book_object.remove(del_element)
- if len(del_element.books) == 0:
- db_session.delete(del_element)
- # if there are elements to add, we add them now!
- if len(add_elements) > 0:
- if db_type == 'languages':
- db_filter = db_object.lang_code
- elif db_type == 'custom':
- db_filter = db_object.value
- else:
- db_filter = db_object.name
- for add_element in add_elements:
- # check if a element with that name exists
- db_element = db_session.query(db_object).filter(db_filter == add_element).first()
- # if no element is found add it
- # if new_element is None:
- if db_type == 'author':
- new_element = db_object(add_element, helper.get_sorted_author(add_element.replace('|', ',')), "")
- elif db_type == 'series':
- new_element = db_object(add_element, add_element)
- elif db_type == 'custom':
- new_element = db_object(value=add_element)
- elif db_type == 'publisher':
- new_element = db_object(add_element, None)
- else: # db_type should be tag or language
- new_element = db_object(add_element)
- if db_element is None:
- db_session.add(new_element)
- db_book_object.append(new_element)
- else:
- if db_type == 'custom':
- if db_element.value != add_element:
- new_element.value = add_element
- # new_element = db_element
- elif db_type == 'languages':
- if db_element.lang_code != add_element:
- db_element.lang_code = add_element
- # new_element = db_element
- elif db_type == 'series':
- if db_element.name != add_element:
- db_element.name = add_element # = add_element # new_element = db_object(add_element, add_element)
- db_element.sort = add_element
- # new_element = db_element
- elif db_type == 'author':
- if db_element.name != add_element:
- db_element.name = add_element
- db_element.sort = add_element.replace('|', ',')
- # new_element = db_element
- elif db_type == 'publisher':
- if db_element.name != add_element:
- db_element.name = add_element
- db_element.sort = None
- # new_element = db_element
- elif db_element.name != add_element:
- db_element.name = add_element
- # new_element = db_element
- # add element to book
- db_book_object.append(db_element)
-
-
# read search results from calibre-database and return it (function is used for feed and simple search
def get_search_results(term):
q = list()
@@ -642,32 +332,12 @@ def get_search_results(term):
db.Books.title.ilike("%" + term + "%"))).all()
-def feed_search(term):
- if term:
- term = term.strip().lower()
- entries = get_search_results( term)
- entriescount = len(entries) if len(entries) > 0 else 1
- pagination = Pagination(1, entriescount, entriescount)
- return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination)
- else:
- return render_xml_template('feed.xml', searchterm="")
-
-
-def render_xml_template(*args, **kwargs):
- #ToDo: return time in current timezone similar to %z
- currtime = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S+00:00")
- xml = render_template(current_time=currtime, *args, **kwargs)
- response = make_response(xml)
- response.headers["Content-Type"] = "application/atom+xml; charset=utf-8"
- return response
-
-
-# Returns the template for redering and includes the instance name
+# Returns the template for rendering and includes the instance name
def render_title_template(*args, **kwargs):
return render_template(instance=config.config_calibre_web_title, *args, **kwargs)
-@web.before_request
+@web.before_app_request
def before_request():
g.user = current_user
g.allow_registration = config.config_public_reg
@@ -678,247 +348,12 @@ def before_request():
return redirect(url_for('web.basic_configuration'))
-# Routing functions
-
-@web.route("/opds")
-@requires_basic_auth_if_no_ano
-def feed_index():
- return render_xml_template('index.xml')
-
-
-@web.route("/opds/osd")
-@requires_basic_auth_if_no_ano
-def feed_osd():
- return render_xml_template('osd.xml', lang='en-EN')
-
-
-@web.route("/opds/search/")
-@requires_basic_auth_if_no_ano
-def feed_cc_search(query):
- return feed_search(query.strip())
-
-
-@web.route("/opds/search", methods=["GET"])
-@requires_basic_auth_if_no_ano
-def feed_normal_search():
- return feed_search(request.args.get("query").strip())
-
-
-@web.route("/opds/new")
-@requires_basic_auth_if_no_ano
-def feed_new():
- off = request.args.get("offset") or 0
- entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
- db.Books, True, [db.Books.timestamp.desc()])
- return render_xml_template('feed.xml', entries=entries, pagination=pagination)
-
-
-@web.route("/opds/discover")
-@requires_basic_auth_if_no_ano
-def feed_discover():
- entries = db.session.query(db.Books).filter(common_filters()).order_by(func.random())\
- .limit(config.config_books_per_page)
- pagination = Pagination(1, config.config_books_per_page, int(config.config_books_per_page))
- return render_xml_template('feed.xml', entries=entries, pagination=pagination)
-
-
-@web.route("/opds/rated")
-@requires_basic_auth_if_no_ano
-def feed_best_rated():
- off = request.args.get("offset") or 0
- entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
- db.Books, db.Books.ratings.any(db.Ratings.rating > 9), [db.Books.timestamp.desc()])
- return render_xml_template('feed.xml', entries=entries, pagination=pagination)
-
-
-@web.route("/opds/hot")
-@requires_basic_auth_if_no_ano
-def feed_hot():
- off = request.args.get("offset") or 0
- all_books = ub.session.query(ub.Downloads, ub.func.count(ub.Downloads.book_id)).order_by(
- ub.func.count(ub.Downloads.book_id).desc()).group_by(ub.Downloads.book_id)
- hot_books = all_books.offset(off).limit(config.config_books_per_page)
- entries = list()
- for book in hot_books:
- downloadBook = db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first()
- if downloadBook:
- entries.append(
- db.session.query(db.Books).filter(common_filters())
- .filter(db.Books.id == book.Downloads.book_id).first()
- )
- else:
- ub.delete_download(book.Downloads.book_id)
- # ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete()
- # ub.session.commit()
- numBooks = entries.__len__()
- pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1),
- config.config_books_per_page, numBooks)
- return render_xml_template('feed.xml', entries=entries, pagination=pagination)
-
-
-@web.route("/opds/author")
-@requires_basic_auth_if_no_ano
-def feed_authorindex():
- off = request.args.get("offset") or 0
- entries = db.session.query(db.Authors).join(db.books_authors_link).join(db.Books).filter(common_filters())\
- .group_by('books_authors_link.author').order_by(db.Authors.sort).limit(config.config_books_per_page).offset(off)
- pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
- len(db.session.query(db.Authors).all()))
- return render_xml_template('feed.xml', listelements=entries, folder='feed_author', pagination=pagination)
-
-
-@web.route("/opds/author/")
-@requires_basic_auth_if_no_ano
-def feed_author(book_id):
- off = request.args.get("offset") or 0
- entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
- db.Books, db.Books.authors.any(db.Authors.id == book_id), [db.Books.timestamp.desc()])
- return render_xml_template('feed.xml', entries=entries, pagination=pagination)
-
-
-@web.route("/opds/publisher")
-@requires_basic_auth_if_no_ano
-def feed_publisherindex():
- off = request.args.get("offset") or 0
- entries = db.session.query(db.Publishers).join(db.books_publishers_link).join(db.Books).filter(common_filters())\
- .group_by('books_publishers_link.publisher').order_by(db.Publishers.sort).limit(config.config_books_per_page).offset(off)
- pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
- len(db.session.query(db.Publishers).all()))
- return render_xml_template('feed.xml', listelements=entries, folder='feed_publisher', pagination=pagination)
-
-
-@web.route("/opds/publisher/")
-@requires_basic_auth_if_no_ano
-def feed_publisher(book_id):
- off = request.args.get("offset") or 0
- entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
- db.Books, db.Books.publishers.any(db.Publishers.id == book_id),
- [db.Books.timestamp.desc()])
- return render_xml_template('feed.xml', entries=entries, pagination=pagination)
-
-
-@web.route("/opds/category")
-@requires_basic_auth_if_no_ano
-def feed_categoryindex():
- off = request.args.get("offset") or 0
- entries = db.session.query(db.Tags).join(db.books_tags_link).join(db.Books).filter(common_filters())\
- .group_by('books_tags_link.tag').order_by(db.Tags.name).offset(off).limit(config.config_books_per_page)
- pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
- len(db.session.query(db.Tags).all()))
- return render_xml_template('feed.xml', listelements=entries, folder='feed_category', pagination=pagination)
-
-
-@web.route("/opds/category/")
-@requires_basic_auth_if_no_ano
-def feed_category(book_id):
- off = request.args.get("offset") or 0
- entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
- db.Books, db.Books.tags.any(db.Tags.id == book_id), [db.Books.timestamp.desc()])
- return render_xml_template('feed.xml', entries=entries, pagination=pagination)
-
-
-@web.route("/opds/series")
-@requires_basic_auth_if_no_ano
-def feed_seriesindex():
- off = request.args.get("offset") or 0
- entries = db.session.query(db.Series).join(db.books_series_link).join(db.Books).filter(common_filters())\
- .group_by('books_series_link.series').order_by(db.Series.sort).offset(off).all()
- pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
- len(db.session.query(db.Series).all()))
- return render_xml_template('feed.xml', listelements=entries, folder='feed_series', pagination=pagination)
-
-
-@web.route("/opds/series/")
-@requires_basic_auth_if_no_ano
-def feed_series(book_id):
- off = request.args.get("offset") or 0
- entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
- db.Books, db.Books.series.any(db.Series.id == book_id), [db.Books.series_index])
- return render_xml_template('feed.xml', entries=entries, pagination=pagination)
-
-
-@web.route("/opds/shelfindex/", defaults={'public': 0})
-@web.route("/opds/shelfindex/")
-@requires_basic_auth_if_no_ano
-def feed_shelfindex(public):
- off = request.args.get("offset") or 0
- if public is not 0:
- shelf = g.public_shelfes
- number = len(shelf)
- else:
- shelf = g.user.shelf
- number = shelf.count()
- pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
- number)
- return render_xml_template('feed.xml', listelements=shelf, folder='feed_shelf', pagination=pagination)
-
-
-@web.route("/opds/shelf/")
-@requires_basic_auth_if_no_ano
-def feed_shelf(book_id):
- off = request.args.get("offset") or 0
- if current_user.is_anonymous:
- shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.is_public == 1, ub.Shelf.id == book_id).first()
- else:
- shelf = ub.session.query(ub.Shelf).filter(ub.or_(ub.and_(ub.Shelf.user_id == int(current_user.id),
- ub.Shelf.id == book_id),
- ub.and_(ub.Shelf.is_public == 1,
- ub.Shelf.id == book_id))).first()
- result = list()
- # user is allowed to access shelf
- if shelf:
- books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == book_id).order_by(
- ub.BookShelf.order.asc()).all()
- for book in books_in_shelf:
- cur_book = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
- result.append(cur_book)
- pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
- len(result))
- return render_xml_template('feed.xml', entries=result, pagination=pagination)
-
-
-@web.route("/opds/download///")
-@requires_basic_auth_if_no_ano
-@download_required
-def get_opds_download_link(book_id, book_format):
- book_format = book_format.split(".")[0]
- book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
- data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper()).first()
- app.logger.info(data.name)
- if current_user.is_authenticated:
- ub.update_download(book_id, int(current_user.id))
- file_name = book.title
- if len(book.authors) > 0:
- file_name = book.authors[0].name + '_' + file_name
- file_name = helper.get_valid_filename(file_name)
- headers = Headers()
- headers["Content-Disposition"] = "attachment; filename*=UTF-8''%s.%s" % (quote(file_name.encode('utf8')),
- book_format)
- try:
- headers["Content-Type"] = mimetypes.types_map['.' + book_format]
- except KeyError:
- headers["Content-Type"] = "application/octet-stream"
- return helper.do_download_file(book, book_format, data, headers)
-
-
-@web.route("/ajax/book/")
-@requires_basic_auth_if_no_ano
-def get_metadata_calibre_companion(uuid):
- entry = db.session.query(db.Books).filter(db.Books.uuid.like("%" + uuid + "%")).first()
- if entry is not None:
- js = render_template('json.txt', entry=entry)
- response = make_response(js)
- response.headers["Content-Type"] = "application/json; charset=utf-8"
- return response
- else:
- return ""
-
@web.route("/ajax/emailstat")
@login_required
def get_email_status_json():
- tasks=helper.global_WorkerThread.get_taskstatus()
+ tasks = global_WorkerThread.get_taskstatus()
answer = helper.render_task_status(tasks)
- js=json.dumps(answer, default=helper.json_serial)
+ js = json.dumps(answer, default=helper.json_serial)
response = make_response(js)
response.headers["Content-Type"] = "application/json; charset=utf-8"
return response
@@ -928,7 +363,7 @@ def get_email_status_json():
# 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):
- domain_text = domain_text.split('@',1)[-1].lower()
+ domain_text = domain_text.split('@', 1)[-1].lower()
sql = "SELECT * FROM registration WHERE :domain LIKE domain;"
result = ub.session.query(ub.Registration).from_statement(text(sql)).params(domain=domain_text).all()
return len(result)
@@ -938,14 +373,14 @@ def check_valid_domain(domain_text):
@login_required
@admin_required
def edit_domain():
- ''' POST /post
- name: 'username', //name of field (column in db)
- pk: 1 //primary key (record id)
- value: 'superuser!' //new value'''
+ # POST /post
+ # name: 'username', //name of field (column in db)
+ # pk: 1 //primary key (record id)
+ # value: 'superuser!' //new value
vals = request.form.to_dict()
answer = ub.session.query(ub.Registration).filter(ub.Registration.id == vals['pk']).first()
# domain_name = request.args.get('domain')
- answer.domain = vals['value'].replace('*','%').replace('?','_').lower()
+ answer.domain = vals['value'].replace('*', '%').replace('?', '_').lower()
ub.session.commit()
return ""
@@ -954,7 +389,7 @@ def edit_domain():
@login_required
@admin_required
def add_domain():
- domain_name = request.form.to_dict()['domainname'].replace('*','%').replace('?','_').lower()
+ domain_name = request.form.to_dict()['domainname'].replace('*', '%').replace('?', '_').lower()
check = ub.session.query(ub.Registration).filter(ub.Registration.domain == domain_name).first()
if not check:
new_domain = ub.Registration(domain=domain_name)
@@ -967,7 +402,7 @@ def add_domain():
@login_required
@admin_required
def delete_domain():
- domain_id = request.form.to_dict()['domainid'].replace('*','%').replace('?','_').lower()
+ domain_id = request.form.to_dict()['domainid'].replace('*', '%').replace('?', '_').lower()
ub.session.query(ub.Registration).filter(ub.Registration.id == domain_id).delete()
ub.session.commit()
# If last domain was deleted, add all domains by default
@@ -983,9 +418,9 @@ def delete_domain():
@admin_required
def list_domain():
answer = ub.session.query(ub.Registration).all()
- json_dumps = json.dumps([{"domain":r.domain.replace('%','*').replace('_','?'),"id":r.id} for r in answer])
- js=json.dumps(json_dumps.replace('"', "'")).lstrip('"').strip('"')
- response = make_response(js.replace("'",'"'))
+ json_dumps = json.dumps([{"domain": r.domain.replace('%', '*').replace('_', '?'), "id": r.id} for r in answer])
+ js = json.dumps(json_dumps.replace('"', "'")).lstrip('"').strip('"')
+ response = make_response(js.replace("'", '"'))
response.headers["Content-Type"] = "application/json; charset=utf-8"
return response
@@ -1048,7 +483,7 @@ def get_authors_json():
if request.method == "GET":
query = request.args.get('q')
entries = db.session.query(db.Authors).filter(db.Authors.name.ilike("%" + query + "%")).all()
- json_dumps = json.dumps([dict(name=r.name.replace('|',',')) for r in entries])
+ json_dumps = json.dumps([dict(name=r.name.replace('|', ',')) for r in entries])
return json_dumps
@@ -1058,7 +493,7 @@ def get_publishers_json():
if request.method == "GET":
query = request.args.get('q')
entries = db.session.query(db.Publishers).filter(db.Publishers.name.ilike("%" + query + "%")).all()
- json_dumps = json.dumps([dict(name=r.name.replace('|',',')) for r in entries])
+ json_dumps = json.dumps([dict(name=r.name.replace('|', ',')) for r in entries])
return json_dumps
@@ -1081,7 +516,7 @@ def get_languages_json():
languages = language_table[get_locale()]
entries_start = [s for key, s in languages.items() if s.lower().startswith(query.lower())]
if len(entries_start) < 5:
- entries = [s for key,s in languages.items() if query in s.lower()]
+ entries = [s for key, s in languages.items() if query in s.lower()]
entries_start.extend(entries[0:(5-len(entries_start))])
entries_start = list(set(entries_start))
json_dumps = json.dumps([dict(name=r) for r in entries_start[0:5]])
@@ -1125,48 +560,6 @@ def get_matching_tags():
return json_dumps
-@web.route("/get_update_status", methods=['GET'])
-@login_required_if_no_ano
-def get_update_status():
- return updater_thread.get_available_updates(request.method)
-
-
-@web.route("/get_updater_status", methods=['GET', 'POST'])
-@login_required
-@admin_required
-def get_updater_status():
- status = {}
- if request.method == "POST":
- commit = request.form.to_dict()
- if "start" in commit and commit['start'] == 'True':
- text = {
- "1": _(u'Requesting update package'),
- "2": _(u'Downloading update package'),
- "3": _(u'Unzipping update package'),
- "4": _(u'Replacing files'),
- "5": _(u'Database connections are closed'),
- "6": _(u'Stopping server'),
- "7": _(u'Update finished, please press okay and reload page'),
- "8": _(u'Update failed:') + u' ' + _(u'HTTP Error'),
- "9": _(u'Update failed:') + u' ' + _(u'Connection error'),
- "10": _(u'Update failed:') + u' ' + _(u'Timeout while establishing connection'),
- "11": _(u'Update failed:') + u' ' + _(u'General error')
- }
- status['text'] = text
- # helper.updater_thread = helper.Updater()
- updater_thread.start()
- status['status'] = updater_thread.get_update_status()
- elif request.method == "GET":
- try:
- status['status'] = updater_thread.get_update_status()
- except AttributeError:
- # thread is not active, occours after restart on update
- status['status'] = 7
- except Exception:
- status['status'] = 11
- return json.dumps(status)
-
-
@web.route("/", defaults={'page': 1})
@web.route('/page/')
@login_required_if_no_ano
@@ -1249,7 +642,7 @@ def hot_books(page):
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
title=_(u"Hot Books (most downloaded)"), page="hot")
else:
- abort(404)
+ abort(404)
@web.route("/rated", defaults={'page': 1})
@@ -1287,7 +680,7 @@ def author_list():
.group_by('books_authors_link.author').order_by(db.Authors.sort).all()
for entry in entries:
entry.Authors.name = entry.Authors.name.replace('|', ',')
- return render_title_template('list.html', entries=entries, folder='author',
+ return render_title_template('list.html', entries=entries, folder='web.author',
title=u"Author list", page="authorlist")
else:
abort(404)
@@ -1298,12 +691,12 @@ def author_list():
@login_required_if_no_ano
def author(book_id, page):
entries, __, pagination = fill_indexpage(page, db.Books, db.Books.authors.any(db.Authors.id == book_id),
- [db.Series.name, db.Books.series_index],db.books_series_link, db.Series)
+ [db.Series.name, db.Books.series_index], db.books_series_link, db.Series)
if entries is None:
flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error")
return redirect(url_for("web.index"))
- name = (db.session.query(db.Authors).filter(db.Authors.id == book_id).first().name).replace('|', ',')
+ name = db.session.query(db.Authors).filter(db.Authors.id == book_id).first().name.replace('|', ',')
author_info = None
other_books = []
@@ -1327,7 +720,7 @@ def publisher_list():
entries = db.session.query(db.Publishers, func.count('books_publishers_link.book').label('count'))\
.join(db.books_publishers_link).join(db.Books).filter(common_filters())\
.group_by('books_publishers_link.publisher').order_by(db.Publishers.sort).all()
- return render_title_template('list.html', entries=entries, folder='publisher',
+ return render_title_template('list.html', entries=entries, folder='web.publisher',
title=_(u"Publisher list"), page="publisherlist")
else:
abort(404)
@@ -1340,10 +733,11 @@ def publisher(book_id, page):
publisher = db.session.query(db.Publishers).filter(db.Publishers.id == book_id).first()
if publisher:
entries, random, pagination = fill_indexpage(page, db.Books,
- db.Books.publishers.any(db.Publishers.id == book_id),
- (db.Series.name, db.Books.series_index), db.books_series_link, db.Series)
+ db.Books.publishers.any(db.Publishers.id == book_id),
+ (db.Series.name, db.Books.series_index), db.books_series_link,
+ db.Series)
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
- title=_(u"Publisher: %(name)s", name=publisher.name), page="publisher")
+ title=_(u"Publisher: %(name)s", name=publisher.name), page="publisher")
else:
abort(404)
@@ -1352,15 +746,18 @@ def get_unique_other_books(library_books, author_books):
# Get all identifiers (ISBN, Goodreads, etc) and filter author's books by that list so we show fewer duplicates
# Note: Not all images will be shown, even though they're available on Goodreads.com.
# See https://www.goodreads.com/topic/show/18213769-goodreads-book-images
- identifiers = reduce(lambda acc, book: acc + map(lambda identifier: identifier.val, book.identifiers), library_books, [])
- other_books = filter(lambda book: book.isbn not in identifiers and book.gid["#text"] not in identifiers, author_books)
+ identifiers = reduce(lambda acc, book: acc + map(lambda identifier: identifier.val, book.identifiers),
+ library_books, [])
+ other_books = filter(lambda book: book.isbn not in identifiers and book.gid["#text"] not in identifiers,
+ author_books)
# Fuzzy match book titles
if levenshtein_support:
library_titles = reduce(lambda acc, book: acc + [book.title], library_books, [])
other_books = filter(lambda author_book: not filter(
lambda library_book:
- Levenshtein.ratio(re.sub(r"\(.*\)", "", author_book.title), library_book) > 0.7, # Remove items in parentheses before comparing
+ # Remove items in parentheses before comparing
+ Levenshtein.ratio(re.sub(r"\(.*\)", "", author_book.title), library_book) > 0.7,
library_titles
), other_books)
@@ -1374,7 +771,7 @@ def series_list():
entries = db.session.query(db.Series, func.count('books_series_link.book').label('count'))\
.join(db.books_series_link).join(db.Books).filter(common_filters())\
.group_by('books_series_link.series').order_by(db.Series.sort).all()
- return render_title_template('list.html', entries=entries, folder='series',
+ return render_title_template('list.html', entries=entries, folder='web.series',
title=_(u"Series list"), page="serieslist")
else:
abort(404)
@@ -1387,7 +784,7 @@ def series(book_id, page):
name = db.session.query(db.Series).filter(db.Series.id == book_id).first()
if name:
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.series.any(db.Series.id == book_id),
- [db.Books.series_index])
+ [db.Books.series_index])
return render_title_template('index.html', random=random, pagination=pagination, entries=entries,
title=_(u"Series: %(serie)s", serie=name.name), page="series")
else:
@@ -1445,7 +842,7 @@ def category_list():
entries = db.session.query(db.Tags, func.count('books_tags_link.book').label('count'))\
.join(db.books_tags_link).join(db.Books).order_by(db.Tags.name).filter(common_filters())\
.group_by('books_tags_link.tag').all()
- return render_title_template('list.html', entries=entries, folder='category',
+ return render_title_template('list.html', entries=entries, folder='web.category',
title=_(u"Category list"), page="catlist")
else:
abort(404)
@@ -1458,7 +855,8 @@ def category(book_id, page):
name = db.session.query(db.Tags).filter(db.Tags.id == book_id).first()
if name:
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.tags.any(db.Tags.id == book_id),
- (db.Series.name, db.Books.series_index),db.books_series_link,db.Series)
+ (db.Series.name, db.Books.series_index),db.books_series_link,
+ db.Series)
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
title=_(u"Category: %(name)s", name=name.name), page="category")
else:
@@ -1499,6 +897,7 @@ def toggle_read(book_id):
u"Custom Column No.%d is not exisiting in calibre database" % config.config_read_column)
return ""
+
@web.route("/book/")
@login_required_if_no_ano
def show_book(book_id):
@@ -1528,13 +927,12 @@ def show_book(book_id):
if not current_user.is_anonymous:
if not config.config_read_column:
- matching_have_read_book = ub.session.query(ub.ReadBook)\
- .filter(ub.and_(ub.ReadBook.user_id == int(current_user.id),
- ub.ReadBook.book_id == book_id)).all()
+ matching_have_read_book = ub.session.query(ub.ReadBook).\
+ filter(ub.and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.book_id == book_id)).all()
have_read = len(matching_have_read_book) > 0 and matching_have_read_book[0].is_read
else:
try:
- matching_have_read_book = getattr(entries,'custom_column_'+str(config.config_read_column))
+ matching_have_read_book = getattr(entries, 'custom_column_'+str(config.config_read_column))
have_read = len(matching_have_read_book) > 0 and matching_have_read_book[0].value
except KeyError:
app.logger.error(
@@ -1544,7 +942,7 @@ def show_book(book_id):
else:
have_read = None
- entries.tags = sort(entries.tags, key = lambda tag: tag.name)
+ entries.tags = sort(entries.tags, key=lambda tag: tag.name)
entries = order_authors(entries)
@@ -1556,8 +954,8 @@ def show_book(book_id):
if media_format.format.lower() in EXTENSIONS_AUDIO:
audioentries.append(media_format.format.lower())
- return render_title_template('detail.html', entry=entries, audioentries=audioentries, cc=cc, is_xhr=request.is_xhr,
- title=entries.title, books_shelfs=book_in_shelfs,
+ return render_title_template('detail.html', entry=entries, audioentries=audioentries, cc=cc,
+ is_xhr=request.is_xhr, title=entries.title, books_shelfs=book_in_shelfs,
have_read=have_read, kindle_list=kindle_list, reader_list=reader_list, page="book")
else:
flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error")
@@ -1576,9 +974,9 @@ def bookmark(book_id, book_format):
return "", 204
lbookmark = ub.Bookmark(user_id=current_user.id,
- book_id=book_id,
- format=book_format,
- bookmark_key=bookmark_key)
+ book_id=book_id,
+ format=book_format,
+ bookmark_key=bookmark_key)
ub.session.merge(lbookmark)
ub.session.commit()
return "", 201
@@ -1588,254 +986,13 @@ def bookmark(book_id, book_format):
@login_required
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()
- # answer = tasks
-
+ tasks = global_WorkerThread.get_taskstatus()
# UIanswer = copy.deepcopy(answer)
answer = helper.render_task_status(tasks)
# foreach row format row
return render_title_template('tasks.html', entries=answer, title=_(u"Tasks"), page="tasks")
-@web.route("/admin")
-@login_required
-def admin_forbidden():
- abort(403)
-
-
-@web.route("/stats")
-@login_required
-def stats():
- counter = db.session.query(db.Books).count()
- authors = db.session.query(db.Authors).count()
- categorys = db.session.query(db.Tags).count()
- series = db.session.query(db.Series).count()
- versions = uploader.book_formats.get_versions()
- versions['Babel'] = 'v' + babelVersion
- versions['Sqlalchemy'] = 'v' + sqlalchemyVersion
- versions['Werkzeug'] = 'v' + werkzeugVersion
- versions['Jinja2'] = 'v' + jinja2Version
- versions['Flask'] = 'v' + flaskVersion
- versions['Flask Login'] = 'v' + flask_loginVersion
- versions['Flask Principal'] = 'v' + flask_principalVersion
- versions['Iso 639'] = 'v' + iso639Version
- versions['pytz'] = 'v' + pytzVersion
-
- versions['Requests'] = 'v' + requests.__version__
- versions['pySqlite'] = 'v' + db.engine.dialect.dbapi.version
- versions['Sqlite'] = 'v' + db.engine.dialect.dbapi.sqlite_version
- versions.update(converter.versioncheck())
- versions.update(server.Server.getNameVersion())
- versions['Python'] = sys.version
- return render_title_template('stats.html', bookcounter=counter, authorcounter=authors, versions=versions,
- categorycounter=categorys, seriecounter=series, title=_(u"Statistics"), page="stat")
-
-
-@web.route("/delete//", defaults={'book_format': ""})
-@web.route("/delete///")
-@login_required
-def delete_book(book_id, book_format):
- if current_user.role_delete_books():
- book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
- if book:
- helper.delete_book(book, config.config_calibre_dir, book_format=book_format.upper())
- if not book_format:
- # delete book from Shelfs, Downloads, Read list
- ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book_id).delete()
- ub.session.query(ub.ReadBook).filter(ub.ReadBook.book_id == book_id).delete()
- ub.delete_download(book_id)
- ub.session.commit()
-
- # check if only this book links to:
- # author, language, series, tags, custom columns
- modify_database_object([u''], book.authors, db.Authors, db.session, 'author')
- modify_database_object([u''], book.tags, db.Tags, db.session, 'tags')
- modify_database_object([u''], book.series, db.Series, db.session, 'series')
- modify_database_object([u''], book.languages, db.Languages, db.session, 'languages')
- modify_database_object([u''], book.publishers, db.Publishers, db.session, 'publishers')
-
- cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
- for c in cc:
- cc_string = "custom_column_" + str(c.id)
- if not c.is_multiple:
- if len(getattr(book, cc_string)) > 0:
- if c.datatype == 'bool' or c.datatype == 'integer':
- del_cc = getattr(book, cc_string)[0]
- getattr(book, cc_string).remove(del_cc)
- db.session.delete(del_cc)
- elif c.datatype == 'rating':
- del_cc = getattr(book, cc_string)[0]
- getattr(book, cc_string).remove(del_cc)
- if len(del_cc.books) == 0:
- db.session.delete(del_cc)
- else:
- del_cc = getattr(book, cc_string)[0]
- getattr(book, cc_string).remove(del_cc)
- db.session.delete(del_cc)
- else:
- modify_database_object([u''], getattr(book, cc_string), db.cc_classes[c.id],
- db.session, 'custom')
- db.session.query(db.Books).filter(db.Books.id == book_id).delete()
- else:
- db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format).delete()
- db.session.commit()
- else:
- # book not found
- app.logger.info('Book with id "'+str(book_id)+'" could not be deleted')
- if book_format:
- return redirect(url_for('edit_book', book_id=book_id))
- else:
- return redirect(url_for('index'))
-
-
-
-@web.route("/gdrive/authenticate")
-@login_required
-@admin_required
-def authenticate_google_drive():
- try:
- authUrl = gdriveutils.Gauth.Instance().auth.GetAuthUrl()
- except gdriveutils.InvalidConfigError:
- flash(_(u'Google Drive setup not completed, try to deactivate and activate Google Drive again'),
- category="error")
- return redirect(url_for('index'))
- return redirect(authUrl)
-
-
-@web.route("/gdrive/callback")
-def google_drive_callback():
- auth_code = request.args.get('code')
- if not auth_code:
- abort(403)
- try:
- credentials = gdriveutils.Gauth.Instance().auth.flow.step2_exchange(auth_code)
- with open(os.path.join(config.get_main_dir,'gdrive_credentials'), 'w') as f:
- f.write(credentials.to_json())
- except ValueError as error:
- app.logger.error(error)
- return redirect(url_for('configuration'))
-
-
-@web.route("/gdrive/watch/subscribe")
-@login_required
-@admin_required
-def watch_gdrive():
- if not config.config_google_drive_watch_changes_response:
- with open(os.path.join(config.get_main_dir,'client_secrets.json'), 'r') as settings:
- filedata = json.load(settings)
- if filedata['web']['redirect_uris'][0].endswith('/'):
- filedata['web']['redirect_uris'][0] = filedata['web']['redirect_uris'][0][:-((len('/gdrive/callback')+1))]
- else:
- filedata['web']['redirect_uris'][0] = filedata['web']['redirect_uris'][0][:-(len('/gdrive/callback'))]
- address = '%s/gdrive/watch/callback' % filedata['web']['redirect_uris'][0]
- notification_id = str(uuid4())
- try:
- result = gdriveutils.watchChange(gdriveutils.Gdrive.Instance().drive, notification_id,
- 'web_hook', address, gdrive_watch_callback_token, current_milli_time() + 604800*1000)
- settings = ub.session.query(ub.Settings).first()
- settings.config_google_drive_watch_changes_response = json.dumps(result)
- ub.session.merge(settings)
- ub.session.commit()
- settings = ub.session.query(ub.Settings).first()
- config.loadSettings()
- except HttpError as e:
- reason=json.loads(e.content)['error']['errors'][0]
- if reason['reason'] == u'push.webhookUrlUnauthorized':
- flash(_(u'Callback domain is not verified, please follow steps to verify domain in google developer console'), category="error")
- else:
- flash(reason['message'], category="error")
-
- return redirect(url_for('configuration'))
-
-
-@web.route("/gdrive/watch/revoke")
-@login_required
-@admin_required
-def revoke_watch_gdrive():
- last_watch_response = config.config_google_drive_watch_changes_response
- if last_watch_response:
- try:
- gdriveutils.stopChannel(gdriveutils.Gdrive.Instance().drive, last_watch_response['id'],
- last_watch_response['resourceId'])
- except HttpError:
- pass
- settings = ub.session.query(ub.Settings).first()
- settings.config_google_drive_watch_changes_response = None
- ub.session.merge(settings)
- ub.session.commit()
- config.loadSettings()
- return redirect(url_for('configuration'))
-
-
-@web.route("/gdrive/watch/callback", methods=['GET', 'POST'])
-def on_received_watch_confirmation():
- app.logger.debug(request.headers)
- if request.headers.get('X-Goog-Channel-Token') == gdrive_watch_callback_token \
- and request.headers.get('X-Goog-Resource-State') == 'change' \
- and request.data:
-
- data = request.data
-
- def updateMetaData():
- app.logger.info('Change received from gdrive')
- app.logger.debug(data)
- try:
- j = json.loads(data)
- app.logger.info('Getting change details')
- response = gdriveutils.getChangeById(gdriveutils.Gdrive.Instance().drive, j['id'])
- app.logger.debug(response)
- if response:
- dbpath = os.path.join(config.config_calibre_dir, "metadata.db")
- if not response['deleted'] and response['file']['title'] == 'metadata.db' and response['file']['md5Checksum'] != hashlib.md5(dbpath):
- tmpDir = tempfile.gettempdir()
- app.logger.info('Database file updated')
- copyfile(dbpath, os.path.join(tmpDir, "metadata.db_" + str(current_milli_time())))
- app.logger.info('Backing up existing and downloading updated metadata.db')
- gdriveutils.downloadFile(None, "metadata.db", os.path.join(tmpDir, "tmp_metadata.db"))
- app.logger.info('Setting up new DB')
- # prevent error on windows, as os.rename does on exisiting files
- move(os.path.join(tmpDir, "tmp_metadata.db"), dbpath)
- db.setup_db()
- except Exception as e:
- app.logger.info(e.message)
- app.logger.exception(e)
- updateMetaData()
- return ''
-
-
-@web.route("/shutdown")
-@login_required
-@admin_required
-def shutdown():
- task = int(request.args.get("parameter").strip())
- if task == 1 or task == 0: # valid commandos received
- # close all database connections
- db.session.close()
- db.engine.dispose()
- ub.session.close()
- ub.engine.dispose()
-
- showtext = {}
- if task == 0:
- showtext['text'] = _(u'Server restarted, please reload page')
- Server.setRestartTyp(True)
- else:
- showtext['text'] = _(u'Performing shutdown of server, please close window')
- Server.setRestartTyp(False)
- # stop gevent/tornado server
- Server.stopServer()
- return json.dumps(showtext)
- else:
- if task == 2:
- db.session.close()
- db.engine.dispose()
- db.setup_db()
- return json.dumps({})
- abort(404)
-
-
@web.route("/search", methods=["GET"])
@login_required_if_no_ano
def search():
@@ -1845,7 +1002,7 @@ def search():
ids = list()
for element in entries:
ids.append(element.id)
- ub.searched_ids[current_user.id] = ids
+ searched_ids[current_user.id] = ids
return render_title_template('search.html', searchterm=term, entries=entries, page="search")
else:
return render_title_template('search.html', searchterm="", page="search")
@@ -1884,9 +1041,12 @@ def advanced_search():
rating_low = request.args.get("ratinghigh")
rating_high = request.args.get("ratinglow")
description = request.args.get("comment")
- if author_name: author_name = author_name.strip().lower().replace(',','|')
- if book_title: book_title = book_title.strip().lower()
- if publisher: publisher = publisher.strip().lower()
+ if author_name:
+ author_name = author_name.strip().lower().replace(',','|')
+ if book_title:
+ book_title = book_title.strip().lower()
+ if publisher:
+ publisher = publisher.strip().lower()
searchterm = []
cc_present = False
@@ -1899,19 +1059,19 @@ def advanced_search():
include_languages_inputs or exclude_languages_inputs or author_name or book_title or \
publisher or pub_start or pub_end or rating_low or rating_high or description or cc_present:
searchterm = []
- searchterm.extend((author_name.replace('|',','), book_title, publisher))
+ searchterm.extend((author_name.replace('|', ','), book_title, publisher))
if pub_start:
try:
searchterm.extend([_(u"Published after ") +
- format_date(datetime.datetime.strptime(pub_start,"%Y-%m-%d"),
- format='medium', locale=get_locale())])
+ format_date(datetime.datetime.strptime(pub_start,"%Y-%m-%d"),
+ format='medium', locale=get_locale())])
except ValueError:
pub_start = u""
if pub_end:
try:
searchterm.extend([_(u"Published before ") +
- format_date(datetime.datetime.strptime(pub_end,"%Y-%m-%d"),
- format='medium', locale=get_locale())])
+ format_date(datetime.datetime.strptime(pub_end,"%Y-%m-%d"),
+ format='medium', locale=get_locale())])
except ValueError:
pub_start = u""
tag_names = db.session.query(db.Tags).filter(db.Tags.id.in_(include_tag_inputs)).all()
@@ -1961,7 +1121,7 @@ def advanced_search():
rating_high = int(rating_high) * 2
q = q.filter(db.Books.ratings.any(db.Ratings.rating <= rating_high))
if rating_low:
- rating_low = int(rating_low) *2
+ rating_low = int(rating_low) * 2
q = q.filter(db.Books.ratings.any(db.Ratings.rating >= rating_low))
if description:
q = q.filter(db.Books.comments.any(db.Comments.text.ilike("%" + description + "%")))
@@ -1973,10 +1133,10 @@ def advanced_search():
if c.datatype == 'bool':
getattr(db.Books, 'custom_column_1')
q = q.filter(getattr(db.Books, 'custom_column_'+str(c.id)).any(
- db.cc_classes[c.id].value == (custom_query== "True") ))
+ db.cc_classes[c.id].value == (custom_query == "True")))
elif c.datatype == 'int':
q = q.filter(getattr(db.Books, 'custom_column_'+str(c.id)).any(
- db.cc_classes[c.id].value == custom_query ))
+ db.cc_classes[c.id].value == custom_query))
else:
q = q.filter(getattr(db.Books, 'custom_column_'+str(c.id)).any(
db.cc_classes[c.id].value.ilike("%" + custom_query + "%")))
@@ -1984,7 +1144,7 @@ def advanced_search():
ids = list()
for element in q:
ids.append(element.id)
- ub.searched_ids[current_user.id] = ids
+ searched_ids[current_user.id] = ids
return render_title_template('search.html', searchterm=searchterm,
entries=q, title=_(u"search"), page="search")
# prepare data for search-form
@@ -2010,7 +1170,8 @@ def get_cover(book_id):
def serve_book(book_id, book_format):
book_format = book_format.split(".")[0]
book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
- data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper()).first()
+ data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper())\
+ .first()
app.logger.info('Serving book: %s', data.name)
if config.config_use_google_drive:
headers = Headers()
@@ -2024,25 +1185,29 @@ def serve_book(book_id, book_format):
return send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format)
-@web.route("/opds/thumb_240_240/")
-@web.route("/opds/cover_240_240/")
-@web.route("/opds/cover_90_90/")
-@web.route("/opds/cover/")
-@requires_basic_auth_if_no_ano
-def feed_get_cover(book_id):
- book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
- return helper.get_book_cover(book.path)
+@web.route("/unreadbooks/", defaults={'page': 1})
+@web.route("/unreadbooks/'")
+@login_required_if_no_ano
+def unread_books(page):
+ return render_read_books(page, False)
+
+
+@web.route("/readbooks/", defaults={'page': 1})
+@web.route("/readbooks/'")
+@login_required_if_no_ano
+def read_books(page):
+ return render_read_books(page, True)
def render_read_books(page, are_read, as_xml=False):
if not config.config_read_column:
readBooks = ub.session.query(ub.ReadBook).filter(ub.ReadBook.user_id == int(current_user.id))\
- .filter(ub.ReadBook.is_read == True).all()
+ .filter(ub.ReadBook.is_read is True).all()
readBookIds = [x.book_id for x in readBooks]
else:
try:
readBooks = db.session.query(db.cc_classes[config.config_read_column])\
- .filter(db.cc_classes[config.config_read_column].value==True).all()
+ .filter(db.cc_classes[config.config_read_column].value is True).all()
readBookIds = [x.book for x in readBooks]
except KeyError:
app.logger.error(u"Custom Column No.%d is not existing in calibre database" % config.config_read_column)
@@ -2053,8 +1218,7 @@ def render_read_books(page, are_read, as_xml=False):
else:
db_filter = ~db.Books.id.in_(readBookIds)
- entries, random, pagination = fill_indexpage(page, db.Books,
- db_filter, [db.Books.timestamp.desc()])
+ entries, random, pagination = fill_indexpage(page, db.Books, db_filter, [db.Books.timestamp.desc()])
if as_xml:
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
@@ -2068,35 +1232,7 @@ def render_read_books(page, are_read, as_xml=False):
total_books = db.session.query(func.count(db.Books.id)).scalar()
name = _(u'Unread Books') + ' (' + str(total_books - len(readBookIds)) + ')'
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
- title=_(name, name=name), page="read")
-
-
-@web.route("/opds/readbooks/")
-@login_required_if_no_ano
-def feed_read_books():
- off = request.args.get("offset") or 0
- return render_read_books(int(off) / (int(config.config_books_per_page)) + 1, True, True)
-
-
-@web.route("/readbooks/", defaults={'page': 1})
-@web.route("/readbooks/'")
-@login_required_if_no_ano
-def read_books(page):
- return render_read_books(page, True)
-
-
-@web.route("/opds/unreadbooks/")
-@login_required_if_no_ano
-def feed_unread_books():
- off = request.args.get("offset") or 0
- return render_read_books(int(off) / (int(config.config_books_per_page)) + 1, False, True)
-
-
-@web.route("/unreadbooks/", defaults={'page': 1})
-@web.route("/unreadbooks/'")
-@login_required_if_no_ano
-def unread_books(page):
- return render_read_books(page, False)
+ title=_(name, name=name), page="read")
@web.route("/read//")
@@ -2111,8 +1247,8 @@ def read_book(book_id, book_format):
bookmark = None
if current_user.is_authenticated:
bookmark = ub.session.query(ub.Bookmark).filter(ub.and_(ub.Bookmark.user_id == int(current_user.id),
- ub.Bookmark.book_id == book_id,
- ub.Bookmark.format == book_format.upper())).first()
+ ub.Bookmark.book_id == book_id,
+ ub.Bookmark.format == book_format.upper())).first()
if book_format.lower() == "epub":
return render_title_template('read.html', bookid=book_id, title=_(u"Read a Book"), bookmark=bookmark)
elif book_format.lower() == "pdf":
@@ -2122,24 +1258,24 @@ def read_book(book_id, book_format):
elif book_format.lower() == "mp3":
entries = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
return render_title_template('listenmp3.html', mp3file=book_id, audioformat=book_format.lower(),
- title=_(u"Read a Book"), entry=entries, bookmark=bookmark)
+ title=_(u"Read a Book"), entry=entries, bookmark=bookmark)
elif book_format.lower() == "m4b":
entries = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
return render_title_template('listenmp3.html', mp3file=book_id, audioformat=book_format.lower(),
- title=_(u"Read a Book"), entry=entries, bookmark=bookmark)
+ title=_(u"Read a Book"), entry=entries, bookmark=bookmark)
elif book_format.lower() == "m4a":
entries = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
return render_title_template('listenmp3.html', mp3file=book_id, audioformat=book_format.lower(),
- title=_(u"Read a Book"), entry=entries, bookmark=bookmark)
+ title=_(u"Read a Book"), entry=entries, bookmark=bookmark)
else:
book_dir = os.path.join(config.get_main_dir, "cps", "static", str(book_id))
if not os.path.exists(book_dir):
os.mkdir(book_dir)
for fileext in ["cbr", "cbt", "cbz"]:
if book_format.lower() == fileext:
- all_name = str(book_id) # + "/" + book.data[0].name + "." + fileext
- #tmp_file = os.path.join(book_dir, book.data[0].name) + "." + fileext
- #if not os.path.exists(all_name):
+ all_name = str(book_id) # + "/" + book.data[0].name + "." + fileext
+ # tmp_file = os.path.join(book_dir, book.data[0].name) + "." + fileext
+ # if not os.path.exists(all_name):
# cbr_file = os.path.join(config.config_calibre_dir, book.path, book.data[0].name) + "." + fileext
# copyfile(cbr_file, tmp_file)
return render_title_template('readcbr.html', comicfile=all_name, title=_(u"Read a Book"),
@@ -2204,7 +1340,8 @@ def register():
flash(_(u"Please fill out all fields!"), category="error")
return render_title_template('register.html', title=_(u"register"), page="register")
- existing_user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == to_save["nickname"].lower()).first()
+ existing_user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == to_save["nickname"]
+ .lower()).first()
existing_email = ub.session.query(ub.User).filter(ub.User.email == to_save["email"].lower()).first()
if not existing_user and not existing_email:
content = ub.User()
@@ -2220,15 +1357,16 @@ def register():
try:
ub.session.add(content)
ub.session.commit()
- register_user_with_oauth(content)
- helper.send_registration_mail(to_save["email"],to_save["nickname"], password)
+ # register_user_with_oauth(content)
+ helper.send_registration_mail(to_save["email"], to_save["nickname"], password)
except Exception:
ub.session.rollback()
flash(_(u"An unknown error occurred. Please try again later."), category="error")
return render_title_template('register.html', title=_(u"register"), page="register")
else:
flash(_(u"Your e-mail is not allowed to register"), category="error")
- app.logger.info('Registering failed for user "' + to_save['nickname'] + '" e-mail adress: ' + to_save["email"])
+ app.logger.info('Registering failed for user "' + to_save['nickname'] + '" e-mail adress: ' +
+ to_save["email"])
return render_title_template('register.html', title=_(u"register"), page="register")
flash(_(u"Confirmation e-mail was send to your e-mail account."), category="success")
return redirect(url_for('login'))
@@ -2236,7 +1374,7 @@ def register():
flash(_(u"This username or e-mail address is already in use."), category="error")
return render_title_template('register.html', title=_(u"register"), page="register")
- register_user_with_oauth()
+ # register_user_with_oauth()
return render_title_template('register.html', config=config, title=_(u"register"), page="register")
@@ -2245,17 +1383,18 @@ def login():
if not config.db_configured:
return redirect(url_for('web.basic_configuration'))
if current_user is not None and current_user.is_authenticated:
- return redirect(url_for('index'))
+ return redirect(url_for('web.index'))
if request.method == "POST":
form = request.form.to_dict()
- user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == form['username'].strip().lower()).first()
+ user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == form['username'].strip().lower())\
+ .first()
if config.config_use_ldap and user:
import ldap
try:
ub.User.try_login(form['username'], form['password'])
login_user(user, remember=True)
flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success")
- return redirect_back(url_for("index"))
+ return redirect_back(url_for("web.index"))
except ldap.INVALID_CREDENTIALS:
ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr)
app.logger.info('LDAP Login failed for user "' + form['username'] + '" IP-adress: ' + ipAdress)
@@ -2387,341 +1526,22 @@ def send_to_kindle(book_id, book_format, convert):
return redirect(request.environ["HTTP_REFERER"])
-@web.route("/shelf/add//")
-@login_required
-def add_to_shelf(shelf_id, book_id):
- shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
- if shelf is None:
- app.logger.info("Invalid shelf specified")
- if not request.is_xhr:
- flash(_(u"Invalid shelf specified"), category="error")
- return redirect(url_for('index'))
- return "Invalid shelf specified", 400
-
- if not shelf.is_public and not shelf.user_id == int(current_user.id):
- app.logger.info("Sorry you are not allowed to add a book to the the shelf: %s" % shelf.name)
- if not request.is_xhr:
- flash(_(u"Sorry you are not allowed to add a book to the the shelf: %(shelfname)s", shelfname=shelf.name),
- category="error")
- return redirect(url_for('index'))
- return "Sorry you are not allowed to add a book to the the shelf: %s" % shelf.name, 403
-
- if shelf.is_public and not current_user.role_edit_shelfs():
- app.logger.info("User is not allowed to edit public shelves")
- if not request.is_xhr:
- flash(_(u"You are not allowed to edit public shelves"), category="error")
- return redirect(url_for('index'))
- return "User is not allowed to edit public shelves", 403
-
- book_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id,
- ub.BookShelf.book_id == book_id).first()
- if book_in_shelf:
- app.logger.info("Book is already part of the shelf: %s" % shelf.name)
- if not request.is_xhr:
- flash(_(u"Book is already part of the shelf: %(shelfname)s", shelfname=shelf.name), category="error")
- return redirect(url_for('index'))
- return "Book is already part of the shelf: %s" % shelf.name, 400
-
- maxOrder = ub.session.query(func.max(ub.BookShelf.order)).filter(ub.BookShelf.shelf == shelf_id).first()
- if maxOrder[0] is None:
- maxOrder = 0
- else:
- maxOrder = maxOrder[0]
-
- ins = ub.BookShelf(shelf=shelf.id, book_id=book_id, order=maxOrder + 1)
- ub.session.add(ins)
- ub.session.commit()
- if not request.is_xhr:
- flash(_(u"Book has been added to shelf: %(sname)s", sname=shelf.name), category="success")
- if "HTTP_REFERER" in request.environ:
- return redirect(request.environ["HTTP_REFERER"])
- else:
- return redirect(url_for('index'))
- return "", 204
-
-
-@web.route("/shelf/massadd/")
-@login_required
-def search_to_shelf(shelf_id):
- shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
- if shelf is None:
- app.logger.info("Invalid shelf specified")
- flash(_(u"Invalid shelf specified"), category="error")
- return redirect(url_for('index'))
-
- if not shelf.is_public and not shelf.user_id == int(current_user.id):
- app.logger.info("You are not allowed to add a book to the the shelf: %s" % shelf.name)
- flash(_(u"You are not allowed to add a book to the the shelf: %(name)s", name=shelf.name), category="error")
- return redirect(url_for('index'))
-
- if shelf.is_public and not current_user.role_edit_shelfs():
- app.logger.info("User is not allowed to edit public shelves")
- flash(_(u"User is not allowed to edit public shelves"), category="error")
- return redirect(url_for('index'))
-
- if current_user.id in ub.searched_ids and ub.searched_ids[current_user.id]:
- books_for_shelf = list()
- books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).all()
- if books_in_shelf:
- book_ids = list()
- for book_id in books_in_shelf:
- book_ids.append(book_id.book_id)
- for id in ub.searched_ids[current_user.id]:
- if id not in book_ids:
- books_for_shelf.append(id)
- else:
- books_for_shelf = ub.searched_ids[current_user.id]
-
- if not books_for_shelf:
- app.logger.info("Books are already part of the shelf: %s" % shelf.name)
- flash(_(u"Books are already part of the shelf: %(name)s", name=shelf.name), category="error")
- return redirect(url_for('index'))
-
- maxOrder = ub.session.query(func.max(ub.BookShelf.order)).filter(ub.BookShelf.shelf == shelf_id).first()
- if maxOrder[0] is None:
- maxOrder = 0
- else:
- maxOrder = maxOrder[0]
-
- for book in books_for_shelf:
- maxOrder = maxOrder + 1
- ins = ub.BookShelf(shelf=shelf.id, book_id=book, order=maxOrder)
- ub.session.add(ins)
- ub.session.commit()
- 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'))
-
-
-@web.route("/shelf/remove//")
-@login_required
-def remove_from_shelf(shelf_id, book_id):
- shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
- if shelf is None:
- app.logger.info("Invalid shelf specified")
- if not request.is_xhr:
- return redirect(url_for('index'))
- return "Invalid shelf specified", 400
-
- # if shelf is public and use is allowed to edit shelfs, or if shelf is private and user is owner
- # allow editing shelfs
- # result shelf public user allowed user owner
- # false 1 0 x
- # true 1 1 x
- # true 0 x 1
- # false 0 x 0
-
- if (not shelf.is_public and shelf.user_id == int(current_user.id)) \
- or (shelf.is_public and current_user.role_edit_shelfs()):
- book_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id,
- ub.BookShelf.book_id == book_id).first()
-
- if book_shelf is None:
- app.logger.info("Book already removed from shelf")
- if not request.is_xhr:
- return redirect(url_for('index'))
- return "Book already removed from shelf", 410
-
- ub.session.delete(book_shelf)
- ub.session.commit()
-
- if not request.is_xhr:
- flash(_(u"Book has been removed from shelf: %(sname)s", sname=shelf.name), category="success")
- return redirect(request.environ["HTTP_REFERER"])
- return "", 204
- else:
- app.logger.info("Sorry you are not allowed to remove a book from this shelf: %s" % shelf.name)
- if not request.is_xhr:
- flash(_(u"Sorry you are not allowed to remove a book from this shelf: %(sname)s", sname=shelf.name),
- category="error")
- return redirect(url_for('index'))
- return "Sorry you are not allowed to remove a book from this shelf: %s" % shelf.name, 403
-
-
-
-@web.route("/shelf/create", methods=["GET", "POST"])
+@web.route("/me", methods=["GET", "POST"])
@login_required
-def create_shelf():
- shelf = ub.Shelf()
- if request.method == "POST":
- to_save = request.form.to_dict()
- if "is_public" in to_save:
- shelf.is_public = 1
- shelf.name = to_save["title"]
- shelf.user_id = int(current_user.id)
- existing_shelf = ub.session.query(ub.Shelf).filter(
- or_((ub.Shelf.name == to_save["title"]) & (ub.Shelf.is_public == 1),
- (ub.Shelf.name == to_save["title"]) & (ub.Shelf.user_id == int(current_user.id)))).first()
- if existing_shelf:
- flash(_(u"A shelf with the name '%(title)s' already exists.", title=to_save["title"]), category="error")
+def profile():
+ content = ub.session.query(ub.User).filter(ub.User.id == int(current_user.id)).first()
+ downloads = list()
+ languages = speaking_language()
+ translations = babel.list_translations() + [LC('en')]
+ oauth_status = None # oauth_status = get_oauth_status()
+ for book in content.downloads:
+ downloadBook = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
+ if downloadBook:
+ downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first())
else:
- try:
- ub.session.add(shelf)
- ub.session.commit()
- flash(_(u"Shelf %(title)s created", title=to_save["title"]), category="success")
- except Exception:
- flash(_(u"There was an error"), category="error")
- return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"create a shelf"), page="shelfcreate")
- else:
- return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"create a shelf"), page="shelfcreate")
-
-
-@web.route("/shelf/edit/", methods=["GET", "POST"])
-@login_required
-def edit_shelf(shelf_id):
- shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
- if request.method == "POST":
- to_save = request.form.to_dict()
- existing_shelf = ub.session.query(ub.Shelf).filter(
- or_((ub.Shelf.name == to_save["title"]) & (ub.Shelf.is_public == 1),
- (ub.Shelf.name == to_save["title"]) & (ub.Shelf.user_id == int(current_user.id)))).filter(
- ub.Shelf.id != shelf_id).first()
- if existing_shelf:
- flash(_(u"A shelf with the name '%(title)s' already exists.", title=to_save["title"]), category="error")
- else:
- shelf.name = to_save["title"]
- if "is_public" in to_save:
- shelf.is_public = 1
- else:
- shelf.is_public = 0
- try:
- ub.session.commit()
- flash(_(u"Shelf %(title)s changed", title=to_save["title"]), category="success")
- except Exception:
- flash(_(u"There was an error"), category="error")
- return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"Edit a shelf"), page="shelfedit")
- else:
- return render_title_template('shelf_edit.html', shelf=shelf, title=_(u"Edit a shelf"), page="shelfedit")
-
-
-@web.route("/shelf/delete/")
-@login_required
-def delete_shelf(shelf_id):
- cur_shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
- deleted = None
- if current_user.role_admin():
- deleted = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).delete()
- else:
- if (not cur_shelf.is_public and cur_shelf.user_id == int(current_user.id)) \
- or (cur_shelf.is_public and current_user.role_edit_shelfs()):
- deleted = ub.session.query(ub.Shelf).filter(ub.or_(ub.and_(ub.Shelf.user_id == int(current_user.id),
- ub.Shelf.id == shelf_id),
- ub.and_(ub.Shelf.is_public == 1,
- ub.Shelf.id == shelf_id))).delete()
-
- if deleted:
- ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).delete()
- ub.session.commit()
- app.logger.info(_(u"successfully deleted shelf %(name)s", name=cur_shelf.name, category="success"))
- return redirect(url_for('index'))
-
-
-@web.route("/shelf/")
-@login_required_if_no_ano
-def show_shelf(shelf_id):
- if current_user.is_anonymous:
- shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.is_public == 1, ub.Shelf.id == shelf_id).first()
- else:
- shelf = ub.session.query(ub.Shelf).filter(ub.or_(ub.and_(ub.Shelf.user_id == int(current_user.id),
- ub.Shelf.id == shelf_id),
- ub.and_(ub.Shelf.is_public == 1,
- ub.Shelf.id == shelf_id))).first()
- result = list()
- # user is allowed to access shelf
- if shelf:
- books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).order_by(
- ub.BookShelf.order.asc()).all()
- for book in books_in_shelf:
- cur_book = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
- if cur_book:
- result.append(cur_book)
- else:
- app.logger.info('Not existing book %s in shelf %s deleted' % (book.book_id, shelf.id))
- ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book.book_id).delete()
- ub.session.commit()
- return render_title_template('shelf.html', entries=result, title=_(u"Shelf: '%(name)s'", name=shelf.name),
- shelf=shelf, page="shelf")
- else:
- flash(_(u"Error opening shelf. Shelf does not exist or is not accessible"), category="error")
- return redirect(url_for("web.index"))
-
-
-@web.route("/shelfdown/")
-def show_shelf_down(shelf_id):
- if current_user.is_anonymous:
- shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.is_public == 1, ub.Shelf.id == shelf_id).first()
- else:
- shelf = ub.session.query(ub.Shelf).filter(ub.or_(ub.and_(ub.Shelf.user_id == int(current_user.id),
- ub.Shelf.id == shelf_id),
- ub.and_(ub.Shelf.is_public == 1,
- ub.Shelf.id == shelf_id))).first()
- result = list()
- # user is allowed to access shelf
- if shelf:
- books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).order_by(
- ub.BookShelf.order.asc()).all()
- for book in books_in_shelf:
- cur_book = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
- if cur_book:
- result.append(cur_book)
- else:
- app.logger.info('Not existing book %s in shelf %s deleted' % (book.book_id, shelf.id))
- ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book.book_id).delete()
- ub.session.commit()
- return render_title_template('shelfdown.html', entries=result, title=_(u"Shelf: '%(name)s'", name=shelf.name),
- shelf=shelf, page="shelf")
- else:
- flash(_(u"Error opening shelf. Shelf does not exist or is not accessible"), category="error")
- return redirect(url_for("web.index"))
-
-@web.route("/shelf/order/", methods=["GET", "POST"])
-@login_required
-def order_shelf(shelf_id):
- if request.method == "POST":
- to_save = request.form.to_dict()
- books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).order_by(
- ub.BookShelf.order.asc()).all()
- counter = 0
- for book in books_in_shelf:
- setattr(book, 'order', to_save[str(book.book_id)])
- counter += 1
- ub.session.commit()
- if current_user.is_anonymous:
- shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.is_public == 1, ub.Shelf.id == shelf_id).first()
- else:
- shelf = ub.session.query(ub.Shelf).filter(ub.or_(ub.and_(ub.Shelf.user_id == int(current_user.id),
- ub.Shelf.id == shelf_id),
- ub.and_(ub.Shelf.is_public == 1,
- ub.Shelf.id == shelf_id))).first()
- result = list()
- if shelf:
- books_in_shelf2 = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id) \
- .order_by(ub.BookShelf.order.asc()).all()
- for book in books_in_shelf2:
- cur_book = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
- result.append(cur_book)
- return render_title_template('shelf_order.html', entries=result,
- title=_(u"Change order of Shelf: '%(name)s'", name=shelf.name),
- shelf=shelf, page="shelforder")
-
-
-@web.route("/me", methods=["GET", "POST"])
-@login_required
-def profile():
- content = ub.session.query(ub.User).filter(ub.User.id == int(current_user.id)).first()
- downloads = list()
- languages = speaking_language()
- translations = babel.list_translations() + [LC('en')]
- oauth_status = None # oauth_status = get_oauth_status()
- for book in content.downloads:
- downloadBook = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
- if downloadBook:
- downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first())
- else:
- ub.delete_download(book.book_id)
- # ub.session.query(ub.Downloads).filter(book.book_id == ub.Downloads.book_id).delete()
- # ub.session.commit()
+ ub.delete_download(book.book_id)
+ # ub.session.query(ub.Downloads).filter(book.book_id == ub.Downloads.book_id).delete()
+ # ub.session.commit()
if request.method == "POST":
to_save = request.form.to_dict()
content.random_books = 0
@@ -2734,7 +1554,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
@@ -2782,1451 +1602,3 @@ def profile():
content=content, downloads=downloads, title=_(u"%(name)s's profile",
name=current_user.nickname), page="me", registered_oauth=oauth_check, oauth_status=oauth_status)
-
-@web.route("/admin/view")
-@login_required
-@admin_required
-def admin():
- version = updater_thread.get_current_version_info()
- if version is False:
- commit = _(u'Unknown')
- else:
- if 'datetime' in version:
- commit = version['datetime']
-
- tz = datetime.timedelta(seconds=time.timezone if (time.localtime().tm_isdst == 0) else time.altzone)
- form_date = datetime.datetime.strptime(commit[:19], "%Y-%m-%dT%H:%M:%S")
- if len(commit) > 19: # check if string has timezone
- if commit[19] == '+':
- form_date -= datetime.timedelta(hours=int(commit[20:22]), minutes=int(commit[23:]))
- elif commit[19] == '-':
- form_date += datetime.timedelta(hours=int(commit[20:22]), minutes=int(commit[23:]))
- commit = format_datetime(form_date - tz, format='short', locale=get_locale())
- else:
- commit = version['version']
-
- content = ub.session.query(ub.User).all()
- settings = ub.session.query(ub.Settings).first()
- return render_title_template("admin.html", content=content, email=settings, config=config, commit=commit,
- title=_(u"Admin page"), page="admin")
-
-
-@web.route("/admin/config", methods=["GET", "POST"])
-@login_required
-@admin_required
-def configuration():
- return configuration_helper(0)
-
-
-@web.route("/admin/viewconfig", methods=["GET", "POST"])
-@login_required
-@admin_required
-def view_configuration():
- reboot_required = False
- if request.method == "POST":
- to_save = request.form.to_dict()
- content = ub.session.query(ub.Settings).first()
- if "config_calibre_web_title" in to_save:
- content.config_calibre_web_title = to_save["config_calibre_web_title"]
- if "config_columns_to_ignore" in to_save:
- content.config_columns_to_ignore = to_save["config_columns_to_ignore"]
- if "config_read_column" in to_save:
- content.config_read_column = int(to_save["config_read_column"])
- if "config_theme" in to_save:
- content.config_theme = int(to_save["config_theme"])
- if "config_title_regex" in to_save:
- if content.config_title_regex != to_save["config_title_regex"]:
- content.config_title_regex = to_save["config_title_regex"]
- reboot_required = True
- if "config_random_books" in to_save:
- content.config_random_books = int(to_save["config_random_books"])
- if "config_books_per_page" in to_save:
- content.config_books_per_page = int(to_save["config_books_per_page"])
- # Mature Content configuration
- if "config_mature_content_tags" in to_save:
- content.config_mature_content_tags = to_save["config_mature_content_tags"].strip()
-
- # Default user configuration
- content.config_default_role = 0
- if "admin_role" in to_save:
- content.config_default_role = content.config_default_role + ub.ROLE_ADMIN
- if "download_role" in to_save:
- content.config_default_role = content.config_default_role + ub.ROLE_DOWNLOAD
- if "upload_role" in to_save:
- content.config_default_role = content.config_default_role + ub.ROLE_UPLOAD
- if "edit_role" in to_save:
- content.config_default_role = content.config_default_role + ub.ROLE_EDIT
- if "delete_role" in to_save:
- content.config_default_role = content.config_default_role + ub.ROLE_DELETE_BOOKS
- if "passwd_role" in to_save:
- content.config_default_role = content.config_default_role + ub.ROLE_PASSWD
- if "passwd_role" in to_save:
- content.config_default_role = content.config_default_role + ub.ROLE_EDIT_SHELFS
- content.config_default_show = 0
- if "show_detail_random" in to_save:
- content.config_default_show = content.config_default_show + ub.DETAIL_RANDOM
- if "show_language" in to_save:
- content.config_default_show = content.config_default_show + ub.SIDEBAR_LANGUAGE
- if "show_series" in to_save:
- content.config_default_show = content.config_default_show + ub.SIDEBAR_SERIES
- if "show_category" in to_save:
- content.config_default_show = content.config_default_show + ub.SIDEBAR_CATEGORY
- if "show_hot" in to_save:
- content.config_default_show = content.config_default_show + ub.SIDEBAR_HOT
- if "show_random" in to_save:
- content.config_default_show = content.config_default_show + ub.SIDEBAR_RANDOM
- if "show_author" in to_save:
- content.config_default_show = content.config_default_show + ub.SIDEBAR_AUTHOR
- if "show_publisher" in to_save:
- content.config_default_show = content.config_default_show + ub.SIDEBAR_PUBLISHER
- if "show_best_rated" in to_save:
- content.config_default_show = content.config_default_show + ub.SIDEBAR_BEST_RATED
- if "show_read_and_unread" in to_save:
- content.config_default_show = content.config_default_show + ub.SIDEBAR_READ_AND_UNREAD
- if "show_recent" in to_save:
- content.config_default_show = content.config_default_show + ub.SIDEBAR_RECENT
- if "show_sorted" in to_save:
- content.config_default_show = content.config_default_show + ub.SIDEBAR_SORTED
- if "show_mature_content" in to_save:
- content.config_default_show = content.config_default_show + ub.MATURE_CONTENT
- ub.session.commit()
- flash(_(u"Calibre-Web configuration updated"), category="success")
- config.loadSettings()
- before_request()
- if reboot_required:
- # db.engine.dispose() # ToDo verify correct
- # ub.session.close()
- # ub.engine.dispose()
- # stop Server
- server.Server.setRestartTyp(True)
- server.Server.stopServer()
- app.logger.info('Reboot required, restarting')
- readColumn = db.session.query(db.Custom_Columns)\
- .filter(db.and_(db.Custom_Columns.datatype == 'bool',db.Custom_Columns.mark_for_delete == 0)).all()
- return render_title_template("config_view_edit.html", content=config, readColumns=readColumn,
- title=_(u"UI Configuration"), page="uiconfig")
-
-
-
-@web.route("/config", methods=["GET", "POST"])
-@unconfigured
-def basic_configuration():
- logout_user()
- return configuration_helper(1)
-
-
-def configuration_helper(origin):
- reboot_required = False
- gdriveError=None
- db_change = False
- success = False
- filedata = None
- if gdriveutils.gdrive_support == False:
- gdriveError = _('Import of optional Google Drive requirements missing')
- else:
- if not os.path.isfile(os.path.join(config.get_main_dir,'client_secrets.json')):
- gdriveError = _('client_secrets.json is missing or not readable')
- else:
- with open(os.path.join(config.get_main_dir,'client_secrets.json'), 'r') as settings:
- filedata=json.load(settings)
- if not 'web' in filedata:
- gdriveError = _('client_secrets.json is not configured for web application')
- if request.method == "POST":
- to_save = request.form.to_dict()
- content = ub.session.query(ub.Settings).first() # type: ub.Settings
- if "config_calibre_dir" in to_save:
- if content.config_calibre_dir != to_save["config_calibre_dir"]:
- content.config_calibre_dir = to_save["config_calibre_dir"]
- db_change = True
- # Google drive setup
- if not os.path.isfile(os.path.join(config.get_main_dir, 'settings.yaml')):
- content.config_use_google_drive = False
- if "config_use_google_drive" in to_save and not content.config_use_google_drive and not gdriveError:
- if filedata:
- if filedata['web']['redirect_uris'][0].endswith('/'):
- filedata['web']['redirect_uris'][0] = filedata['web']['redirect_uris'][0][:-1]
- with open(os.path.join(config.get_main_dir,'settings.yaml'), 'w') as f:
- yaml = "client_config_backend: settings\nclient_config_file: %(client_file)s\n" \
- "client_config:\n" \
- " client_id: %(client_id)s\n client_secret: %(client_secret)s\n" \
- " redirect_uri: %(redirect_uri)s\n\nsave_credentials: True\n" \
- "save_credentials_backend: file\nsave_credentials_file: %(credential)s\n\n" \
- "get_refresh_token: True\n\noauth_scope:\n" \
- " - https://www.googleapis.com/auth/drive\n"
- f.write(yaml % {'client_file': os.path.join(config.get_main_dir,'client_secrets.json'),
- 'client_id': filedata['web']['client_id'],
- 'client_secret': filedata['web']['client_secret'],
- 'redirect_uri': filedata['web']['redirect_uris'][0],
- 'credential': os.path.join(config.get_main_dir,'gdrive_credentials')})
- else:
- flash(_(u'client_secrets.json is not configured for web application'), category="error")
- return render_title_template("config_edit.html", content=config, origin=origin,
- gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
- goodreads=goodreads_support, title=_(u"Basic Configuration"),
- page="config")
- # always show google drive settings, but in case of error deny support
- if "config_use_google_drive" in to_save and not gdriveError:
- content.config_use_google_drive = "config_use_google_drive" in to_save
- else:
- content.config_use_google_drive = 0
- if "config_google_drive_folder" in to_save:
- if content.config_google_drive_folder != to_save["config_google_drive_folder"]:
- content.config_google_drive_folder = to_save["config_google_drive_folder"]
- gdriveutils.deleteDatabaseOnChange()
-
- if "config_port" in to_save:
- if content.config_port != int(to_save["config_port"]):
- content.config_port = int(to_save["config_port"])
- reboot_required = True
- if "config_keyfile" in to_save:
- if content.config_keyfile != to_save["config_keyfile"]:
- if os.path.isfile(to_save["config_keyfile"]) or to_save["config_keyfile"] is u"":
- content.config_keyfile = to_save["config_keyfile"]
- reboot_required = True
- else:
- ub.session.commit()
- flash(_(u'Keyfile location is not valid, please enter correct path'), category="error")
- return render_title_template("config_edit.html", content=config, origin=origin,
- gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
- goodreads=goodreads_support, title=_(u"Basic Configuration"),
- page="config")
- if "config_certfile" in to_save:
- if content.config_certfile != to_save["config_certfile"]:
- if os.path.isfile(to_save["config_certfile"]) or to_save["config_certfile"] is u"":
- content.config_certfile = to_save["config_certfile"]
- reboot_required = True
- else:
- ub.session.commit()
- flash(_(u'Certfile location is not valid, please enter correct path'), category="error")
- return render_title_template("config_edit.html", content=config, origin=origin,
- gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
- goodreads=goodreads_support, title=_(u"Basic Configuration"),
- page="config")
- content.config_uploading = 0
- content.config_anonbrowse = 0
- content.config_public_reg = 0
- if "config_uploading" in to_save and to_save["config_uploading"] == "on":
- content.config_uploading = 1
- if "config_anonbrowse" in to_save and to_save["config_anonbrowse"] == "on":
- content.config_anonbrowse = 1
- if "config_public_reg" in to_save and to_save["config_public_reg"] == "on":
- content.config_public_reg = 1
-
- if "config_converterpath" in to_save:
- content.config_converterpath = to_save["config_converterpath"].strip()
- if "config_calibre" in to_save:
- content.config_calibre = to_save["config_calibre"].strip()
- if "config_ebookconverter" in to_save:
- content.config_ebookconverter = int(to_save["config_ebookconverter"])
-
- #LDAP configuratop,
- if "config_use_ldap" in to_save and to_save["config_use_ldap"] == "on":
- if not "config_ldap_provider_url" in to_save or not "config_ldap_dn" in to_save:
- ub.session.commit()
- flash(_(u'Please enter a LDAP provider and a DN'), category="error")
- return render_title_template("config_edit.html", content=config, origin=origin,
- gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
- goodreads=goodreads_support, title=_(u"Basic Configuration"),
- page="config")
- else:
- content.config_use_ldap = 1
- content.config_ldap_provider_url = to_save["config_ldap_provider_url"]
- content.config_ldap_dn = to_save["config_ldap_dn"]
- db_change = True
-
- # Remote login configuration
- content.config_remote_login = ("config_remote_login" in to_save and to_save["config_remote_login"] == "on")
- if not content.config_remote_login:
- ub.session.query(ub.RemoteAuthToken).delete()
-
- # Goodreads configuration
- content.config_use_goodreads = ("config_use_goodreads" in to_save and to_save["config_use_goodreads"] == "on")
- if "config_goodreads_api_key" in to_save:
- content.config_goodreads_api_key = to_save["config_goodreads_api_key"]
- if "config_goodreads_api_secret" in to_save:
- content.config_goodreads_api_secret = to_save["config_goodreads_api_secret"]
- if "config_updater" in to_save:
- content.config_updatechannel = int(to_save["config_updater"])
-
- # GitHub OAuth configuration
- content.config_use_github_oauth = ("config_use_github_oauth" in to_save and to_save["config_use_github_oauth"] == "on")
- if "config_github_oauth_client_id" in to_save:
- content.config_github_oauth_client_id = to_save["config_github_oauth_client_id"]
- if "config_github_oauth_client_secret" in to_save:
- content.config_github_oauth_client_secret = to_save["config_github_oauth_client_secret"]
-
- if content.config_github_oauth_client_id != config.config_github_oauth_client_id or \
- content.config_github_oauth_client_secret != config.config_github_oauth_client_secret:
- reboot_required = True
-
- # Google OAuth configuration
- content.config_use_google_oauth = ("config_use_google_oauth" in to_save and to_save["config_use_google_oauth"] == "on")
- if "config_google_oauth_client_id" in to_save:
- content.config_google_oauth_client_id = to_save["config_google_oauth_client_id"]
- if "config_google_oauth_client_secret" in to_save:
- content.config_google_oauth_client_secret = to_save["config_google_oauth_client_secret"]
-
- if content.config_google_oauth_client_id != config.config_google_oauth_client_id or \
- content.config_google_oauth_client_secret != config.config_google_oauth_client_secret:
- reboot_required = True
-
- if "config_log_level" in to_save:
- content.config_log_level = int(to_save["config_log_level"])
- if content.config_logfile != to_save["config_logfile"]:
- # check valid path, only path or file
- if os.path.dirname(to_save["config_logfile"]):
- if os.path.exists(os.path.dirname(to_save["config_logfile"])) and \
- os.path.basename(to_save["config_logfile"]) and not os.path.isdir(to_save["config_logfile"]):
- content.config_logfile = to_save["config_logfile"]
- else:
- ub.session.commit()
- flash(_(u'Logfile location is not valid, please enter correct path'), category="error")
- return render_title_template("config_edit.html", content=config, origin=origin,
- gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
- goodreads=goodreads_support, title=_(u"Basic Configuration"),
- page="config")
- else:
- content.config_logfile = to_save["config_logfile"]
- reboot_required = True
-
- # Rarfile Content configuration
- if "config_rarfile_location" in to_save and to_save['config_rarfile_location'] is not u"":
- check = helper.check_unrar(to_save["config_rarfile_location"].strip())
- if not check[0] :
- content.config_rarfile_location = to_save["config_rarfile_location"].strip()
- else:
- flash(check[1], category="error")
- return render_title_template("config_edit.html", content=config, origin=origin,
- gdrive=gdriveutils.gdrive_support, goodreads=goodreads_support,
- rarfile_support=rar_support, title=_(u"Basic Configuration"))
- try:
- if content.config_use_google_drive and is_gdrive_ready() and not \
- os.path.exists(os.path.join(content.config_calibre_dir, "metadata.db")):
- gdriveutils.downloadFile(None, "metadata.db", config.config_calibre_dir + "/metadata.db")
- if db_change:
- if config.db_configured:
- db.session.close()
- db.engine.dispose()
- ub.session.commit()
- flash(_(u"Calibre-Web configuration updated"), category="success")
- config.loadSettings()
- app.logger.setLevel(config.config_log_level)
- logging.getLogger("book_formats").setLevel(config.config_log_level)
- except Exception as e:
- flash(e, category="error")
- return render_title_template("config_edit.html", content=config, origin=origin,
- gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
- goodreads=goodreads_support, rarfile_support=rar_support,
- title=_(u"Basic Configuration"), page="config")
- if db_change:
- reload(db)
- if not db.setup_db():
- flash(_(u'DB location is not valid, please enter correct path'), category="error")
- return render_title_template("config_edit.html", content=config, origin=origin,
- gdrive=gdriveutils.gdrive_support,gdriveError=gdriveError,
- goodreads=goodreads_support, rarfile_support=rar_support,
- title=_(u"Basic Configuration"), page="config")
- if reboot_required:
- # stop Server
- server.Server.setRestartTyp(True)
- server.Server.stopServer()
- app.logger.info('Reboot required, restarting')
- if origin:
- success = True
- if is_gdrive_ready() and gdriveutils.gdrive_support == True: # and config.config_use_google_drive == True:
- gdrivefolders=gdriveutils.listRootFolders()
- else:
- gdrivefolders=list()
- return render_title_template("config_edit.html", origin=origin, success=success, content=config,
- show_authenticate_google_drive=not is_gdrive_ready(),
- gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
- gdrivefolders=gdrivefolders, rarfile_support=rar_support,
- goodreads=goodreads_support, title=_(u"Basic Configuration"), page="config")
-
-
-@web.route("/admin/user/new", methods=["GET", "POST"])
-@login_required
-@admin_required
-def new_user():
- content = ub.User()
- languages = speaking_language()
- translations = [LC('en')] + babel.list_translations()
- if request.method == "POST":
- to_save = request.form.to_dict()
- content.default_language = to_save["default_language"]
- content.mature_content = "show_mature_content" in to_save
- if "locale" in to_save:
- content.locale = to_save["locale"]
- content.sidebar_view = 0
- if "show_random" in to_save:
- content.sidebar_view += ub.SIDEBAR_RANDOM
- if "show_language" in to_save:
- content.sidebar_view += ub.SIDEBAR_LANGUAGE
- if "show_series" in to_save:
- content.sidebar_view += ub.SIDEBAR_SERIES
- if "show_category" in to_save:
- content.sidebar_view += ub.SIDEBAR_CATEGORY
- if "show_hot" in to_save:
- content.sidebar_view += ub.SIDEBAR_HOT
- if "show_read_and_unread" in to_save:
- content.sidebar_view += ub.SIDEBAR_READ_AND_UNREAD
- if "show_best_rated" in to_save:
- content.sidebar_view += ub.SIDEBAR_BEST_RATED
- if "show_author" in to_save:
- content.sidebar_view += ub.SIDEBAR_AUTHOR
- if "show_publisher" in to_save:
- content.sidebar_view += ub.SIDEBAR_PUBLISHER
- if "show_detail_random" in to_save:
- content.sidebar_view += ub.DETAIL_RANDOM
- if "show_sorted" in to_save:
- content.sidebar_view += ub.SIDEBAR_SORTED
- if "show_recent" in to_save:
- content.sidebar_view += ub.SIDEBAR_RECENT
-
- content.role = 0
- if "admin_role" in to_save:
- content.role = content.role + ub.ROLE_ADMIN
- if "download_role" in to_save:
- content.role = content.role + ub.ROLE_DOWNLOAD
- if "upload_role" in to_save:
- content.role = content.role + ub.ROLE_UPLOAD
- if "edit_role" in to_save:
- content.role = content.role + ub.ROLE_EDIT
- if "delete_role" in to_save:
- content.role = content.role + ub.ROLE_DELETE_BOOKS
- if "passwd_role" in to_save:
- content.role = content.role + ub.ROLE_PASSWD
- if "edit_shelf_role" in to_save:
- content.role = content.role + ub.ROLE_EDIT_SHELFS
- if not to_save["nickname"] or not to_save["email"] or not to_save["password"]:
- flash(_(u"Please fill out all fields!"), category="error")
- return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
- title=_(u"Add new user"))
- content.password = generate_password_hash(to_save["password"])
- content.nickname = to_save["nickname"]
- 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", new_user=1, content=content, translations=translations,
- title=_(u"Add new user"))
- else:
- content.email = to_save["email"]
- try:
- ub.session.add(content)
- ub.session.commit()
- flash(_(u"User '%(user)s' created", user=content.nickname), category="success")
- return redirect(url_for('admin'))
- except IntegrityError:
- ub.session.rollback()
- flash(_(u"Found an existing account for this e-mail address or nickname."), category="error")
- else:
- content.role = config.config_default_role
- content.sidebar_view = config.config_default_show
- content.mature_content = bool(config.config_default_show & ub.MATURE_CONTENT)
- return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
- languages=languages, title=_(u"Add new user"), page="newuser")
-
-
-@web.route("/admin/mailsettings", methods=["GET", "POST"])
-@login_required
-@admin_required
-def edit_mailsettings():
- content = ub.session.query(ub.Settings).first()
- if request.method == "POST":
- to_save = request.form.to_dict()
- content.mail_server = to_save["mail_server"]
- content.mail_port = int(to_save["mail_port"])
- content.mail_login = to_save["mail_login"]
- content.mail_password = to_save["mail_password"]
- content.mail_from = to_save["mail_from"]
- content.mail_use_ssl = int(to_save["mail_use_ssl"])
- try:
- ub.session.commit()
- except Exception as e:
- flash(e, category="error")
- if "test" in to_save and to_save["test"]:
- if current_user.kindle_mail:
- result = helper.send_test_mail(current_user.kindle_mail, current_user.nickname)
- if result is None:
- flash(_(u"Test e-mail successfully send to %(kindlemail)s", kindlemail=current_user.kindle_mail),
- category="success")
- else:
- flash(_(u"There was an error sending the Test e-mail: %(res)s", res=result), category="error")
- else:
- flash(_(u"Please configure your kindle e-mail address first..."), category="error")
- else:
- flash(_(u"E-mail server settings updated"), category="success")
- return render_title_template("email_edit.html", content=content, title=_(u"Edit e-mail server settings"),
- page="mailset")
-
-
-@web.route("/admin/user/", methods=["GET", "POST"])
-@login_required
-@admin_required
-def edit_user(user_id):
- content = ub.session.query(ub.User).filter(ub.User.id == int(user_id)).first() # type: ub.User
- downloads = list()
- languages = speaking_language()
- translations = babel.list_translations() + [LC('en')]
- for book in content.downloads:
- downloadbook = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
- if downloadbook:
- downloads.append(downloadbook)
- else:
- ub.delete_download(book.book_id)
- # ub.session.query(ub.Downloads).filter(book.book_id == ub.Downloads.book_id).delete()
- # ub.session.commit()
- if request.method == "POST":
- to_save = request.form.to_dict()
- if "delete" in to_save:
- 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'))
- else:
- if "password" in to_save and to_save["password"]:
- content.password = generate_password_hash(to_save["password"])
-
- if "admin_role" in to_save and not content.role_admin():
- content.role = content.role + ub.ROLE_ADMIN
- elif "admin_role" not in to_save and content.role_admin():
- content.role = content.role - ub.ROLE_ADMIN
-
- if "download_role" in to_save and not content.role_download():
- content.role = content.role + ub.ROLE_DOWNLOAD
- elif "download_role" not in to_save and content.role_download():
- content.role = content.role - ub.ROLE_DOWNLOAD
-
- if "upload_role" in to_save and not content.role_upload():
- content.role = content.role + ub.ROLE_UPLOAD
- elif "upload_role" not in to_save and content.role_upload():
- content.role = content.role - ub.ROLE_UPLOAD
-
- if "edit_role" in to_save and not content.role_edit():
- content.role = content.role + ub.ROLE_EDIT
- elif "edit_role" not in to_save and content.role_edit():
- content.role = content.role - ub.ROLE_EDIT
-
- if "delete_role" in to_save and not content.role_delete_books():
- content.role = content.role + ub.ROLE_DELETE_BOOKS
- elif "delete_role" not in to_save and content.role_delete_books():
- content.role = content.role - ub.ROLE_DELETE_BOOKS
-
- if "passwd_role" in to_save and not content.role_passwd():
- content.role = content.role + ub.ROLE_PASSWD
- elif "passwd_role" not in to_save and content.role_passwd():
- content.role = content.role - ub.ROLE_PASSWD
-
- if "edit_shelf_role" in to_save and not content.role_edit_shelfs():
- content.role = content.role + ub.ROLE_EDIT_SHELFS
- elif "edit_shelf_role" not in to_save and content.role_edit_shelfs():
- content.role = content.role - ub.ROLE_EDIT_SHELFS
-
- if "show_random" in to_save and not content.show_random_books():
- content.sidebar_view += ub.SIDEBAR_RANDOM
- elif "show_random" not in to_save and content.show_random_books():
- content.sidebar_view -= ub.SIDEBAR_RANDOM
-
- if "show_language" in to_save and not content.show_language():
- content.sidebar_view += ub.SIDEBAR_LANGUAGE
- elif "show_language" not in to_save and content.show_language():
- content.sidebar_view -= ub.SIDEBAR_LANGUAGE
-
- if "show_series" in to_save and not content.show_series():
- content.sidebar_view += ub.SIDEBAR_SERIES
- elif "show_series" not in to_save and content.show_series():
- content.sidebar_view -= ub.SIDEBAR_SERIES
-
- if "show_category" in to_save and not content.show_category():
- content.sidebar_view += ub.SIDEBAR_CATEGORY
- elif "show_category" not in to_save and content.show_category():
- content.sidebar_view -= ub.SIDEBAR_CATEGORY
-
- if "show_recent" in to_save and not content.show_recent():
- content.sidebar_view += ub.SIDEBAR_RECENT
- elif "show_recent" not in to_save and content.show_recent():
- content.sidebar_view -= ub.SIDEBAR_RECENT
-
- if "show_sorted" in to_save and not content.show_sorted():
- content.sidebar_view += ub.SIDEBAR_SORTED
- elif "show_sorted" not in to_save and content.show_sorted():
- content.sidebar_view -= ub.SIDEBAR_SORTED
-
- if "show_publisher" in to_save and not content.show_publisher():
- content.sidebar_view += ub.SIDEBAR_PUBLISHER
- elif "show_publisher" not in to_save and content.show_publisher():
- content.sidebar_view -= ub.SIDEBAR_PUBLISHER
-
- if "show_hot" in to_save and not content.show_hot_books():
- content.sidebar_view += ub.SIDEBAR_HOT
- elif "show_hot" not in to_save and content.show_hot_books():
- content.sidebar_view -= ub.SIDEBAR_HOT
-
- if "show_best_rated" in to_save and not content.show_best_rated_books():
- content.sidebar_view += ub.SIDEBAR_BEST_RATED
- elif "show_best_rated" not in to_save and content.show_best_rated_books():
- content.sidebar_view -= ub.SIDEBAR_BEST_RATED
-
- if "show_read_and_unread" in to_save and not content.show_read_and_unread():
- content.sidebar_view += ub.SIDEBAR_READ_AND_UNREAD
- elif "show_read_and_unread" not in to_save and content.show_read_and_unread():
- content.sidebar_view -= ub.SIDEBAR_READ_AND_UNREAD
-
- if "show_author" in to_save and not content.show_author():
- content.sidebar_view += ub.SIDEBAR_AUTHOR
- elif "show_author" not in to_save and content.show_author():
- content.sidebar_view -= ub.SIDEBAR_AUTHOR
-
- if "show_detail_random" in to_save and not content.show_detail_random():
- content.sidebar_view += ub.DETAIL_RANDOM
- elif "show_detail_random" not in to_save and content.show_detail_random():
- content.sidebar_view -= ub.DETAIL_RANDOM
-
- content.mature_content = "show_mature_content" in to_save
-
- if "default_language" in to_save:
- content.default_language = to_save["default_language"]
- if "locale" in to_save and to_save["locale"]:
- content.locale = to_save["locale"]
- if to_save["email"] and to_save["email"] != content.email:
- content.email = to_save["email"]
- 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")
- return render_title_template("user_edit.html", translations=translations, languages=languages, new_user=0,
- content=content, downloads=downloads, title=_(u"Edit User %(nick)s",
- nick=content.nickname), page="edituser")
-
-
-@web.route("/admin/resetpassword/")
-@login_required
-@admin_required
-def reset_password(user_id):
- if not config.config_public_reg:
- abort(404)
- if current_user is not None and current_user.is_authenticated:
- existing_user = ub.session.query(ub.User).filter(ub.User.id == user_id).first()
- password = helper.generate_random_password()
- existing_user.password = generate_password_hash(password)
- try:
- ub.session.commit()
- helper.send_registration_mail(existing_user.email, existing_user.nickname, password, True)
- flash(_(u"Password for user %(user)s reset", user=existing_user.nickname), category="success")
- except Exception:
- ub.session.rollback()
- flash(_(u"An unknown error occurred. Please try again later."), category="error")
- return redirect(url_for('admin'))
-
-
-def render_edit_book(book_id):
- db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort)
- cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
- book = db.session.query(db.Books)\
- .filter(db.Books.id == book_id).filter(common_filters()).first()
-
- if not book:
- flash(_(u"Error opening eBook. File does not exist or file is not accessible"), category="error")
- return redirect(url_for("web.index"))
-
- for indx in range(0, len(book.languages)):
- book.languages[indx].language_name = language_table[get_locale()][book.languages[indx].lang_code]
-
- book = order_authors(book)
-
- author_names = []
- for authr in book.authors:
- author_names.append(authr.name.replace('|', ','))
-
- # Option for showing convertbook button
- valid_source_formats=list()
- if config.config_ebookconverter == 2:
- for file in book.data:
- if file.format.lower() in EXTENSIONS_CONVERT:
- valid_source_formats.append(file.format.lower())
-
- # Determine what formats don't already exist
- allowed_conversion_formats = EXTENSIONS_CONVERT.copy()
- for file in book.data:
- try:
- allowed_conversion_formats.remove(file.format.lower())
- except Exception:
- app.logger.warning(file.format.lower() + ' already removed from list.')
-
- return render_title_template('book_edit.html', book=book, authors=author_names, cc=cc,
- title=_(u"edit metadata"), page="editbook",
- conversion_formats=allowed_conversion_formats,
- source_formats=valid_source_formats)
-
-
-def edit_cc_data(book_id, book, to_save):
- cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
- for c in cc:
- cc_string = "custom_column_" + str(c.id)
- if not c.is_multiple:
- if len(getattr(book, cc_string)) > 0:
- cc_db_value = getattr(book, cc_string)[0].value
- else:
- cc_db_value = None
- if to_save[cc_string].strip():
- if c.datatype == 'bool':
- if to_save[cc_string] == 'None':
- to_save[cc_string] = None
- else:
- to_save[cc_string] = 1 if to_save[cc_string] == 'True' else 0
- if to_save[cc_string] != cc_db_value:
- if cc_db_value is not None:
- if to_save[cc_string] is not None:
- setattr(getattr(book, cc_string)[0], 'value', to_save[cc_string])
- else:
- del_cc = getattr(book, cc_string)[0]
- getattr(book, cc_string).remove(del_cc)
- db.session.delete(del_cc)
- else:
- cc_class = db.cc_classes[c.id]
- new_cc = cc_class(value=to_save[cc_string], book=book_id)
- db.session.add(new_cc)
- elif c.datatype == 'int':
- if to_save[cc_string] == 'None':
- to_save[cc_string] = None
- if to_save[cc_string] != cc_db_value:
- if cc_db_value is not None:
- if to_save[cc_string] is not None:
- setattr(getattr(book, cc_string)[0], 'value', to_save[cc_string])
- else:
- del_cc = getattr(book, cc_string)[0]
- getattr(book, cc_string).remove(del_cc)
- db.session.delete(del_cc)
- else:
- cc_class = db.cc_classes[c.id]
- new_cc = cc_class(value=to_save[cc_string], book=book_id)
- db.session.add(new_cc)
-
- else:
- if c.datatype == 'rating':
- to_save[cc_string] = str(int(float(to_save[cc_string]) * 2))
- if to_save[cc_string].strip() != cc_db_value:
- if cc_db_value is not None:
- # remove old cc_val
- del_cc = getattr(book, cc_string)[0]
- getattr(book, cc_string).remove(del_cc)
- if len(del_cc.books) == 0:
- db.session.delete(del_cc)
- cc_class = db.cc_classes[c.id]
- new_cc = db.session.query(cc_class).filter(
- cc_class.value == to_save[cc_string].strip()).first()
- # if no cc val is found add it
- if new_cc is None:
- new_cc = cc_class(value=to_save[cc_string].strip())
- db.session.add(new_cc)
- db.session.flush()
- new_cc = db.session.query(cc_class).filter(
- cc_class.value == to_save[cc_string].strip()).first()
- # add cc value to book
- getattr(book, cc_string).append(new_cc)
- else:
- if cc_db_value is not None:
- # remove old cc_val
- del_cc = getattr(book, cc_string)[0]
- getattr(book, cc_string).remove(del_cc)
- if len(del_cc.books) == 0:
- db.session.delete(del_cc)
- else:
- input_tags = to_save[cc_string].split(',')
- input_tags = list(map(lambda it: it.strip(), input_tags))
- modify_database_object(input_tags, getattr(book, cc_string), db.cc_classes[c.id], db.session,
- 'custom')
- return cc
-
-def upload_single_file(request, book, book_id):
- # Check and handle Uploaded file
- if 'btn-upload-format' in request.files:
- requested_file = request.files['btn-upload-format']
- # check for empty request
- if requested_file.filename != '':
- if '.' in requested_file.filename:
- file_ext = requested_file.filename.rsplit('.', 1)[-1].lower()
- if file_ext not in EXTENSIONS_UPLOAD:
- flash(_("File extension '%(ext)s' is not allowed to be uploaded to this server", ext=file_ext),
- category="error")
- return redirect(url_for('show_book', book_id=book.id))
- else:
- flash(_('File to be uploaded must have an extension'), category="error")
- return redirect(url_for('show_book', book_id=book.id))
-
- file_name = book.path.rsplit('/', 1)[-1]
- filepath = os.path.normpath(os.path.join(config.config_calibre_dir, book.path))
- saved_filename = os.path.join(filepath, file_name + '.' + file_ext)
-
- # check if file path exists, otherwise create it, copy file to calibre path and delete temp file
- if not os.path.exists(filepath):
- try:
- os.makedirs(filepath)
- except OSError:
- flash(_(u"Failed to create path %(path)s (Permission denied).", path=filepath), category="error")
- return redirect(url_for('show_book', book_id=book.id))
- try:
- requested_file.save(saved_filename)
- except OSError:
- flash(_(u"Failed to store file %(file)s.", file=saved_filename), category="error")
- return redirect(url_for('show_book', book_id=book.id))
-
- file_size = os.path.getsize(saved_filename)
- is_format = db.session.query(db.Data).filter(db.Data.book == book_id).\
- filter(db.Data.format == file_ext.upper()).first()
-
- # Format entry already exists, no need to update the database
- if is_format:
- app.logger.info('Book format already existing')
- else:
- db_format = db.Data(book_id, file_ext.upper(), file_size, file_name)
- db.session.add(db_format)
- db.session.commit()
- db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort)
-
- # Queue uploader info
- uploadText=_(u"File format %(ext)s added to %(book)s", ext=file_ext.upper(), book=book.title)
- helper.global_WorkerThread.add_upload(current_user.nickname,
- "" + uploadText + " ")
-
-def upload_cover(request, book):
- if 'btn-upload-cover' in request.files:
- requested_file = request.files['btn-upload-cover']
- # check for empty request
- if requested_file.filename != '':
- file_ext = requested_file.filename.rsplit('.', 1)[-1].lower()
- filepath = os.path.normpath(os.path.join(config.config_calibre_dir, book.path))
- saved_filename = os.path.join(filepath, 'cover.' + file_ext)
-
- # check if file path exists, otherwise create it, copy file to calibre path and delete temp file
- if not os.path.exists(filepath):
- try:
- os.makedirs(filepath)
- except OSError:
- flash(_(u"Failed to create path for cover %(path)s (Permission denied).", cover=filepath),
- category="error")
- return redirect(url_for('show_book', book_id=book.id))
- try:
- requested_file.save(saved_filename)
- # im=Image.open(saved_filename)
- book.has_cover = 1
- except OSError:
- flash(_(u"Failed to store cover-file %(cover)s.", cover=saved_filename), category="error")
- return redirect(url_for('show_book', book_id=book.id))
- except IOError:
- flash(_(u"Cover-file is not a valid image file" % saved_filename), category="error")
- return redirect(url_for('show_book', book_id=book.id))
-
-@web.route("/admin/book/", methods=['GET', 'POST'])
-@login_required_if_no_ano
-@edit_required
-def edit_book(book_id):
- # Show form
- if request.method != 'POST':
- return render_edit_book(book_id)
-
- # create the function for sorting...
- db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort)
- book = db.session.query(db.Books)\
- .filter(db.Books.id == book_id).filter(common_filters()).first()
-
- # Book not found
- if not book:
- flash(_(u"Error opening eBook. File does not exist or file is not accessible"), category="error")
- return redirect(url_for("web.index"))
-
- upload_single_file(request, book, book_id)
- upload_cover(request, book)
- try:
- to_save = request.form.to_dict()
- # Update book
- edited_books_id = None
- #handle book title
- if book.title != to_save["book_title"].rstrip().strip():
- if to_save["book_title"] == '':
- to_save["book_title"] = _(u'unknown')
- book.title = to_save["book_title"].rstrip().strip()
- edited_books_id = book.id
-
- # handle author(s)
- input_authors = to_save["author_name"].split('&')
- input_authors = list(map(lambda it: it.strip().replace(',', '|'), input_authors))
- # we have all author names now
- if input_authors == ['']:
- input_authors = [_(u'unknown')] # prevent empty Author
-
- modify_database_object(input_authors, book.authors, db.Authors, db.session, 'author')
-
- # Search for each author if author is in database, if not, authorname and sorted authorname is generated new
- # everything then is assembled for sorted author field in database
- sort_authors_list = list()
- for inp in input_authors:
- stored_author = db.session.query(db.Authors).filter(db.Authors.name == inp).first()
- if not stored_author:
- stored_author = helper.get_sorted_author(inp)
- else:
- stored_author = stored_author.sort
- sort_authors_list.append(helper.get_sorted_author(stored_author))
- sort_authors = ' & '.join(sort_authors_list)
- if book.author_sort != sort_authors:
- edited_books_id = book.id
- book.author_sort = sort_authors
-
-
- if config.config_use_google_drive:
- gdriveutils.updateGdriveCalibreFromLocal()
-
- error = False
- if edited_books_id:
- error = helper.update_dir_stucture(edited_books_id, config.config_calibre_dir, input_authors[0])
-
- if not error:
- if to_save["cover_url"]:
- if helper.save_cover(to_save["cover_url"], book.path) is True:
- book.has_cover = 1
- else:
- flash(_(u"Cover is not a jpg file, can't save"), category="error")
-
- if book.series_index != to_save["series_index"]:
- book.series_index = to_save["series_index"]
-
- # Handle book comments/description
- if len(book.comments):
- book.comments[0].text = to_save["description"]
- else:
- book.comments.append(db.Comments(text=to_save["description"], book=book.id))
-
- # Handle book tags
- input_tags = to_save["tags"].split(',')
- input_tags = list(map(lambda it: it.strip(), input_tags))
- modify_database_object(input_tags, book.tags, db.Tags, db.session, 'tags')
-
- # Handle book series
- input_series = [to_save["series"].strip()]
- input_series = [x for x in input_series if x != '']
- modify_database_object(input_series, book.series, db.Series, db.session, 'series')
-
- if to_save["pubdate"]:
- try:
- book.pubdate = datetime.datetime.strptime(to_save["pubdate"], "%Y-%m-%d")
- except ValueError:
- book.pubdate = db.Books.DEFAULT_PUBDATE
- else:
- book.pubdate = db.Books.DEFAULT_PUBDATE
-
- if to_save["publisher"]:
- publisher = to_save["publisher"].rstrip().strip()
- if len(book.publishers) == 0 or (len(book.publishers) > 0 and publisher != book.publishers[0].name):
- modify_database_object([publisher], book.publishers, db.Publishers, db.session, 'publisher')
- elif len(book.publishers):
- modify_database_object([], book.publishers, db.Publishers, db.session, 'publisher')
-
-
- # handle book languages
- input_languages = to_save["languages"].split(',')
- input_languages = [x.strip().lower() for x in input_languages if x != '']
- input_l = []
- invers_lang_table = [x.lower() for x in language_table[get_locale()].values()]
- for lang in input_languages:
- try:
- res = list(language_table[get_locale()].keys())[invers_lang_table.index(lang)]
- input_l.append(res)
- except ValueError:
- app.logger.error('%s is not a valid language' % lang)
- flash(_(u"%(langname)s is not a valid language", langname=lang), category="error")
- modify_database_object(input_l, book.languages, db.Languages, db.session, 'languages')
-
- # handle book ratings
- if to_save["rating"].strip():
- old_rating = False
- if len(book.ratings) > 0:
- old_rating = book.ratings[0].rating
- ratingx2 = int(float(to_save["rating"]) * 2)
- if ratingx2 != old_rating:
- is_rating = db.session.query(db.Ratings).filter(db.Ratings.rating == ratingx2).first()
- if is_rating:
- book.ratings.append(is_rating)
- else:
- new_rating = db.Ratings(rating=ratingx2)
- book.ratings.append(new_rating)
- if old_rating:
- book.ratings.remove(book.ratings[0])
- else:
- if len(book.ratings) > 0:
- book.ratings.remove(book.ratings[0])
-
- # handle cc data
- edit_cc_data(book_id, book, to_save)
-
- db.session.commit()
- if config.config_use_google_drive:
- gdriveutils.updateGdriveCalibreFromLocal()
- if "detail_view" in to_save:
- return redirect(url_for('show_book', book_id=book.id))
- else:
- flash(_("Metadata successfully updated"), category="success")
- return render_edit_book(book_id)
- else:
- db.session.rollback()
- flash(error, category="error")
- return render_edit_book(book_id)
- except Exception as e:
- app.logger.exception(e)
- db.session.rollback()
- flash(_("Error editing book, please check logfile for details"), category="error")
- return redirect(url_for('show_book', book_id=book.id))
-
-
-@web.route("/upload", methods=["GET", "POST"])
-@login_required_if_no_ano
-@upload_required
-def upload():
- if not config.config_uploading:
- abort(404)
- if request.method == 'POST' and 'btn-upload' in request.files:
- for requested_file in request.files.getlist("btn-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()
- if file_ext not in EXTENSIONS_UPLOAD:
- flash(
- _("File extension '%(ext)s' is not allowed to be uploaded to this server",
- ext=file_ext), category="error")
- return redirect(url_for('index'))
- 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
- authr = meta.author
- tags = meta.tags
- series = meta.series
- series_index = meta.series_id
- title_dir = helper.get_valid_filename(title)
- author_dir = helper.get_valid_filename(authr)
- filepath = os.path.join(config.config_calibre_dir, author_dir, title_dir)
- saved_filename = os.path.join(filepath, title_dir + meta.extension.lower())
-
- # check if file path exists, otherwise create it, copy file to calibre path and delete temp file
- if not os.path.exists(filepath):
- try:
- os.makedirs(filepath)
- except OSError:
- flash(_(u"Failed to create path %(path)s (Permission denied).", path=filepath), category="error")
- return redirect(url_for('index'))
- try:
- copyfile(meta.file_path, saved_filename)
- except OSError:
- flash(_(u"Failed to store file %(file)s (Permission denied).", file=saved_filename), category="error")
- return redirect(url_for('index'))
- try:
- os.unlink(meta.file_path)
- except OSError:
- flash(_(u"Failed to delete file %(file)s (Permission denied).", file= meta.file_path),
- category="warning")
-
- if meta.cover is None:
- has_cover = 0
- copyfile(os.path.join(config.get_main_dir, "cps/static/generic_cover.jpg"),
- os.path.join(filepath, "cover.jpg"))
- else:
- has_cover = 1
- move(meta.cover, os.path.join(filepath, "cover.jpg"))
-
- # handle authors
- is_author = db.session.query(db.Authors).filter(db.Authors.name == authr).first()
- if is_author:
- db_author = is_author
- 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()
- if is_series:
- db_series = is_series
- elif series != '':
- db_series = db.Series(series, "")
- db.session.add(db_series)
-
- # add language actually one value in list
- input_language = meta.languages
- db_language = None
- if input_language != "":
- input_language = isoLanguages.get(name=input_language).part3
- hasLanguage = db.session.query(db.Languages).filter(db.Languages.lang_code == input_language).first()
- if hasLanguage:
- db_language = hasLanguage
- 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),
- series_index, datetime.datetime.now(), path, has_cover, db_author, [], db_language)
- db_book.authors.append(db_author)
- if db_series:
- db_book.series.append(db_series)
- if db_language is not None:
- 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)
- db.session.flush()
-
- # add comment
- book_id = db_book.id
- 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)
- book = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
-
- # upload book to gdrive if nesseccary and add "(bookid)" to folder name
- if config.config_use_google_drive:
- gdriveutils.updateGdriveCalibreFromLocal()
- error = helper.update_dir_stucture(book.id, config.config_calibre_dir)
- db.session.commit()
- if config.config_use_google_drive:
- gdriveutils.updateGdriveCalibreFromLocal()
- if error:
- flash(error, category="error")
- uploadText=_(u"File %(file)s uploaded", file=book.title)
- helper.global_WorkerThread.add_upload(current_user.nickname,
- "" + uploadText + " ")
-
- # create data for displaying display Full language name instead of iso639.part3language
- if db_language is not None:
- book.languages[0].language_name = _(meta.languages)
- author_names = []
- for author in db_book.authors:
- author_names.append(author.name)
- if len(request.files.getlist("btn-upload")) < 2:
- cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.
- datatype.notin_(db.cc_exceptions)).all()
- if current_user.role_edit() or current_user.role_admin():
- return render_title_template('book_edit.html', book=book, authors=author_names,
- cc=cc, title=_(u"edit metadata"), page="upload")
- book_in_shelfs = []
- kindle_list = helper.check_send_to_kindle(book)
- reader_list = helper.check_read_formats(book)
-
- return render_title_template('detail.html', entry=book, cc=cc,
- title=book.title, books_shelfs=book_in_shelfs, kindle_list=kindle_list,
- reader_list=reader_list, page="upload")
- return redirect(url_for("web.index"))
-
-
-@web.route("/admin/book/convert/", methods=['POST'])
-@login_required_if_no_ano
-@edit_required
-def convert_bookformat(book_id):
- # check to see if we have form fields to work with - if not send user back
- book_format_from = request.form.get('book_format_from', None)
- book_format_to = request.form.get('book_format_to', None)
-
- if (book_format_from is None) or (book_format_to is None):
- flash(_(u"Source or destination format for conversion missing"), category="error")
- return redirect(request.environ["HTTP_REFERER"])
-
- app.logger.debug('converting: book id: ' + str(book_id) +
- ' from: ' + request.form['book_format_from'] +
- ' to: ' + request.form['book_format_to'])
- rtn = helper.convert_book_format(book_id, config.config_calibre_dir, book_format_from.upper(),
- book_format_to.upper(), current_user.nickname)
-
- if rtn is None:
- flash(_(u"Book successfully queued for converting to %(book_format)s",
- book_format=book_format_to),
- category="success")
- else:
- flash(_(u"There was an error converting this book: %(res)s", res=rtn), category="error")
- return redirect(request.environ["HTTP_REFERER"])
-
-'''
-def register_oauth_blueprint(blueprint, show_name):
- if blueprint.name != "":
- oauth_check[blueprint.name] = show_name
-
-
-def register_user_with_oauth(user=None):
- all_oauth = {}
- for oauth in oauth_check.keys():
- if oauth + '_oauth_user_id' in session and session[oauth + '_oauth_user_id'] != '':
- all_oauth[oauth] = oauth_check[oauth]
- if len(all_oauth.keys()) == 0:
- return
- if user is None:
- flash(_(u"Register with %s" % ", ".join(list(all_oauth.values()))), category="success")
- else:
- for oauth in all_oauth.keys():
- # Find this OAuth token in the database, or create it
- query = ub.session.query(ub.OAuth).filter_by(
- provider=oauth,
- provider_user_id=session[oauth + "_oauth_user_id"],
- )
- try:
- oauth = query.one()
- oauth.user_id = user.id
- except NoResultFound:
- # no found, return error
- return
- try:
- ub.session.commit()
- except Exception as e:
- app.logger.exception(e)
- ub.session.rollback()
-
-
-def logout_oauth_user():
- for oauth in oauth_check.keys():
- if oauth + '_oauth_user_id' in session:
- session.pop(oauth + '_oauth_user_id')
-
-
-github_blueprint = make_github_blueprint(
- client_id=config.config_github_oauth_client_id,
- client_secret=config.config_github_oauth_client_secret,
- redirect_to="github_login",)
-
-google_blueprint = make_google_blueprint(
- client_id=config.config_google_oauth_client_id,
- client_secret=config.config_google_oauth_client_secret,
- redirect_to="google_login",
- scope=[
- "https://www.googleapis.com/auth/plus.me",
- "https://www.googleapis.com/auth/userinfo.email",
- ]
-)
-
-app.register_blueprint(google_blueprint, url_prefix="/login")
-app.register_blueprint(github_blueprint, url_prefix='/login')
-
-github_blueprint.backend = OAuthBackend(ub.OAuth, ub.session, user=current_user, user_required=True)
-google_blueprint.backend = OAuthBackend(ub.OAuth, ub.session, user=current_user, user_required=True)
-
-
-if config.config_use_github_oauth:
- register_oauth_blueprint(github_blueprint, 'GitHub')
-if config.config_use_google_oauth:
- register_oauth_blueprint(google_blueprint, 'Google')
-
-
-@oauth_authorized.connect_via(github_blueprint)
-def github_logged_in(blueprint, token):
- if not token:
- flash(_("Failed to log in with GitHub."), category="error")
- return False
-
- resp = blueprint.session.get("/user")
- if not resp.ok:
- flash(_("Failed to fetch user info from GitHub."), category="error")
- return False
-
- github_info = resp.json()
- github_user_id = str(github_info["id"])
- return oauth_update_token(blueprint, token, github_user_id)
-
-
-@oauth_authorized.connect_via(google_blueprint)
-def google_logged_in(blueprint, token):
- if not token:
- flash(_("Failed to log in with Google."), category="error")
- return False
-
- resp = blueprint.session.get("/oauth2/v2/userinfo")
- if not resp.ok:
- flash(_("Failed to fetch user info from Google."), category="error")
- return False
-
- google_info = resp.json()
- google_user_id = str(google_info["id"])
-
- return oauth_update_token(blueprint, token, google_user_id)
-
-
-def oauth_update_token(blueprint, token, provider_user_id):
- session[blueprint.name + "_oauth_user_id"] = provider_user_id
- session[blueprint.name + "_oauth_token"] = token
-
- # Find this OAuth token in the database, or create it
- query = ub.session.query(ub.OAuth).filter_by(
- provider=blueprint.name,
- provider_user_id=provider_user_id,
- )
- try:
- oauth = query.one()
- # update token
- oauth.token = token
- except NoResultFound:
- oauth = ub.OAuth(
- provider=blueprint.name,
- provider_user_id=provider_user_id,
- token=token,
- )
- try:
- ub.session.add(oauth)
- ub.session.commit()
- except Exception as e:
- app.logger.exception(e)
- ub.session.rollback()
-
- # Disable Flask-Dance's default behavior for saving the OAuth token
- return False
-
-
-def bind_oauth_or_register(provider, provider_user_id, redirect_url):
- query = ub.session.query(ub.OAuth).filter_by(
- provider=provider,
- provider_user_id=provider_user_id,
- )
- try:
- oauth = query.one()
- # already bind with user, just login
- if oauth.user:
- login_user(oauth.user)
- return redirect(url_for('index'))
- else:
- # bind to current user
- if current_user and current_user.is_authenticated:
- oauth.user = current_user
- try:
- ub.session.add(oauth)
- ub.session.commit()
- except Exception as e:
- app.logger.exception(e)
- ub.session.rollback()
- return redirect(url_for('register'))
- except NoResultFound:
- return redirect(url_for(redirect_url))
-
-
-def get_oauth_status():
- status = []
- query = ub.session.query(ub.OAuth).filter_by(
- user_id=current_user.id,
- )
- try:
- oauths = query.all()
- for oauth in oauths:
- status.append(oauth.provider)
- return status
- except NoResultFound:
- return None
-
-
-def unlink_oauth(provider):
- if request.host_url + 'me' != request.referrer:
- pass
- query = ub.session.query(ub.OAuth).filter_by(
- provider=provider,
- user_id=current_user.id,
- )
- try:
- oauth = query.one()
- if current_user and current_user.is_authenticated:
- oauth.user = current_user
- try:
- ub.session.delete(oauth)
- ub.session.commit()
- logout_oauth_user()
- flash(_("Unlink to %(oauth)s success.", oauth=oauth_check[provider]), category="success")
- except Exception as e:
- app.logger.exception(e)
- ub.session.rollback()
- flash(_("Unlink to %(oauth)s failed.", oauth=oauth_check[provider]), category="error")
- except NoResultFound:
- app.logger.warning("oauth %s for user %d not fount" % (provider, current_user.id))
- flash(_("Not linked to %(oauth)s.", oauth=oauth_check[provider]), category="error")
- return redirect(url_for('profile'))
-
-
-# notify on OAuth provider error
-@oauth_error.connect_via(github_blueprint)
-def github_error(blueprint, error, error_description=None, error_uri=None):
- msg = (
- "OAuth error from {name}! "
- "error={error} description={description} uri={uri}"
- ).format(
- name=blueprint.name,
- error=error,
- description=error_description,
- uri=error_uri,
- )
- flash(msg, category="error")
-
-
-@web.route('/github')
-@github_oauth_required
-def github_login():
- if not github.authorized:
- return redirect(url_for('github.login'))
- account_info = github.get('/user')
- if account_info.ok:
- account_info_json = account_info.json()
- return bind_oauth_or_register(github_blueprint.name, account_info_json['id'], 'github.login')
- flash(_(u"GitHub Oauth error, please retry later."), category="error")
- return redirect(url_for('login'))
-
-
-@web.route('/unlink/github', methods=["GET"])
-@login_required
-def github_login_unlink():
- return unlink_oauth(github_blueprint.name)
-
-
-@web.route('/google')
-@google_oauth_required
-def google_login():
- if not google.authorized:
- return redirect(url_for("google.login"))
- resp = google.get("/oauth2/v2/userinfo")
- if resp.ok:
- account_info_json = resp.json()
- return bind_oauth_or_register(google_blueprint.name, account_info_json['id'], 'google.login')
- flash(_(u"Google Oauth error, please retry later."), category="error")
- return redirect(url_for('login'))
-
-
-@oauth_error.connect_via(google_blueprint)
-def google_error(blueprint, error, error_description=None, error_uri=None):
- msg = (
- "OAuth error from {name}! "
- "error={error} description={description} uri={uri}"
- ).format(
- name=blueprint.name,
- error=error,
- description=error_description,
- uri=error_uri,
- )
- flash(msg, category="error")
-
-
-@web.route('/unlink/google', methods=["GET"])
-@login_required
-def google_login_unlink():
- return unlink_oauth(google_blueprint.name)
-'''