mirror of
https://github.com/janeczku/calibre-web
synced 2024-11-28 04:19:59 +00:00
Add UI support for archived books.
Archived books will no longer appear in any book lists or searches, and may only be restored from the Archive view.
This commit is contained in:
parent
e404da4192
commit
c0239a659c
@ -70,7 +70,7 @@ class _Settings(_Base):
|
|||||||
config_remote_login = Column(Boolean, default=False)
|
config_remote_login = Column(Boolean, default=False)
|
||||||
|
|
||||||
config_default_role = Column(SmallInteger, default=0)
|
config_default_role = Column(SmallInteger, default=0)
|
||||||
config_default_show = Column(SmallInteger, default=6143)
|
config_default_show = Column(SmallInteger, default=38911)
|
||||||
config_columns_to_ignore = Column(String)
|
config_columns_to_ignore = Column(String)
|
||||||
|
|
||||||
config_restricted_tags = Column(String, default="")
|
config_restricted_tags = Column(String, default="")
|
||||||
|
@ -80,9 +80,10 @@ MATURE_CONTENT = 1 << 11
|
|||||||
SIDEBAR_PUBLISHER = 1 << 12
|
SIDEBAR_PUBLISHER = 1 << 12
|
||||||
SIDEBAR_RATING = 1 << 13
|
SIDEBAR_RATING = 1 << 13
|
||||||
SIDEBAR_FORMAT = 1 << 14
|
SIDEBAR_FORMAT = 1 << 14
|
||||||
|
SIDEBAR_ARCHIVED = 1 << 15
|
||||||
|
|
||||||
ADMIN_USER_ROLES = sum(r for r in ALL_ROLES.values()) & ~ROLE_EDIT_SHELFS & ~ROLE_ANONYMOUS
|
ADMIN_USER_ROLES = sum(r for r in ALL_ROLES.values()) & ~ROLE_EDIT_SHELFS & ~ROLE_ANONYMOUS
|
||||||
ADMIN_USER_SIDEBAR = (SIDEBAR_FORMAT << 1) - 1
|
ADMIN_USER_SIDEBAR = (SIDEBAR_ARCHIVED << 1) - 1
|
||||||
|
|
||||||
UPDATE_STABLE = 0 << 0
|
UPDATE_STABLE = 0 << 0
|
||||||
AUTO_UPDATE_STABLE = 1 << 0
|
AUTO_UPDATE_STABLE = 1 << 0
|
||||||
|
@ -683,7 +683,19 @@ def render_task_status(tasklist):
|
|||||||
|
|
||||||
|
|
||||||
# Language and content filters for displaying in the UI
|
# Language and content filters for displaying in the UI
|
||||||
def common_filters():
|
def common_filters(allow_show_archived=False):
|
||||||
|
if not allow_show_archived:
|
||||||
|
archived_books = (
|
||||||
|
ub.session.query(ub.ArchivedBook)
|
||||||
|
.filter(ub.ArchivedBook.user_id == int(current_user.id))
|
||||||
|
.filter(ub.ArchivedBook.is_archived == True)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
archived_book_ids = [archived_book.book_id for archived_book in archived_books]
|
||||||
|
archived_filter = db.Books.id.notin_(archived_book_ids)
|
||||||
|
else:
|
||||||
|
archived_filter = true()
|
||||||
|
|
||||||
if current_user.filter_language() != "all":
|
if current_user.filter_language() != "all":
|
||||||
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
|
||||||
else:
|
else:
|
||||||
@ -708,7 +720,7 @@ def common_filters():
|
|||||||
pos_content_cc_filter = true()
|
pos_content_cc_filter = true()
|
||||||
neg_content_cc_filter = false()
|
neg_content_cc_filter = false()
|
||||||
return and_(lang_filter, pos_content_tags_filter, ~neg_content_tags_filter,
|
return and_(lang_filter, pos_content_tags_filter, ~neg_content_tags_filter,
|
||||||
pos_content_cc_filter, ~neg_content_cc_filter)
|
pos_content_cc_filter, ~neg_content_cc_filter, archived_filter)
|
||||||
|
|
||||||
|
|
||||||
def tags_filters():
|
def tags_filters():
|
||||||
@ -765,15 +777,19 @@ def order_authors(entry):
|
|||||||
|
|
||||||
# Fill indexpage with all requested data from database
|
# Fill indexpage with all requested data from database
|
||||||
def fill_indexpage(page, database, db_filter, order, *join):
|
def fill_indexpage(page, database, db_filter, order, *join):
|
||||||
|
return fill_indexpage_with_archived_books(page, database, db_filter, order, False, *join)
|
||||||
|
|
||||||
|
|
||||||
|
def fill_indexpage_with_archived_books(page, database, db_filter, order, allow_show_archived, *join):
|
||||||
if current_user.show_detail_random():
|
if current_user.show_detail_random():
|
||||||
randm = db.session.query(db.Books).filter(common_filters())\
|
randm = db.session.query(db.Books).filter(common_filters(allow_show_archived))\
|
||||||
.order_by(func.random()).limit(config.config_random_books)
|
.order_by(func.random()).limit(config.config_random_books)
|
||||||
else:
|
else:
|
||||||
randm = false()
|
randm = false()
|
||||||
off = int(int(config.config_books_per_page) * (page - 1))
|
off = int(int(config.config_books_per_page) * (page - 1))
|
||||||
pagination = Pagination(page, config.config_books_per_page,
|
pagination = Pagination(page, config.config_books_per_page,
|
||||||
len(db.session.query(database).filter(db_filter).filter(common_filters()).all()))
|
len(db.session.query(database).filter(db_filter).filter(common_filters(allow_show_archived)).all()))
|
||||||
entries = db.session.query(database).join(*join, isouter=True).filter(db_filter).filter(common_filters()).\
|
entries = db.session.query(database).join(*join, isouter=True).filter(db_filter).filter(common_filters(allow_show_archived)).\
|
||||||
order_by(*order).offset(off).limit(config.config_books_per_page).all()
|
order_by(*order).offset(off).limit(config.config_books_per_page).all()
|
||||||
for book in entries:
|
for book in entries:
|
||||||
book = order_authors(book)
|
book = order_authors(book)
|
||||||
|
@ -216,6 +216,8 @@ if ( $( 'body.book' ).length > 0 ) {
|
|||||||
.prependTo( '[aria-label^="Download, send"]' );
|
.prependTo( '[aria-label^="Download, send"]' );
|
||||||
$( '#have_read_cb' )
|
$( '#have_read_cb' )
|
||||||
.after( '<label class="block-label readLbl" for="#have_read_cb"></label>' );
|
.after( '<label class="block-label readLbl" for="#have_read_cb"></label>' );
|
||||||
|
$( '#archived_cb' )
|
||||||
|
.after( '<label class="block-label readLbl" for="#archived_cb"></label>' );
|
||||||
$( '#shelf-actions' ).prependTo( '[aria-label^="Download, send"]' );
|
$( '#shelf-actions' ).prependTo( '[aria-label^="Download, send"]' );
|
||||||
|
|
||||||
|
|
||||||
@ -586,6 +588,20 @@ $( '#have_read_cb:checked' ).attr({
|
|||||||
'data-viewport': '.btn-toolbar' })
|
'data-viewport': '.btn-toolbar' })
|
||||||
.addClass('readunread-btn-tooltip');
|
.addClass('readunread-btn-tooltip');
|
||||||
|
|
||||||
|
$( '#archived_cb' ).attr({
|
||||||
|
'data-toggle': 'tooltip',
|
||||||
|
'title': $( '#archived_cb').attr('data-unchecked'),
|
||||||
|
'data-placement': 'bottom',
|
||||||
|
'data-viewport': '.btn-toolbar' })
|
||||||
|
.addClass('readunread-btn-tooltip');
|
||||||
|
|
||||||
|
$( '#archived_cb:checked' ).attr({
|
||||||
|
'data-toggle': 'tooltip',
|
||||||
|
'title': $( '#archived_cb').attr('data-checked'),
|
||||||
|
'data-placement': 'bottom',
|
||||||
|
'data-viewport': '.btn-toolbar' })
|
||||||
|
.addClass('readunread-btn-tooltip');
|
||||||
|
|
||||||
$( 'button#delete' ).attr({
|
$( 'button#delete' ).attr({
|
||||||
'data-toggle-two': 'tooltip',
|
'data-toggle-two': 'tooltip',
|
||||||
'title': $( 'button#delete' ).text(), //'Delete'
|
'title': $( 'button#delete' ).text(), //'Delete'
|
||||||
@ -601,6 +617,14 @@ $( '#have_read_cb' ).click(function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$( '#archived_cb' ).click(function() {
|
||||||
|
if ( $( '#archived_cb:checked' ).length > 0 ) {
|
||||||
|
$( this ).attr('data-original-title', $('#archived_cb').attr('data-checked'));
|
||||||
|
} else {
|
||||||
|
$( this).attr('data-original-title', $('#archived_cb').attr('data-unchecked'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$( '.btn-group[aria-label="Edit/Delete book"] a' ).attr({
|
$( '.btn-group[aria-label="Edit/Delete book"] a' ).attr({
|
||||||
'data-toggle': 'tooltip',
|
'data-toggle': 'tooltip',
|
||||||
'title': $( '#edit_book' ).text(), // 'Edit'
|
'title': $( '#edit_book' ).text(), // 'Edit'
|
||||||
|
@ -25,6 +25,14 @@ $("#have_read_cb").on("change", function() {
|
|||||||
$(this).closest("form").submit();
|
$(this).closest("form").submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
$("#archived_form").ajaxForm();
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#archived_cb").on("change", function() {
|
||||||
|
$(this).closest("form").submit();
|
||||||
|
});
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
var templates = {
|
var templates = {
|
||||||
add: _.template(
|
add: _.template(
|
||||||
|
@ -202,6 +202,14 @@
|
|||||||
</label>
|
</label>
|
||||||
</form>
|
</form>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<form id="archived_form" action="{{ url_for('web.toggle_archived', book_id=entry.id)}}" method="POST">
|
||||||
|
<label class="block-label">
|
||||||
|
<input id="archived_cb" data-checked="{{_('Restore from archive')}}" data-unchecked="{{_('Add to archive')}}" type="checkbox" {% if is_archived %}checked{% endif %} >
|
||||||
|
<span>{{_('Archived')}}</span>
|
||||||
|
</label>
|
||||||
|
</form>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -97,10 +97,13 @@ def get_sidebar_config(kwargs=None):
|
|||||||
sidebar.append({"glyph": "glyphicon-file", "text": _('File formats'), "link": 'web.formats_list', "id": "format",
|
sidebar.append({"glyph": "glyphicon-file", "text": _('File formats'), "link": 'web.formats_list', "id": "format",
|
||||||
"visibility": constants.SIDEBAR_FORMAT, 'public': True,
|
"visibility": constants.SIDEBAR_FORMAT, 'public': True,
|
||||||
"page": "format", "show_text": _('Show file formats selection'), "config_show":True})
|
"page": "format", "show_text": _('Show file formats selection'), "config_show":True})
|
||||||
|
sidebar.append(
|
||||||
|
{"glyph": "glyphicon-trash", "text": _('Archived Books'), "link": 'web.books_list', "id": "archived",
|
||||||
|
"visibility": constants.SIDEBAR_ARCHIVED, 'public': (not g.user.is_anonymous), "page": "archived",
|
||||||
|
"show_text": _('Show archived books'), "config_show": True})
|
||||||
return sidebar
|
return sidebar
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class UserBase:
|
class UserBase:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
59
cps/web.py
59
cps/web.py
@ -46,10 +46,10 @@ from werkzeug.security import generate_password_hash, check_password_hash
|
|||||||
from . import constants, config, logger, isoLanguages, services, worker
|
from . import constants, config, logger, isoLanguages, services, worker
|
||||||
from . import searched_ids, lm, babel, db, ub, config, get_locale, app
|
from . import searched_ids, lm, babel, db, ub, config, get_locale, app
|
||||||
from .gdriveutils import getFileFromEbooksFolder, do_gdrive_download
|
from .gdriveutils import getFileFromEbooksFolder, do_gdrive_download
|
||||||
from .helper import common_filters, get_search_results, fill_indexpage, speaking_language, check_valid_domain, \
|
from .helper import common_filters, get_search_results, fill_indexpage, fill_indexpage_with_archived_books, \
|
||||||
order_authors, get_typeahead, render_task_status, json_serial, get_cc_columns, \
|
speaking_language, check_valid_domain, order_authors, get_typeahead, render_task_status, json_serial, \
|
||||||
get_book_cover, get_download_link, send_mail, generate_random_password, send_registration_mail, \
|
get_cc_columns, get_book_cover, get_download_link, send_mail, generate_random_password, \
|
||||||
check_send_to_kindle, check_read_formats, lcase, tags_filters, reset_password
|
send_registration_mail, check_send_to_kindle, check_read_formats, lcase, tags_filters, reset_password
|
||||||
from .pagination import Pagination
|
from .pagination import Pagination
|
||||||
from .redirect import redirect_back
|
from .redirect import redirect_back
|
||||||
|
|
||||||
@ -342,6 +342,23 @@ def toggle_read(book_id):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@web.route("/ajax/togglearchived/<int:book_id>", methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def toggle_archived(book_id):
|
||||||
|
archived_book = ub.session.query(ub.ArchivedBook).filter(and_(ub.ArchivedBook.user_id == int(current_user.id),
|
||||||
|
ub.ArchivedBook.book_id == book_id)).first()
|
||||||
|
if archived_book:
|
||||||
|
archived_book.is_archived = not archived_book.is_archived
|
||||||
|
else:
|
||||||
|
archived_book = ub.ArchivedBook()
|
||||||
|
archived_book.user_id = int(current_user.id)
|
||||||
|
archived_book.book_id = book_id
|
||||||
|
archived_book.is_archived = True
|
||||||
|
ub.session.merge(archived_book)
|
||||||
|
ub.session.commit()
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@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
|
||||||
@ -537,6 +554,8 @@ def books_list(data, sort, book_id, page):
|
|||||||
return render_category_books(page, book_id, order)
|
return render_category_books(page, book_id, order)
|
||||||
elif data == "language":
|
elif data == "language":
|
||||||
return render_language_books(page, book_id, order)
|
return render_language_books(page, book_id, order)
|
||||||
|
elif data == "archived":
|
||||||
|
return render_archived_books(page, order)
|
||||||
else:
|
else:
|
||||||
entries, random, pagination = fill_indexpage(page, db.Books, True, order)
|
entries, random, pagination = fill_indexpage(page, db.Books, True, order)
|
||||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||||
@ -1011,6 +1030,26 @@ def render_read_books(page, are_read, as_xml=False, order=None, *args, **kwargs)
|
|||||||
title=name, page=pagename)
|
title=name, page=pagename)
|
||||||
|
|
||||||
|
|
||||||
|
def render_archived_books(page, order):
|
||||||
|
order = order or []
|
||||||
|
archived_books = (
|
||||||
|
ub.session.query(ub.ArchivedBook)
|
||||||
|
.filter(ub.ArchivedBook.user_id == int(current_user.id))
|
||||||
|
.filter(ub.ArchivedBook.is_archived == True)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
archived_book_ids = [archived_book.book_id for archived_book in archived_books]
|
||||||
|
|
||||||
|
archived_filter = db.Books.id.in_(archived_book_ids)
|
||||||
|
|
||||||
|
entries, random, pagination = fill_indexpage_with_archived_books(page, db.Books, archived_filter, order,
|
||||||
|
allow_show_archived=True)
|
||||||
|
|
||||||
|
name = _(u'Archived Books') + ' (' + str(len(archived_book_ids)) + ')'
|
||||||
|
pagename = "archived"
|
||||||
|
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||||
|
title=name, page=pagename)
|
||||||
|
|
||||||
# ################################### Download/Send ##################################################################
|
# ################################### Download/Send ##################################################################
|
||||||
|
|
||||||
|
|
||||||
@ -1423,7 +1462,8 @@ def read_book(book_id, book_format):
|
|||||||
@web.route("/book/<int:book_id>")
|
@web.route("/book/<int:book_id>")
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
def show_book(book_id):
|
def show_book(book_id):
|
||||||
entries = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
|
entries = db.session.query(db.Books).filter(and_(db.Books.id == book_id,
|
||||||
|
common_filters(allow_show_archived=True))).first()
|
||||||
if entries:
|
if entries:
|
||||||
for index in range(0, len(entries.languages)):
|
for index in range(0, len(entries.languages)):
|
||||||
try:
|
try:
|
||||||
@ -1451,8 +1491,14 @@ def show_book(book_id):
|
|||||||
log.error("Custom Column No.%d is not existing in calibre database", config.config_read_column)
|
log.error("Custom Column No.%d is not existing in calibre database", config.config_read_column)
|
||||||
have_read = None
|
have_read = None
|
||||||
|
|
||||||
|
archived_book = ub.session.query(ub.ArchivedBook).\
|
||||||
|
filter(and_(ub.ArchivedBook.user_id == int(current_user.id),
|
||||||
|
ub.ArchivedBook.book_id == book_id)).first()
|
||||||
|
is_archived = archived_book and archived_book.is_archived
|
||||||
|
|
||||||
else:
|
else:
|
||||||
have_read = None
|
have_read = None
|
||||||
|
is_archived = None
|
||||||
|
|
||||||
entries.tags = sort(entries.tags, key=lambda tag: tag.name)
|
entries.tags = sort(entries.tags, key=lambda tag: tag.name)
|
||||||
|
|
||||||
@ -1468,7 +1514,8 @@ def show_book(book_id):
|
|||||||
|
|
||||||
return render_title_template('detail.html', entry=entries, audioentries=audioentries, cc=cc,
|
return render_title_template('detail.html', entry=entries, audioentries=audioentries, cc=cc,
|
||||||
is_xhr=request.is_xhr, title=entries.title, books_shelfs=book_in_shelfs,
|
is_xhr=request.is_xhr, title=entries.title, books_shelfs=book_in_shelfs,
|
||||||
have_read=have_read, kindle_list=kindle_list, reader_list=reader_list, page="book")
|
have_read=have_read, is_archived=is_archived, kindle_list=kindle_list,
|
||||||
|
reader_list=reader_list, page="book")
|
||||||
else:
|
else:
|
||||||
log.debug(u"Error opening eBook. File does not exist or file is not accessible:")
|
log.debug(u"Error opening eBook. File does not exist or file is not accessible:")
|
||||||
flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error")
|
flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error")
|
||||||
|
Loading…
Reference in New Issue
Block a user