1
0
mirror of https://github.com/janeczku/calibre-web synced 2024-12-29 11:30:31 +00:00

Read and archive bit visible in book table

This commit is contained in:
Ozzie Isaacs 2021-10-24 21:22:08 +02:00
parent 516e76de4f
commit f6a2b8a9ef
7 changed files with 124 additions and 44 deletions

View File

@ -605,13 +605,6 @@ class CalibreDB():
filter(self.common_filters(allow_show_archived)).first()
def get_book_read_archived(self, book_id, read_column, allow_show_archived=False):
# Add missing relationships for inter database joins
#setattr(Books, "is_archived",
# relationship(ub.ArchivedBook,
# uselist=False,
# foreign_keys=ub.ArchivedBook.book_id,
# primaryjoin=and_(Books.id == ub.ArchivedBook.book_id,
# int(current_user.id) == ub.ArchivedBook.user_id)))
if not read_column:
bd = (self.session.query(Books, ub.ReadBook.read_status, ub.ArchivedBook.is_archived).select_from(Books)
.join(ub.ReadBook, and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.book_id == book_id),
@ -704,11 +697,13 @@ class CalibreDB():
return outcome[offset:offset + limit]
# Fill indexpage with all requested data from database
def fill_indexpage(self, page, pagesize, database, db_filter, order, *join):
return self.fill_indexpage_with_archived_books(page, pagesize, db_filter, order, False, database, join)
def fill_indexpage(self, page, pagesize, database, db_filter, order,
join_archive_read=False, config_read_column=0, *join):
return self.fill_indexpage_with_archived_books(page, database, pagesize, db_filter, order, False,
join_archive_read, config_read_column, *join)
def fill_indexpage_with_archived_books(self, page, pagesize, db_filter, order, allow_show_archived,
*args):
def fill_indexpage_with_archived_books(self, page, database, pagesize, db_filter, order, allow_show_archived,
join_archive_read, config_read_column, *join):
pagesize = pagesize or self.config.config_books_per_page
if current_user.show_detail_random():
randm = self.session.query(Books) \
@ -717,15 +712,26 @@ class CalibreDB():
.limit(self.config.config_random_books).all()
else:
randm = false()
if len(args) > 1:
if isinstance(args[0], DeclarativeMeta):
query = self.session.query(args[0])
if join_archive_read:
if not config_read_column:
query = (self.session.query(database, ub.ReadBook.read_status, ub.ArchivedBook.is_archived)
.select_from(Books)
.outerjoin(ub.ReadBook,
and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.book_id == Books.id)))
else:
query = self.session.query(*args[0])
join = args[1]
try:
read_column = cc_classes[config_read_column]
query = (self.session.query(database, read_column.value, ub.ArchivedBook.is_archived)
.select_from(Books)
.outerjoin(read_column, read_column.book == Books.id))
except (KeyError, AttributeError):
log.error("Custom Column No.%d is not existing in calibre database", read_column)
# Skip linking read column and return None instead of read status
query =self.session.query(database, None, ub.ArchivedBook.is_archived)
query = query.outerjoin(ub.ArchivedBook, and_(Books.id == ub.ArchivedBook.book_id,
int(current_user.id) == ub.ArchivedBook.user_id))
else:
join = tuple()
query = self.session.query(args)
query = self.session.query(database)
off = int(int(pagesize) * (page - 1))
indx = len(join)
@ -793,16 +799,29 @@ class CalibreDB():
return self.session.query(Books) \
.filter(and_(Books.authors.any(and_(*q)), func.lower(Books.title).ilike("%" + title + "%"))).first()
def search_query(self, term, *join):
def search_query(self, term, config_read_column, *join):
term.strip().lower()
self.session.connection().connection.connection.create_function("lower", 1, lcase)
q = list()
authorterms = re.split("[, ]+", term)
for authorterm in authorterms:
q.append(Books.authors.any(func.lower(Authors.name).ilike("%" + authorterm + "%")))
query = (self.session.query(Books, ub.ArchivedBook.is_archived)
.outerjoin(ub.ArchivedBook, and_(Books.id == ub.ArchivedBook.book_id,
int(current_user.id) == ub.ArchivedBook.user_id)))
if not config_read_column:
query = (self.session.query(Books, ub.ArchivedBook.is_archived, ub.ReadBook).select_from(Books)
.outerjoin(ub.ReadBook, and_(Books.id == ub.ReadBook.book_id,
int(current_user.id) == ub.ReadBook.user_id)))
else:
try:
read_column = cc_classes[config_read_column]
query = (self.session.query(Books, ub.ArchivedBook.is_archived, read_column.value).select_from(Books)
.outerjoin(read_column, read_column.book == Books.id))
except (KeyError, AttributeError):
log.error("Custom Column No.%d is not existing in calibre database", config_read_column)
# Skip linking read column
query = self.session.query(Books, ub.ArchivedBook.is_archived, None)
query = query.outerjoin(ub.ArchivedBook, and_(Books.id == ub.ArchivedBook.book_id,
int(current_user.id) == ub.ArchivedBook.user_id))
if len(join) == 6:
query = query.outerjoin(join[0], join[1]).outerjoin(join[2]).outerjoin(join[3], join[4]).outerjoin(join[5])
if len(join) == 3:

View File

@ -1161,13 +1161,22 @@ def edit_list_book(param):
ret = Response(json.dumps({'success': True,
'newValue': ' & '.join([author.replace('|',',') for author in input_authors])}),
mimetype='application/json')
elif param =='is_archive':
# ToDo save
ret = Response(json.dumps({'success': True, 'newValue': vals['value']}),
mimetype='application/json')
elif param =='read_status':
# ToDo save
ret = Response(json.dumps({'success': True, 'newValue': vals['value']}),
mimetype='application/json')
elif param.startswith("custom_column_"):
new_val = dict()
new_val[param] = vals['value']
edit_single_cc_data(book.id, book, param[14:], new_val)
ret = Response(json.dumps({'success': True, 'newValue': vals['value']}),
mimetype='application/json')
else:
return _("Parameter not found"), 400
book.last_modified = datetime.utcnow()
try:
calibre_db.session.commit()

View File

@ -425,6 +425,7 @@ def render_show_shelf(shelf_type, shelf_id, page_no, sort_param):
db.Books,
ub.BookShelf.shelf == shelf_id,
[ub.BookShelf.order.asc()],
False, 0,
ub.BookShelf, ub.BookShelf.book_id == db.Books.id)
# delete chelf entries where book is not existent anymore, can happen if book is deleted outside calibre-web
wrong_entries = calibre_db.session.query(ub.BookShelf) \

View File

@ -631,14 +631,21 @@ function singleUserFormatter(value, row) {
}
function checkboxFormatter(value, row){
if(value & this.column)
if (value & this.column)
return '<input type="checkbox" class="chk" data-pk="' + row.id + '" data-name="' + this.field + '" checked onchange="checkboxChange(this, ' + row.id + ', \'' + this.name + '\', ' + this.column + ')">';
else
return '<input type="checkbox" class="chk" data-pk="' + row.id + '" data-name="' + this.field + '" onchange="checkboxChange(this, ' + row.id + ', \'' + this.name + '\', ' + this.column + ')">';
}
function bookCheckboxFormatter(value, row){
if (value)
return '<input type="checkbox" class="chk" data-pk="' + row.id + '" data-name="' + this.field + '" checked onchange="BookCheckboxChange(this, ' + row.id + ', \'' + this.name + '\')">';
else
return '<input type="checkbox" class="chk" data-pk="' + row.id + '" data-name="' + this.field + '" onchange="BookCheckboxChange(this, ' + row.id + ', \'' + this.name + '\')">';
}
function singlecheckboxFormatter(value, row){
if(value)
if (value)
return '<input type="checkbox" class="chk" data-pk="' + row.id + '" data-name="' + this.field + '" checked onchange="checkboxChange(this, ' + row.id + ', \'' + this.name + '\', 0)">';
else
return '<input type="checkbox" class="chk" data-pk="' + row.id + '" data-name="' + this.field + '" onchange="checkboxChange(this, ' + row.id + ', \'' + this.name + '\', 0)">';
@ -790,7 +797,7 @@ function handleListServerResponse (data) {
function checkboxChange(checkbox, userId, field, field_index) {
$.ajax({
method: "post",
url: window.location.pathname + "/../../ajax/editlistusers/" + field,
url: getPath() + "/ajax/editlistusers/" + field,
data: {"pk": userId, "field_index": field_index, "value": checkbox.checked},
error: function(data) {
handleListServerResponse([{type:"danger", message:data.responseText}])
@ -799,6 +806,19 @@ function checkboxChange(checkbox, userId, field, field_index) {
});
}
function BookCheckboxChange(checkbox, userId, field) {
$.ajax({
method: "post",
url: getPath() + "/ajax/editbooks/" + field,
data: {"pk": userId, "value": checkbox.checked},
error: function(data) {
handleListServerResponse([{type:"danger", message:data.responseText}])
},
success: handleListServerResponse
});
}
function selectHeader(element, field) {
if (element.value !== "None") {
confirmDialog(element.id, "GeneralChangeModal", 0, function () {

View File

@ -14,13 +14,13 @@
>{{ show_text }}</th>
{%- endmacro %}
{% macro book_checkbox_row(parameter, array_field, show_text, element, value, sort) -%}
<!--th data-name="{{parameter}}" data-field="{{parameter}}"
{% macro book_checkbox_row(parameter, show_text, sort) -%}
<th data-name="{{parameter}}" data-field="{{parameter}}"
{% if sort %}data-sortable="true" {% endif %}
data-visible="{{visiblility.get(parameter)}}"
data-formatter="checkboxFormatter">
data-formatter="bookCheckboxFormatter">
{{show_text}}
</th-->
</th>
{%- endmacro %}
@ -71,7 +71,8 @@
<!--th data-field="pubdate" data-type="date" data-visible="{{visiblility.get('pubdate')}}" data-viewformat="dd.mm.yyyy" id="pubdate" data-sortable="true">{{_('Publishing Date')}}</th-->
{{ text_table_row('publishers', _('Enter Publishers'),_('Publishers'), false, true) }}
<th data-field="comments" id="comments" data-escape="true" data-editable-mode="popup" data-visible="{{visiblility.get('comments')}}" data-sortable="false" {% if g.user.role_edit() %} data-editable-type="wysihtml5" data-editable-url="{{ url_for('editbook.edit_list_book', param='comments')}}" data-edit="true" data-editable-title="{{_('Enter comments')}}"{% endif %}>{{_('Comments')}}</th>
<!-- data-editable-formatter="comment_display" -->
{{ book_checkbox_row('is_archived', _('Enter Archiv Status'), false)}}
{{ book_checkbox_row('read_status', _('Enter Read Status'), false)}}
{% for c in cc %}
{% if c.datatype == "int" %}
<th data-field="custom_column_{{ c.id|string }}" id="custom_column_{{ c.id|string }}" data-visible="{{visiblility.get('custom_column_'+ c.id|string)}}" data-sortable="false" {% if g.user.role_edit() %} data-editable-type="number" data-editable-placeholder="1" data-editable-step="1" data-editable-url="{{ url_for('editbook.edit_list_book', param='custom_column_'+ c.id|string)}}" data-edit="true" data-editable-title="{{_('Enter ') + c.name}}"{% endif %}>{{c.name}}</th>

View File

@ -228,7 +228,7 @@
<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.is_archived %}checked{% endif %} >
<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>

View File

@ -406,6 +406,7 @@ def render_books_list(data, sort, book_id, page):
else:
website = data or "newest"
entries, random, pagination = calibre_db.fill_indexpage(page, 0, db.Books, True, order,
False, 0,
db.books_series_link,
db.Books.id == db.books_series_link.c.book,
db.Series)
@ -419,6 +420,7 @@ def render_rated_books(page, book_id, order):
db.Books,
db.Books.ratings.any(db.Ratings.rating > 9),
order,
False, 0,
db.books_series_link,
db.Books.id == db.books_series_link.c.book,
db.Series)
@ -482,6 +484,7 @@ def render_downloaded_books(page, order, user_id):
db.Books,
ub.Downloads.user_id == user_id,
order,
False, 0,
ub.Downloads, db.Books.id == ub.Downloads.book_id)
for book in entries:
if not calibre_db.session.query(db.Books).filter(calibre_db.common_filters()) \
@ -504,6 +507,7 @@ def render_author_books(page, author_id, order):
db.Books,
db.Books.authors.any(db.Authors.id == author_id),
[order[0], db.Series.name, db.Books.series_index],
False, 0,
db.books_series_link,
db.Books.id == db.books_series_link.c.book,
db.Series)
@ -535,6 +539,7 @@ def render_publisher_books(page, book_id, order):
db.Books,
db.Books.publishers.any(db.Publishers.id == book_id),
[db.Series.name, order[0], db.Books.series_index],
False, 0,
db.books_series_link,
db.Books.id == db.books_series_link.c.book,
db.Series)
@ -590,6 +595,7 @@ def render_category_books(page, book_id, order):
db.Books,
db.Books.tags.any(db.Tags.id == book_id),
[order[0], db.Series.name, db.Books.series_index],
False, 0,
db.books_series_link,
db.Books.id == db.books_series_link.c.book,
db.Series)
@ -625,6 +631,7 @@ def render_read_books(page, are_read, as_xml=False, order=None):
db.Books,
db_filter,
order,
False, 0,
db.books_series_link,
db.Books.id == db.books_series_link.c.book,
db.Series,
@ -639,6 +646,7 @@ def render_read_books(page, are_read, as_xml=False, order=None):
db.Books,
db_filter,
order,
False, 0,
db.books_series_link,
db.Books.id == db.books_series_link.c.book,
db.Series,
@ -676,11 +684,12 @@ def render_archived_books(page, order):
archived_filter = db.Books.id.in_(archived_book_ids)
entries, random, pagination = calibre_db.fill_indexpage_with_archived_books(page, 0,
entries, random, pagination = calibre_db.fill_indexpage_with_archived_books(page, db.Books,
0,
archived_filter,
order,
True,
db.Books)
False, 0)
name = _(u'Archived Books') + ' (' + str(len(archived_book_ids)) + ')'
pagename = "archived"
@ -770,7 +779,7 @@ def list_books():
sort = request.args.get("sort", "id")
order = request.args.get("order", "").lower()
state = None
join = list()
join = tuple()
if sort == "state":
state = json.loads(request.args.get("state", "[]"))
@ -802,27 +811,48 @@ def list_books():
books = calibre_db.search_query(search).all()
filtered_count = len(books)
else:
books = (calibre_db.session.query(db.Books,ub.ArchivedBook.is_archived)
.outerjoin(ub.ArchivedBook, and_(db.Books.id == ub.ArchivedBook.book_id,
int(current_user.id) == ub.ArchivedBook.user_id))
if not config.config_read_column:
books = (calibre_db.session.query(db.Books, ub.ReadBook.read_status, ub.ArchivedBook.is_archived)
.select_from(db.Books)
.outerjoin(ub.ReadBook,
and_(ub.ReadBook.user_id == int(current_user.id),
ub.ReadBook.book_id == db.Books.id)))
else:
try:
read_column = db.cc_classes[config.config_read_column]
books = (calibre_db.session.query(db.Books, read_column.value, ub.ArchivedBook.is_archived)
.select_from(db.Books)
.outerjoin(read_column, read_column.book == db.Books.id))
except (KeyError, AttributeError):
log.error("Custom Column No.%d is not existing in calibre database", read_column)
# Skip linking read column and return None instead of read status
books =calibre_db.session.query(db.Books, None, ub.ArchivedBook.is_archived)
books = (books.outerjoin(ub.ArchivedBook, and_(db.Books.id == ub.ArchivedBook.book_id,
int(current_user.id) == ub.ArchivedBook.user_id))
.filter(calibre_db.common_filters()).all())
entries = calibre_db.get_checkbox_sorted(books, state, off, limit, order, True)
elif search:
entries, filtered_count, __ = calibre_db.get_search_results(search, off, order, limit, *tuple(join))
entries, filtered_count, __ = calibre_db.get_search_results(search,
off,
order,
limit,
config.config_read_column,
*join)
else:
join.append(ub.ArchivedBook)
join.append(and_(db.Books.id == ub.ArchivedBook.book_id,int(current_user.id) == ub.ArchivedBook.user_id))
entries, __, __ = calibre_db.fill_indexpage((int(off) / (int(limit)) + 1),
limit,
(db.Books, ub.ArchivedBook),
db.Books,
True,
order,
*tuple(join))
True,
config.config_read_column,
*join)
result = list()
for entry in entries:
val = entry[0]
val.is_archived = entry[1] == True
val.read_status = entry[1] == ub.ReadBook.STATUS_FINISHED
val.is_archived = entry[2] is True
for index in range(0, len(val.languages)):
val.languages[index].language_name = isoLanguages.get_language_name(get_locale(), val.languages[
index].lang_code)