From 1290a45fb5727f309d362a8a58dfa04c435d9a50 Mon Sep 17 00:00:00 2001 From: Thomas Peetz Date: Mon, 28 Apr 2025 15:47:07 +0200 Subject: [PATCH] kontor-api: Add details pages for Comics, Artists and MediaFiles --- kontor-api/pyproject.toml | 1 + kontor-api/src/db/models/comic.py | 30 +++++++- kontor-api/src/static/images/cross.png | Bin 0 -> 544 bytes kontor-api/src/static/images/tick.png | Bin 0 -> 634 bytes .../src/templates/comic/artist_detail.html | 13 ++-- .../src/templates/comic/comic_detail.html | 38 +++++++--- kontor-api/src/templates/comic/comics.html | 3 +- .../src/templates/comic/publisher_detail.html | 45 ++++++++++++ .../src/templates/comic/publishers.html | 31 +++++++++ .../src/templates/components/actor_cards.html | 6 ++ .../src/templates/components/check.html | 5 ++ .../src/templates/components/comic_cards.html | 2 +- .../src/templates/components/navbar.html | 1 + .../templates/components/publisher_cards.html | 6 ++ .../src/templates/media/actor_detail.html | 45 ++++++++++++ kontor-api/src/templates/media/actors.html | 32 +++++++++ .../src/templates/media/file_detail.html | 65 ++++++++++++++++++ kontor-api/src/webapps/comic/route_comics.py | 15 +++- kontor-api/src/webapps/media/route_media.py | 4 +- kontor-api/uv.lock | 11 +++ 20 files changed, 331 insertions(+), 22 deletions(-) create mode 100644 kontor-api/src/static/images/cross.png create mode 100644 kontor-api/src/static/images/tick.png create mode 100644 kontor-api/src/templates/comic/publisher_detail.html create mode 100644 kontor-api/src/templates/comic/publishers.html create mode 100644 kontor-api/src/templates/components/actor_cards.html create mode 100644 kontor-api/src/templates/components/check.html create mode 100644 kontor-api/src/templates/components/publisher_cards.html create mode 100644 kontor-api/src/templates/media/actor_detail.html create mode 100644 kontor-api/src/templates/media/actors.html create mode 100644 kontor-api/src/templates/media/file_detail.html diff --git a/kontor-api/pyproject.toml b/kontor-api/pyproject.toml index 5714289..9ab9798 100644 --- a/kontor-api/pyproject.toml +++ b/kontor-api/pyproject.toml @@ -21,4 +21,5 @@ dependencies = [ "python-dotenv>=1.1.0", "python-jose>=3.4.0", "python-multipart>=0.0.20", + "natsort>=8.4.0", ] diff --git a/kontor-api/src/db/models/comic.py b/kontor-api/src/db/models/comic.py index e83d28b..423ad7c 100644 --- a/kontor-api/src/db/models/comic.py +++ b/kontor-api/src/db/models/comic.py @@ -1,3 +1,5 @@ +from typing import Dict, List +from natsort import natsorted from sqlalchemy import Column, ForeignKey, Integer, String from sqlalchemy.dialects.mysql import BIT from sqlalchemy.orm import relationship @@ -24,7 +26,7 @@ class Comic(Base, BaseMixin): publisher = relationship("Publisher", back_populates="comics") current_order = Column(BIT(1)) completed = Column(BIT(1)) - issues = relationship("Issue") + issues = relationship("Issue", order_by="Issue.issue_number") story_arcs = relationship("StoryArc") trade_paperbacks = relationship("TradePaperback") volumes = relationship("Volume") @@ -36,6 +38,21 @@ class Comic(Base, BaseMixin): def __str__(self): return f'{self.title}({self.id})' + def get_artists(self) -> Dict[str, List[str]]: + works: Dict[str, List[str]] = {} + for work in self.comic_works: + work_type = work.work_type.name + artist = work.artist + if work_type in works: + works[work_type].append(artist) + else: + works[work_type] = [artist] + return works + + def sorted_issues(self): + sorted_issues = natsorted(self.issues, key=lambda x: getattr(x, 'issue_number')) + return sorted_issues + class Volume(Base, BaseMixin): __tablename__ = "volume" @@ -77,6 +94,17 @@ class Artist(Base, BaseMixin): name = Column(String(length=255), nullable=False) comic_works = relationship("ComicWork") + def get_comics(self) -> Dict[str, List[str]]: + works: Dict[str, List[str]] = {} + for work in self.comic_works: + work_type = work.work_type.name + comic = work.comic + if work_type in works: + works[work_type].append(comic) + else: + works[work_type] = [comic] + return works + class WorkType(Base, BaseMixin): __tablename__ = "worktype" diff --git a/kontor-api/src/static/images/cross.png b/kontor-api/src/static/images/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..6b9fa6dd36ee8165272a13dd263f573507c78ca6 GIT binary patch literal 544 zcmV+*0^j|KP)L-ku(! z6_?D-?!0+#=VtbVZQGdTnZt~apI_HPK#=zVadHM((E`e*C+RoFb)Qo8-U{Lb7{`Tz zw4B8FZ|o?Wox+p=1wp47C;7ar*Xu~;a?<=sjPv>+otDjJ6FaGt!YnNyxQQhp)G1V! zk;r6ZtyV)c8pTbiRAnHRNXTxti%=+p$4aG2*+mMM&xrdiU^`VPk^N*+HX98^7!HT% zwA%;A{T)GxeQ|RcxyzV%! z$AbYD+)i1R64zB?q}NmTz}5|04~J#YG_goA*Eq(QJvp7pG14hUj1pZ^t>3S*xqHUO ze~r;}zTY_XkZ*}d@gm!;N90h8nBQenBUZ_ukZKNicn*hc_Pmc!Jn|2=s<~}>!Sb>Qm3!QP46b_JFw5YU70Tu$X}=T}ez@@t%j iG9vD)nDux55?}x$+|UyQVK_bj0000tYd4K$mX5uyr2F@fdffp{&DSHtl4|Bn9=ukpCx`#%PTUr-D(@b7;C zhJXJjrnw{;1KBM=6&|E`fsNrGL!Y6%zUh}QUl`(@V)PmQFtotEKmafTHP0uP}7&%m4pcKQ#X)BiAJ2y+PrtBI>9eEIt2-_c7)?*Lsf z5vX5*Af@m-wBJRV%#Fiz=BdPr0!2^a2d-yv7gSU);Z6{`~Oy?E5qSnHUln4*Y%!){F!Y1~5WXoC44g zb7l_)X~q^V6MmWR7e3wj|L|Wb!|^}Y86N$^h+kv_Kw-fP!~#If$6(B4$)LlK#&G6; zC&ShMSAb$5tA9Xg5dOsg@-z^@3;;QS9f&!gG&3|;{Da~@Q2ZB({s%XJ5&#fj0J|In U+D>(nEdT%j07*qoM6N<$g0@&8X#fBK literal 0 HcmV?d00001 diff --git a/kontor-api/src/templates/comic/artist_detail.html b/kontor-api/src/templates/comic/artist_detail.html index 2c69b0d..58ee61b 100644 --- a/kontor-api/src/templates/comic/artist_detail.html +++ b/kontor-api/src/templates/comic/artist_detail.html @@ -2,14 +2,14 @@ {% block title %} - Comic Detail + Artist Detail {% endblock %} {% block content %}
-

Comic Detail

+

Artist Detail

@@ -23,9 +23,14 @@ Works - {% for work in artist.comic_works %} + {% for work in artist.get_comics() %}

- {{work.work_type.name}}: {{work.comic.title}} + {{work}}: +

    + {% for comic in artist.get_comics()[work] %} +
  • {{comic.title}}
  • + {% endfor %} +

{% endfor %} diff --git a/kontor-api/src/templates/comic/comic_detail.html b/kontor-api/src/templates/comic/comic_detail.html index 57965fc..7a903e9 100644 --- a/kontor-api/src/templates/comic/comic_detail.html +++ b/kontor-api/src/templates/comic/comic_detail.html @@ -6,12 +6,7 @@ {% endblock %} {% block content %} -
-
-
-

Comic Detail

-
-
+
@@ -26,17 +21,26 @@ - + + @@ -46,6 +50,20 @@ + + + + + + + +
Completed{{comic.completed}} + {% with check=comic.completed %} + {% include "components/check.html" %} + {% endwith %} +
Works - {% for work in comic.comic_works %} + {% for work in comic.get_artists() %}

- {{work.work_type.name}}: {{work.artist.name}} + {{work}}: +

    + {% for artist in comic.get_artists()[work] %} +
  • {{artist.name}}
  • + {% endfor %} +

{% endfor %} -
Data CreatedData Modified {{comic.last_modified_date}}
Data Version{{comic.version}}
Issues + +
diff --git a/kontor-api/src/templates/comic/comics.html b/kontor-api/src/templates/comic/comics.html index 6da1b24..91b6513 100644 --- a/kontor-api/src/templates/comic/comics.html +++ b/kontor-api/src/templates/comic/comics.html @@ -19,8 +19,7 @@
{% with obj=comic %} {% include "components/comic_cards.html" %} - {% endwith %} - + {% endwith %} {% if loop.index %3 %}
{% else %} diff --git a/kontor-api/src/templates/comic/publisher_detail.html b/kontor-api/src/templates/comic/publisher_detail.html new file mode 100644 index 0000000..6429d58 --- /dev/null +++ b/kontor-api/src/templates/comic/publisher_detail.html @@ -0,0 +1,45 @@ +{% extends "shared/base.html" %} + + +{% block title %} + Publisher Detail +{% endblock %} + +{% block content %} +
+
+
+

Publisher Detail

+
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Publisher Name{{publisher.name}}
Comics + +
Data Created{{publisher.created_date}}
Data Modified{{publisher.last_modified_date}}
+
+
+{% endblock %} diff --git a/kontor-api/src/templates/comic/publishers.html b/kontor-api/src/templates/comic/publishers.html new file mode 100644 index 0000000..3eaedc8 --- /dev/null +++ b/kontor-api/src/templates/comic/publishers.html @@ -0,0 +1,31 @@ +{% extends "shared/base.html" %} + +{% block title %} + Publisher List +{% endblock %} + +{% block content %} + {% with msg=msg %} + {% include "components/alerts.html" %} + {% endwith %} +
+
+
+

Find Publishers..

+
+
+
+ {% for publisher in publishers %} +
+ {% with obj=publisher %} + {% include "components/publisher_cards.html" %} + {% endwith %} + {% if loop.index %3 %} +
+ {% else %} +

+ {% endif %} + {% endfor %} +
+
+{% endblock %} diff --git a/kontor-api/src/templates/components/actor_cards.html b/kontor-api/src/templates/components/actor_cards.html new file mode 100644 index 0000000..8678b0e --- /dev/null +++ b/kontor-api/src/templates/components/actor_cards.html @@ -0,0 +1,6 @@ +
+
+
{{obj.name}}
+ Read more +
+
diff --git a/kontor-api/src/templates/components/check.html b/kontor-api/src/templates/components/check.html new file mode 100644 index 0000000..b2b6263 --- /dev/null +++ b/kontor-api/src/templates/components/check.html @@ -0,0 +1,5 @@ +{% if check == 1 %} + +{% else %} + +{% endif %} diff --git a/kontor-api/src/templates/components/comic_cards.html b/kontor-api/src/templates/components/comic_cards.html index 4d0354f..2a1a5fc 100644 --- a/kontor-api/src/templates/components/comic_cards.html +++ b/kontor-api/src/templates/components/comic_cards.html @@ -2,7 +2,7 @@
{{obj.title}}

Publisher : {{obj.publisher.name}}

-

Completed : {{obj.completed}}

+

Completed : {% with check=obj.completed %}{% include "components/check.html" %}{% endwith %}

Read more
diff --git a/kontor-api/src/templates/components/navbar.html b/kontor-api/src/templates/components/navbar.html index 24f428f..3d4f974 100644 --- a/kontor-api/src/templates/components/navbar.html +++ b/kontor-api/src/templates/components/navbar.html @@ -16,6 +16,7 @@ diff --git a/kontor-api/src/templates/components/publisher_cards.html b/kontor-api/src/templates/components/publisher_cards.html new file mode 100644 index 0000000..e2a6050 --- /dev/null +++ b/kontor-api/src/templates/components/publisher_cards.html @@ -0,0 +1,6 @@ +
+
+
{{obj.name}}
+ Read more +
+
diff --git a/kontor-api/src/templates/media/actor_detail.html b/kontor-api/src/templates/media/actor_detail.html new file mode 100644 index 0000000..f163f73 --- /dev/null +++ b/kontor-api/src/templates/media/actor_detail.html @@ -0,0 +1,45 @@ +{% extends "shared/base.html" %} + + +{% block title %} + Actor Detail +{% endblock %} + +{% block content %} +
+
+
+

Actor Detail

+
+
+ +
+ + + + + + + + + + + + + + + + + + + +
Actor Name{{actor.name}}
Works + +
Data Created{{actor.created_date}}
Data Modified{{actor.last_modified_date}}
+
+
+{% endblock %} diff --git a/kontor-api/src/templates/media/actors.html b/kontor-api/src/templates/media/actors.html new file mode 100644 index 0000000..836d614 --- /dev/null +++ b/kontor-api/src/templates/media/actors.html @@ -0,0 +1,32 @@ +{% extends "shared/base.html" %} + +{% block title %} + MediaFile Actors +{% endblock %} + +{% block content %} + {% with msg=msg %} + {% include "components/alerts.html" %} + {% endwith %} +
+
+
+

Actors..

+
+
+
+ {% for actor in actors %} +
+ {% with obj=actor %} + {% include "components/actor_cards.html" %} + {% endwith %} + + {% if loop.index %3 %} +
+ {% else %} +

+ {% endif %} + {% endfor %} +
+
+{% endblock %} diff --git a/kontor-api/src/templates/media/file_detail.html b/kontor-api/src/templates/media/file_detail.html new file mode 100644 index 0000000..186444b --- /dev/null +++ b/kontor-api/src/templates/media/file_detail.html @@ -0,0 +1,65 @@ +{% extends "shared/base.html" %} + + +{% block title %} + MediaFile Detail +{% endblock %} + +{% block content %} +
+
+
+

MediaFile Detail

+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MediaFile Title{{mediafile.title}}
MediaFile URL{{mediafile.url}}
MediaFile Cloudlink{{mediafile.cloud_link}}
MediaFile Download?{{mediafile.should_download}}
MediaFile Review?{{mediafile.review}}
Actors + +
Data Created{{mediafile.created_date}}
Data Modified{{mediafile.last_modified_date}}
Data Version{{mediafile.version}}
+
+
+{% endblock %} diff --git a/kontor-api/src/webapps/comic/route_comics.py b/kontor-api/src/webapps/comic/route_comics.py index 524ea76..565bd26 100644 --- a/kontor-api/src/webapps/comic/route_comics.py +++ b/kontor-api/src/webapps/comic/route_comics.py @@ -4,8 +4,7 @@ from fastapi import APIRouter, Request from fastapi.templating import Jinja2Templates from src.apis.utils import SessionDep -from src.db.models.comic import Comic, Artist -from src.schema.comics.comic import get_comic_details +from src.db.models.comic import Comic, Artist, Publisher templates = Jinja2Templates(directory="src/templates") router = APIRouter(include_in_schema=False, prefix="/comic") @@ -29,3 +28,15 @@ def get_artists(db: SessionDep, request: Request, msg: str = None): def artist_detail(artist_id: UUID, request: Request, db: SessionDep): artist = db.get(Artist, artist_id) return templates.TemplateResponse("comic/artist_detail.html", {"request": request, "artist": artist}) + +@router.get("/publishers") +def get_publishers(db: SessionDep, request: Request, msg: str = None): + publishers = db.query(Publisher).all() + return templates.TemplateResponse("comic/publishers.html", {"request": request, "publishers": publishers}) + +@router.get("/publishers/{publisher_id}") +def publisher_details(publisher_id: UUID, request: Request, db: SessionDep, msg: str = None): + publisher = db.get(Publisher, publisher_id) + if publisher is None: + msg = "Could not find Publisher" + return templates.TemplateResponse("comic/publisher_detail.html", {"request": request, "msg": msg, "publisher": publisher}) diff --git a/kontor-api/src/webapps/media/route_media.py b/kontor-api/src/webapps/media/route_media.py index 602690f..b957f49 100644 --- a/kontor-api/src/webapps/media/route_media.py +++ b/kontor-api/src/webapps/media/route_media.py @@ -27,6 +27,6 @@ def get_actors(db: SessionDep, request: Request, msg: str = None): @router.get("/actors/{actor_id}") def artist_detail(actor_id: UUID, request: Request, db: SessionDep): - mediaactor = db.get(MediaActor, actor_id) - return templates.TemplateResponse("media/artist_detail.html", {"request": request, "mediaactor": mediaactor}) + actor = db.get(MediaActor, actor_id) + return templates.TemplateResponse("media/actor_detail.html", {"request": request, "actor": actor}) diff --git a/kontor-api/uv.lock b/kontor-api/uv.lock index 14578de..f12445d 100644 --- a/kontor-api/uv.lock +++ b/kontor-api/uv.lock @@ -284,6 +284,7 @@ dependencies = [ { name = "fastapi", extra = ["standard"] }, { name = "httpx" }, { name = "mariadb" }, + { name = "natsort" }, { name = "pathlib" }, { name = "platformdirs" }, { name = "pytest" }, @@ -302,6 +303,7 @@ requires-dist = [ { name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" }, { name = "httpx", specifier = "==0.24.1" }, { name = "mariadb", specifier = ">=1.1.12" }, + { name = "natsort", specifier = ">=8.4.0" }, { name = "pathlib", specifier = ">=1.0.1" }, { name = "platformdirs", specifier = ">=4.3.7" }, { name = "pytest", specifier = "==7.4.0" }, @@ -376,6 +378,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload_time = "2022-08-14T12:40:09.779Z" }, ] +[[package]] +name = "natsort" +version = "8.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e2/a9/a0c57aee75f77794adaf35322f8b6404cbd0f89ad45c87197a937764b7d0/natsort-8.4.0.tar.gz", hash = "sha256:45312c4a0e5507593da193dedd04abb1469253b601ecaf63445ad80f0a1ea581", size = 76575, upload_time = "2023-06-20T04:17:19.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/82/7a9d0550484a62c6da82858ee9419f3dd1ccc9aa1c26a1e43da3ecd20b0d/natsort-8.4.0-py3-none-any.whl", hash = "sha256:4732914fb471f56b5cce04d7bae6f164a592c7712e1c85f9ef585e197299521c", size = 38268, upload_time = "2023-06-20T04:17:17.522Z" }, +] + [[package]] name = "packaging" version = "25.0"