mirror of
https://github.com/janeczku/calibre-web
synced 2024-11-24 10:37:23 +00:00
Uploader progress bar
Fixes imports and routes Merge branch 'master' into Develop Finished routing
This commit is contained in:
parent
d6ee8f75e9
commit
f5235b1d4c
68
cps/admin.py
68
cps/admin.py
@ -22,11 +22,11 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from flask import Blueprint
|
from flask import Blueprint, flash, redirect, url_for
|
||||||
from flask import abort, request
|
from flask import abort, request, make_response
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user, logout_user
|
||||||
from web import admin_required, render_title_template, flash, redirect, url_for, before_request, logout_user, \
|
from web import admin_required, render_title_template, before_request, speaking_language, unconfigured, \
|
||||||
speaking_language, unconfigured
|
login_required_if_no_ano, check_valid_domain
|
||||||
from cps import db, ub, Server, get_locale, config, app, updater_thread, babel
|
from cps import db, ub, Server, get_locale, config, app, updater_thread, babel
|
||||||
import json
|
import json
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
@ -36,9 +36,9 @@ from flask_babel import gettext as _
|
|||||||
from babel import Locale as LC
|
from babel import Locale as LC
|
||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
from gdriveutils import is_gdrive_ready, gdrive_support, downloadFile, deleteDatabaseOnChange, listRootFolders
|
from gdriveutils import is_gdrive_ready, gdrive_support, downloadFile, deleteDatabaseOnChange, listRootFolders
|
||||||
from web import login_required_if_no_ano, check_valid_domain
|
|
||||||
import helper
|
import helper
|
||||||
from werkzeug.security import generate_password_hash
|
from werkzeug.security import generate_password_hash
|
||||||
|
from sqlalchemy.sql.expression import text
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from goodreads.client import GoodreadsClient
|
from goodreads.client import GoodreadsClient
|
||||||
@ -218,6 +218,62 @@ def view_configuration():
|
|||||||
title=_(u"UI Configuration"), page="uiconfig")
|
title=_(u"UI Configuration"), page="uiconfig")
|
||||||
|
|
||||||
|
|
||||||
|
@admi.route("/ajax/editdomain", methods=['POST'])
|
||||||
|
@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
|
||||||
|
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()
|
||||||
|
ub.session.commit()
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@admi.route("/ajax/adddomain", methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
|
def add_domain():
|
||||||
|
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)
|
||||||
|
ub.session.add(new_domain)
|
||||||
|
ub.session.commit()
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@admi.route("/ajax/deletedomain", methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
|
def delete_domain():
|
||||||
|
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
|
||||||
|
if not ub.session.query(ub.Registration).count():
|
||||||
|
new_domain = ub.Registration(domain="%.%")
|
||||||
|
ub.session.add(new_domain)
|
||||||
|
ub.session.commit()
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@admi.route("/ajax/domainlist")
|
||||||
|
@login_required
|
||||||
|
@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("'", '"'))
|
||||||
|
response.headers["Content-Type"] = "application/json; charset=utf-8"
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
@admi.route("/config", methods=["GET", "POST"])
|
@admi.route("/config", methods=["GET", "POST"])
|
||||||
@unconfigured
|
@unconfigured
|
||||||
def basic_configuration():
|
def basic_configuration():
|
||||||
|
@ -22,12 +22,13 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# opds routing functions
|
# opds routing functions
|
||||||
from cps import config, language_table, get_locale, app, ub
|
from cps import config, language_table, get_locale, app, ub, global_WorkerThread
|
||||||
from flask import request, flash, redirect, url_for, abort, Markup
|
from flask import request, flash, redirect, url_for, abort, Markup, Response
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
import datetime
|
import datetime
|
||||||
import db
|
import db
|
||||||
import os
|
import os
|
||||||
|
import json
|
||||||
from flask_babel import gettext as _
|
from flask_babel import gettext as _
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
import helper
|
import helper
|
||||||
@ -206,9 +207,9 @@ def delete_book(book_id, book_format):
|
|||||||
# book not found
|
# book not found
|
||||||
app.logger.info('Book with id "'+str(book_id)+'" could not be deleted')
|
app.logger.info('Book with id "'+str(book_id)+'" could not be deleted')
|
||||||
if book_format:
|
if book_format:
|
||||||
return redirect(url_for('edit_book', book_id=book_id))
|
return redirect(url_for('editbook.edit_book', book_id=book_id))
|
||||||
else:
|
else:
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('web.index'))
|
||||||
|
|
||||||
|
|
||||||
def render_edit_book(book_id):
|
def render_edit_book(book_id):
|
||||||
@ -341,10 +342,10 @@ def upload_single_file(request, book, book_id):
|
|||||||
if file_ext not in EXTENSIONS_UPLOAD:
|
if file_ext not in EXTENSIONS_UPLOAD:
|
||||||
flash(_("File extension '%(ext)s' is not allowed to be uploaded to this server", ext=file_ext),
|
flash(_("File extension '%(ext)s' is not allowed to be uploaded to this server", ext=file_ext),
|
||||||
category="error")
|
category="error")
|
||||||
return redirect(url_for('show_book', book_id=book.id))
|
return redirect(url_for('web.show_book', book_id=book.id))
|
||||||
else:
|
else:
|
||||||
flash(_('File to be uploaded must have an extension'), category="error")
|
flash(_('File to be uploaded must have an extension'), category="error")
|
||||||
return redirect(url_for('show_book', book_id=book.id))
|
return redirect(url_for('web.show_book', book_id=book.id))
|
||||||
|
|
||||||
file_name = book.path.rsplit('/', 1)[-1]
|
file_name = book.path.rsplit('/', 1)[-1]
|
||||||
filepath = os.path.normpath(os.path.join(config.config_calibre_dir, book.path))
|
filepath = os.path.normpath(os.path.join(config.config_calibre_dir, book.path))
|
||||||
@ -356,12 +357,12 @@ def upload_single_file(request, book, book_id):
|
|||||||
os.makedirs(filepath)
|
os.makedirs(filepath)
|
||||||
except OSError:
|
except OSError:
|
||||||
flash(_(u"Failed to create path %(path)s (Permission denied).", path=filepath), category="error")
|
flash(_(u"Failed to create path %(path)s (Permission denied).", path=filepath), category="error")
|
||||||
return redirect(url_for('show_book', book_id=book.id))
|
return redirect(url_for('web.show_book', book_id=book.id))
|
||||||
try:
|
try:
|
||||||
requested_file.save(saved_filename)
|
requested_file.save(saved_filename)
|
||||||
except OSError:
|
except OSError:
|
||||||
flash(_(u"Failed to store file %(file)s.", file=saved_filename), category="error")
|
flash(_(u"Failed to store file %(file)s.", file=saved_filename), category="error")
|
||||||
return redirect(url_for('show_book', book_id=book.id))
|
return redirect(url_for('web.show_book', book_id=book.id))
|
||||||
|
|
||||||
file_size = os.path.getsize(saved_filename)
|
file_size = os.path.getsize(saved_filename)
|
||||||
is_format = db.session.query(db.Data).filter(db.Data.book == book_id).\
|
is_format = db.session.query(db.Data).filter(db.Data.book == book_id).\
|
||||||
@ -378,7 +379,7 @@ def upload_single_file(request, book, book_id):
|
|||||||
|
|
||||||
# Queue uploader info
|
# Queue uploader info
|
||||||
uploadText=_(u"File format %(ext)s added to %(book)s", ext=file_ext.upper(), book=book.title)
|
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,
|
global_WorkerThread.add_upload(current_user.nickname,
|
||||||
"<a href=\"" + url_for('show_book', book_id=book.id) + "\">" + uploadText + "</a>")
|
"<a href=\"" + url_for('show_book', book_id=book.id) + "\">" + uploadText + "</a>")
|
||||||
|
|
||||||
def upload_cover(request, book):
|
def upload_cover(request, book):
|
||||||
@ -397,17 +398,17 @@ def upload_cover(request, book):
|
|||||||
except OSError:
|
except OSError:
|
||||||
flash(_(u"Failed to create path for cover %(path)s (Permission denied).", cover=filepath),
|
flash(_(u"Failed to create path for cover %(path)s (Permission denied).", cover=filepath),
|
||||||
category="error")
|
category="error")
|
||||||
return redirect(url_for('show_book', book_id=book.id))
|
return redirect(url_for('web.show_book', book_id=book.id))
|
||||||
try:
|
try:
|
||||||
requested_file.save(saved_filename)
|
requested_file.save(saved_filename)
|
||||||
# im=Image.open(saved_filename)
|
# im=Image.open(saved_filename)
|
||||||
book.has_cover = 1
|
book.has_cover = 1
|
||||||
except OSError:
|
except OSError:
|
||||||
flash(_(u"Failed to store cover-file %(cover)s.", cover=saved_filename), category="error")
|
flash(_(u"Failed to store cover-file %(cover)s.", cover=saved_filename), category="error")
|
||||||
return redirect(url_for('show_book', book_id=book.id))
|
return redirect(url_for('web.show_book', book_id=book.id))
|
||||||
except IOError:
|
except IOError:
|
||||||
flash(_(u"Cover-file is not a valid image file" % saved_filename), category="error")
|
flash(_(u"Cover-file is not a valid image file" % saved_filename), category="error")
|
||||||
return redirect(url_for('show_book', book_id=book.id))
|
return redirect(url_for('web.show_book', book_id=book.id))
|
||||||
|
|
||||||
@editbook.route("/admin/book/<int:book_id>", methods=['GET', 'POST'])
|
@editbook.route("/admin/book/<int:book_id>", methods=['GET', 'POST'])
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
@ -554,7 +555,7 @@ def edit_book(book_id):
|
|||||||
if config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
gdriveutils.updateGdriveCalibreFromLocal()
|
gdriveutils.updateGdriveCalibreFromLocal()
|
||||||
if "detail_view" in to_save:
|
if "detail_view" in to_save:
|
||||||
return redirect(url_for('show_book', book_id=book.id))
|
return redirect(url_for('web.show_book', book_id=book.id))
|
||||||
else:
|
else:
|
||||||
flash(_("Metadata successfully updated"), category="success")
|
flash(_("Metadata successfully updated"), category="success")
|
||||||
return render_edit_book(book_id)
|
return render_edit_book(book_id)
|
||||||
@ -566,7 +567,7 @@ def edit_book(book_id):
|
|||||||
app.logger.exception(e)
|
app.logger.exception(e)
|
||||||
db.session.rollback()
|
db.session.rollback()
|
||||||
flash(_("Error editing book, please check logfile for details"), category="error")
|
flash(_("Error editing book, please check logfile for details"), category="error")
|
||||||
return redirect(url_for('show_book', book_id=book.id))
|
return redirect(url_for('web.show_book', book_id=book.id))
|
||||||
|
|
||||||
|
|
||||||
@editbook.route("/upload", methods=["GET", "POST"])
|
@editbook.route("/upload", methods=["GET", "POST"])
|
||||||
@ -704,8 +705,8 @@ def upload():
|
|||||||
if error:
|
if error:
|
||||||
flash(error, category="error")
|
flash(error, category="error")
|
||||||
uploadText=_(u"File %(file)s uploaded", file=book.title)
|
uploadText=_(u"File %(file)s uploaded", file=book.title)
|
||||||
helper.global_WorkerThread.add_upload(current_user.nickname,
|
global_WorkerThread.add_upload(current_user.nickname,
|
||||||
"<a href=\"" + url_for('show_book', book_id=book.id) + "\">" + uploadText + "</a>")
|
"<a href=\"" + url_for('web.show_book', book_id=book.id) + "\">" + uploadText + "</a>")
|
||||||
|
|
||||||
# create data for displaying display Full language name instead of iso639.part3language
|
# create data for displaying display Full language name instead of iso639.part3language
|
||||||
if db_language is not None:
|
if db_language is not None:
|
||||||
@ -714,19 +715,13 @@ def upload():
|
|||||||
for author in db_book.authors:
|
for author in db_book.authors:
|
||||||
author_names.append(author.name)
|
author_names.append(author.name)
|
||||||
if len(request.files.getlist("btn-upload")) < 2:
|
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():
|
if current_user.role_edit() or current_user.role_admin():
|
||||||
return render_title_template('book_edit.html', book=book, authors=author_names,
|
resp = {"location": url_for('editbook.edit_book', book_id=db_book.id)}
|
||||||
cc=cc, title=_(u"edit metadata"), page="upload")
|
return Response(json.dumps(resp), mimetype='application/json')
|
||||||
book_in_shelfs = []
|
else:
|
||||||
kindle_list = helper.check_send_to_kindle(book)
|
resp = {"location": url_for('web.show_book', book_id=db_book.id)}
|
||||||
reader_list = helper.check_read_formats(book)
|
return Response(json.dumps(resp), mimetype='application/json')
|
||||||
|
return Response(json.dumps({"location": url_for("web.index")}), mimetype='application/json')
|
||||||
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"))
|
|
||||||
|
|
||||||
|
|
||||||
@editbook.route("/admin/book/convert/<int:book_id>", methods=['POST'])
|
@editbook.route("/admin/book/convert/<int:book_id>", methods=['POST'])
|
||||||
|
@ -187,7 +187,7 @@ def bind_oauth_or_register(provider, provider_user_id, redirect_url):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
app.logger.exception(e)
|
app.logger.exception(e)
|
||||||
ub.session.rollback()
|
ub.session.rollback()
|
||||||
return redirect(url_for('register'))
|
return redirect(url_for('web.register'))
|
||||||
except NoResultFound:
|
except NoResultFound:
|
||||||
return redirect(url_for(redirect_url))
|
return redirect(url_for(redirect_url))
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ def github_error(blueprint, error, error_description=None, error_uri=None):
|
|||||||
flash(msg, category="error")
|
flash(msg, category="error")
|
||||||
|
|
||||||
|
|
||||||
@web.route('/github')
|
@oauth.route('/github')
|
||||||
@github_oauth_required
|
@github_oauth_required
|
||||||
def github_login():
|
def github_login():
|
||||||
if not github.authorized:
|
if not github.authorized:
|
||||||
@ -260,13 +260,13 @@ def github_login():
|
|||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
|
|
||||||
@web.route('/unlink/github', methods=["GET"])
|
@oauth.route('/unlink/github', methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
def github_login_unlink():
|
def github_login_unlink():
|
||||||
return unlink_oauth(github_blueprint.name)
|
return unlink_oauth(github_blueprint.name)
|
||||||
|
|
||||||
|
|
||||||
@web.route('/google')
|
@oauth.route('/google')
|
||||||
@google_oauth_required
|
@google_oauth_required
|
||||||
def google_login():
|
def google_login():
|
||||||
if not google.authorized:
|
if not google.authorized:
|
||||||
@ -293,7 +293,7 @@ def google_error(blueprint, error, error_description=None, error_uri=None):
|
|||||||
flash(msg, category="error")
|
flash(msg, category="error")
|
||||||
|
|
||||||
|
|
||||||
@web.route('/unlink/google', methods=["GET"])
|
@oauth.route('/unlink/google', methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
def google_login_unlink():
|
def google_login_unlink():
|
||||||
return unlink_oauth(google_blueprint.name)
|
return unlink_oauth(google_blueprint.name)
|
||||||
|
8
cps/static/css/upload.css
Normal file
8
cps/static/css/upload.css
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
@media (min-device-width: 768px) {
|
||||||
|
.modal-dialog {
|
||||||
|
position: absolute;
|
||||||
|
top: 45%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%) !important;
|
||||||
|
}
|
||||||
|
}
|
198
cps/static/js/uploadprogress.js
Normal file
198
cps/static/js/uploadprogress.js
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* bootstrap-uploadprogress
|
||||||
|
* github: https://github.com/jakobadam/bootstrap-uploadprogress
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Jakob Aarøe Dam
|
||||||
|
* Version 1.0.0
|
||||||
|
* Licensed under the MIT license.
|
||||||
|
*/
|
||||||
|
(function($){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
$.support.xhrFileUpload = !!(window.FileReader && window.ProgressEvent);
|
||||||
|
$.support.xhrFormData = !!window.FormData;
|
||||||
|
|
||||||
|
if(!$.support.xhrFileUpload || !$.support.xhrFormData){
|
||||||
|
// skip decorating form
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var template = '<div class="modal fade" id="file-progress-modal">\
|
||||||
|
<div class="modal-dialog">\
|
||||||
|
<div class="modal-content">\
|
||||||
|
<div class="modal-header">\
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>\
|
||||||
|
<h4 class="modal-title">Uploading</h4>\
|
||||||
|
</div>\
|
||||||
|
<div class="modal-body">\
|
||||||
|
<div class="modal-message"></div>\
|
||||||
|
<div class="progress">\
|
||||||
|
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="0" aria-valuemin="0"\
|
||||||
|
aria-valuemax="100" style="width: 0%;min-width: 2em;">\
|
||||||
|
0%\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
<div class="modal-footer" style="display:none">\
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
</div>';
|
||||||
|
|
||||||
|
var UploadProgress = function(element, options){
|
||||||
|
this.options = options;
|
||||||
|
this.$element = $(element);
|
||||||
|
};
|
||||||
|
|
||||||
|
UploadProgress.prototype = {
|
||||||
|
|
||||||
|
constructor: function() {
|
||||||
|
this.$form = this.$element;
|
||||||
|
this.$form.on('submit', $.proxy(this.submit, this));
|
||||||
|
this.$modal = $(this.options.template);
|
||||||
|
this.$modal_message = this.$modal.find('.modal-message');
|
||||||
|
this.$modal_title = this.$modal.find('.modal-title');
|
||||||
|
this.$modal_footer = this.$modal.find('.modal-footer');
|
||||||
|
this.$modal_bar = this.$modal.find('.progress-bar');
|
||||||
|
|
||||||
|
this.$modal.on('hidden.bs.modal', $.proxy(this.reset, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
reset: function(){
|
||||||
|
this.$modal_title = this.$modal_title.text('Uploading');
|
||||||
|
this.$modal_footer.hide();
|
||||||
|
this.$modal_bar.addClass('progress-bar-success');
|
||||||
|
this.$modal_bar.removeClass('progress-bar-danger');
|
||||||
|
if(this.xhr){
|
||||||
|
this.xhr.abort();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
submit: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
this.$modal.modal({
|
||||||
|
backdrop: 'static',
|
||||||
|
keyboard: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// We need the native XMLHttpRequest for the progress event
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
this.xhr = xhr;
|
||||||
|
|
||||||
|
xhr.addEventListener('load', $.proxy(this.success, this, xhr));
|
||||||
|
xhr.addEventListener('error', $.proxy(this.error, this, xhr));
|
||||||
|
//xhr.addEventListener('abort', function(){});
|
||||||
|
|
||||||
|
xhr.upload.addEventListener('progress', $.proxy(this.progress, this));
|
||||||
|
|
||||||
|
var form = this.$form;
|
||||||
|
|
||||||
|
xhr.open(form.attr('method'), form.attr("action"));
|
||||||
|
xhr.setRequestHeader('X-REQUESTED-WITH', 'XMLHttpRequest');
|
||||||
|
|
||||||
|
var data = new FormData(form.get(0));
|
||||||
|
xhr.send(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
success: function(xhr) {
|
||||||
|
if(xhr.status == 0 || xhr.status >= 400){
|
||||||
|
// HTTP 500 ends up here!?!
|
||||||
|
return this.error(xhr);
|
||||||
|
}
|
||||||
|
this.set_progress(100);
|
||||||
|
var url;
|
||||||
|
var content_type = xhr.getResponseHeader('Content-Type');
|
||||||
|
|
||||||
|
// make it possible to return the redirect URL in
|
||||||
|
// a JSON response
|
||||||
|
if(content_type.indexOf('application/json') !== -1){
|
||||||
|
var response = $.parseJSON(xhr.responseText);
|
||||||
|
console.log(response);
|
||||||
|
url = response.location;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
url = this.options.redirect_url;
|
||||||
|
}
|
||||||
|
window.location.href = url;
|
||||||
|
},
|
||||||
|
|
||||||
|
// handle form error
|
||||||
|
// we replace the form with the returned one
|
||||||
|
error: function(xhr){
|
||||||
|
this.$modal_title.text('Upload failed');
|
||||||
|
|
||||||
|
this.$modal_bar.removeClass('progress-bar-success');
|
||||||
|
this.$modal_bar.addClass('progress-bar-danger');
|
||||||
|
this.$modal_footer.show();
|
||||||
|
|
||||||
|
var content_type = xhr.getResponseHeader('Content-Type');
|
||||||
|
|
||||||
|
// Replace the contents of the form, with the returned html
|
||||||
|
if(xhr.status === 422){
|
||||||
|
var new_html = $.parseHTML(xhr.responseText);
|
||||||
|
this.replace_form(new_html);
|
||||||
|
this.$modal.modal('hide');
|
||||||
|
}
|
||||||
|
// Write the error response to the document.
|
||||||
|
else{
|
||||||
|
var response_text = xhr.responseText;
|
||||||
|
if(content_type.indexOf('text/plain') !== -1){
|
||||||
|
response_text = '<pre>' + response_text + '</pre>';
|
||||||
|
}
|
||||||
|
document.write(xhr.responseText);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
set_progress: function(percent){
|
||||||
|
var txt = percent + '%';
|
||||||
|
if (percent == 100) {
|
||||||
|
txt = this.options.uploaded_msg;
|
||||||
|
}
|
||||||
|
this.$modal_bar.attr('aria-valuenow', percent);
|
||||||
|
this.$modal_bar.text(txt);
|
||||||
|
this.$modal_bar.css('width', percent + '%');
|
||||||
|
},
|
||||||
|
|
||||||
|
progress: function(/*ProgressEvent*/e){
|
||||||
|
var percent = Math.round((e.loaded / e.total) * 100);
|
||||||
|
this.set_progress(percent);
|
||||||
|
},
|
||||||
|
|
||||||
|
// replace_form replaces the contents of the current form
|
||||||
|
// with the form in the html argument.
|
||||||
|
// We use the id of the current form to find the new form in the html
|
||||||
|
replace_form: function(html){
|
||||||
|
var new_form;
|
||||||
|
var form_id = this.$form.attr('id');
|
||||||
|
if(form_id !== undefined){
|
||||||
|
new_form = $(html).find('#' + form_id);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
new_form = $(html).find('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the filestyle again
|
||||||
|
new_form.find(':file').filestyle({buttonBefore: true});
|
||||||
|
this.$form.html(new_form.children());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.uploadprogress = function(options, value){
|
||||||
|
return this.each(function(){
|
||||||
|
var _options = $.extend({}, $.fn.uploadprogress.defaults, options);
|
||||||
|
var file_progress = new UploadProgress(this, _options);
|
||||||
|
file_progress.constructor();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.uploadprogress.defaults = {
|
||||||
|
template: template,
|
||||||
|
uploaded_msg: "Upload done, processing, please wait..."
|
||||||
|
//redirect_url: ...
|
||||||
|
|
||||||
|
// need to customize stuff? Add here, and change code accordingly.
|
||||||
|
};
|
||||||
|
|
||||||
|
})(window.jQuery);
|
@ -27,21 +27,21 @@
|
|||||||
{% for entry in entries %}
|
{% for entry in entries %}
|
||||||
<div id="books" class="col-sm-3 col-lg-2 col-xs-6 book">
|
<div id="books" class="col-sm-3 col-lg-2 col-xs-6 book">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ url_for('show_book', book_id=entry.id) }}">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}">
|
||||||
{% if entry.has_cover %}
|
{% if entry.has_cover %}
|
||||||
<img src="{{ url_for('get_cover', book_id=entry.id) }}" />
|
<img src="{{ url_for('web.get_cover', book_id=entry.id) }}" />
|
||||||
{% else %}
|
{% else %}
|
||||||
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" />
|
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
<a href="{{ url_for('show_book', book_id=entry.id) }}">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}">
|
||||||
<p class="title">{{entry.title|shortentitle}}</p>
|
<p class="title">{{entry.title|shortentitle}}</p>
|
||||||
</a>
|
</a>
|
||||||
<p class="author">
|
<p class="author">
|
||||||
{% for author in entry.authors %}
|
{% for author in entry.authors %}
|
||||||
<a href="{{url_for('author', book_id=author.id) }}">{{author.name.replace('|',',')}}</a>
|
<a href="{{url_for('web.author', book_id=author.id) }}">{{author.name.replace('|',',')}}</a>
|
||||||
{% if not loop.last %}
|
{% if not loop.last %}
|
||||||
&
|
&
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<form role="form" action="{{ url_for('web.edit_book', book_id=book.id) }}" method="post" enctype="multipart/form-data" id="book_edit_frm">
|
<form role="form" action="{{ url_for('editbook.edit_book', book_id=book.id) }}" method="post" enctype="multipart/form-data" id="book_edit_frm">
|
||||||
<div class="col-sm-9 col-xs-12">
|
<div class="col-sm-9 col-xs-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="book_title">{{_('Book Title')}}</label>
|
<label for="book_title">{{_('Book Title')}}</label>
|
||||||
@ -196,7 +196,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<a href="{{ url_for('web.delete_book', book_id=book.id) }}" class="btn btn-danger">{{_('Delete')}}</a>
|
<a href="{{ url_for('editbook.delete_book', book_id=book.id) }}" class="btn btn-danger">{{_('Delete')}}</a>
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Back')}}</button>
|
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Back')}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
{% if show_authenticate_google_drive and g.user.is_authenticated and content.config_use_google_drive %}
|
{% if show_authenticate_google_drive and g.user.is_authenticated and content.config_use_google_drive %}
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
<a href="{{ url_for('authenticate_google_drive') }}" class="btn btn-primary">{{_('Authenticate Google Drive')}}</a>
|
<a href="{{ url_for('gdrive.authenticate_google_drive') }}" class="btn btn-primary">{{_('Authenticate Google Drive')}}</a>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if show_authenticate_google_drive and g.user.is_authenticated and not content.config_use_google_drive %}
|
{% if show_authenticate_google_drive and g.user.is_authenticated and not content.config_use_google_drive %}
|
||||||
@ -56,10 +56,10 @@
|
|||||||
<label for="config_google_drive_watch_changes_response">{{_('Metadata Watch Channel ID')}}</label>
|
<label for="config_google_drive_watch_changes_response">{{_('Metadata Watch Channel ID')}}</label>
|
||||||
<div class="form-group input-group required">
|
<div class="form-group input-group required">
|
||||||
<input type="text" class="form-control" name="config_google_drive_watch_changes_response" id="config_google_drive_watch_changes_response" value="{{ content.config_google_drive_watch_changes_response['id'] }} expires on {{ content.config_google_drive_watch_changes_response['expiration'] | strftime }}" autocomplete="off" disabled="">
|
<input type="text" class="form-control" name="config_google_drive_watch_changes_response" id="config_google_drive_watch_changes_response" value="{{ content.config_google_drive_watch_changes_response['id'] }} expires on {{ content.config_google_drive_watch_changes_response['expiration'] | strftime }}" autocomplete="off" disabled="">
|
||||||
<span class="input-group-btn"><a href="{{ url_for('revoke_watch_gdrive') }}" class="btn btn-primary">{{_('Revoke')}}</a></span>
|
<span class="input-group-btn"><a href="{{ url_for('gdrive.revoke_watch_gdrive') }}" class="btn btn-primary">{{_('Revoke')}}</a></span>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ url_for('watch_gdrive') }}" class="btn btn-primary">Enable watch of metadata.db</a>
|
<a href="{{ url_for('gdrive.watch_gdrive') }}" class="btn btn-primary">Enable watch of metadata.db</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -224,8 +224,8 @@
|
|||||||
{% for shelf in g.user.shelf %}
|
{% for shelf in g.user.shelf %}
|
||||||
{% if not shelf.id in books_shelfs and shelf.is_public != 1 %}
|
{% if not shelf.id in books_shelfs and shelf.is_public != 1 %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for('web.add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
<a href="{{ url_for('shelf.add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
data-remove-href="{{ url_for('web.remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
data-remove-href="{{ url_for('shelf.remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
data-shelf-action="add"
|
data-shelf-action="add"
|
||||||
>
|
>
|
||||||
{{shelf.name}}
|
{{shelf.name}}
|
||||||
@ -236,8 +236,8 @@
|
|||||||
{% for shelf in g.public_shelfes %}
|
{% for shelf in g.public_shelfes %}
|
||||||
{% if not shelf.id in books_shelfs %}
|
{% if not shelf.id in books_shelfs %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for('web.add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
<a href="{{ url_for('shelf.add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
data-remove-href="{{ url_for('web.remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
data-remove-href="{{ url_for('shelf.remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
data-shelf-action="add"
|
data-shelf-action="add"
|
||||||
>
|
>
|
||||||
{{shelf.name}}
|
{{shelf.name}}
|
||||||
@ -251,8 +251,8 @@
|
|||||||
{% if books_shelfs %}
|
{% if books_shelfs %}
|
||||||
{% for shelf in g.user.shelf %}
|
{% for shelf in g.user.shelf %}
|
||||||
{% if shelf.id in books_shelfs and shelf.is_public != 1 %}
|
{% if shelf.id in books_shelfs and shelf.is_public != 1 %}
|
||||||
<a href="{{ url_for('web.remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
<a href="{{ url_for('shelf.remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
data-add-href="{{ url_for('web.add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
data-add-href="{{ url_for('shelf.add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
class="btn btn-sm btn-default" role="button" data-shelf-action="remove"
|
class="btn btn-sm btn-default" role="button" data-shelf-action="remove"
|
||||||
>
|
>
|
||||||
<span class="glyphicon glyphicon-remove"></span> {{shelf.name}}
|
<span class="glyphicon glyphicon-remove"></span> {{shelf.name}}
|
||||||
@ -261,8 +261,8 @@
|
|||||||
{%endfor%}
|
{%endfor%}
|
||||||
{% for shelf in g.public_shelfes %}
|
{% for shelf in g.public_shelfes %}
|
||||||
{% if shelf.id in books_shelfs %}
|
{% if shelf.id in books_shelfs %}
|
||||||
<a href="{{ url_for('web.remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
<a href="{{ url_for('shelf.remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
data-add-href="{{ url_for('web.add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
data-add-href="{{ url_for('shelf.add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
class="btn btn-sm btn-default" role="button" data-shelf-action="remove"
|
class="btn btn-sm btn-default" role="button" data-shelf-action="remove"
|
||||||
>
|
>
|
||||||
<span class="glyphicon glyphicon-remove"></span> {{shelf.name}}
|
<span class="glyphicon glyphicon-remove"></span> {{shelf.name}}
|
||||||
@ -279,7 +279,7 @@
|
|||||||
{% if g.user.role_edit() %}
|
{% if g.user.role_edit() %}
|
||||||
<div class="btn-toolbar" role="toolbar">
|
<div class="btn-toolbar" role="toolbar">
|
||||||
<div class="btn-group" role="group" aria-label="Edit/Delete book">
|
<div class="btn-group" role="group" aria-label="Edit/Delete book">
|
||||||
<a href="{{ url_for('web.edit_book', book_id=entry.id) }}" class="btn btn-sm btn-warning" id="edit_book" role="button"><span class="glyphicon glyphicon-edit"></span> {{_('Edit metadata')}}</a>
|
<a href="{{ url_for('editbook.edit_book', book_id=entry.id) }}" class="btn btn-sm btn-warning" id="edit_book" role="button"><span class="glyphicon glyphicon-edit"></span> {{_('Edit metadata')}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -8,18 +8,18 @@
|
|||||||
<div class="col-sm-3 col-lg-2 col-xs-6 book">
|
<div class="col-sm-3 col-lg-2 col-xs-6 book">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
{% if entry.has_cover is defined %}
|
{% if entry.has_cover is defined %}
|
||||||
<a href="{{ url_for('show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||||
<img src="{{ url_for('get_cover', book_id=entry.id) }}" alt="{{ entry.title }}" />
|
<img src="{{ url_for('web.get_cover', book_id=entry.id) }}" alt="{{ entry.title }}" />
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
<a href="{{ url_for('show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||||
<p class="title">{{entry.title|shortentitle}}</p>
|
<p class="title">{{entry.title|shortentitle}}</p>
|
||||||
</a>
|
</a>
|
||||||
<p class="author">
|
<p class="author">
|
||||||
{% for author in entry.authors %}
|
{% for author in entry.authors %}
|
||||||
<a href="{{url_for('author', book_id=author.id) }}">{{author.name.replace('|',',')|shortentitle(30)}}</a>
|
<a href="{{url_for('web.author', book_id=author.id) }}">{{author.name.replace('|',',')|shortentitle(30)}}</a>
|
||||||
{% if not loop.last %}
|
{% if not loop.last %}
|
||||||
&
|
&
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -41,16 +41,16 @@
|
|||||||
</form>
|
</form>
|
||||||
{% if g.allow_registration %}
|
{% if g.allow_registration %}
|
||||||
<h2>{{_('Allowed domains for registering')}}</h2>
|
<h2>{{_('Allowed domains for registering')}}</h2>
|
||||||
<table class="table table-no-bordered" id="domain-table" data-url="{{url_for('list_domain')}}" data-id-field="id" data-show-header="false" data-editable-mode="inline">
|
<table class="table table-no-bordered" id="domain-table" data-url="{{url_for('admin.list_domain')}}" data-id-field="id" data-show-header="false" data-editable-mode="inline">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th data-field="domain" id="domain" data-editable-type="text" data-editable-url="{{ url_for('edit_domain')}}" data-editable="true" data-editable-title="{{_('Enter domainname')}}"></th>
|
<th data-field="domain" id="domain" data-editable-type="text" data-editable-url="{{ url_for('admin.edit_domain')}}" data-editable="true" data-editable-title="{{_('Enter domainname')}}"></th>
|
||||||
<th data-field="id" id="id" data-visible="false"></th>
|
<th data-field="id" id="id" data-visible="false"></th>
|
||||||
<th data-align="right" data-formatter="TableActions"></th>
|
<th data-align="right" data-formatter="TableActions"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
<form id="domain_add" action="{{ url_for('add_domain')}}" method="POST">
|
<form id="domain_add" action="{{ url_for('admin.add_domain')}}" method="POST">
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
<label for="domainname">{{_('Add Domain')}}</label>
|
<label for="domainname">{{_('Add Domain')}}</label>
|
||||||
<input type="text" class="form-control" name="domainname" id="domainname" >
|
<input type="text" class="form-control" name="domainname" id="domainname" >
|
||||||
@ -71,7 +71,6 @@
|
|||||||
<div class="modal-body text-center">
|
<div class="modal-body text-center">
|
||||||
<p>{{_('Do you really want to delete this domain rule?')}}</p>
|
<p>{{_('Do you really want to delete this domain rule?')}}</p>
|
||||||
<button type="button" class="btn btn-danger" id="btndeletedomain" >{{_('Delete')}}</button>
|
<button type="button" class="btn btn-danger" id="btndeletedomain" >{{_('Delete')}}</button>
|
||||||
<!--a href="{{ url_for('delete_domain')}}" class="btn btn-danger">{{_('Delete')}}</a-->
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Back')}}</button>
|
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Back')}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
<div class="container text-center">
|
<div class="container text-center">
|
||||||
<h1>{{ error_code }}</h1>
|
<h1>{{ error_code }}</h1>
|
||||||
<h3>{{ error_name }}</h3>
|
<h3>{{ error_name }}</h3>
|
||||||
<a href="{{url_for('index')}}" title="{{ _('Back to home') }}">{{_('Back to home')}}</a>
|
<a href="{{url_for('web.index')}}" title="{{ _('Back to home') }}">{{_('Back to home')}}</a>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-2 col-sm-2 col-md-1" align="left"><span class="badge">{{lang_counter[loop.index0].bookcount}}</span></div>
|
<div class="col-xs-2 col-sm-2 col-md-1" align="left"><span class="badge">{{lang_counter[loop.index0].bookcount}}</span></div>
|
||||||
<div class="col-xs-10 col-sm-10 col-md-11"><a id="list_{{loop.index0}}" href="{{url_for('language', name=lang.lang_code)}}">{{lang.name}}</a></div>
|
<div class="col-xs-10 col-sm-10 col-md-11"><a id="list_{{loop.index0}}" href="{{url_for('web.language', name=lang.lang_code)}}">{{lang.name}}</a></div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||||
<link href="{{ url_for('static', filename='css/libs/bootstrap.min.css') }}" rel="stylesheet" media="screen">
|
<link href="{{ url_for('static', filename='css/libs/bootstrap.min.css') }}" rel="stylesheet" media="screen">
|
||||||
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" media="screen">
|
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" media="screen">
|
||||||
|
<link href="{{ url_for('static', filename='css/upload.css') }}" rel="stylesheet" media="screen">
|
||||||
{% if g.current_theme == 1 %}
|
{% if g.current_theme == 1 %}
|
||||||
<link href="{{ url_for('static', filename='css/caliBlur.min.css') }}" rel="stylesheet" media="screen">
|
<link href="{{ url_for('static', filename='css/caliBlur.min.css') }}" rel="stylesheet" media="screen">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -59,7 +60,7 @@
|
|||||||
{% if g.user.role_upload() or g.user.role_admin()%}
|
{% if g.user.role_upload() or g.user.role_admin()%}
|
||||||
{% if g.allow_upload %}
|
{% if g.allow_upload %}
|
||||||
<li>
|
<li>
|
||||||
<form id="form-upload" class="navbar-form" action="{{ url_for('web.upload') }}" method="post" enctype="multipart/form-data">
|
<form id="form-upload" class="navbar-form" action="{{ url_for('editbook.upload') }}" method="post" enctype="multipart/form-data">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<span class="btn btn-default btn-file">{{_('Upload')}}<input id="btn-upload" name="btn-upload" type="file" multiple></span>
|
<span class="btn btn-default btn-file">{{_('Upload')}}<input id="btn-upload" name="btn-upload" type="file" multiple></span>
|
||||||
</div>
|
</div>
|
||||||
@ -103,14 +104,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div id="loader" hidden="true">
|
|
||||||
<center>
|
|
||||||
<h3>{{_('Uploading...')}}</h3>
|
|
||||||
<span>{{_("please don't refresh the page")}}</span>.
|
|
||||||
<br />
|
|
||||||
<img src="{{ url_for('static', filename='img/loader.gif') }}">
|
|
||||||
</center>
|
|
||||||
</div>
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
{% if g.user.is_authenticated or g.user.is_anonymous %}
|
{% if g.user.is_authenticated or g.user.is_anonymous %}
|
||||||
@ -240,6 +233,7 @@
|
|||||||
<script src="{{ url_for('static', filename='js/libs/plugins.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/libs/plugins.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/libs/jquery.form.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/libs/jquery.form.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/uploadprogress.js') }}"> </script>
|
||||||
{% if g.current_theme == 1 %}
|
{% if g.current_theme == 1 %}
|
||||||
<script src="{{ url_for('static', filename='js/libs/jquery.visible.min.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/libs/jquery.visible.min.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/libs/compromise.min.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/libs/compromise.min.js') }}"></script>
|
||||||
@ -247,9 +241,9 @@
|
|||||||
<script src="{{ url_for('static', filename='js/caliBlur.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/caliBlur.js') }}"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function () {
|
$(function() {
|
||||||
$("#btn-upload").change(function () {
|
$("#form-upload").uploadprogress({redirect_url: '{{ url_for('web.index')}}'});
|
||||||
$("#loader").show();
|
$("#btn-upload").change(function() {
|
||||||
$("#form-upload").submit();
|
$("#form-upload").submit();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
{% if entry.has_cover %}
|
{% if entry.has_cover %}
|
||||||
<img src="{{ url_for('get_cover', cover_path=entry.path.replace('\\','/')) }}" alt="{{ entry.title }}" /> {% else %}
|
<img src="{{ url_for('web.get_cover', cover_path=entry.path.replace('\\','/')) }}" alt="{{ entry.title }}" /> {% else %}
|
||||||
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" alt="{{ entry.title }}" /> {% endif %}
|
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" alt="{{ entry.title }}" /> {% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -117,7 +117,7 @@
|
|||||||
<div class="sm2-playlist-wrapper">
|
<div class="sm2-playlist-wrapper">
|
||||||
<ul class="sm2-playlist-bd">
|
<ul class="sm2-playlist-bd">
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for('serve_book', book_id=mp3file,book_format=audioformat)}}"></a>
|
<a href="{{ url_for('web.serve_book', book_id=mp3file,book_format=audioformat)}}"></a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -129,7 +129,7 @@
|
|||||||
filePath: "{{ url_for('static', filename='js/libs/') }}",
|
filePath: "{{ url_for('static', filename='js/libs/') }}",
|
||||||
cssPath: "{{ url_for('static', filename='css/') }}",
|
cssPath: "{{ url_for('static', filename='css/') }}",
|
||||||
bookUrl: "{{ url_for('static', filename=mp3file) }}/",
|
bookUrl: "{{ url_for('static', filename=mp3file) }}/",
|
||||||
bookmarkUrl: "{{ url_for('bookmark', book_id=mp3file, book_format=audioformat.upper()) }}",
|
bookmarkUrl: "{{ url_for('web.bookmark', book_id=mp3file, book_format=audioformat.upper()) }}",
|
||||||
bookmark: "{{ bookmark.bookmark_key if bookmark != None }}",
|
bookmark: "{{ bookmark.bookmark_key if bookmark != None }}",
|
||||||
useBookmarks: "{{ g.user.is_authenticated | tojson }}"
|
useBookmarks: "{{ g.user.is_authenticated | tojson }}"
|
||||||
};
|
};
|
||||||
|
@ -19,17 +19,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<button type="submit" name="submit" class="btn btn-default">{{_('Submit')}}</button>
|
<button type="submit" name="submit" class="btn btn-default">{{_('Submit')}}</button>
|
||||||
{% if config.config_remote_login %}
|
{% if config.config_remote_login %}
|
||||||
<a href="{{url_for('remote_login')}}" class="pull-right">{{_('Log in with magic link')}}</a>
|
<a href="{{url_for('web.remote_login')}}" class="pull-right">{{_('Log in with magic link')}}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if config.config_use_github_oauth %}
|
{% if config.config_use_github_oauth %}
|
||||||
<a href="{{url_for('github_login')}}" class="pull-right">
|
<a href="{{url_for('oauth.github_login')}}" class="pull-right">
|
||||||
<svg height="32" class="octicon octicon-mark-github" viewBox="0 0 16 16" version="1.1" width="32" aria-hidden="true">
|
<svg height="32" class="octicon octicon-mark-github" viewBox="0 0 16 16" version="1.1" width="32" aria-hidden="true">
|
||||||
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
|
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if config.config_use_google_oauth %}
|
{% if config.config_use_google_oauth %}
|
||||||
<a href="{{url_for('google_login')}}" class="pull-right">
|
<a href="{{url_for('oauth.google_login')}}" class="pull-right">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
|
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
|
||||||
width="40" height="40"
|
width="40" height="40"
|
||||||
viewBox="0 3 48 49"
|
viewBox="0 3 48 49"
|
||||||
|
@ -81,8 +81,8 @@
|
|||||||
window.calibre = {
|
window.calibre = {
|
||||||
filePath: "{{ url_for('static', filename='js/libs/') }}",
|
filePath: "{{ url_for('static', filename='js/libs/') }}",
|
||||||
cssPath: "{{ url_for('static', filename='css/') }}",
|
cssPath: "{{ url_for('static', filename='css/') }}",
|
||||||
bookmarkUrl: "{{ url_for('bookmark', book_id=bookid, book_format='EPUB') }}",
|
bookmarkUrl: "{{ url_for('web.bookmark', book_id=bookid, book_format='EPUB') }}",
|
||||||
bookUrl: "{{ url_for('get_download_link_ext', book_id=bookid, book_format='epub', anyname='file.epub') }}",
|
bookUrl: "{{ url_for('web.get_download_link_ext', book_id=bookid, book_format='epub', anyname='file.epub') }}",
|
||||||
bookmark: "{{ bookmark.bookmark_key if bookmark != None }}",
|
bookmark: "{{ bookmark.bookmark_key if bookmark != None }}",
|
||||||
useBookmarks: "{{ g.user.is_authenticated | tojson }}"
|
useBookmarks: "{{ g.user.is_authenticated | tojson }}"
|
||||||
};
|
};
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<script>
|
<script>
|
||||||
document.onreadystatechange = function () {
|
document.onreadystatechange = function () {
|
||||||
if (document.readyState == "complete") {
|
if (document.readyState == "complete") {
|
||||||
init("{{ url_for('serve_book', book_id=comicfile, book_format=extension) }}");
|
init("{{ url_for('web.serve_book', book_id=comicfile, book_format=extension) }}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -44,7 +44,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||||||
<script src="{{ url_for('static', filename='js/libs/pdf.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/libs/pdf.js') }}"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var DEFAULT_URL = "{{ url_for('serve_book', book_id=pdffile, book_format='pdf') }}";
|
var DEFAULT_URL = "{{ url_for('web.serve_book', book_id=pdffile, book_format='pdf') }}";
|
||||||
var PDFWORKER_LOCATION="{{ url_for('static', filename='js/libs/pdf.worker.js') }}";
|
var PDFWORKER_LOCATION="{{ url_for('static', filename='js/libs/pdf.worker.js') }}";
|
||||||
var IMAGE_LOCATION="{{ url_for('static', filename='/images/') }}";
|
var IMAGE_LOCATION="{{ url_for('static', filename='/images/') }}";
|
||||||
var PDFWORKER_LOCATION_JS="{{ url_for('static', filename='js/libs/pdf.worker') }}";
|
var PDFWORKER_LOCATION_JS="{{ url_for('static', filename='js/libs/pdf.worker') }}";
|
||||||
|
@ -109,7 +109,7 @@
|
|||||||
$("#area").width($("#area").width());
|
$("#area").width($("#area").width());
|
||||||
$("#content").width($("#content").width());
|
$("#content").width($("#content").width());
|
||||||
//bind text
|
//bind text
|
||||||
$("#content").load("{{ url_for('serve_book', book_id=txtfile,book_format='txt') }}",function(textStr) {
|
$("#content").load("{{ url_for('web.serve_book', book_id=txtfile,book_format='txt') }}",function(textStr) {
|
||||||
$(this).height($(this).parent().height()*0.95);
|
$(this).height($(this).parent().height()*0.95);
|
||||||
$(this).text(textStr);
|
$(this).text(textStr);
|
||||||
});
|
});
|
||||||
|
@ -13,14 +13,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<button type="submit" id="submit" class="btn btn-primary">{{_('Register')}}</button>
|
<button type="submit" id="submit" class="btn btn-primary">{{_('Register')}}</button>
|
||||||
{% if config.config_use_github_oauth %}
|
{% if config.config_use_github_oauth %}
|
||||||
<a href="{{url_for('github_login')}}" class="pull-right">
|
<a href="{{url_for('oauth.github_login')}}" class="pull-right">
|
||||||
<svg height="32" class="octicon octicon-mark-github" viewBox="0 0 16 16" version="1.1" width="32" aria-hidden="true">
|
<svg height="32" class="octicon octicon-mark-github" viewBox="0 0 16 16" version="1.1" width="32" aria-hidden="true">
|
||||||
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
|
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if config.config_use_google_oauth %}
|
{% if config.config_use_google_oauth %}
|
||||||
<a href="{{url_for('google_login')}}" class="pull-right">
|
<a href="{{url_for('oauth.google_login')}}" class="pull-right">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
|
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
|
||||||
width="40" height="40"
|
width="40" height="40"
|
||||||
viewBox="0 3 48 49"
|
viewBox="0 3 48 49"
|
||||||
|
@ -19,12 +19,12 @@
|
|||||||
(function () {
|
(function () {
|
||||||
// Poll the server to check if the user has authenticated
|
// Poll the server to check if the user has authenticated
|
||||||
var t = setInterval(function () {
|
var t = setInterval(function () {
|
||||||
$.post('{{url_for("token_verified")}}', { token: '{{token}}' })
|
$.post('{{url_for("web.token_verified")}}', { token: '{{token}}' })
|
||||||
.done(function(response) {
|
.done(function(response) {
|
||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
// Wait a tick so cookies are updated
|
// Wait a tick so cookies are updated
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
window.location.href = '{{url_for("index")}}';
|
window.location.href = '{{url_for("web.index")}}';
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
<ul id="add-to-shelves" class="dropdown-menu" aria-labelledby="add-to-shelf">
|
<ul id="add-to-shelves" class="dropdown-menu" aria-labelledby="add-to-shelf">
|
||||||
{% for shelf in g.user.shelf %}
|
{% for shelf in g.user.shelf %}
|
||||||
{% if shelf.is_public != 1 %}
|
{% if shelf.is_public != 1 %}
|
||||||
<li><a href="{{ url_for('search_to_shelf', shelf_id=shelf.id) }}"> {{shelf.name}}</a></li>
|
<li><a href="{{ url_for('shelf.search_to_shelf', shelf_id=shelf.id) }}"> {{shelf.name}}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for shelf in g.public_shelfes %}
|
{% for shelf in g.public_shelfes %}
|
||||||
<li><a href="{{ url_for('search_to_shelf', shelf_id=shelf.id) }}">{{shelf.name}}</a></li>
|
<li><a href="{{ url_for('shelf.search_to_shelf', shelf_id=shelf.id) }}">{{shelf.name}}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
<div id="{{entry.id}}" class="list-group-item">{{entry.title}}</div>
|
<div id="{{entry.id}}" class="list-group-item">{{entry.title}}</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<button onclick="sendData('{{ url_for('order_shelf', shelf_id=shelf.id) }}')" class="btn btn-default" id="ChangeOrder">{{_('Change order')}}</button>
|
<button onclick="sendData('{{ url_for('shelf.order_shelf', shelf_id=shelf.id) }}')" class="btn btn-default" id="ChangeOrder">{{_('Change order')}}</button>
|
||||||
<a href="{{ url_for('show_shelf', shelf_id=shelf.id) }}" class="btn btn-default">{{_('Back')}}</a>
|
<a href="{{ url_for('shelf.show_shelf', shelf_id=shelf.id) }}" class="btn btn-default">{{_('Back')}}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
<p class="title">{{entry.title|shortentitle}}</p>
|
<p class="title">{{entry.title|shortentitle}}</p>
|
||||||
<p class="author">
|
<p class="author">
|
||||||
{% for author in entry.authors %}
|
{% for author in entry.authors %}
|
||||||
<a href="{{url_for('author', book_id=author.id) }}">{{author.name.replace('|',',')}}</a>
|
<a href="{{url_for('web.author', book_id=author.id) }}">{{author.name.replace('|',',')}}</a>
|
||||||
{% if not loop.last %}
|
{% if not loop.last %}
|
||||||
&
|
&
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -53,7 +53,7 @@
|
|||||||
{% if entry.data|length < 2 %}
|
{% if entry.data|length < 2 %}
|
||||||
|
|
||||||
{% for format in entry.data %}
|
{% for format in entry.data %}
|
||||||
<a href="{{ url_for('get_download_link_ext', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}" id="btnGroupDrop1{{format.format|lower}}" class="btn btn-primary" role="button">
|
<a href="{{ url_for('web.get_download_link_ext', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}" id="btnGroupDrop1{{format.format|lower}}" class="btn btn-primary" role="button">
|
||||||
<span class="glyphicon glyphicon-download"></span>{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
|
<span class="glyphicon glyphicon-download"></span>{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% if ( g.user and g.user.role_passwd() or g.user.role_admin() ) and not content.role_anonymous() %}
|
{% if ( g.user and g.user.role_passwd() or g.user.role_admin() ) and not content.role_anonymous() %}
|
||||||
{% if g.user and g.user.role_admin() and g.allow_registration and not new_user and not profile %}
|
{% if g.user and g.user.role_admin() and g.allow_registration and not new_user and not profile %}
|
||||||
<div class="btn btn-default" id="resend_password"><a href="{{url_for('reset_password', user_id = content.id) }}">{{_('Reset user Password')}}</a></div>
|
<div class="btn btn-default" id="resend_password"><a href="{{url_for('admin.reset_password', user_id = content.id) }}">{{_('Reset user Password')}}</a></div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="password">{{_('Password')}}</label>
|
<label for="password">{{_('Password')}}</label>
|
||||||
@ -161,7 +161,7 @@
|
|||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<button type="submit" id="submit" class="btn btn-default">{{_('Submit')}}</button>
|
<button type="submit" id="submit" class="btn btn-default">{{_('Submit')}}</button>
|
||||||
{% if not profile %}
|
{% if not profile %}
|
||||||
<a href="{{ url_for('admin') }}" id="back" class="btn btn-default">{{_('Back')}}</a>
|
<a href="{{ url_for('admin.admin') }}" id="back" class="btn btn-default">{{_('Back')}}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -171,8 +171,8 @@
|
|||||||
<h2>{{_('Recent Downloads')}}</h2>
|
<h2>{{_('Recent Downloads')}}</h2>
|
||||||
{% for entry in downloads %}
|
{% for entry in downloads %}
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<a class="pull-left" href="{{ url_for('show_book', book_id=entry.id) }}">
|
<a class="pull-left" href="{{ url_for('web.show_book', book_id=entry.id) }}">
|
||||||
<img class="media-object" width="100" src="{{ url_for('get_cover', book_id=entry.id) }}" alt="...">
|
<img class="media-object" width="100" src="{{ url_for('web.get_cover', book_id=entry.id) }}" alt="...">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -599,6 +599,8 @@ class Config:
|
|||||||
# everywhere to curent should work. Migration is done by checking if relevant coloums are existing, and than adding
|
# everywhere to curent should work. Migration is done by checking if relevant coloums are existing, and than adding
|
||||||
# rows with SQL commands
|
# rows with SQL commands
|
||||||
def migrate_Database():
|
def migrate_Database():
|
||||||
|
if not engine.dialect.has_table(engine.connect(), "book_read_link"):
|
||||||
|
ReadBook.__table__.create(bind=engine)
|
||||||
if not engine.dialect.has_table(engine.connect(), "bookmark"):
|
if not engine.dialect.has_table(engine.connect(), "bookmark"):
|
||||||
Bookmark.__table__.create(bind=engine)
|
Bookmark.__table__.create(bind=engine)
|
||||||
if not engine.dialect.has_table(engine.connect(), "registration"):
|
if not engine.dialect.has_table(engine.connect(), "registration"):
|
||||||
|
@ -65,6 +65,7 @@ logger = logging.getLogger("book_formats")
|
|||||||
try:
|
try:
|
||||||
from wand.image import Image
|
from wand.image import Image
|
||||||
from wand import version as ImageVersion
|
from wand import version as ImageVersion
|
||||||
|
from wand.exceptions import PolicyError
|
||||||
use_generic_pdf_cover = False
|
use_generic_pdf_cover = False
|
||||||
except (ImportError, RuntimeError) as e:
|
except (ImportError, RuntimeError) as e:
|
||||||
logger.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e)
|
logger.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e)
|
||||||
@ -160,12 +161,18 @@ def pdf_preview(tmp_file_path, tmp_dir):
|
|||||||
if use_generic_pdf_cover:
|
if use_generic_pdf_cover:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg"
|
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg"
|
||||||
with Image(filename=tmp_file_path + "[0]", resolution=150) as img:
|
with Image(filename=tmp_file_path + "[0]", resolution=150) as img:
|
||||||
img.compression_quality = 88
|
img.compression_quality = 88
|
||||||
img.save(filename=os.path.join(tmp_dir, cover_file_name))
|
img.save(filename=os.path.join(tmp_dir, cover_file_name))
|
||||||
return cover_file_name
|
return cover_file_name
|
||||||
|
except PolicyError as ex:
|
||||||
|
logger.warning('Pdf extraction forbidden by Imagemagick policy: %s', ex)
|
||||||
|
return None
|
||||||
|
except Exception as ex:
|
||||||
|
logger.warning('Cannot extract cover image, using default: %s', ex)
|
||||||
|
return None
|
||||||
|
|
||||||
def get_versions():
|
def get_versions():
|
||||||
if not use_generic_pdf_cover:
|
if not use_generic_pdf_cover:
|
||||||
@ -197,5 +204,5 @@ def upload(uploadfile):
|
|||||||
md5.update(filename.encode('utf-8'))
|
md5.update(filename.encode('utf-8'))
|
||||||
tmp_file_path = os.path.join(tmp_dir, md5.hexdigest())
|
tmp_file_path = os.path.join(tmp_dir, md5.hexdigest())
|
||||||
uploadfile.save(tmp_file_path)
|
uploadfile.save(tmp_file_path)
|
||||||
meta = book_formats.process(tmp_file_path, filename_root, file_extension)
|
meta = process(tmp_file_path, filename_root, file_extension)
|
||||||
return meta
|
return meta
|
||||||
|
77
cps/web.py
77
cps/web.py
@ -31,7 +31,6 @@ import os
|
|||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
from flask_login import login_user, logout_user, login_required, current_user
|
from flask_login import login_user, logout_user, login_required, current_user
|
||||||
from flask_babel import gettext as _
|
from flask_babel import gettext as _
|
||||||
|
|
||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
from werkzeug.datastructures import Headers
|
from werkzeug.datastructures import Headers
|
||||||
from babel import Locale as LC
|
from babel import Locale as LC
|
||||||
@ -50,6 +49,7 @@ import gdriveutils
|
|||||||
from redirect import redirect_back
|
from redirect import redirect_back
|
||||||
from cps import lm, babel, ub, config, get_locale, language_table, app
|
from cps import lm, babel, ub, config, get_locale, language_table, app
|
||||||
from pagination import Pagination
|
from pagination import Pagination
|
||||||
|
# from admin import check_valid_domain
|
||||||
# from oauth_bb import oauth_check, register_user_with_oauth
|
# from oauth_bb import oauth_check, register_user_with_oauth
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -280,6 +280,15 @@ def speaking_language(languages=None):
|
|||||||
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
|
||||||
return languages
|
return languages
|
||||||
|
|
||||||
|
# checks if domain is in database (including wildcards)
|
||||||
|
# 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()
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
# Orders all Authors in the list according to authors sort
|
# Orders all Authors in the list according to authors sort
|
||||||
def order_authors(entry):
|
def order_authors(entry):
|
||||||
@ -359,72 +368,6 @@ def get_email_status_json():
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
# checks if domain is in database (including wildcards)
|
|
||||||
# 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()
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
@web.route("/ajax/editdomain", methods=['POST'])
|
|
||||||
@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
|
|
||||||
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()
|
|
||||||
ub.session.commit()
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
@web.route("/ajax/adddomain", methods=['POST'])
|
|
||||||
@login_required
|
|
||||||
@admin_required
|
|
||||||
def add_domain():
|
|
||||||
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)
|
|
||||||
ub.session.add(new_domain)
|
|
||||||
ub.session.commit()
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
@web.route("/ajax/deletedomain", methods=['POST'])
|
|
||||||
@login_required
|
|
||||||
@admin_required
|
|
||||||
def delete_domain():
|
|
||||||
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
|
|
||||||
if not ub.session.query(ub.Registration).count():
|
|
||||||
new_domain = ub.Registration(domain="%.%")
|
|
||||||
ub.session.add(new_domain)
|
|
||||||
ub.session.commit()
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
@web.route("/ajax/domainlist")
|
|
||||||
@login_required
|
|
||||||
@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("'", '"'))
|
|
||||||
response.headers["Content-Type"] = "application/json; charset=utf-8"
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@web.route("/ajax/getcomic/<int:book_id>/<book_format>/<int:page>")
|
@web.route("/ajax/getcomic/<int:book_id>/<book_format>/<int:page>")
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -1 +0,0 @@
|
|||||||
python_ldap>=3.0.0
|
|
@ -14,6 +14,8 @@ six==1.10.0
|
|||||||
# goodreads
|
# goodreads
|
||||||
goodreads>=0.3.2
|
goodreads>=0.3.2
|
||||||
python-Levenshtein>=0.12.0
|
python-Levenshtein>=0.12.0
|
||||||
|
# ldap login
|
||||||
|
python_ldap>=3.0.0
|
||||||
# other
|
# other
|
||||||
lxml>=3.8.0
|
lxml>=3.8.0
|
||||||
rarfile>=2.7
|
rarfile>=2.7
|
||||||
|
Loading…
Reference in New Issue
Block a user