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.
pull/1164/head
Michael Shavit 5 years ago
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

@ -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…
Cancel
Save