Compare commits

..

5 Commits

Author SHA1 Message Date
c539255bf9 More UI improvements and fix a regression on manufacturer filtering 2025-12-12 23:55:09 +01:00
fc527d5cd1 Minor fixes to labels and dates 2025-12-12 00:08:43 +01:00
f45d754c91 More fixes to lables 2025-12-10 23:38:04 +01:00
e9c9ede357 Fix a bug in magazine edit 2025-12-10 23:03:48 +01:00
39b0a9378b Magazine UI (#54)
* Work in progress to implement magazines and issues UI

* Fully implement UI for magazines
2025-12-10 22:58:39 +01:00
13 changed files with 77 additions and 18 deletions

View File

@@ -475,6 +475,7 @@ class MagazineAdmin(SortableAdminBase, admin.ModelAdmin):
"fields": ( "fields": (
"published", "published",
"name", "name",
"website",
"publisher", "publisher",
"ISBN", "ISBN",
"language", "language",

View File

@@ -0,0 +1,18 @@
# Generated by Django 6.0 on 2025-12-12 14:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("bookshelf", "0026_alter_basebook_language_alter_magazine_image_and_more"),
]
operations = [
migrations.AddField(
model_name="magazine",
name="website",
field=models.URLField(blank=True),
),
]

View File

@@ -1,5 +1,6 @@
import os import os
import shutil import shutil
from urllib.parse import urlparse
from django.db import models from django.db import models
from django.conf import settings from django.conf import settings
from django.urls import reverse from django.urls import reverse
@@ -169,6 +170,7 @@ class Catalog(BaseBook):
class Magazine(BaseModel): class Magazine(BaseModel):
name = models.CharField(max_length=200) name = models.CharField(max_length=200)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE) publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
website = models.URLField(blank=True)
ISBN = models.CharField(max_length=17, blank=True) # 13 + dashes ISBN = models.CharField(max_length=17, blank=True) # 13 + dashes
image = models.ImageField( image = models.ImageField(
blank=True, blank=True,
@@ -205,6 +207,10 @@ class Magazine(BaseModel):
kwargs={"uuid": self.uuid} kwargs={"uuid": self.uuid}
) )
def website_short(self):
if self.website:
return urlparse(self.website).netloc.replace("www.", "")
class MagazineIssue(BaseBook): class MagazineIssue(BaseBook):
magazine = models.ForeignKey( magazine = models.ForeignKey(

View File

@@ -49,3 +49,5 @@ class CatalogSerializer(serializers.ModelSerializer):
"price", "price",
) )
read_only_fields = ("creation_time", "updated_time") read_only_fields = ("creation_time", "updated_time")
# FIXME: add Magazine and MagazineIssue serializers

View File

@@ -38,3 +38,5 @@ class CatalogGet(RetrieveAPIView):
def get_queryset(self): def get_queryset(self):
return Book.objects.get_published(self.request.user) return Book.objects.get_published(self.request.user)
# FIXME: add Magazine and MagazineIssue views

View File

@@ -1,4 +1,5 @@
import os import os
from urllib.parse import urlparse
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.conf import settings from django.conf import settings
@@ -57,6 +58,10 @@ class Manufacturer(models.Model):
}, },
) )
def website_short(self):
if self.website:
return urlparse(self.website).netloc.replace("www.", "")
def logo_thumbnail(self): def logo_thumbnail(self):
return get_image_preview(self.logo.url) return get_image_preview(self.logo.url)

View File

@@ -61,8 +61,7 @@
<thead> <thead>
<tr> <tr>
<th colspan="2" scope="row"> <th colspan="2" scope="row">
{% if type == "catalog" %}Catalog {{ label|capfirst }}
{% elif type == "book" %}Book{% endif %}
</th> </th>
</tr> </tr>
</thead> </thead>
@@ -70,7 +69,9 @@
{% if type == "catalog" %} {% if type == "catalog" %}
<tr> <tr>
<th class="w-33" scope="row">Manufacturer</th> <th class="w-33" scope="row">Manufacturer</th>
<td>{{ book.manufacturer }}</td> <td>
<a href="{% url 'filtered' _filter="manufacturer" search=book.manufacturer.slug %}">{{ book.manufacturer }}{% if book.manufacturer.website %}</a> <a href="{{ book.manufacturer.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}
</td>
</tr> </tr>
<tr> <tr>
<th class="w-33" scope="row">Scales</th> <th class="w-33" scope="row">Scales</th>
@@ -97,7 +98,10 @@
{% elif type == "magazineissue" %} {% elif type == "magazineissue" %}
<tr> <tr>
<th class="w-33" scope="row">Magazine</th> <th class="w-33" scope="row">Magazine</th>
<td><a href="{% url 'magazine' book.magazine.pk %}">{{ book.magazine }}</a></td> <td>
<a href="{% url 'magazine' book.magazine.pk %}">{{ book.magazine }}</a>
{% if book.magazine.website %} <a href="{{ book.magazine.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}
</td>
</tr> </tr>
<tr> <tr>
<th class="w-33" scope="row">Publisher</th> <th class="w-33" scope="row">Publisher</th>
@@ -112,7 +116,7 @@
</tr> </tr>
<tr> <tr>
<th class="w-33" scope="row">Date</th> <th class="w-33" scope="row">Date</th>
<td>{{ book.publication_year|default:"-" }} / {{ book.publication_month|default:"-" }}</td> <td>{{ book.publication_year|default:"-" }} / {{ book.get_publication_month_display|default:"-" }}</td>
</tr> </tr>
{% endif %} {% endif %}
<tr> <tr>

View File

@@ -24,7 +24,7 @@
<thead> <thead>
<tr> <tr>
<th colspan="2" scope="row"> <th colspan="2" scope="row">
{{ d.type | capfirst }} {{ d.label|capfirst }}
<div class="float-end"> <div class="float-end">
{% if not d.item.published %} {% if not d.item.published %}
<span class="badge text-bg-warning">Unpublished</span> <span class="badge text-bg-warning">Unpublished</span>
@@ -37,7 +37,9 @@
{% if d.type == "catalog" %} {% if d.type == "catalog" %}
<tr> <tr>
<th class="w-33" scope="row">Manufacturer</th> <th class="w-33" scope="row">Manufacturer</th>
<td>{{ d.item.manufacturer }}</td> <td>
<a href="{% url 'filtered' _filter="manufacturer" search=d.item.manufacturer.slug %}">{{ d.item.manufacturer }}{% if d.item.manufacturer.website %}</a> <a href="{{ d.item.manufacturer.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}
</td>
</tr> </tr>
<tr> <tr>
<th class="w-33" scope="row">Scales</th> <th class="w-33" scope="row">Scales</th>

View File

@@ -1,4 +1,5 @@
{% load static %} {% load static %}
{% load dynamic_url %}
<div class="col"> <div class="col">
<div class="card shadow-sm"> <div class="card shadow-sm">
{% if d.type == "magazine" %} {% if d.type == "magazine" %}
@@ -41,7 +42,8 @@
<thead> <thead>
<tr> <tr>
<th colspan="2" scope="row"> <th colspan="2" scope="row">
{{ d.type | capfirst }} {{ d.label|capfirst }}
<div class="float-end"> <div class="float-end">
{% if not d.item.published %} {% if not d.item.published %}
<span class="badge text-bg-warning">Unpublished</span> <span class="badge text-bg-warning">Unpublished</span>
@@ -56,6 +58,11 @@
<th class="w-33" scope="row">Magazine</th> <th class="w-33" scope="row">Magazine</th>
<td>{{ d.item.magazine }}</td> <td>{{ d.item.magazine }}</td>
</tr> </tr>
{% else %}
<tr>
<th class="w-33" scope="row">Website</th>
<td>{% if d.item.website %}<a href="{{ d.item.website }}" target="_blank">{{ d.item.website_short }}</td>{% else %}-{% endif %}</td>
</tr>
{% endif %} {% endif %}
<tr> <tr>
<th class="w-33" scope="row">Publisher</th> <th class="w-33" scope="row">Publisher</th>
@@ -71,7 +78,7 @@
</tr> </tr>
<tr> <tr>
<th class="w-33" scope="row">Date</th> <th class="w-33" scope="row">Date</th>
<td>{{ d.item.publication_year|default:"-" }} / {{ d.item.publication_month|default:"-" }}</td> <td>{{ d.item.publication_year|default:"-" }} / {{ d.item.get_publication_month_display|default:"-" }}</td>
</tr> </tr>
<tr> <tr>
<th class="w-33" scope="row">Pages</th> <th class="w-33" scope="row">Pages</th>
@@ -90,7 +97,7 @@
{% else %} {% else %}
<a class="btn btn-sm btn-outline-primary" href="{{ d.item.get_absolute_url }}">Show all data</a> <a class="btn btn-sm btn-outline-primary" href="{{ d.item.get_absolute_url }}">Show all data</a>
{% endif %} {% endif %}
{% if request.user.is_staff %}<a class="btn btn-sm btn-outline-danger" href="{% url 'admin:bookshelf_magazineissue_change' d.item.pk %}">Edit</a>{% endif %} {% if request.user.is_staff %}<a class="btn btn-sm btn-outline-danger" href="{% dynamic_admin_url 'bookshelf' d.type d.item.pk %}">Edit</a>{% endif %}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -17,12 +17,10 @@
<td><img class="logo" src="{{ d.item.logo.url }}" alt="{{ d.item.name }} logo"></td> <td><img class="logo" src="{{ d.item.logo.url }}" alt="{{ d.item.name }} logo"></td>
</tr> </tr>
{% endif %} {% endif %}
{% if d.item.website %}
<tr> <tr>
<th class="w-33" scope="row">Website</th> <th class="w-33" scope="row">Website</th>
<td><a href="{{ d.item.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a></td> <td>{% if d.item.website %}<a href="{{ d.item.website }}" target="_blank">{{ d.item.website_short }}</td>{% else %}-{% endif %}</td>
</tr> </tr>
{% endif %}
<tr> <tr>
<th class="w-33" scope="row">Category</th> <th class="w-33" scope="row">Category</th>
<td>{{ d.item.category | title }}</td> <td>{{ d.item.category | title }}</td>

View File

@@ -88,7 +88,7 @@
<tbody class="table-group-divider"> <tbody class="table-group-divider">
<tr> <tr>
<th class="w-33" scope="row">Name</th> <th class="w-33" scope="row">Name</th>
<td>{{ magazine }} </td> <td>{{ magazine }}</td>
</tr> </tr>
<tr> <tr>
<th class="w-33" scope="row">Publisher</th> <th class="w-33" scope="row">Publisher</th>
@@ -97,6 +97,14 @@
{% if magazine.publisher.website %} <a href="{{ magazine.publisher.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %} {% if magazine.publisher.website %} <a href="{{ magazine.publisher.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}
</td> </td>
</tr> </tr>
<tr>
<th class="w-33" scope="row">Website</th>
<td>{% if magazine.website %}<a href="{{ magazine.website }}" target="_blank">{{ magazine.website_short }}</td>{% else %}-{% endif %}</td>
</tr>
<tr>
<th class="w-33" scope="row">Language</th>
<td>{{ magazine.get_language_display }}</td>
</tr>
<tr> <tr>
<th scope="row">ISBN</th> <th scope="row">ISBN</th>
<td>{{ magazine.ISBN | default:"-" }}</td> <td>{{ magazine.ISBN | default:"-" }}</td>

View File

@@ -73,11 +73,14 @@ class GetData(View):
.filter(self.filter) .filter(self.filter)
) )
def get(self, request, filter=Q(), page=1): def get(self, request, page=1):
self.filter = filter
data = [] data = []
for item in self.get_data(request): for item in self.get_data(request):
data.append({"type": self.item_type, "item": item}) data.append({
"type": self.item_type,
"label": self.item_type.capitalize(),
"item": item
})
paginator = Paginator(data, get_items_per_page()) paginator = Paginator(data, get_items_per_page())
data = paginator.get_page(page) data = paginator.get_page(page)
@@ -669,6 +672,7 @@ class GetMagazine(View):
data = [ data = [
{ {
"type": "magazineissue", "type": "magazineissue",
"label": "Magazine issue",
"item": i, "item": i,
} }
for i in magazine.issue.get_published(request.user).all() for i in magazine.issue.get_published(request.user).all()
@@ -712,6 +716,7 @@ class GetMagazineIssue(View):
"documents": documents, "documents": documents,
"properties": properties, "properties": properties,
"type": "magazineissue", "type": "magazineissue",
"label": "Magazine issue",
}, },
) )
@@ -742,6 +747,7 @@ class GetBookCatalog(View):
"documents": documents, "documents": documents,
"properties": properties, "properties": properties,
"type": selector, "type": selector,
"label": selector.capitalize(),
}, },
) )

View File

@@ -1,4 +1,4 @@
from ram.utils import git_suffix from ram.utils import git_suffix
__version__ = "0.18.1" __version__ = "0.18.5"
__version__ += git_suffix(__file__) __version__ += git_suffix(__file__)