Upated testresult

Bugfix book table
This commit is contained in:
Ozzie Isaacs 2021-12-05 13:04:13 +01:00
parent cd5711e651
commit d217676350
11 changed files with 3226 additions and 585 deletions

View File

@ -756,16 +756,21 @@ class CalibreDB():
except Exception as ex: except Exception as ex:
log.debug_or_exception(ex) log.debug_or_exception(ex)
# display authors in right order # display authors in right order
entries = self.order_authors(entries, True) entries = self.order_authors(entries, True, join_archive_read)
return entries, randm, pagination return entries, randm, pagination
# Orders all Authors in the list according to authors sort # Orders all Authors in the list according to authors sort
def order_authors(self, entries, list_return=False): def order_authors(self, entries, list_return=False, combined=False):
for entry in entries: for entry in entries:
sort_authors = entry.author_sort.split('&') if combined:
sort_authors = entry.Books.author_sort.split('&')
ids = [a.id for a in entry.Books.authors]
else:
sort_authors = entry.author_sort.split('&')
ids = [a.id for a in entry.authors]
authors_ordered = list() authors_ordered = list()
error = False error = False
ids = [a.id for a in entry.authors]
for auth in sort_authors: for auth in sort_authors:
results = self.session.query(Authors).filter(Authors.sort == auth.lstrip().strip()).all() results = self.session.query(Authors).filter(Authors.sort == auth.lstrip().strip()).all()
# ToDo: How to handle not found authorname # ToDo: How to handle not found authorname
@ -776,7 +781,10 @@ class CalibreDB():
if r.id in ids: if r.id in ids:
authors_ordered.append(r) authors_ordered.append(r)
if not error: if not error:
entry.authors = authors_ordered if combined:
entry.Books.authors = authors_ordered
else:
entry.authors = authors_ordered
if list_return: if list_return:
return entries return entries
else: else:
@ -841,7 +849,8 @@ class CalibreDB():
)) ))
# read search results from calibre-database and return it (function is used for feed and simple search # read search results from calibre-database and return it (function is used for feed and simple search
def get_search_results(self, term, offset=None, order=None, limit=None, config_read_column=False, *join): def get_search_results(self, term, offset=None, order=None, limit=None, allow_show_archived=False,
config_read_column=False, *join):
order = order[0] if order else [Books.sort] order = order[0] if order else [Books.sort]
pagination = None pagination = None
result = self.search_query(term, config_read_column, *join).order_by(*order).all() result = self.search_query(term, config_read_column, *join).order_by(*order).all()

View File

@ -50,6 +50,7 @@ from .services.worker import WorkerThread
from .tasks.upload import TaskUpload from .tasks.upload import TaskUpload
from .render_template import render_title_template from .render_template import render_title_template
from .usermanagement import login_required_if_no_ano from .usermanagement import login_required_if_no_ano
from .kobo_sync_status import change_archived_books
try: try:
from functools import wraps from functools import wraps
@ -1185,10 +1186,9 @@ def edit_list_book(param):
ret = Response(json.dumps({'success': True, ret = Response(json.dumps({'success': True,
'newValue': ' & '.join([author.replace('|',',') for author in input_authors])}), 'newValue': ' & '.join([author.replace('|',',') for author in input_authors])}),
mimetype='application/json') mimetype='application/json')
elif param =='is_archive': elif param =='is_archived':
# ToDo save change_archived_books(book.id, vals['value']=="True")
ret = Response(json.dumps({'success': True, 'newValue': vals['value']}), ret = ""
mimetype='application/json')
elif param =='read_status': elif param =='read_status':
# ToDo save # ToDo save
ret = Response(json.dumps({'success': True, 'newValue': vals['value']}), ret = Response(json.dumps({'success': True, 'newValue': vals['value']}),
@ -1197,8 +1197,12 @@ def edit_list_book(param):
new_val = dict() new_val = dict()
new_val[param] = vals['value'] new_val[param] = vals['value']
edit_single_cc_data(book.id, book, param[14:], new_val) edit_single_cc_data(book.id, book, param[14:], new_val)
ret = Response(json.dumps({'success': True, 'newValue': vals['value']}), # ToDo: Very hacky find better solution
mimetype='application/json') if vals['value'] in ["True", "False"]:
ret = ""
else:
ret = Response(json.dumps({'success': True, 'newValue': vals['value']}),
mimetype='application/json')
else: else:
return _("Parameter not found"), 400 return _("Parameter not found"), 400
book.last_modified = datetime.utcnow() book.last_modified = datetime.utcnow()

View File

@ -52,7 +52,7 @@ except ImportError:
from . import calibre_db from . import calibre_db
from .tasks.convert import TaskConvert from .tasks.convert import TaskConvert
from . import logger, config, get_locale, db, ub from . import logger, config, get_locale, db, ub, kobo_sync_status
from . import gdriveutils as gd from . import gdriveutils as gd
from .constants import STATIC_DIR as _STATIC_DIR from .constants import STATIC_DIR as _STATIC_DIR
from .subproc_wrapper import process_wait from .subproc_wrapper import process_wait
@ -431,7 +431,8 @@ def update_dir_structure_file(book_id, calibrepath, first_author, orignal_filepa
for file in file_list: for file in file_list:
shutil.move(os.path.normcase(os.path.join(dir_name, file)), shutil.move(os.path.normcase(os.path.join(dir_name, file)),
os.path.normcase(os.path.join(new_path + dir_name[len(path):], file))) os.path.normcase(os.path.join(new_path + dir_name[len(path):], file)))
# os.unlink(os.path.normcase(os.path.join(dir_name, file))) # change location in database to new author/title path
localbook.path = os.path.join(new_authordir, new_titledir).replace('\\','/')
except (OSError) as ex: except (OSError) as ex:
log.error("Rename title from: %s to %s: %s", path, new_path, ex) log.error("Rename title from: %s to %s: %s", path, new_path, ex)
log.debug(ex, exc_info=True) log.debug(ex, exc_info=True)
@ -441,12 +442,11 @@ def update_dir_structure_file(book_id, calibrepath, first_author, orignal_filepa
# Rename all files from old names to new names # Rename all files from old names to new names
try: try:
clean_author_database(renamed_author, calibrepath) clean_author_database(renamed_author, calibrepath)
if first_author not in renamed_author: if first_author not in renamed_author:
clean_author_database([first_author], calibrepath, localbook) clean_author_database([first_author], calibrepath, localbook)
if not renamed_author and not orignal_filepath and len(os.listdir(os.path.dirname(path))) == 0: if not renamed_author and not orignal_filepath and len(os.listdir(os.path.dirname(path))) == 0:
shutil.rmtree(os.path.dirname(path)) shutil.rmtree(os.path.dirname(path))
except (OSError) as ex: except (OSError, FileNotFoundError) as ex:
log.error("Error in rename file in path %s", ex) log.error("Error in rename file in path %s", ex)
log.debug(ex, exc_info=True) log.debug(ex, exc_info=True)
return _("Error in rename file in path: %(error)s", error=str(ex)) return _("Error in rename file in path: %(error)s", error=str(ex))

View File

@ -949,7 +949,8 @@ def HandleBookDeletionRequest(book_uuid):
return redirect_or_proxy_request() return redirect_or_proxy_request()
book_id = book.id book_id = book.id
archived_book = ( is_archived = kobo_sync_status.change_archived_books(book_id, True)
'''archived_book = (
ub.session.query(ub.ArchivedBook) ub.session.query(ub.ArchivedBook)
.filter(ub.ArchivedBook.book_id == book_id) .filter(ub.ArchivedBook.book_id == book_id)
.first() .first()
@ -960,8 +961,8 @@ def HandleBookDeletionRequest(book_uuid):
archived_book.last_modified = datetime.datetime.utcnow() archived_book.last_modified = datetime.datetime.utcnow()
ub.session.merge(archived_book) ub.session.merge(archived_book)
ub.session_commit() ub.session_commit()'''
if archived_book.is_archived: if is_archived:
kobo_sync_status.remove_synced_book(book_id) kobo_sync_status.remove_synced_book(book_id)
return "", 204 return "", 204

View File

@ -20,7 +20,7 @@
from flask_login import current_user from flask_login import current_user
from . import ub from . import ub
import datetime import datetime
from sqlalchemy.sql.expression import or_ from sqlalchemy.sql.expression import or_, and_
# Add the current book id to kobo_synced_books table for current user, if entry is already present, # Add the current book id to kobo_synced_books table for current user, if entry is already present,
# do nothing (safety precaution) # do nothing (safety precaution)
@ -42,18 +42,18 @@ def remove_synced_book(book_id):
ub.session_commit() ub.session_commit()
def add_archived_books(book_id): def change_archived_books(book_id, state=None, message=None):
archived_book = (ub.session.query(ub.ArchivedBook) archived_book = ub.session.query(ub.ArchivedBook).filter(and_(ub.ArchivedBook.user_id == int(current_user.id),
.filter(ub.ArchivedBook.book_id == book_id) ub.ArchivedBook.book_id == book_id)).first()
.filter(ub.ArchivedBook.user_id == current_user.id)
.first())
if not archived_book: if not archived_book:
archived_book = ub.ArchivedBook(user_id=current_user.id, book_id=book_id) archived_book = ub.ArchivedBook(user_id=current_user.id, book_id=book_id)
archived_book.is_archived = True
archived_book.is_archived = state if state else not archived_book.is_archived
archived_book.last_modified = datetime.datetime.utcnow() archived_book.last_modified = datetime.datetime.utcnow()
ub.session.merge(archived_book) ub.session.merge(archived_book)
ub.session_commit() ub.session_commit(message)
return archived_book.is_archived
# select all books which are synced by the current user and do not belong to a synced shelf and them to archive # select all books which are synced by the current user and do not belong to a synced shelf and them to archive
@ -65,7 +65,7 @@ def update_on_sync_shelfs(user_id):
.filter(or_(ub.Shelf.kobo_sync == 0, ub.Shelf.kobo_sync == None)) .filter(or_(ub.Shelf.kobo_sync == 0, ub.Shelf.kobo_sync == None))
.filter(ub.KoboSyncedBooks.user_id == user_id).all()) .filter(ub.KoboSyncedBooks.user_id == user_id).all())
for b in books_to_archive: for b in books_to_archive:
add_archived_books(b.book_id) change_archived_books(b.book_id, True)
ub.session.query(ub.KoboSyncedBooks) \ ub.session.query(ub.KoboSyncedBooks) \
.filter(ub.KoboSyncedBooks.book_id == b.book_id) \ .filter(ub.KoboSyncedBooks.book_id == b.book_id) \
.filter(ub.KoboSyncedBooks.user_id == user_id).delete() .filter(ub.KoboSyncedBooks.user_id == user_id).delete()

View File

@ -528,8 +528,8 @@ def get_metadata_calibre_companion(uuid, library):
def feed_search(term): def feed_search(term):
if term: if term:
entries, __, ___ = calibre_db.get_search_results(term, config_read_column=config.config_read_column) entries, __, ___ = calibre_db.get_search_results(term, config_read_column=config.config_read_column)
entriescount = len(entries) if len(entries) > 0 else 1 entries_count = len(entries) if len(entries) > 0 else 1
pagination = Pagination(1, entriescount, entriescount) pagination = Pagination(1, entries_count, entries_count)
return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination) return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination)
else: else:
return render_xml_template('feed.xml', searchterm="") return render_xml_template('feed.xml', searchterm="")

View File

@ -810,10 +810,11 @@ function checkboxChange(checkbox, userId, field, field_index) {
} }
function BookCheckboxChange(checkbox, userId, field) { function BookCheckboxChange(checkbox, userId, field) {
var value = checkbox.checked ? "True" : "False";
$.ajax({ $.ajax({
method: "post", method: "post",
url: getPath() + "/ajax/editbooks/" + field, url: getPath() + "/ajax/editbooks/" + field,
data: {"pk": userId, "value": checkbox.checked}, data: {"pk": userId, "value": value},
error: function(data) { error: function(data) {
handleListServerResponse([{type:"danger", message:data.responseText}]) handleListServerResponse([{type:"danger", message:data.responseText}])
}, },

View File

@ -71,8 +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--> <!--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) }} {{ 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> <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>
{{ book_checkbox_row('is_archived', _('Enter Archiv Status'), false)}} {{ book_checkbox_row('is_archived', _('Archiv Status'), false)}}
{{ book_checkbox_row('read_status', _('Enter Read Status'), false)}} {{ book_checkbox_row('read_status', _('Read Status'), false)}}
{% for c in cc %} {% for c in cc %}
{% if c.datatype == "int" %} {% 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> <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>
@ -89,7 +89,7 @@
{% elif c.datatype == "comments" %} {% elif c.datatype == "comments" %}
<th data-field="custom_column_{{ c.id|string }}" id="custom_column_{{ c.id|string }}" data-escape="true" data-editable-mode="popup" data-visible="{{visiblility.get('custom_column_'+ c.id|string)}}" data-sortable="false" {% if g.user.role_edit() %} data-editable-type="wysihtml5" 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> <th data-field="custom_column_{{ c.id|string }}" id="custom_column_{{ c.id|string }}" data-escape="true" data-editable-mode="popup" data-visible="{{visiblility.get('custom_column_'+ c.id|string)}}" data-sortable="false" {% if g.user.role_edit() %} data-editable-type="wysihtml5" 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>
{% elif c.datatype == "bool" %} {% elif c.datatype == "bool" %}
{{ book_checkbox_row('custom_column_' + c.id|string, _('Enter ') + c.name, c.name, visiblility, all_roles, false)}} {{ book_checkbox_row('custom_column_' + c.id|string, c.name, false)}}
{% else %} {% else %}
<!--{{ text_table_row('custom_column_' + c.id|string, _('Enter ') + c.name, c.name, false, false) }} --> <!--{{ text_table_row('custom_column_' + c.id|string, _('Enter ') + c.name, c.name, false, false) }} -->
{% endif %} {% endif %}

View File

@ -41,21 +41,21 @@
{% for entry in entries %} {% for entry in entries %}
<div class="col-sm-3 col-lg-2 col-xs-6 book"> <div class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="cover"> <div class="cover">
{% if entry.has_cover is defined %} {% if entry.Books.has_cover is defined %}
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false"> <a href="{{ url_for('web.show_book', book_id=entry.Books.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
<span class="img" title="{{entry.title}}" > <span class="img" title="{{entry.Books.title}}" >
<img src="{{ url_for('web.get_cover', book_id=entry.id) }}" alt="{{ entry.title }}" /> <img src="{{ url_for('web.get_cover', book_id=entry.Books.id) }}" alt="{{ entry.Books.title }}" />
{% if entry.id in read_book_ids %}<span class="badge read glyphicon glyphicon-ok"></span>{% endif %} {% if entry.Books.id in read_book_ids %}<span class="badge read glyphicon glyphicon-ok"></span>{% endif %}
</span> </span>
</a> </a>
{% endif %} {% endif %}
</div> </div>
<div class="meta"> <div class="meta">
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false"> <a href="{{ url_for('web.show_book', book_id=entry.Books.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
<p title="{{entry.title}}" class="title">{{entry.title|shortentitle}}</p> <p title="{{entry.Books.title}}" class="title">{{entry.Books.title|shortentitle}}</p>
</a> </a>
<p class="author"> <p class="author">
{% for author in entry.authors %} {% for author in entry.Books.authors %}
{% if loop.index > g.config_authors_max and g.config_authors_max != 0 %} {% if loop.index > g.config_authors_max and g.config_authors_max != 0 %}
{% if not loop.first %} {% if not loop.first %}
<span class="author-hidden-divider">&amp;</span> <span class="author-hidden-divider">&amp;</span>
@ -71,24 +71,24 @@
<a class="author-name" href="{{url_for('web.books_list', data='author', sort_param='new', book_id=author.id) }}">{{author.name.replace('|',',')|shortentitle(30)}}</a> <a class="author-name" href="{{url_for('web.books_list', data='author', sort_param='new', book_id=author.id) }}">{{author.name.replace('|',',')|shortentitle(30)}}</a>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% for format in entry.data %} {% for format in entry.Books.data %}
{% if format.format|lower in g.constants.EXTENSIONS_AUDIO %} {% if format.format|lower in g.constants.EXTENSIONS_AUDIO %}
<span class="glyphicon glyphicon-music"></span> <span class="glyphicon glyphicon-music"></span>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</p> </p>
{% if entry.series.__len__() > 0 %} {% if entry.Books.series.__len__() > 0 %}
<p class="series"> <p class="series">
<a href="{{url_for('web.books_list', data='series', sort_param='new', book_id=entry.series[0].id )}}"> <a href="{{url_for('web.books_list', data='series', sort_param='new', book_id=entry.Books.series[0].id )}}">
{{entry.series[0].name}} {{entry.Books.series[0].name}}
</a> </a>
({{entry.series_index|formatseriesindex}}) ({{entry.Books.series_index|formatseriesindex}})
</p> </p>
{% endif %} {% endif %}
{% if entry.ratings.__len__() > 0 %} {% if entry.Books.ratings.__len__() > 0 %}
<div class="rating"> <div class="rating">
{% for number in range((entry.ratings[0].rating/2)|int(2)) %} {% for number in range((entry.Books.ratings[0].rating/2)|int(2)) %}
<span class="glyphicon glyphicon-star good"></span> <span class="glyphicon glyphicon-star good"></span>
{% if loop.last and loop.index < 5 %} {% if loop.last and loop.index < 5 %}
{% for numer in range(5 - loop.index) %} {% for numer in range(5 - loop.index) %}

View File

@ -56,6 +56,7 @@ from .redirect import redirect_back
from .usermanagement import login_required_if_no_ano from .usermanagement import login_required_if_no_ano
from .kobo_sync_status import remove_synced_book from .kobo_sync_status import remove_synced_book
from .render_template import render_title_template from .render_template import render_title_template
from .kobo_sync_status import change_archived_books
feature_support = { feature_support = {
'ldap': bool(services.ldap), 'ldap': bool(services.ldap),
@ -197,17 +198,8 @@ def toggle_read(book_id):
@web.route("/ajax/togglearchived/<int:book_id>", methods=['POST']) @web.route("/ajax/togglearchived/<int:book_id>", methods=['POST'])
@login_required @login_required
def toggle_archived(book_id): def toggle_archived(book_id):
archived_book = ub.session.query(ub.ArchivedBook).filter(and_(ub.ArchivedBook.user_id == int(current_user.id), is_archived = change_archived_books(book_id, message="Book {} archivebit toggled".format(book_id))
ub.ArchivedBook.book_id == book_id)).first() if is_archived:
if archived_book:
archived_book.is_archived = not archived_book.is_archived
archived_book.last_modified = datetime.utcnow()
else:
archived_book = ub.ArchivedBook(user_id=current_user.id, book_id=book_id)
archived_book.is_archived = True
ub.session.merge(archived_book)
ub.session_commit("Book {} archivebit toggled".format(book_id))
if archived_book.is_archived:
remove_synced_book(book_id) remove_synced_book(book_id)
return "" return ""
@ -759,6 +751,7 @@ def render_search_results(term, offset=None, order=None, limit=None):
offset, offset,
order, order,
limit, limit,
False,
config.config_read_column, config.config_read_column,
*join) *join)
return render_title_template('search.html', return render_title_template('search.html',
@ -836,7 +829,7 @@ def list_books():
elif not state: elif not state:
order = [db.Books.timestamp.desc()] order = [db.Books.timestamp.desc()]
total_count = filtered_count = calibre_db.session.query(db.Books).filter(calibre_db.common_filters(False)).count() total_count = filtered_count = calibre_db.session.query(db.Books).filter(calibre_db.common_filters(allow_show_archived=True)).count()
if state is not None: if state is not None:
if search: if search:
books = calibre_db.search_query(search, config.config_read_column).all() books = calibre_db.search_query(search, config.config_read_column).all()
@ -860,24 +853,26 @@ def list_books():
books =calibre_db.session.query(db.Books, None, ub.ArchivedBook.is_archived) 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, books = (books.outerjoin(ub.ArchivedBook, and_(db.Books.id == ub.ArchivedBook.book_id,
int(current_user.id) == ub.ArchivedBook.user_id)) int(current_user.id) == ub.ArchivedBook.user_id))
.filter(calibre_db.common_filters()).all()) .filter(calibre_db.common_filters(allow_show_archived=True)).all())
entries = calibre_db.get_checkbox_sorted(books, state, off, limit, order, True) entries = calibre_db.get_checkbox_sorted(books, state, off, limit, order, True)
elif search: elif search:
entries, filtered_count, __ = calibre_db.get_search_results(search, entries, filtered_count, __ = calibre_db.get_search_results(search,
off, off,
[order,''], [order,''],
limit, limit,
True,
config.config_read_column, config.config_read_column,
*join) *join)
else: else:
entries, __, __ = calibre_db.fill_indexpage((int(off) / (int(limit)) + 1), entries, __, __ = calibre_db.fill_indexpage_with_archived_books((int(off) / (int(limit)) + 1),
limit, db.Books,
db.Books, limit,
True, True,
order, order,
True, True,
config.config_read_column, True,
*join) config.config_read_column,
*join)
result = list() result = list()
for entry in entries: for entry in entries:

File diff suppressed because it is too large Load Diff