mirror of
https://github.com/janeczku/calibre-web
synced 2024-12-25 01:20:32 +00:00
Refactored send email by make use of ajax calls instead of posting the page
Always use getPath instead of pathname
This commit is contained in:
parent
2b9f920454
commit
321db4d712
@ -172,10 +172,6 @@ def check_send_to_ereader(entry):
|
||||
book_formats.append({'format': 'Epub',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to eReader', format='Epub')})
|
||||
if 'MOBI' in formats:
|
||||
book_formats.append({'format': 'Mobi',
|
||||
'convert': 0,
|
||||
'text': _('Send %(format)s to eReader', format='Mobi')})
|
||||
if 'PDF' in formats:
|
||||
book_formats.append({'format': 'Pdf',
|
||||
'convert': 0,
|
||||
@ -205,8 +201,8 @@ def check_read_formats(entry):
|
||||
|
||||
|
||||
# Files are processed in the following order/priority:
|
||||
# 1: If Mobi file is existing, it's directly send to eReader email,
|
||||
# 2: If Epub file is existing, it's converted and send to eReader email,
|
||||
# 1: If epub file is existing, it's directly send to eReader email,
|
||||
# 2: If mobi file is existing, it's converted and send to eReader email,
|
||||
# 3: If Pdf file is existing, it's directly send to eReader email
|
||||
def send_mail(book_id, book_format, convert, ereader_mail, calibrepath, user_id):
|
||||
"""Send email with attachments"""
|
||||
@ -214,7 +210,7 @@ def send_mail(book_id, book_format, convert, ereader_mail, calibrepath, user_id)
|
||||
|
||||
if convert == 1:
|
||||
# returns None if success, otherwise errormessage
|
||||
return convert_book_format(book_id, calibrepath, 'epub', book_format.lower(), user_id, ereader_mail)
|
||||
return convert_book_format(book_id, calibrepath, 'mobi', book_format.lower(), user_id, ereader_mail)
|
||||
if convert == 2:
|
||||
# returns None if success, otherwise errormessage
|
||||
return convert_book_format(book_id, calibrepath, 'azw3', book_format.lower(), user_id, ereader_mail)
|
||||
|
@ -314,9 +314,6 @@ $(document).mouseup(function (e) {
|
||||
});
|
||||
});
|
||||
|
||||
// Split path name to array and remove blanks
|
||||
url = window.location.pathname
|
||||
|
||||
// Move create shelf
|
||||
$("#nav_createshelf").prependTo(".your-shelves");
|
||||
|
||||
@ -360,31 +357,6 @@ $(document).on("click", ".dropdown-toggle", function () {
|
||||
});
|
||||
});
|
||||
|
||||
// Fade out content on page unload
|
||||
// delegate all clicks on "a" tag (links)
|
||||
/*$(document).on("click", "a:not(.btn-toolbar a, a[href*='shelf/remove'], .identifiers a, .bookinfo , .btn-group > a, #add-to-shelves a, #book-list a, .stat.blur a )", function () {
|
||||
|
||||
// get the href attribute
|
||||
var newUrl = $(this).attr("href");
|
||||
|
||||
// veryfy if the new url exists or is a hash
|
||||
if (!newUrl || newUrl[0] === "#") {
|
||||
// set that hash
|
||||
location.hash = newUrl;
|
||||
return;
|
||||
}
|
||||
|
||||
now, fadeout the html (whole page)
|
||||
$( '.blur-wrapper' ).fadeOut(250);
|
||||
$(".row-fluid .col-sm-10").fadeOut(500,function () {
|
||||
// when the animation is complete, set the new location
|
||||
location = newUrl;
|
||||
});
|
||||
|
||||
// prevent the default browser behavior.
|
||||
return false;
|
||||
});*/
|
||||
|
||||
// Collapse long text into read-more
|
||||
$("div.comments").readmore({
|
||||
collapsedHeight: 134,
|
||||
@ -447,6 +419,8 @@ if ($("body.author").length > 0) {
|
||||
}
|
||||
}
|
||||
|
||||
// Split path name to array and remove blanks
|
||||
url = window.location.pathname
|
||||
// Ereader Page - add class to iframe body on ereader page after it loads.
|
||||
backurl = "../../book/" + url[2]
|
||||
$("body.epub #title-controls")
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
|
||||
* Copyright (C) 2018 jkrehm
|
||||
* Copyright (C) 2018-2023 jkrehm, 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
|
||||
@ -17,6 +17,35 @@
|
||||
|
||||
/* global _ */
|
||||
|
||||
function handleResponse (data) {
|
||||
$(".row-fluid.text-center").remove();
|
||||
$("#flash_danger").remove();
|
||||
$("#flash_success").remove();
|
||||
if (!jQuery.isEmptyObject(data)) {
|
||||
if($("#bookDetailsModal").is(":visible")) {
|
||||
data.forEach(function (item) {
|
||||
$(".modal-header").after('<div id="flash_' + item.type +
|
||||
'" class="text-center alert alert-' + item.type + '">' + item.message + '</div>');
|
||||
});
|
||||
} else {
|
||||
data.forEach(function (item) {
|
||||
$(".navbar").after('<div class="row-fluid text-center">' +
|
||||
'<div id="flash_' + item.type + '" class="alert alert-' + item.type + '">' + item.message + '</div>' +
|
||||
'</div>');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
$(".sendbtn-form").click(function() {
|
||||
$.ajax({
|
||||
method: 'post',
|
||||
url: $(this).data('href'),
|
||||
success: function (data) {
|
||||
handleResponse(data)
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$(function() {
|
||||
$("#have_read_form").ajaxForm();
|
||||
});
|
||||
|
@ -36,7 +36,7 @@ function init(logType) {
|
||||
d.innerHTML = "loading ...";
|
||||
|
||||
$.ajax({
|
||||
url: window.location.pathname + "/../../ajax/log/" + logType,
|
||||
url: getPath() + "/../../ajax/log/" + logType,
|
||||
datatype: "text",
|
||||
cache: false
|
||||
})
|
||||
|
@ -85,14 +85,6 @@ $(document).on("change", "select[data-controlall]", function() {
|
||||
}
|
||||
});
|
||||
|
||||
/*$(document).on("click", "#sendbtn", function (event) {
|
||||
postButton(event, $(this).data('action'));
|
||||
});
|
||||
|
||||
$(document).on("click", ".sendbutton", function (event) {
|
||||
// $(".sendbutton").on("click", "body", function(event) {
|
||||
postButton(event, $(this).data('action'));
|
||||
});*/
|
||||
|
||||
$(document).on("click", ".postAction", function (event) {
|
||||
// $(".sendbutton").on("click", "body", function(event) {
|
||||
@ -100,7 +92,6 @@ $(document).on("click", ".postAction", function (event) {
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Syntax has to be bind not on, otherwise problems with firefox
|
||||
$(".container-fluid").bind("dragenter dragover", function () {
|
||||
if($("#btn-upload").length && !$('body').hasClass('shelforder')) {
|
||||
@ -321,7 +312,7 @@ $(function() {
|
||||
folder: folder,
|
||||
filter: filt
|
||||
},
|
||||
url: window.location.pathname + request_path,
|
||||
url: getPath() + request_path,
|
||||
success: function success(data) {
|
||||
if ($("#element_selected").text() ==="") {
|
||||
$("#element_selected").text(data.cwd);
|
||||
@ -434,7 +425,7 @@ $(function() {
|
||||
}
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: window.location.pathname + "/../../get_update_status",
|
||||
url: getPath() + "/../../get_update_status",
|
||||
success: function success(data) {
|
||||
$this.html(buttonText);
|
||||
|
||||
@ -538,6 +529,7 @@ $(function() {
|
||||
$("#bookDetailsModal")
|
||||
.on("show.bs.modal", function(e) {
|
||||
$("#flash_danger").remove();
|
||||
$("#flash_success").remove();
|
||||
var $modalBody = $(this).find(".modal-body");
|
||||
|
||||
// Prevent static assets from loading multiple times
|
||||
@ -650,7 +642,6 @@ $(function() {
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
$("#user_submit").click(function() {
|
||||
this.closest("form").submit();
|
||||
});
|
||||
@ -682,7 +673,7 @@ $(function() {
|
||||
$.ajax({
|
||||
method:"post",
|
||||
dataType: "json",
|
||||
url: window.location.pathname + "/../../ajax/simulatedbchange",
|
||||
url: getPath() + "/../../ajax/simulatedbchange",
|
||||
data: {config_calibre_dir: $("#config_calibre_dir").val(), csrf_token: $("input[name='csrf_token']").val()},
|
||||
success: function success(data) {
|
||||
if ( data.change ) {
|
||||
@ -713,13 +704,13 @@ $(function() {
|
||||
var loader = "/../..";
|
||||
$("#flash_success").remove();
|
||||
$("#flash_danger").remove();
|
||||
$.post(window.location.pathname + request_path, $(this).closest("form").serialize(), function(data) {
|
||||
$.post(getPath() + request_path, $(this).closest("form").serialize(), function(data) {
|
||||
$('#config_upload_formats').val(data.config_upload);
|
||||
if(data.reboot) {
|
||||
$("#spinning_success").show();
|
||||
var rebootInterval = setInterval(function(){
|
||||
$.get({
|
||||
url:window.location.pathname + "/../../admin/alive",
|
||||
url:getPath() + "/../../admin/alive",
|
||||
success: function (d, statusText, xhr) {
|
||||
if (xhr.status < 400) {
|
||||
$("#spinning_success").hide();
|
||||
@ -745,7 +736,6 @@ $(function() {
|
||||
$(this).data('value'),
|
||||
function(value){
|
||||
postButton(event, $("#delete_shelf").data("action"));
|
||||
// $("#delete_shelf").closest("form").submit()
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -49,7 +49,7 @@ $(function() {
|
||||
method: "post",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
dataType: "json",
|
||||
url: window.location.pathname + "/../ajax/canceltask",
|
||||
url: getPath() + "/../ajax/canceltask",
|
||||
data: JSON.stringify({"task_id": taskId}),
|
||||
});
|
||||
});
|
||||
|
660
cps/templates/detail.html
Normal file → Executable file
660
cps/templates/detail.html
Normal file → Executable file
@ -1,326 +1,370 @@
|
||||
{% extends is_xhr|yesno("fragment.html", "layout.html") %}
|
||||
{% block body %}
|
||||
<div class="single">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-lg-3 col-xs-5">
|
||||
<div class="cover">
|
||||
<!-- Always use full-sized image for the detail page -->
|
||||
<img id="detailcover" title="{{entry.title}}" src="{{url_for('web.get_cover', book_id=entry.id, resolution='og', c=entry|last_modified)}}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-9 col-lg-9 book-meta">
|
||||
<div class="btn-toolbar" role="toolbar">
|
||||
<div class="btn-group" role="group" aria-label="Download, send to eReader, reading">
|
||||
{% if current_user.role_download() %}
|
||||
{% if entry.data|length %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if entry.data|length < 2 %}
|
||||
<button id="Download" type="button" class="btn btn-primary">
|
||||
{{_('Download')}} :
|
||||
</button>
|
||||
{% for format in entry.data %}
|
||||
<a href="{{ url_for('web.download_link', 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 }})
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<button id="btnGroupDrop1" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-download"></span> {{_('Download')}}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
||||
{% for format in entry.data %}
|
||||
<li><a href="{{ url_for('web.download_link', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}">{{format.format}} ({{ format.uncompressed_size|filesizeformat }})</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-lg-3 col-xs-5">
|
||||
<div class="cover">
|
||||
<!-- Always use full-sized image for the detail page -->
|
||||
<img id="detailcover" title="{{ entry.title }}"
|
||||
src="{{ url_for('web.get_cover', book_id=entry.id, resolution='og', c=entry|last_modified) }}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-9 col-lg-9 book-meta">
|
||||
<div class="btn-toolbar" role="toolbar">
|
||||
<div class="btn-group" role="group" aria-label="Download, send to E-Reader, reading">
|
||||
{% if current_user.role_download() %}
|
||||
{% if entry.data|length %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if entry.data|length < 2 %}
|
||||
<button id="Download" type="button" class="btn btn-primary">
|
||||
{{ _('Download') }} :
|
||||
</button>
|
||||
{% for format in entry.data %}
|
||||
<a href="{{ url_for('web.download_link', 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 }})
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<button id="btnGroupDrop1" type="button" class="btn btn-primary dropdown-toggle"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-download"></span> {{ _('Download') }}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
||||
{% for format in entry.data %}
|
||||
<li>
|
||||
<a href="{{ url_for('web.download_link', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}">{{ format.format }}
|
||||
({{ format.uncompressed_size|filesizeformat }})</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if current_user.kindle_mail and entry.email_share_list %}
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
{% if entry.email_share_list.__len__() == 1 %}
|
||||
<div class="btn-group" role="group">
|
||||
<button id="sendbtn" class="btn btn-primary sendbtn-form" data-href="{{url_for('web.send_to_ereader', book_id=entry.id, book_format=entry.email_share_list[0]['format'], convert=entry.email_share_list[0]['convert'])}}">
|
||||
<span class="glyphicon glyphicon-send"></span> {{entry.email_share_list[0]['text']}}
|
||||
</button>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="btn-group" role="group">
|
||||
<button id="sendbtn2" type="button" class="btn btn-primary dropdown-toggle"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-send"></span>{{ _('Send to eReader') }}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="send-to-ereader">
|
||||
{% for format in entry.email_share_list %}
|
||||
<li>
|
||||
<a class="sendbtn-form" data-href="{{url_for('web.send_to_ereader', book_id=entry.id, book_format=format['format'], convert=format['convert'])}}">{{ format['text'] }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if entry.reader_list and current_user.role_viewer() %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if entry.reader_list|length > 1 %}
|
||||
<button id="read-in-browser" type="button" class="btn btn-primary dropdown-toggle"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-book"></span> {{ _('Read in Browser') }}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="read-in-browser">
|
||||
{% for format in entry.reader_list %}
|
||||
<li><a target="_blank"
|
||||
href="{{ url_for('web.read_book', book_id=entry.id, book_format=format) }}">{{ format }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<a target="_blank"
|
||||
href="{{ url_for('web.read_book', book_id=entry.id, book_format=entry.reader_list[0]) }}"
|
||||
id="readbtn" class="btn btn-primary" role="button"><span
|
||||
class="glyphicon glyphicon-book"></span> {{ _('Read in Browser') }}
|
||||
- {{ entry.reader_list[0] }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if entry.audio_entries|length > 0 and current_user.role_viewer() %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if entry.audio_entries|length > 1 %}
|
||||
<button id="listen-in-browser" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-music"></span> {{ _('Listen in Browser') }}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="listen-in-browser">
|
||||
{% for format in entry.reader_list %}
|
||||
<li><a target="_blank" href="{{ url_for('web.read_book', book_id=entry.id, book_format=format) }}">{{ format }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<ul class="dropdown-menu" aria-labelledby="listen-in-browser">
|
||||
|
||||
{% for format in entry.data %}
|
||||
{% if format.format|lower in entry.audio_entries %}
|
||||
<li><a target="_blank"
|
||||
href="{{ url_for('web.read_book', book_id=entry.id, book_format=format.format|lower) }}">{{ format.format|lower }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<a target="_blank" href="{{ url_for('web.read_book', book_id=entry.id, book_format=entry.audio_entries[0]) }}" id="listenbtn" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-music"></span> {{ _('Listen in Browser') }} - {{ entry.audio_entries[0] }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<h2 id="title">{{ entry.title }}</h2>
|
||||
<p class="author">
|
||||
{% for author in entry.ordered_authors %}
|
||||
<a href="{{ url_for('web.books_list', data='author', sort_param='stored', book_id=author.id ) }}">{{ author.name.replace('|',',') }}</a>
|
||||
{% if not loop.last %}
|
||||
&
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% if entry.ratings.__len__() > 0 %}
|
||||
<div class="rating">
|
||||
<p>
|
||||
{% for number in range((entry.ratings[0].rating/2)|int(2)) %}
|
||||
<span class="glyphicon glyphicon-star good"></span>
|
||||
{% if loop.last and loop.index < 5 %}
|
||||
{% for numer in range(5 - loop.index) %}
|
||||
<span class="glyphicon glyphicon-star-empty"></span>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if entry.series|length > 0 %}
|
||||
<p>{{ _("Book %(index)s of %(range)s", index=entry.series_index | formatfloat(2), range=(url_for('web.books_list', data='series', sort_param='stored', book_id=entry.series[0].id)|escapedlink(entry.series[0].name))|safe) }}</p>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if entry.languages.__len__() > 0 %}
|
||||
<div class="languages">
|
||||
<p>
|
||||
<span class="label label-default">{{ _('Language') }}: {% for language in entry.languages %}
|
||||
{{ language.language_name }}{% if not loop.last %}, {% endif %}{% endfor %}</span>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if entry.identifiers|length > 0 %}
|
||||
<div class="identifiers">
|
||||
<p>
|
||||
<span class="glyphicon glyphicon-link"></span>
|
||||
{% for identifier in entry.identifiers %}
|
||||
<a href="{{ identifier }}" target="_blank" class="btn btn-xs btn-success"
|
||||
role="button">{{ identifier.format_type() }}</a>
|
||||
{% endfor %}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if entry.tags|length > 0 %}
|
||||
|
||||
<div class="tags">
|
||||
<p>
|
||||
<span class="glyphicon glyphicon-tags"></span>
|
||||
|
||||
{% for tag in entry.tags %}
|
||||
<a href="{{ url_for('web.books_list', data='category', sort_param='stored', book_id=tag.id) }}"
|
||||
class="btn btn-xs btn-info" role="button">{{ tag.name }}</a>
|
||||
{% endfor %}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if entry.publishers|length > 0 %}
|
||||
<div class="publishers">
|
||||
<p>
|
||||
<span>{{ _('Publisher') }}:
|
||||
<a href="{{ url_for('web.books_list', data='publisher', sort_param='stored', book_id=entry.publishers[0].id ) }}">{{ entry.publishers[0].name }}</a>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if (entry.pubdate|string)[:10] != '0101-01-01' %}
|
||||
<div class="publishing-date">
|
||||
<p>{{ _('Published') }}: {{ entry.pubdate|formatdate }} </p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if cc|length > 0 %}
|
||||
|
||||
|
||||
{% for c in cc %}
|
||||
<div class="real_custom_columns">
|
||||
{% if entry['custom_column_' ~ c.id]|length > 0 %}
|
||||
{{ c.name }}:
|
||||
{% for column in entry['custom_column_' ~ c.id] %}
|
||||
{% if c.datatype == 'rating' %}
|
||||
{{ (column.value / 2)|formatfloat }}
|
||||
{% else %}
|
||||
{% if c.datatype == 'bool' %}
|
||||
{% if column.value == true %}
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
{% else %}
|
||||
<span class="glyphicon glyphicon-remove"></span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if c.datatype == 'float' %}
|
||||
{{ column.value|formatfloat(2) }}
|
||||
{% elif c.datatype == 'datetime' %}
|
||||
{{ column.value|formatdate }}
|
||||
{% elif c.datatype == 'comments' %}
|
||||
{{ column.value|safe }}
|
||||
{% elif c.datatype == 'series' %}
|
||||
{{ '%s [%s]' % (column.value, column.extra|formatfloat(2)) }}
|
||||
{% elif c.datatype == 'text' %}
|
||||
{{ column.value.strip() }}{% if not loop.last %}, {% endif %}
|
||||
{% else %}
|
||||
{{ column.value }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if not current_user.is_anonymous %}
|
||||
|
||||
<div class="custom_columns">
|
||||
<p>
|
||||
<form id="have_read_form" action="{{ url_for('web.toggle_read', book_id=entry.id) }}"
|
||||
method="POST">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<label class="block-label">
|
||||
<input id="have_read_cb" data-checked="{{ _('Mark As Unread') }}"
|
||||
data-unchecked="{{ _('Mark As Read') }}" type="checkbox"
|
||||
{% if entry.read_status %}checked{% endif %}>
|
||||
<span>{{ _('Read') }}</span>
|
||||
</label>
|
||||
</form>
|
||||
</p>
|
||||
{% if current_user.check_visibility(32768) %}
|
||||
<p>
|
||||
<form id="archived_form" action="{{ url_for('web.toggle_archived', book_id=entry.id) }}"
|
||||
method="POST">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<label class="block-label">
|
||||
<input id="archived_cb" data-checked="{{ _('Restore from archive') }}"
|
||||
data-unchecked="{{ _('Add to archive') }}" type="checkbox"
|
||||
{% if entry.is_archived %}checked{% endif %}>
|
||||
<span>{{ _('Archived') }}</span>
|
||||
</label>
|
||||
</form>
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if entry.comments|length > 0 and entry.comments[0].text|length > 0 %}
|
||||
<div class="comments">
|
||||
<h3 id="decription">{{ _('Description:') }}</h3>
|
||||
{{ entry.comments[0].text|safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<div class="more-stuff">
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
{% if current_user.shelf.all() or g.shelves_access %}
|
||||
<div id="shelf-actions" class="btn-toolbar" role="toolbar">
|
||||
<div class="btn-group" role="group" aria-label="Add to shelves">
|
||||
<button id="add-to-shelf" type="button"
|
||||
class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-list"></span> {{ _('Add to shelf') }}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul id="add-to-shelves" class="dropdown-menu" aria-labelledby="add-to-shelf">
|
||||
{% for shelf in g.shelves_access %}
|
||||
{% if not shelf.id in books_shelfs and ( not shelf.is_public or current_user.role_edit_shelfs() ) %}
|
||||
<li>
|
||||
<a data-href="{{ url_for('shelf.add_to_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"
|
||||
>
|
||||
{{ shelf.name }}{% if shelf.is_public == 1 %}
|
||||
{{ _('(Public)') }}{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div id="remove-from-shelves" class="btn-group" role="group"
|
||||
aria-label="Remove from shelves">
|
||||
{% if books_shelfs %}
|
||||
{% for shelf in g.shelves_access %}
|
||||
{% if shelf.id in books_shelfs %}
|
||||
<a data-href="{{ url_for('shelf.remove_from_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"
|
||||
>
|
||||
<span {% if not shelf.is_public or current_user.role_edit_shelfs() %}
|
||||
class="glyphicon glyphicon-remove"
|
||||
{% endif %}></span> {{ shelf.name }}{% if shelf.is_public == 1 %} {{ _('(Public)') }}{% endif %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="shelf-action-errors" class="pull-left" role="alert"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if current_user.role_edit() %}
|
||||
<div class="btn-toolbar" role="toolbar">
|
||||
<div class="btn-group" role="group" aria-label="Edit/Delete book">
|
||||
<a href="{{ url_for('edit-book.show_edit_book', book_id=entry.id) }}"
|
||||
class="btn btn-sm btn-primary" id="edit_book" role="button"><span
|
||||
class="glyphicon glyphicon-edit"></span> {{ _('Edit Metadata') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if current_user.kindle_mail and entry.email_share_list %}
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
{% if entry.email_share_list.__len__() == 1 %}
|
||||
<div id="sendbtn" data-action="{{url_for('web.send_to_ereader', book_id=entry.id, book_format=entry.email_share_list[0]['format'], convert=entry.email_share_list[0]['convert'])}}" data-text="{{_('Send to eReader')}}" class="btn btn-primary postAction" role="button"><span class="glyphicon glyphicon-send"></span> {{entry.email_share_list[0]['text']}}</div>
|
||||
{% else %}
|
||||
<div class="btn-group" role="group">
|
||||
<button id="sendbtn2" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-send"></span>{{_('Send to eReader')}}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="send-to-ereader">
|
||||
{% for format in entry.email_share_list %}
|
||||
<li><a class="postAction" data-action="{{url_for('web.send_to_ereader', book_id=entry.id, book_format=format['format'], convert=format['convert'])}}">{{format['text']}}</a></li>
|
||||
{%endfor%}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if entry.reader_list and current_user.role_viewer() %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if entry.reader_list|length > 1 %}
|
||||
<button id="read-in-browser" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-book"></span> {{_('Read in Browser')}}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="read-in-browser">
|
||||
{% for format in entry.reader_list %}
|
||||
<li><a target="_blank" href="{{ url_for('web.read_book', book_id=entry.id, book_format=format) }}">{{format}}</a></li>
|
||||
{%endfor%}
|
||||
</ul>
|
||||
{% else %}
|
||||
<a target="_blank" href="{{url_for('web.read_book', book_id=entry.id, book_format=entry.reader_list[0])}}" id="readbtn" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-book"></span> {{_('Read in Browser')}} - {{entry.reader_list[0]}}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if entry.audio_entries|length > 0 and current_user.role_viewer() %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if entry.audio_entries|length > 1 %}
|
||||
<button id="listen-in-browser" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-music"></span> {{_('Listen in Browser')}}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="listen-in-browser">
|
||||
{% for format in entry.reader_list %}
|
||||
<li><a target="_blank" href="{{ url_for('web.read_book', book_id=entry.id, book_format=format) }}">{{format}}</a></li>
|
||||
{%endfor%}
|
||||
</ul>
|
||||
<ul class="dropdown-menu" aria-labelledby="listen-in-browser">
|
||||
|
||||
{% for format in entry.data %}
|
||||
{% if format.format|lower in entry.audio_entries %}
|
||||
<li><a target="_blank" href="{{ url_for('web.read_book', book_id=entry.id, book_format=format.format|lower) }}">{{format.format|lower }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<a target="_blank" href="{{url_for('web.read_book', book_id=entry.id, book_format=entry.audio_entries[0])}}" id="listenbtn" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-music"></span> {{_('Listen in Browser')}} - {{entry.audio_entries[0]}}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<h2 id="title">{{entry.title}}</h2>
|
||||
<p class="author">
|
||||
{% for author in entry.ordered_authors %}
|
||||
<a href="{{url_for('web.books_list', data='author', sort_param='stored', book_id=author.id ) }}">{{author.name.replace('|',',')}}</a>
|
||||
{% if not loop.last %}
|
||||
&
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% if entry.ratings.__len__() > 0 %}
|
||||
<div class="rating">
|
||||
<p>
|
||||
{% for number in range((entry.ratings[0].rating/2)|int(2)) %}
|
||||
<span class="glyphicon glyphicon-star good"></span>
|
||||
{% if loop.last and loop.index < 5 %}
|
||||
{% for numer in range(5 - loop.index) %}
|
||||
<span class="glyphicon glyphicon-star-empty"></span>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if entry.series|length > 0 %}
|
||||
<p>{{_("Book %(index)s of %(range)s", index=entry.series_index | formatfloat(2), range=(url_for('web.books_list', data='series', sort_param='stored', book_id=entry.series[0].id)|escapedlink(entry.series[0].name))|safe)}}</p>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if entry.languages.__len__() > 0 %}
|
||||
<div class="languages">
|
||||
<p>
|
||||
<span class="label label-default">{{_('Language')}}: {% for language in entry.languages %}{{language.language_name}}{% if not loop.last %}, {% endif %}{% endfor %}</span>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if entry.identifiers|length > 0 %}
|
||||
<div class="identifiers">
|
||||
<p>
|
||||
<span class="glyphicon glyphicon-link"></span>
|
||||
{% for identifier in entry.identifiers %}
|
||||
<a href="{{identifier}}" target="_blank" class="btn btn-xs btn-success" role="button">{{identifier.format_type()}}</a>
|
||||
{%endfor%}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if entry.tags|length > 0 %}
|
||||
|
||||
<div class="tags">
|
||||
<p>
|
||||
<span class="glyphicon glyphicon-tags"></span>
|
||||
|
||||
{% for tag in entry.tags %}
|
||||
<a href="{{ url_for('web.books_list', data='category', sort_param='stored', book_id=tag.id) }}" class="btn btn-xs btn-info" role="button">{{tag.name}}</a>
|
||||
{%endfor%}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if entry.publishers|length > 0 %}
|
||||
<div class="publishers">
|
||||
<p>
|
||||
<span>{{_('Publisher')}}:
|
||||
<a href="{{url_for('web.books_list', data='publisher', sort_param='stored', book_id=entry.publishers[0].id ) }}">{{entry.publishers[0].name}}</a>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if (entry.pubdate|string)[:10] != '0101-01-01' %}
|
||||
<div class="publishing-date">
|
||||
<p>{{_('Published')}}: {{entry.pubdate|formatdate}} </p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if cc|length > 0 %}
|
||||
|
||||
|
||||
{% for c in cc %}
|
||||
<div class="real_custom_columns">
|
||||
{% if entry['custom_column_' ~ c.id]|length > 0 %}
|
||||
{{ c.name }}:
|
||||
{% for column in entry['custom_column_' ~ c.id] %}
|
||||
{% if c.datatype == 'rating' %}
|
||||
{{ (column.value / 2)|formatfloat }}
|
||||
{% else %}
|
||||
{% if c.datatype == 'bool' %}
|
||||
{% if column.value == true %}
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
{% else %}
|
||||
<span class="glyphicon glyphicon-remove"></span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if c.datatype == 'float' %}
|
||||
{{ column.value|formatfloat(2) }}
|
||||
{% elif c.datatype == 'datetime' %}
|
||||
{{ column.value|formatdate }}
|
||||
{% elif c.datatype == 'comments' %}
|
||||
{{column.value|safe}}
|
||||
{% elif c.datatype == 'series' %}
|
||||
{{ '%s [%s]' % (column.value, column.extra|formatfloat(2)) }}
|
||||
{% elif c.datatype == 'text' %}
|
||||
{{ column.value.strip() }}{% if not loop.last %}, {% endif %}
|
||||
{% else %}
|
||||
{{ column.value }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if not current_user.is_anonymous %}
|
||||
|
||||
<div class="custom_columns">
|
||||
<p>
|
||||
<form id="have_read_form" action="{{ url_for('web.toggle_read', book_id=entry.id)}}" method="POST">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<label class="block-label">
|
||||
<input id="have_read_cb" data-checked="{{_('Mark As Unread')}}" data-unchecked="{{_('Mark As Read')}}" type="checkbox" {% if entry.read_status %}checked{% endif %} >
|
||||
<span>{{_('Read')}}</span>
|
||||
</label>
|
||||
</form>
|
||||
</p>
|
||||
{% if current_user.check_visibility(32768) %}
|
||||
<p>
|
||||
<form id="archived_form" action="{{ url_for('web.toggle_archived', book_id=entry.id)}}" method="POST">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<label class="block-label">
|
||||
<input id="archived_cb" data-checked="{{_('Restore from archive')}}" data-unchecked="{{_('Add to archive')}}" type="checkbox" {% if entry.is_archived %}checked{% endif %} >
|
||||
<span>{{_('Archived')}}</span>
|
||||
</label>
|
||||
</form>
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if entry.comments|length > 0 and entry.comments[0].text|length > 0%}
|
||||
<div class="comments">
|
||||
<h3 id="decription">{{_('Description:')}}</h3>
|
||||
{{entry.comments[0].text|safe}}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<div class="more-stuff">
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
{% if current_user.shelf.all() or g.shelves_access %}
|
||||
<div id="shelf-actions" class="btn-toolbar" role="toolbar">
|
||||
<div class="btn-group" role="group" aria-label="Add to shelves">
|
||||
<button id="add-to-shelf" type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-list"></span> {{_('Add to shelf')}}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul id="add-to-shelves" class="dropdown-menu" aria-labelledby="add-to-shelf">
|
||||
{% for shelf in g.shelves_access %}
|
||||
{% if not shelf.id in books_shelfs and ( not shelf.is_public or current_user.role_edit_shelfs() ) %}
|
||||
<li>
|
||||
<a data-href="{{ url_for('shelf.add_to_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"
|
||||
>
|
||||
{{shelf.name}}{% if shelf.is_public == 1 %} {{_('(Public)')}}{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{%endfor%}
|
||||
</ul>
|
||||
</div>
|
||||
<div id="remove-from-shelves" class="btn-group" role="group" aria-label="Remove from shelves">
|
||||
{% if books_shelfs %}
|
||||
{% for shelf in g.shelves_access %}
|
||||
{% if shelf.id in books_shelfs %}
|
||||
<a data-href="{{ url_for('shelf.remove_from_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"
|
||||
>
|
||||
<span {% if not shelf.is_public or current_user.role_edit_shelfs() %}
|
||||
class="glyphicon glyphicon-remove"
|
||||
{% endif %}></span> {{shelf.name}}{% if shelf.is_public == 1 %} {{_('(Public)')}}{% endif %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{%endfor%}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="shelf-action-errors" class="pull-left" role="alert"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if current_user.role_edit() %}
|
||||
<div class="btn-toolbar" role="toolbar">
|
||||
<div class="btn-group" role="group" aria-label="Edit/Delete book">
|
||||
<a href="{{ url_for('edit-book.show_edit_book', book_id=entry.id) }}" class="btn btn-sm btn-primary" id="edit_book" role="button"><span class="glyphicon glyphicon-edit"></span> {{_('Edit Metadata')}}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/template" id="template-shelf-add">
|
||||
<li>
|
||||
<a data-href="<%= add %>" data-remove-href="<%= remove %>" data-shelf-action="add">
|
||||
<%= content %>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-href="<%= add %>" data-remove-href="<%= remove %>" data-shelf-action="add">
|
||||
<%= content %>
|
||||
</a>
|
||||
</li>
|
||||
</script>
|
||||
<script type="text/template" id="template-shelf-remove">
|
||||
<a data-href="<%= remove %>" data-add-href="<%= add %>" class="btn btn-sm btn-default" data-shelf-action="remove">
|
||||
<span class="glyphicon glyphicon-remove"></span> <%= content %>
|
||||
</a>
|
||||
<a data-href="<%= remove %>" data-add-href="<%= add %>" class="btn btn-sm btn-default"
|
||||
data-shelf-action="remove">
|
||||
<span class="glyphicon glyphicon-remove"></span> <%= content %>
|
||||
</a>
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='js/details.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/fullscreen.js') }}"></script>
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
18
cps/web.py
Normal file → Executable file
18
cps/web.py
Normal file → Executable file
@ -25,7 +25,7 @@ import chardet # dependency of requests
|
||||
import copy
|
||||
|
||||
from flask import Blueprint, jsonify
|
||||
from flask import request, redirect, send_from_directory, make_response, flash, abort, url_for
|
||||
from flask import request, redirect, send_from_directory, make_response, flash, abort, url_for, Response
|
||||
from flask import session as flask_session
|
||||
from flask_babel import gettext as _
|
||||
from flask_babel import get_locale
|
||||
@ -1214,22 +1214,20 @@ def download_link(book_id, book_format, anyname):
|
||||
@download_required
|
||||
def send_to_ereader(book_id, book_format, convert):
|
||||
if not config.get_mail_server_configured():
|
||||
flash(_("Please configure the SMTP mail settings first."), category="error")
|
||||
response = [{'type': "danger", 'message': _("Please configure the SMTP mail settings first...")}]
|
||||
return Response(json.dumps(response), mimetype='application/json')
|
||||
elif current_user.kindle_mail:
|
||||
result = send_mail(book_id, book_format, convert, current_user.kindle_mail, config.config_calibre_dir,
|
||||
current_user.name)
|
||||
if result is None:
|
||||
flash(_("Success! Book queued for sending to %(eReadermail)s", eReadermail=current_user.kindle_mail),
|
||||
category="success")
|
||||
ub.update_download(book_id, int(current_user.id))
|
||||
response = [{'type': "success", 'message': _("Success! Book queued for sending to %(eReadermail)s",
|
||||
eReadermail=current_user.kindle_mail)}]
|
||||
else:
|
||||
flash(_("Oops! There was an error sending book: %(res)s", res=result), category="error")
|
||||
response = [{'type': "danger", 'message': _("Oops! There was an error sending book: %(res)s", res=result)}]
|
||||
else:
|
||||
flash(_("Oops! Please update your profile with a valid eReader Email."), category="error")
|
||||
if "HTTP_REFERER" in request.environ:
|
||||
return redirect(request.environ["HTTP_REFERER"])
|
||||
else:
|
||||
return redirect(url_for('web.index'))
|
||||
response = [{'type': "danger", 'message': _("Oops! Please update your profile with a valid eReader Email.")}]
|
||||
return Response(json.dumps(response), mimetype='application/json')
|
||||
|
||||
|
||||
# ################################### Login Logout ##################################################################
|
||||
|
Loading…
Reference in New Issue
Block a user