Handle genres and authors casing
This commit is contained in:
@@ -380,7 +380,7 @@ def list_books(
|
|||||||
click.echo("-" * 75)
|
click.echo("-" * 75)
|
||||||
|
|
||||||
for book in books:
|
for book in books:
|
||||||
authors_str = ", ".join(a.name for a in book.authors)[:22]
|
authors_str = ", ".join(a.name.title() for a in book.authors)[:22]
|
||||||
if len(authors_str) == 22:
|
if len(authors_str) == 22:
|
||||||
authors_str += "..."
|
authors_str += "..."
|
||||||
owner_str = book.owner.username if book.owner else ""
|
owner_str = book.owner.username if book.owner else ""
|
||||||
@@ -459,7 +459,7 @@ def search_books(
|
|||||||
click.echo("-" * 72)
|
click.echo("-" * 72)
|
||||||
|
|
||||||
for book in books:
|
for book in books:
|
||||||
authors_str = ", ".join(a.name for a in book.authors)[:27]
|
authors_str = ", ".join(a.name.title() for a in book.authors)[:27]
|
||||||
if len(authors_str) == 27:
|
if len(authors_str) == 27:
|
||||||
authors_str += "..."
|
authors_str += "..."
|
||||||
click.echo(f"{book.id:<4} {book.title[:32]:<35} {authors_str:<30}")
|
click.echo(f"{book.id:<4} {book.title[:32]:<35} {authors_str:<30}")
|
||||||
@@ -502,7 +502,7 @@ def import_book(
|
|||||||
fetch_cover=not no_cover,
|
fetch_cover=not no_cover,
|
||||||
)
|
)
|
||||||
click.echo(
|
click.echo(
|
||||||
f"Imported book: {book.title} by {', '.join(a.name for a in book.authors)} (ID: {book.id})"
|
f"Imported book: {book.title} by {', '.join(a.name.title() for a in book.authors)} (ID: {book.id})"
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
click.echo(f"Error importing book: {e}", err=True)
|
click.echo(f"Error importing book: {e}", err=True)
|
||||||
|
|||||||
@@ -645,13 +645,14 @@ def get_books_by_location(
|
|||||||
|
|
||||||
|
|
||||||
def _get_or_create_author(name: str) -> Author:
|
def _get_or_create_author(name: str) -> Author:
|
||||||
"""Get existing author or create a new one."""
|
"""Get existing author or create a new one. Always store as lowercase."""
|
||||||
|
normalized = name.strip().lower()
|
||||||
author = db.session.execute(
|
author = db.session.execute(
|
||||||
select(Author).filter(Author.name == name)
|
select(Author).filter(Author.name == normalized)
|
||||||
).scalar_one_or_none()
|
).scalar_one_or_none()
|
||||||
|
|
||||||
if author is None:
|
if author is None:
|
||||||
author = Author(name=name)
|
author = Author(name=normalized)
|
||||||
db.session.add(author)
|
db.session.add(author)
|
||||||
# Don't commit here - let the caller handle the transaction
|
# Don't commit here - let the caller handle the transaction
|
||||||
|
|
||||||
@@ -659,13 +660,14 @@ def _get_or_create_author(name: str) -> Author:
|
|||||||
|
|
||||||
|
|
||||||
def _get_or_create_genre(name: str) -> Genre:
|
def _get_or_create_genre(name: str) -> Genre:
|
||||||
"""Get existing genre or create a new one."""
|
"""Get existing genre or create a new one. Always store as lowercase."""
|
||||||
|
normalized = name.strip().lower()
|
||||||
genre = db.session.execute(
|
genre = db.session.execute(
|
||||||
select(Genre).filter(Genre.name == name)
|
select(Genre).filter(Genre.name == normalized)
|
||||||
).scalar_one_or_none()
|
).scalar_one_or_none()
|
||||||
|
|
||||||
if genre is None:
|
if genre is None:
|
||||||
genre = Genre(name=name)
|
genre = Genre(name=normalized)
|
||||||
db.session.add(genre)
|
db.session.add(genre)
|
||||||
# Don't commit here - let the caller handle the transaction
|
# Don't commit here - let the caller handle the transaction
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<div class="bg-light p-3 rounded mb-4">
|
<div class="bg-light p-3 rounded mb-4">
|
||||||
<h6 class="fw-bold">{{ book.title }}</h6>
|
<h6 class="fw-bold">{{ book.title }}</h6>
|
||||||
{% if book.authors %}
|
{% if book.authors %}
|
||||||
<p class="text-muted small mb-1">by {{ book.authors | join(', ') }}</p>
|
<p class="text-muted small mb-1">by {{ book.authors | map('title') | join(', ') }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if book.isbn %}
|
{% if book.isbn %}
|
||||||
<p class="text-muted small mb-0">ISBN: {{ book.isbn }}</p>
|
<p class="text-muted small mb-0">ISBN: {{ book.isbn }}</p>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
{% if book.authors %}
|
{% if book.authors %}
|
||||||
<p class="card-text text-muted small text-truncate mb-2">
|
<p class="card-text text-muted small text-truncate mb-2">
|
||||||
by {{ book.authors | join(', ') }}
|
by {{ book.authors | map('title') | join(', ') }}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
{% if book.genres %}
|
{% if book.genres %}
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
{% for genre in book.genres[:2] %}
|
{% for genre in book.genres[:2] %}
|
||||||
<span class="badge bg-light text-dark small me-1">{{ genre }}</span>
|
<span class="badge bg-light text-dark small me-1">{{ genre|title }}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if book.genres|length > 2 %}
|
{% if book.genres|length > 2 %}
|
||||||
<span class="badge bg-light text-dark small">+{{ book.genres|length - 2 }}</span>
|
<span class="badge bg-light text-dark small">+{{ book.genres|length - 2 }}</span>
|
||||||
|
|||||||
@@ -21,12 +21,12 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label for="authors" class="form-label">Authors</label>
|
<label for="authors" class="form-label">Authors</label>
|
||||||
<textarea class="form-control" id="authors" name="authors" rows="2"
|
<textarea class="form-control" id="authors" name="authors" rows="2"
|
||||||
placeholder="One author per line">{% if book and book.authors %}{{ book.authors | join('\n') }}{% endif %}</textarea>
|
placeholder="One author per line">{% if book and book.authors %}{{ book.authors | map('title') | join('\n') }}{% endif %}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label for="genres" class="form-label">Genres</label>
|
<label for="genres" class="form-label">Genres</label>
|
||||||
<textarea class="form-control" id="genres" name="genres" rows="2"
|
<textarea class="form-control" id="genres" name="genres" rows="2"
|
||||||
placeholder="One genre per line">{% if book and book.genres %}{{ book.genres | join('\n') }}{% endif %}</textarea>
|
placeholder="One genre per line">{% if book and book.genres %}{{ book.genres | map('title') | join('\n') }}{% endif %}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -155,12 +155,12 @@
|
|||||||
};
|
};
|
||||||
new Tagify(document.querySelector('#genres'), {
|
new Tagify(document.querySelector('#genres'), {
|
||||||
...commmon_settings,
|
...commmon_settings,
|
||||||
whitelist: {{ genres | map(attribute = 'name') | list | pprint }},
|
whitelist: {{ genres | map(attribute = 'name') | map('title') | list | pprint }},
|
||||||
dropdown: { enabled: 0, closeOnSelect: false }
|
dropdown: { enabled: 0, closeOnSelect: false }
|
||||||
});
|
});
|
||||||
new Tagify(document.querySelector('#authors'), {
|
new Tagify(document.querySelector('#authors'), {
|
||||||
...commmon_settings,
|
...commmon_settings,
|
||||||
whitelist: {{ authors | map(attribute = 'name') | list | pprint }},
|
whitelist: {{ authors | map(attribute = 'name') | map('title') | list | pprint }},
|
||||||
dropdown: { enabled: 0, closeOnSelect: false }
|
dropdown: { enabled: 0, closeOnSelect: false }
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
Reference in New Issue
Block a user