1
0
mirror of https://github.com/janeczku/calibre-web synced 2024-11-28 12:30:00 +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:
Michael Shavit 2020-01-25 18:29:17 -05:00
parent e404da4192
commit c0239a659c
8 changed files with 121 additions and 14 deletions

View File

@ -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="")

View File

@ -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

View File

@ -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)

View File

@ -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'

View File

@ -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(

View File

@ -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 %}

View File

@ -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

View File

@ -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")