diff --git a/kontor-api/src/db/models/comic.py b/kontor-api/src/db/models/comic.py
index e5e3851..f498571 100644
--- a/kontor-api/src/db/models/comic.py
+++ b/kontor-api/src/db/models/comic.py
@@ -95,6 +95,8 @@ class StoryArc(Base, BaseMixin):
class Issue(Base, BaseMixin):
__tablename__ = "issue"
issue_number = Column(String)
+ title = Column(String, nullable=True)
+ published_on: Mapped[datetime] = mapped_column(nullable=True)
in_stock = Column(Boolean)
is_read = Column(Boolean)
comic_id = Column(String, ForeignKey("comic.id"), nullable=False)
diff --git a/kontor-api/src/templates/comic/issue_detail.html b/kontor-api/src/templates/comic/issue_detail.html
index bbaa42d..75514fe 100644
--- a/kontor-api/src/templates/comic/issue_detail.html
+++ b/kontor-api/src/templates/comic/issue_detail.html
@@ -20,6 +20,14 @@
Issue Number |
{{issue.issue_number}} |
+
+ | Full Title |
+ {{issue.title}} |
+
+
+ | Published |
+ {{issue.published_on}} |
+
| Auf Lager |
@@ -56,6 +64,10 @@
| Data Modified |
{{issue.last_modified_date}} |
+
+ | Data Version |
+ {{issue.version}} |
+
diff --git a/kontor-scripts/db/models/comic.py b/kontor-scripts/db/models/comic.py
index 35e1efa..07da295 100644
--- a/kontor-scripts/db/models/comic.py
+++ b/kontor-scripts/db/models/comic.py
@@ -35,14 +35,15 @@ class Publisher(Base):
self.parent_publisher_id = import_data['parent_publisher_id']
def export_dict(self) -> Dict[AnyStr, Any]:
- item: Dict[AnyStr, Any] = {}
- item['id'] = self.id
- item['created_date'] = str(self.created_date)
- item['last_modified_date'] = str(self.last_modified_date)
- item['version'] = self.version
- item['name'] = self.name
- item['weblink'] = self.weblink
- item['parent_publisher_id'] = self.parent_publisher_id
+ item: Dict[AnyStr, Any] = {
+ 'id': self.id,
+ 'created_date': str(self.created_date),
+ 'last_modified_date': str(self.last_modified_date),
+ 'version': self.version,
+ 'name': self.name,
+ 'weblink': self.weblink,
+ 'parent_publisher_id': self.parent_publisher_id
+ }
return item
@@ -79,16 +80,17 @@ class Comic(Base, BaseMixin):
self.weblink = import_data['weblink']
def export_dict(self) -> Dict[AnyStr, Any]:
- item: Dict[AnyStr, Any] = {}
- item['id'] = self.id
- item['created_date'] = str(self.created_date)
- item['last_modified_date'] = str(self.last_modified_date)
- item['version'] = self.version
- item['title'] = self.title
- item['publisher_id'] = self.publisher_id
- item['current_order'] = self.current_order
- item['completed'] = self.completed
- item['weblink'] = self.weblink
+ item: Dict[AnyStr, Any] = {
+ 'id': self.id,
+ 'created_date': str(self.created_date),
+ 'last_modified_date': str(self.last_modified_date),
+ 'version': self.version,
+ 'title': self.title,
+ 'publisher_id': self.publisher_id,
+ 'current_order': self.current_order,
+ 'completed': self.completed,
+ 'weblink': self.weblink
+ }
return item
@@ -168,20 +170,23 @@ class StoryArc(Base, BaseMixin):
self.volume_id = import_data['volume_id']
def export_dict(self) -> Dict[AnyStr, Any]:
- item: Dict[AnyStr, Any] = {}
- item['id'] = self.id
- item['created_date'] = str(self.created_date)
- item['last_modified_date'] = str(self.last_modified_date)
- item['version'] = self.version
- item['name'] = self.name
- item['comic_id'] = self.comic_id
- item['volume_id'] = self.volume_id
+ item: Dict[AnyStr, Any] = {
+ 'id': self.id,
+ 'created_date': str(self.created_date),
+ 'last_modified_date': str(self.last_modified_date),
+ 'version': self.version,
+ 'name': self.name,
+ 'comic_id': self.comic_id,
+ 'volume_id': self.volume_id
+ }
return item
class Issue(Base, BaseMixin):
__tablename__ = "issue"
issue_number = Column(String)
+ title = Column(String, nullable=True)
+ published_on: Mapped[datetime] = mapped_column(nullable=True)
in_stock = Column(Boolean)
is_read = Column(Boolean)
comic_id = Column(String, ForeignKey("comic.id"), nullable=False)
@@ -197,6 +202,8 @@ class Issue(Base, BaseMixin):
self.last_modified_date = import_data['last_modified_date']
self.version = import_data['version']
self.issue_number = import_data['issue_number']
+ self.title = import_data['title']
+ self.published_on = import_data['published_on']
self.in_stock = import_data['in_stock']
self.is_read = import_data['is_read']
self.comic_id = import_data['comic_id']
@@ -204,17 +211,20 @@ class Issue(Base, BaseMixin):
self.story_arc_id = import_data['story_arc_id']
def export_dict(self) -> Dict[AnyStr, Any]:
- item: Dict[AnyStr, Any] = {}
- item['id'] = self.id
- item['created_date'] = str(self.created_date)
- item['last_modified_date'] = str(self.last_modified_date)
- item['version'] = self.version
- item['issue_number'] = self.issue_number
- item['in_stock'] = self.in_stock
- item['is_read'] = self.is_read
- item['comic_id'] = self.comic_id
- item['volume_id'] = self.volume_id
- item['story_arc_id'] = self.story_arc_id
+ item: Dict[AnyStr, Any] = {
+ 'id': self.id,
+ 'created_date': str(self.created_date),
+ 'last_modified_date': str(self.last_modified_date),
+ 'version': self.version,
+ 'issue_number': self.issue_number,
+ 'title': self.title,
+ 'published_on': str(self.published_on),
+ 'in_stock': self.in_stock,
+ 'is_read': self.is_read,
+ 'comic_id': self.comic_id,
+ 'volume_id': self.volume_id,
+ 'story_arc_id': self.story_arc_id
+ }
return item
@@ -234,13 +244,14 @@ class Artist(Base, BaseMixin):
self.weblink = import_data['weblink']
def export_dict(self) -> Dict[AnyStr, Any]:
- item: Dict[AnyStr, Any] = {}
- item['id'] = self.id
- item['created_date'] = str(self.created_date)
- item['last_modified_date'] = str(self.last_modified_date)
- item['version'] = self.version
- item['name'] = self.name
- item['weblink'] = self.weblink
+ item: Dict[AnyStr, Any] = {
+ 'id': self.id,
+ 'created_date': str(self.created_date),
+ 'last_modified_date': str(self.last_modified_date),
+ 'version': self.version,
+ 'name': self.name,
+ 'weblink': self.weblink
+ }
return item
@@ -263,12 +274,13 @@ class WorkType(Base, BaseMixin):
self.name = import_data['name']
def export_dict(self) -> Dict[AnyStr, Any]:
- item: Dict[AnyStr, Any] = {}
- item['id'] = self.id
- item['created_date'] = str(self.created_date)
- item['last_modified_date'] = str(self.last_modified_date)
- item['version'] = self.version
- item['name'] = self.name
+ item: Dict[AnyStr, Any] = {
+ 'id': self.id,
+ 'created_date': str(self.created_date),
+ 'last_modified_date': str(self.last_modified_date),
+ 'version': self.version,
+ 'name': self.name
+ }
return item
@@ -291,12 +303,13 @@ class ComicWork(Base, BaseMixin):
self.work_type_id = import_data['work_type_id']
def export_dict(self) -> Dict[AnyStr, Any]:
- item: Dict[AnyStr, Any] = {}
- item['id'] = self.id
- item['created_date'] = str(self.created_date)
- item['last_modified_date'] = str(self.last_modified_date)
- item['version'] = self.version
- item['comic_id'] = self.comic_id
- item['artist_id'] = self.artist_id
- item['work_type_id'] = self.work_type_id
+ item: Dict[AnyStr, Any] = {
+ 'id': self.id,
+ 'created_date': str(self.created_date),
+ 'last_modified_date': str(self.last_modified_date),
+ 'version': self.version,
+ 'comic_id': self.comic_id,
+ 'artist_id': self.artist_id,
+ 'work_type_id': self.work_type_id
+ }
return item
diff --git a/kontor-spring/build.gradle b/kontor-spring/build.gradle
index 844fdc1..585e603 100644
--- a/kontor-spring/build.gradle
+++ b/kontor-spring/build.gradle
@@ -64,7 +64,8 @@ dependencies {
implementation 'com.h2database:h2'
implementation libs.hsqldb
implementation 'org.postgresql:postgresql'
- runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
+ //runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
+ implementation libs.hypersistence
implementation libs.mail
implementation libs.jackson
implementation libs.gson
diff --git a/kontor-spring/gradle/libs.versions.toml b/kontor-spring/gradle/libs.versions.toml
index 8f74e77..39ad0b9 100644
--- a/kontor-spring/gradle/libs.versions.toml
+++ b/kontor-spring/gradle/libs.versions.toml
@@ -24,6 +24,7 @@ gson = "2.9.0"
jackson = "2.16.1"
json_simple = "1.1.1"
mail = "1.6.2"
+hypersistence = "3.9.10"
[libraries]
args4j = { module = "args4j:args4j", version.ref = "args4j" }
@@ -40,6 +41,7 @@ jackson = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref
json = { module = "com.googlecode.json-simple:json-simple", version.ref ="json_simple" }
mail = { module = "com.sun.mail:javax.mail", version.ref ="mail" }
sqlite-jdbc = { module = "org.xerial:sqlite-jdbc", version.ref = "sqlite" }
+hypersistence = { module = "io.hypersistence:hypersistence-utils-hibernate-63", version.ref = "hypersistence" }
vaadin-bom = { module = "com.vaadin:vaadin-bom", version.ref = "vaadin" }
asciidoctorGradleJvmGems = { module = "org.asciidoctor:asciidoctor-gradle-jvm-gems", version.ref= "asciidoctor" }
asciidoctorGradleJvm = { module = "org.asciidoctor:asciidoctor-gradle-jvm", version.ref= "asciidoctor" }
diff --git a/kontor-spring/src/main/java/de/thpeetz/kontor/comics/data/Issue.java b/kontor-spring/src/main/java/de/thpeetz/kontor/comics/data/Issue.java
index 02392e2..cea9663 100644
--- a/kontor-spring/src/main/java/de/thpeetz/kontor/comics/data/Issue.java
+++ b/kontor-spring/src/main/java/de/thpeetz/kontor/comics/data/Issue.java
@@ -2,8 +2,10 @@ package de.thpeetz.kontor.comics.data;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import de.thpeetz.kontor.common.data.AbstractEntity;
-import io.micrometer.common.lang.Nullable;
+import de.thpeetz.kontor.common.data.*;
+import io.hypersistence.utils.hibernate.type.basic.YearMonthDateType;
+import jakarta.annotation.Nullable;
+import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
@@ -13,6 +15,9 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
+import org.hibernate.annotations.Type;
+
+import java.time.YearMonth;
@Getter
@Setter
@@ -42,6 +47,14 @@ public class Issue extends AbstractEntity {
@NotEmpty
private String issueNumber;
+ @Nullable
+ private String title;
+
+ @Nullable
+ @Type(YearMonthDateType.class)
+ @Column(name = "published_on", columnDefinition = "date")
+ private YearMonth publishedOn;
+
private Boolean isRead;
private Boolean inStock;
diff --git a/kontor-spring/src/main/java/de/thpeetz/kontor/comics/views/IssueForm.java b/kontor-spring/src/main/java/de/thpeetz/kontor/comics/views/IssueForm.java
index 5bb117f..a54d9ec 100644
--- a/kontor-spring/src/main/java/de/thpeetz/kontor/comics/views/IssueForm.java
+++ b/kontor-spring/src/main/java/de/thpeetz/kontor/comics/views/IssueForm.java
@@ -1,5 +1,7 @@
package de.thpeetz.kontor.comics.views;
+import java.time.*;
+import java.time.format.*;
import java.util.List;
import com.vaadin.flow.component.ComponentEvent;
@@ -9,12 +11,13 @@ import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.combobox.ComboBox;
+import com.vaadin.flow.component.datepicker.*;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;
-import com.vaadin.flow.data.binder.BeanValidationBinder;
-import com.vaadin.flow.data.binder.Binder;
+import com.vaadin.flow.data.binder.*;
+import com.vaadin.flow.data.converter.*;
import de.thpeetz.kontor.comics.data.*;
import lombok.extern.slf4j.Slf4j;
@@ -24,6 +27,8 @@ public class IssueForm extends FormLayout {
ComboBox comic = new ComboBox<>("Comic");
ComboBox volume = new ComboBox<>("Volume");
TextField issueNumber = new TextField("Issue number");
+ TextField title = new TextField("Full Title");
+ TextField publishedOn = new TextField("Published");
Checkbox isRead = new Checkbox("Read");
Checkbox inStock = new Checkbox("In stock");
@@ -35,11 +40,28 @@ public class IssueForm extends FormLayout {
public IssueForm(List comics) {
addClassName("issue-form");
+ binder.forField(publishedOn).withConverter(new Converter() {
+ @Override
+ public Result convertToModel(String value, ValueContext context) {
+ try {
+ YearMonth result = YearMonth.parse(value);
+ return Result.ok(result);
+ } catch (DateTimeParseException e) {
+ return Result.error("invalid year-month format");
+ }
+ }
+
+ @Override
+ public String convertToPresentation(YearMonth value, ValueContext context) {
+ if (value == null) return "";
+ return value.format(DateTimeFormatter.ofPattern("yyyy-MM"));
+ }
+ }).bind(Issue::getPublishedOn, Issue::setPublishedOn);
binder.bindInstanceFields(this);
comic.setItems(comics);
comic.setItemLabelGenerator(Comic::getTitle);
- add(comic, volume, issueNumber, isRead, inStock, createButtonsLayout());
+ add(comic, volume, issueNumber, title, publishedOn, isRead, inStock, createButtonsLayout());
}
private HorizontalLayout createButtonsLayout() {
diff --git a/kontor-spring/src/main/java/de/thpeetz/kontor/comics/views/IssueView.java b/kontor-spring/src/main/java/de/thpeetz/kontor/comics/views/IssueView.java
index 64d7634..1978c9d 100644
--- a/kontor-spring/src/main/java/de/thpeetz/kontor/comics/views/IssueView.java
+++ b/kontor-spring/src/main/java/de/thpeetz/kontor/comics/views/IssueView.java
@@ -53,6 +53,10 @@ public class IssueView extends VerticalLayout {
.setHeader("Volume").setResizable(true).setSortable(true);
Grid.Column issueNumberColumn = grid.addColumn(Issue::getIssueNumber)
.setHeader("Heft Nummer").setResizable(true).setSortable(true);
+ Grid.Column issueTitleColumn = grid.addColumn(Issue::getTitle)
+ .setHeader("Full Title").setResizable(true).setSortable(true);
+ Grid.Column publishedOncolumn = grid.addColumn(Issue::getPublishedOn)
+ .setHeader("Published").setResizable(true).setSortable(true);
Grid.Column isReadColumn = grid.addComponentColumn(issueColumn -> StatusIcon.create(issueColumn.getIsRead()))
.setHeader("Gelesen?").setWidth("6rem").setSortable(true);
Grid.Column inStockColumn = grid.addComponentColumn(issueColumn -> StatusIcon.create(issueColumn.getInStock()))
@@ -126,6 +130,8 @@ public class IssueView extends VerticalLayout {
columnToggleContextMenu.addColumnToggleItem(titleColumn);
columnToggleContextMenu.addColumnToggleItem(volumeColumn);
columnToggleContextMenu.addColumnToggleItem(issueNumberColumn);
+ columnToggleContextMenu.addColumnToggleItem(issueTitleColumn);
+ columnToggleContextMenu.addColumnToggleItem(publishedOncolumn);
columnToggleContextMenu.addColumnToggleItem(isReadColumn);
columnToggleContextMenu.addColumnToggleItem(inStockColumn);
HorizontalLayout toolbar = new HorizontalLayout(comicFilter, addIssueButton, menuButton);
diff --git a/kontor-spring/src/main/java/de/thpeetz/kontor/tysc/services/SportService.java b/kontor-spring/src/main/java/de/thpeetz/kontor/tysc/services/SportService.java
index 9536ec5..1fc7ff4 100644
--- a/kontor-spring/src/main/java/de/thpeetz/kontor/tysc/services/SportService.java
+++ b/kontor-spring/src/main/java/de/thpeetz/kontor/tysc/services/SportService.java
@@ -5,7 +5,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
-import de.thpeetz.kontor.admin.data.MetaDataTable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -177,7 +176,7 @@ public class SportService {
}
private String updateSportFields(Sport sport, Map fields) {
- String status = "";
+ StringBuilder status = new StringBuilder();
for (Map.Entry entry : fields.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
@@ -185,11 +184,11 @@ public class SportService {
case "id", "created_date", "last_modified_date", "version":
break;
case "table_name":
- status += sport.updateName(value);
+ status.append(sport.updateName(value));
default:
log.info("field {} is unknown for table {}", key, sport.getClass().getName());
}
}
- return status;
+ return status.toString();
}
}