Merge branch 'master' of https://github.com/janeczku/calibre-web
This commit is contained in:
commit
2f3f13afb9
|
@ -245,7 +245,7 @@ def list_users():
|
||||||
off = int(request.args.get("offset") or 0)
|
off = int(request.args.get("offset") or 0)
|
||||||
limit = int(request.args.get("limit") or 10)
|
limit = int(request.args.get("limit") or 10)
|
||||||
search = request.args.get("search")
|
search = request.args.get("search")
|
||||||
sort = request.args.get("sort", "state")
|
sort = request.args.get("sort", "id")
|
||||||
order = request.args.get("order", "").lower()
|
order = request.args.get("order", "").lower()
|
||||||
state = None
|
state = None
|
||||||
if sort == "state":
|
if sort == "state":
|
||||||
|
@ -254,7 +254,7 @@ def list_users():
|
||||||
if sort != "state" and order:
|
if sort != "state" and order:
|
||||||
order = text(sort + " " + order)
|
order = text(sort + " " + order)
|
||||||
elif not state:
|
elif not state:
|
||||||
order = ub.User.name.desc()
|
order = ub.User.id.asc()
|
||||||
|
|
||||||
all_user = ub.session.query(ub.User)
|
all_user = ub.session.query(ub.User)
|
||||||
if not config.config_anonbrowse:
|
if not config.config_anonbrowse:
|
||||||
|
@ -371,7 +371,7 @@ def edit_list_user(param):
|
||||||
'message':_(u"No admin user remaining, can't remove admin role",
|
'message':_(u"No admin user remaining, can't remove admin role",
|
||||||
nick=user.name)}), mimetype='application/json')
|
nick=user.name)}), mimetype='application/json')
|
||||||
user.role &= ~int(vals['field_index'])
|
user.role &= ~int(vals['field_index'])
|
||||||
elif param == 'sidebar_view':
|
elif param.startswith('sidebar'):
|
||||||
if user.name == "Guest" and int(vals['field_index']) == constants.SIDEBAR_READ_AND_UNREAD:
|
if user.name == "Guest" and int(vals['field_index']) == constants.SIDEBAR_READ_AND_UNREAD:
|
||||||
raise Exception(_("Guest can't have this view"))
|
raise Exception(_("Guest can't have this view"))
|
||||||
if vals['value'] == 'true':
|
if vals['value'] == 'true':
|
||||||
|
|
|
@ -324,19 +324,19 @@ def delete_book(book_id, book_format, jsonResponse):
|
||||||
result, error = helper.delete_book(book, config.config_calibre_dir, book_format=book_format.upper())
|
result, error = helper.delete_book(book, config.config_calibre_dir, book_format=book_format.upper())
|
||||||
if not result:
|
if not result:
|
||||||
if jsonResponse:
|
if jsonResponse:
|
||||||
return json.dumps({"location": url_for("editbook.edit_book"),
|
return json.dumps([{"location": url_for("editbook.edit_book", book_id=book_id),
|
||||||
"type": "alert",
|
"type": "danger",
|
||||||
"format": "",
|
"format": "",
|
||||||
"error": error}),
|
"message": error}])
|
||||||
else:
|
else:
|
||||||
flash(error, category="error")
|
flash(error, category="error")
|
||||||
return redirect(url_for('editbook.edit_book', book_id=book_id))
|
return redirect(url_for('editbook.edit_book', book_id=book_id))
|
||||||
if error:
|
if error:
|
||||||
if jsonResponse:
|
if jsonResponse:
|
||||||
warning = {"location": url_for("editbook.edit_book"),
|
warning = {"location": url_for("editbook.edit_book", book_id=book_id),
|
||||||
"type": "warning",
|
"type": "warning",
|
||||||
"format": "",
|
"format": "",
|
||||||
"error": error}
|
"message": error}
|
||||||
else:
|
else:
|
||||||
flash(error, category="warning")
|
flash(error, category="warning")
|
||||||
if not book_format:
|
if not book_format:
|
||||||
|
@ -348,6 +348,15 @@ def delete_book(book_id, book_format, jsonResponse):
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
log.debug_or_exception(ex)
|
log.debug_or_exception(ex)
|
||||||
calibre_db.session.rollback()
|
calibre_db.session.rollback()
|
||||||
|
if jsonResponse:
|
||||||
|
return json.dumps([{"location": url_for("editbook.edit_book", book_id=book_id),
|
||||||
|
"type": "danger",
|
||||||
|
"format": "",
|
||||||
|
"message": ex}])
|
||||||
|
else:
|
||||||
|
flash(str(ex), category="error")
|
||||||
|
return redirect(url_for('editbook.edit_book', book_id=book_id))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# book not found
|
# book not found
|
||||||
log.error('Book with id "%s" could not be deleted: not found', book_id)
|
log.error('Book with id "%s" could not be deleted: not found', book_id)
|
||||||
|
|
|
@ -30,6 +30,7 @@ from flask_babel import gettext as _
|
||||||
from flask_dance.consumer import oauth_authorized, oauth_error
|
from flask_dance.consumer import oauth_authorized, oauth_error
|
||||||
from flask_dance.contrib.github import make_github_blueprint, github
|
from flask_dance.contrib.github import make_github_blueprint, github
|
||||||
from flask_dance.contrib.google import make_google_blueprint, google
|
from flask_dance.contrib.google import make_google_blueprint, google
|
||||||
|
from oauthlib.oauth2 import TokenExpiredError, InvalidGrantError
|
||||||
from flask_login import login_user, current_user, login_required
|
from flask_login import login_user, current_user, login_required
|
||||||
from sqlalchemy.orm.exc import NoResultFound
|
from sqlalchemy.orm.exc import NoResultFound
|
||||||
|
|
||||||
|
@ -146,6 +147,7 @@ def bind_oauth_or_register(provider_id, provider_user_id, redirect_url, provider
|
||||||
ub.session.add(oauth_entry)
|
ub.session.add(oauth_entry)
|
||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
flash(_(u"Link to %(oauth)s Succeeded", oauth=provider_name), category="success")
|
flash(_(u"Link to %(oauth)s Succeeded", oauth=provider_name), category="success")
|
||||||
|
log.info("Link to {} Succeeded".format(provider_name))
|
||||||
return redirect(url_for('web.profile'))
|
return redirect(url_for('web.profile'))
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
log.debug_or_exception(ex)
|
log.debug_or_exception(ex)
|
||||||
|
@ -194,6 +196,7 @@ def unlink_oauth(provider):
|
||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
logout_oauth_user()
|
logout_oauth_user()
|
||||||
flash(_(u"Unlink to %(oauth)s Succeeded", oauth=oauth_check[provider]), category="success")
|
flash(_(u"Unlink to %(oauth)s Succeeded", oauth=oauth_check[provider]), category="success")
|
||||||
|
log.info("Unlink to {} Succeeded".format(oauth_check[provider]))
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
log.debug_or_exception(ex)
|
log.debug_or_exception(ex)
|
||||||
ub.session.rollback()
|
ub.session.rollback()
|
||||||
|
@ -257,11 +260,13 @@ if ub.oauth_support:
|
||||||
def github_logged_in(blueprint, token):
|
def github_logged_in(blueprint, token):
|
||||||
if not token:
|
if not token:
|
||||||
flash(_(u"Failed to log in with GitHub."), category="error")
|
flash(_(u"Failed to log in with GitHub."), category="error")
|
||||||
|
log.error("Failed to log in with GitHub")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
resp = blueprint.session.get("/user")
|
resp = blueprint.session.get("/user")
|
||||||
if not resp.ok:
|
if not resp.ok:
|
||||||
flash(_(u"Failed to fetch user info from GitHub."), category="error")
|
flash(_(u"Failed to fetch user info from GitHub."), category="error")
|
||||||
|
log.error("Failed to fetch user info from GitHub")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
github_info = resp.json()
|
github_info = resp.json()
|
||||||
|
@ -273,11 +278,13 @@ if ub.oauth_support:
|
||||||
def google_logged_in(blueprint, token):
|
def google_logged_in(blueprint, token):
|
||||||
if not token:
|
if not token:
|
||||||
flash(_(u"Failed to log in with Google."), category="error")
|
flash(_(u"Failed to log in with Google."), category="error")
|
||||||
|
log.error("Failed to log in with Google")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
resp = blueprint.session.get("/oauth2/v2/userinfo")
|
resp = blueprint.session.get("/oauth2/v2/userinfo")
|
||||||
if not resp.ok:
|
if not resp.ok:
|
||||||
flash(_(u"Failed to fetch user info from Google."), category="error")
|
flash(_(u"Failed to fetch user info from Google."), category="error")
|
||||||
|
log.error("Failed to fetch user info from Google")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
google_info = resp.json()
|
google_info = resp.json()
|
||||||
|
@ -318,11 +325,16 @@ if ub.oauth_support:
|
||||||
def github_login():
|
def github_login():
|
||||||
if not github.authorized:
|
if not github.authorized:
|
||||||
return redirect(url_for('github.login'))
|
return redirect(url_for('github.login'))
|
||||||
|
try:
|
||||||
account_info = github.get('/user')
|
account_info = github.get('/user')
|
||||||
if account_info.ok:
|
if account_info.ok:
|
||||||
account_info_json = account_info.json()
|
account_info_json = account_info.json()
|
||||||
return bind_oauth_or_register(oauthblueprints[0]['id'], account_info_json['id'], 'github.login', 'github')
|
return bind_oauth_or_register(oauthblueprints[0]['id'], account_info_json['id'], 'github.login', 'github')
|
||||||
flash(_(u"GitHub Oauth error, please retry later."), category="error")
|
flash(_(u"GitHub Oauth error, please retry later."), category="error")
|
||||||
|
log.error("GitHub Oauth error, please retry later")
|
||||||
|
except (InvalidGrantError, TokenExpiredError) as e:
|
||||||
|
flash(_(u"GitHub Oauth error: {}").format(e), category="error")
|
||||||
|
log.error(e)
|
||||||
return redirect(url_for('web.login'))
|
return redirect(url_for('web.login'))
|
||||||
|
|
||||||
|
|
||||||
|
@ -337,11 +349,16 @@ def github_login_unlink():
|
||||||
def google_login():
|
def google_login():
|
||||||
if not google.authorized:
|
if not google.authorized:
|
||||||
return redirect(url_for("google.login"))
|
return redirect(url_for("google.login"))
|
||||||
|
try:
|
||||||
resp = google.get("/oauth2/v2/userinfo")
|
resp = google.get("/oauth2/v2/userinfo")
|
||||||
if resp.ok:
|
if resp.ok:
|
||||||
account_info_json = resp.json()
|
account_info_json = resp.json()
|
||||||
return bind_oauth_or_register(oauthblueprints[1]['id'], account_info_json['id'], 'google.login', 'google')
|
return bind_oauth_or_register(oauthblueprints[1]['id'], account_info_json['id'], 'google.login', 'google')
|
||||||
flash(_(u"Google Oauth error, please retry later."), category="error")
|
flash(_(u"Google Oauth error, please retry later."), category="error")
|
||||||
|
log.error("Google Oauth error, please retry later")
|
||||||
|
except (InvalidGrantError, TokenExpiredError) as e:
|
||||||
|
flash(_(u"Google Oauth error: {}").format(e), category="error")
|
||||||
|
log.error(e)
|
||||||
return redirect(url_for('web.login'))
|
return redirect(url_for('web.login'))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %}
|
||||||
{% macro text_table_row(parameter, edit_text, show_text, validate) -%}
|
{% macro text_table_row(parameter, edit_text, show_text, validate, sort) -%}
|
||||||
<th data-field="{{ parameter }}" id="{{ parameter }}" data-sortable="true"
|
<th data-field="{{ parameter }}" id="{{ parameter }}"
|
||||||
|
{% if sort %}data-sortable="true" {% endif %}
|
||||||
data-visible = "{{visiblility.get(parameter)}}"
|
data-visible = "{{visiblility.get(parameter)}}"
|
||||||
{% if g.user.role_edit() %}
|
{% if g.user.role_edit() %}
|
||||||
data-editable-type="text"
|
data-editable-type="text"
|
||||||
|
@ -43,16 +44,16 @@
|
||||||
<th data-field="state" data-checkbox="true" data-sortable="true"></th>
|
<th data-field="state" data-checkbox="true" data-sortable="true"></th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<th data-field="id" id="id" data-visible="false" data-switchable="false"></th>
|
<th data-field="id" id="id" data-visible="false" data-switchable="false"></th>
|
||||||
{{ text_table_row('title', _('Enter Title'),_('Title'), true) }}
|
{{ text_table_row('title', _('Enter Title'),_('Title'), true, true) }}
|
||||||
{{ text_table_row('sort', _('Enter Title Sort'),_('Title Sort'), false) }}
|
{{ text_table_row('sort', _('Enter Title Sort'),_('Title Sort'), false, true) }}
|
||||||
{{ text_table_row('author_sort', _('Enter Author Sort'),_('Author Sort'), false) }}
|
{{ text_table_row('author_sort', _('Enter Author Sort'),_('Author Sort'), false, true) }}
|
||||||
{{ text_table_row('authors', _('Enter Authors'),_('Authors'), true) }}
|
{{ text_table_row('authors', _('Enter Authors'),_('Authors'), true) }}
|
||||||
{{ text_table_row('tags', _('Enter Categories'),_('Categories'), false) }}
|
{{ text_table_row('tags', _('Enter Categories'),_('Categories'), false, false) }}
|
||||||
{{ text_table_row('series', _('Enter Series'),_('Series'), false) }}
|
{{ text_table_row('series', _('Enter Series'),_('Series'), false, false) }}
|
||||||
<th data-field="series_index" id="series_index" data-visible="{{visiblility.get('series_index')}}" data-edit-validate="{{ _('This Field is Required') }}" data-sortable="true" {% if g.user.role_edit() %} data-editable-type="number" data-editable-placeholder="1" data-editable-step="0.01" data-editable-min="0" data-editable-url="{{ url_for('editbook.edit_list_book', param='series_index')}}" data-edit="true" data-editable-title="{{_('Enter title')}}"{% endif %}>{{_('Series Index')}}</th>
|
<th data-field="series_index" id="series_index" data-visible="{{visiblility.get('series_index')}}" data-edit-validate="{{ _('This Field is Required') }}" data-sortable="true" {% if g.user.role_edit() %} data-editable-type="number" data-editable-placeholder="1" data-editable-step="0.01" data-editable-min="0" data-editable-url="{{ url_for('editbook.edit_list_book', param='series_index')}}" data-edit="true" data-editable-title="{{_('Enter title')}}"{% endif %}>{{_('Series Index')}}</th>
|
||||||
{{ text_table_row('languages', _('Enter Languages'),_('Languages'), false) }}
|
{{ text_table_row('languages', _('Enter Languages'),_('Languages'), false, false) }}
|
||||||
<!--th data-field="pubdate" data-type="date" data-visible="{{visiblility.get('pubdate')}}" data-viewformat="dd.mm.yyyy" id="pubdate" data-sortable="true">{{_('Publishing Date')}}</th-->
|
<!--th data-field="pubdate" data-type="date" data-visible="{{visiblility.get('pubdate')}}" data-viewformat="dd.mm.yyyy" id="pubdate" data-sortable="true">{{_('Publishing Date')}}</th-->
|
||||||
{{ text_table_row('publishers', _('Enter Publishers'),_('Publishers'), false) }}
|
{{ text_table_row('publishers', _('Enter Publishers'),_('Publishers'), false, false) }}
|
||||||
{% if g.user.role_delete_books() and g.user.role_edit()%}
|
{% if g.user.role_delete_books() and g.user.role_edit()%}
|
||||||
<th data-align="right" data-formatter="EbookActions" data-switchable="false">{{_('Delete')}}</th>
|
<th data-align="right" data-formatter="EbookActions" data-switchable="false">{{_('Delete')}}</th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
{% for message in get_flashed_messages(with_categories=True) %}
|
{% for message in get_flashed_messages(with_categories=True) %}
|
||||||
{%if message[0] == "error" %}
|
{%if message[0] == "error" %}
|
||||||
<div class="row-fluid text-center" style="margin-top: -20px;">
|
<div class="row-fluid text-center" style="margin-top: -20px;">
|
||||||
<div id="flash_alert" class="alert alert-danger">{{ message[1] }}</div>
|
<div id="flash_danger" class="alert alert-danger">{{ message[1] }}</div>
|
||||||
</div>
|
</div>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{%if message[0] == "info" %}
|
{%if message[0] == "info" %}
|
||||||
|
|
11
cps/web.py
11
cps/web.py
|
@ -26,6 +26,7 @@ from datetime import datetime
|
||||||
import json
|
import json
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import chardet # dependency of requests
|
import chardet # dependency of requests
|
||||||
|
import copy
|
||||||
|
|
||||||
from babel.dates import format_date
|
from babel.dates import format_date
|
||||||
from babel import Locale as LC
|
from babel import Locale as LC
|
||||||
|
@ -756,13 +757,12 @@ def list_books():
|
||||||
off = int(request.args.get("offset") or 0)
|
off = int(request.args.get("offset") or 0)
|
||||||
limit = int(request.args.get("limit") or config.config_books_per_page)
|
limit = int(request.args.get("limit") or config.config_books_per_page)
|
||||||
search = request.args.get("search")
|
search = request.args.get("search")
|
||||||
sort = request.args.get("sort", "state")
|
sort = request.args.get("sort", "id")
|
||||||
order = request.args.get("order", "").lower()
|
order = request.args.get("order", "").lower()
|
||||||
state = None
|
state = None
|
||||||
|
|
||||||
if sort == "state":
|
if sort == "state":
|
||||||
state = json.loads(request.args.get("state", "[]"))
|
state = json.loads(request.args.get("state", "[]"))
|
||||||
|
|
||||||
if sort != "state" and order:
|
if sort != "state" and order:
|
||||||
order = [text(sort + " " + order)]
|
order = [text(sort + " " + order)]
|
||||||
elif not state:
|
elif not state:
|
||||||
|
@ -831,9 +831,12 @@ def author_list():
|
||||||
charlist = calibre_db.session.query(func.upper(func.substr(db.Authors.sort, 1, 1)).label('char')) \
|
charlist = calibre_db.session.query(func.upper(func.substr(db.Authors.sort, 1, 1)).label('char')) \
|
||||||
.join(db.books_authors_link).join(db.Books).filter(calibre_db.common_filters()) \
|
.join(db.books_authors_link).join(db.Books).filter(calibre_db.common_filters()) \
|
||||||
.group_by(func.upper(func.substr(db.Authors.sort, 1, 1))).all()
|
.group_by(func.upper(func.substr(db.Authors.sort, 1, 1))).all()
|
||||||
for entry in entries:
|
# If not creating a copy, readonly databases can not display authornames with "|" in it as changing the name
|
||||||
|
# starts a change session
|
||||||
|
autor_copy = copy.deepcopy(entries)
|
||||||
|
for entry in autor_copy:
|
||||||
entry.Authors.name = entry.Authors.name.replace('|', ',')
|
entry.Authors.name = entry.Authors.name.replace('|', ',')
|
||||||
return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist,
|
return render_title_template('list.html', entries=autor_copy, folder='web.books_list', charlist=charlist,
|
||||||
title=u"Authors", page="authorlist", data='author', order=order_no)
|
title=u"Authors", page="authorlist", data='author', order=order_no)
|
||||||
else:
|
else:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
|
@ -26,7 +26,7 @@ python-ldap>=3.0.0,<3.4.0
|
||||||
Flask-SimpleLDAP>=1.4.0,<1.5.0
|
Flask-SimpleLDAP>=1.4.0,<1.5.0
|
||||||
|
|
||||||
#oauth
|
#oauth
|
||||||
Flask-Dance>=1.4.0,<3.1.0
|
Flask-Dance>=1.4.0,<4.1.0
|
||||||
SQLAlchemy-Utils>=0.33.5,<0.38.0
|
SQLAlchemy-Utils>=0.33.5,<0.38.0
|
||||||
|
|
||||||
# extracting metadata
|
# extracting metadata
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user