11 Commits

Author SHA1 Message Date
Thomas Peetz 9476d8853e add MediaLofiView
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-24 12:55:05 +02:00
tpeetz 8cc58aed5b implement routes for MediaFile, MediaVideo and MediaLofi
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-08-23 21:31:49 +02:00
tpeetz ec274a60d9 add build an git info
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-23 00:48:18 +02:00
tpeetz 5b7c41c829 add Routes and Processors
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-22 02:04:48 +02:00
Thomas Peetz f73ec33aeb add CheckLinkProcessor
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 7s
2026-08-21 19:46:56 +02:00
Thomas Peetz cdde57e033 remove deploy.gradle and use deploy--kontor.sh
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-08-19 16:42:16 +02:00
tpeetz 9d07ed9bfb add script to deploy Kontor from Nexus
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-19 14:39:46 +00:00
Thomas Peetz 59e705d012 using Gradle to deploy Kontor
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-08-19 15:57:53 +02:00
Thomas Peetz 3b50a94928 add monitoring of Spring Boot Camel routes
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-08-19 13:51:32 +02:00
Thomas Peetz fd5bb14e77 add Container build file to package precompiled binary
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-08-18 17:11:10 +02:00
tpeetz a786607608 fix build problems
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
2026-08-16 23:01:14 +02:00
60 changed files with 1052 additions and 187 deletions
+12
View File
@@ -0,0 +1,12 @@
# Posted by barth, modified by community. See post 'Timeline' for change history
# Retrieved 2026-08-19, License - CC BY-SA 4.0
NEXUS_URL=https://nexus.thpeetz.de
MAVEN_REPO=maven-snapshots
GROUP_ID=de.thpeetz
ARTIFACT_ID=kontor-spring
VERSION=0.3.0-SNAPSHOT
FILE_EXTENSION=jar
download_url=$(curl -X GET "${NEXUS_URL}/service/rest/v1/search/assets?repository=${MAVEN_REPO}&maven.groupId=${GROUP_ID}&maven.artifactId=${ARTIFACT_ID}&maven.baseVersion=${VERSION}&maven.extension=${FILE_EXTENSION}" -H "accept: application/json" | jq -rc '.items | .[].downloadUrl' | sort | tail -n 1)
wget $download_url
+3 -1
View File
@@ -14,7 +14,9 @@ ENV PATH="/root/.local/bin:${PATH}"
WORKDIR /app WORKDIR /app
COPY ./pyproject.toml . COPY ./pyproject.toml .
RUN --mount=type=bind,source=/home/tpeetz/projects/kontor/kontor-model,target=/container/kontor-model uv add /container/kontor-model #RUN --mount=type=bind,source=/home/tpeetz/projects/kontor/kontor-model,target=/container/kontor-model uv add /container/kontor-model
#COPY ../kontor-model/ /container
RUN uv add /container/kontor-model
RUN uv sync RUN uv sync
# ------------------------------- Production Stage ------------------------------ ## # ------------------------------- Production Stage ------------------------------ ##
+2 -2
View File
@@ -15,7 +15,7 @@ parser.add_argument("--config", "-c", default="kontor-docker")
parser.add_argument("--verbose", "-v", action="count", default=0) parser.add_argument("--verbose", "-v", action="count", default=0)
parser.add_argument("--server", "-s", default="127.0.0.1") parser.add_argument("--server", "-s", default="127.0.0.1")
parser.add_argument("--port", "-p", default="61616") parser.add_argument("--port", "-p", default="61616")
parser.add_argument("--destination", "-d", default="media.link.add") parser.add_argument("--destination", "-d", default="media.link")
args = parser.parse_args() args = parser.parse_args()
@@ -33,6 +33,6 @@ if __name__ == "__main__":
link: Link = Link(url=args.url) link: Link = Link(url=args.url)
json_bytes = msgspec.json.encode(link) json_bytes = msgspec.json.encode(link)
conn.send(body=json_bytes, destination=args.destination) conn.send(body=json_bytes.decode(), destination=args.destination)
logger.info("kontor.add_link finished") logger.info("kontor.add_link finished")
+9
View File
@@ -0,0 +1,9 @@
FROM docker.io/alpine/java:21-jdk AS run
RUN mkdir -p /logs
COPY ./build/libs/kontor-spring-0.3.0-SNAPSHOT.jar app.jar
EXPOSE 8100
CMD ["java", "-jar", "-Dspring.profiles.active=prod", "-Dvaadin.productionMode=true", "app.jar"]
+14 -31
View File
@@ -1,25 +1,8 @@
buildscript {
configurations.classpath {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'com.burgstaller' && details.requested.name == 'okhttp-digest' && details.requested.version == '1.10') {
details.useTarget "io.github.rburgst:${details.requested.name}:1.21"
details.because 'Dependency has moved'
}
}
}
repositories {
mavenCentral()
maven { setUrl("https://nexus.thpeetz.de/repository/maven-central") }
maven { setUrl("https://maven.vaadin.com/vaadin-prereleases") }
maven { setUrl("https://repo.spring.io/milestone") }
}
}
plugins { plugins {
id 'java' id 'java'
id 'application' id 'application'
id 'maven-publish' id 'maven-publish'
id "com.google.cloud.artifactregistry.gradle-plugin" version "2.2.0" //id "com.google.cloud.artifactregistry.gradle-plugin" version "2.2.0"
id 'jvm-test-suite' id 'jvm-test-suite'
id 'jacoco' id 'jacoco'
id 'test-report-aggregation' id 'test-report-aggregation'
@@ -28,23 +11,21 @@ plugins {
alias(libs.plugins.spring.dependencies) alias(libs.plugins.spring.dependencies)
alias(libs.plugins.vaadin) alias(libs.plugins.vaadin)
alias(libs.plugins.lombok) alias(libs.plugins.lombok)
//alias(libs.plugins.asciidoctorPdf) //id 'com.github.ksoichiro.build.info' version '0.2.0'
//alias(libs.plugins.asciidoctorConvert) //id 'com.pasam.gradle.buildinfo' version '0.1.3'
//alias(libs.plugins.asciidoctorGems) id 'com.gorylenko.gradle-git-properties' version '4.0.1'
//id "de.infolektuell.typst" version "0.8.0"
} }
repositories { repositories {
maven { setUrl("https://nexus.thpeetz.de/repository/maven-central") } maven { setUrl("https://nexus.thpeetz.de/repository/maven-central") }
mavenCentral() mavenCentral()
//ruby.gems()
maven { setUrl("https://maven.vaadin.com/vaadin-prereleases") } maven { setUrl("https://maven.vaadin.com/vaadin-prereleases") }
maven { setUrl("https://repo.spring.io/milestone") } maven { setUrl("https://repo.spring.io/milestone") }
maven { setUrl("https://maven.vaadin.com/vaadin-addons") } maven { setUrl("https://maven.vaadin.com/vaadin-addons") }
} }
java { java {
sourceCompatibility = JavaVersion.VERSION_21 sourceCompatibility = JavaVersion.VERSION_17
} }
configurations { configurations {
@@ -63,11 +44,15 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.apache.camel.springboot:camel-spring-boot-starter' implementation 'org.apache.camel.springboot:camel-spring-boot-starter'
implementation 'org.apache.camel.springboot:camel-jms-starter' implementation 'org.apache.camel.springboot:camel-jms-starter'
implementation 'org.apache.camel.springboot:camel-metrics-starter'
implementation 'org.apache.camel.springboot:camel-micrometer-starter'
implementation 'org.apache.activemq:artemis-jakarta-client' implementation 'org.apache.activemq:artemis-jakarta-client'
//implementation libs.artemis //implementation libs.artemis
implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-actuator'
developmentOnly 'org.springframework.boot:spring-boot-devtools' developmentOnly 'org.springframework.boot:spring-boot-devtools'
implementation 'io.micrometer:micrometer-registry-prometheus' implementation 'io.micrometer:micrometer-registry-prometheus'
implementation libs.jolokia.core
implementation libs.prometheus.collector
implementation 'org.springframework.security:spring-security-oauth2-jose' implementation 'org.springframework.security:spring-security-oauth2-jose'
implementation 'org.springframework.security:spring-security-oauth2-resource-server' implementation 'org.springframework.security:spring-security-oauth2-resource-server'
implementation 'com.h2database:h2' implementation 'com.h2database:h2'
@@ -79,6 +64,7 @@ dependencies {
implementation libs.jackson implementation libs.jackson
implementation libs.gson implementation libs.gson
implementation libs.json implementation libs.json
implementation libs.jsoup
implementation 'org.hibernate.orm:hibernate-community-dialects' implementation 'org.hibernate.orm:hibernate-community-dialects'
testImplementation('org.springframework.boot:spring-boot-starter-test') { testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
@@ -90,8 +76,6 @@ dependencies {
testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
compileOnly 'org.projectlombok:lombok' compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok'
//asciidoctorGems libs.rouge
//asciidoctorGems libs.diagram
} }
dependencyManagement { dependencyManagement {
@@ -117,11 +101,6 @@ publishing {
password = project.findProperty('nexusPassword') password = project.findProperty('nexusPassword')
} }
} }
// maven {
// name = "gitlabPackageRegistry"
// url = uri("https://gitlab.com/api/v4/projects/64726715/packages/maven")
// credentials(PasswordCredentials)
// }
} }
} }
@@ -133,6 +112,10 @@ bootRun {
args = ["--spring.profiles.active=${project.properties['profile'] ?: 'prod'}"] args = ["--spring.profiles.active=${project.properties['profile'] ?: 'prod'}"]
} }
springBoot {
buildInfo()
}
task dockerImage(type: Exec) { task dockerImage(type: Exec) {
dependsOn(bootJar) dependsOn(bootJar)
commandLine "docker", "build", ".", "-t", "kontor:${project.version}" commandLine "docker", "build", ".", "-t", "kontor:${project.version}"
+8 -19
View File
@@ -3,19 +3,14 @@ gradle = "8.6"
args4j = "2.33" args4j = "2.33"
commonscli = "1.5.0" commonscli = "1.5.0"
junit = "5.8.2" junit = "5.8.2"
logback = "1.1.2" logback = "1.6.3"
mockito = "1.9.5" mockito = "1.9.5"
picoli = "4.7.0" picoli = "4.7.0"
slf4j = "1.7.22" slf4j = "2.0.18"
hsqldb = "2.7.1" hsqldb = "2.7.1"
sqlite = "3.25.2" sqlite = "3.25.2"
spotbugs = "6.0.7" spotbugs = "6.0.7"
#asciidoctor = "4.0.2"
#rouge = "3.15.0"
#diagram = "2.2.2"
#diagram = "2.3.1"
sonarqube = "3.3" sonarqube = "3.3"
cimtConventions = "1.0.0-SNAPSHOT"
springboot = "3.2.5" springboot = "3.2.5"
springdependencies = "1.1.4" springdependencies = "1.1.4"
vaadin = "24.4.23" vaadin = "24.4.23"
@@ -25,8 +20,11 @@ lombok = "8.11"
gson = "2.9.0" gson = "2.9.0"
jackson = "2.16.1" jackson = "2.16.1"
json_simple = "1.1.1" json_simple = "1.1.1"
jsoup = "1.23.1"
mail = "1.6.2" mail = "1.6.2"
hypersistence = "3.9.10" hypersistence = "3.9.10"
jolokia = "2.6.1"
prometheus = "1.6.0"
[libraries] [libraries]
args4j = { module = "args4j:args4j", version.ref = "args4j" } args4j = { module = "args4j:args4j", version.ref = "args4j" }
@@ -39,6 +37,7 @@ picocli = { module = "info.picocli:picocli", version.ref = "picoli" }
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
hsqldb = { module = "org.hsqldb:hsqldb", version.ref = "hsqldb" } hsqldb = { module = "org.hsqldb:hsqldb", version.ref = "hsqldb" }
gson = { module = "com.google.code.gson:gson", version.ref = "gson" } gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
jackson = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" } jackson = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
json = { module = "com.googlecode.json-simple:json-simple", version.ref ="json_simple" } json = { module = "com.googlecode.json-simple:json-simple", version.ref ="json_simple" }
mail = { module = "com.sun.mail:javax.mail", version.ref ="mail" } mail = { module = "com.sun.mail:javax.mail", version.ref ="mail" }
@@ -47,11 +46,8 @@ hypersistence = { module = "io.hypersistence:hypersistence-utils-hibernate-63",
vaadin-bom = { module = "com.vaadin:vaadin-bom", version.ref = "vaadin" } vaadin-bom = { module = "com.vaadin:vaadin-bom", version.ref = "vaadin" }
camel-bom = { module = "org.apache.camel.springboot:camel-spring-boot-bom", version.ref = "camel"} camel-bom = { module = "org.apache.camel.springboot:camel-spring-boot-bom", version.ref = "camel"}
artemis = { module = "org.apache.activemq:artemis-jms-server", version.ref = "artemis" } artemis = { module = "org.apache.activemq:artemis-jms-server", version.ref = "artemis" }
#asciidoctorGradleJvmGems = { module = "org.asciidoctor:asciidoctor-gradle-jvm-gems", version.ref= "asciidoctor" } jolokia-core = { module = "org.jolokia:jolokia-core", version.ref = "jolokia" }
#asciidoctorGradleJvm = { module = "org.asciidoctor:asciidoctor-gradle-jvm", version.ref= "asciidoctor" } prometheus-collector = { module = "io.prometheus.jmx:collector", version.ref = "prometheus" }
#asciidoctorGradleJvmPdf = { module = "org.asciidoctor:asciidoctor-gradle-jvm-pdf", version.ref= "asciidoctor" }
#rouge = { module = "rubygems:rouge", version.ref = "rouge" }
#diagram = { module = "rubygems:asciidoctor-diagram", version.ref = "diagram" }
[bundles] [bundles]
logback = ["logbackCore", "logbackClassic"] logback = ["logbackCore", "logbackClassic"]
@@ -59,13 +55,6 @@ logback = ["logbackCore", "logbackClassic"]
[plugins] [plugins]
spotbugs = { id = "com.github.spotbugs", version.ref = "spotbugs" } spotbugs = { id = "com.github.spotbugs", version.ref = "spotbugs" }
sonarqube = { id = "org.sonarqube", version.ref = "sonarqube" } sonarqube = { id = "org.sonarqube", version.ref = "sonarqube" }
#asciidoctorPdf = { id = "org.asciidoctor.jvm.pdf", version.ref = "asciidoctor" }
#asciidoctorConvert = { id = "org.asciidoctor.jvm.convert", version.ref = "asciidoctor" }
#asciidoctorGems = { id = "org.asciidoctor.jvm.gems", version.ref = "asciidoctor" }
javaConvention = { id = "de.cimt.java-conventions", version.ref = "cimtConventions" }
applicationConvention = { id = "de.cimt.application-conventions", version.ref = "cimtConventions" }
libraryConvention = { id = "de.cimt.library-conventions", version.ref = "cimtConventions" }
#asciidoctorConvention = { id = "de.cimt.asciidoctor-conventions", version.ref = "cimtConventions" }
spring-boot = { id = "org.springframework.boot", version.ref = "springboot"} spring-boot = { id = "org.springframework.boot", version.ref = "springboot"}
spring-dependencies = { id = "io.spring.dependency-management", version.ref = "springdependencies" } spring-dependencies = { id = "io.spring.dependency-management", version.ref = "springdependencies" }
vaadin = { id = "com.vaadin", version.ref = "vaadin" } vaadin = { id = "com.vaadin", version.ref = "vaadin" }
@@ -14,8 +14,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import de.thpeetz.kontor.data.tysc.CardSet; import de.thpeetz.kontor.data.tysc.CardSet;
import de.thpeetz.kontor.views.tysc.CardSetForm;
import de.thpeetz.kontor.views.tysc.CardSetView;
@SpringBootTest @SpringBootTest
class CardSetViewTest { class CardSetViewTest {
@@ -14,8 +14,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import de.thpeetz.kontor.data.tysc.Card; import de.thpeetz.kontor.data.tysc.Card;
import de.thpeetz.kontor.views.tysc.CardForm;
import de.thpeetz.kontor.views.tysc.CardView;
@SpringBootTest @SpringBootTest
class CardViewTest { class CardViewTest {
@@ -14,8 +14,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import de.thpeetz.kontor.data.tysc.FieldPosition; import de.thpeetz.kontor.data.tysc.FieldPosition;
import de.thpeetz.kontor.views.tysc.PositionForm;
import de.thpeetz.kontor.views.tysc.PositionView;
@SpringBootTest @SpringBootTest
class FieldPositionViewTest { class FieldPositionViewTest {
@@ -14,8 +14,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import de.thpeetz.kontor.data.tysc.Player; import de.thpeetz.kontor.data.tysc.Player;
import de.thpeetz.kontor.views.tysc.PlayerForm;
import de.thpeetz.kontor.views.tysc.PlayerView;
@SpringBootTest @SpringBootTest
class PlayerViewTest { class PlayerViewTest {
@@ -14,8 +14,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import de.thpeetz.kontor.data.tysc.Rooster; import de.thpeetz.kontor.data.tysc.Rooster;
import de.thpeetz.kontor.views.tysc.RoosterForm;
import de.thpeetz.kontor.views.tysc.RoosterView;
@SpringBootTest @SpringBootTest
class RoosterViewTest { class RoosterViewTest {
@@ -14,8 +14,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import de.thpeetz.kontor.data.tysc.Sport; import de.thpeetz.kontor.data.tysc.Sport;
import de.thpeetz.kontor.views.tysc.SportForm;
import de.thpeetz.kontor.views.tysc.SportView;
@SpringBootTest @SpringBootTest
class SportViewTest { class SportViewTest {
@@ -14,8 +14,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import de.thpeetz.kontor.data.tysc.Team; import de.thpeetz.kontor.data.tysc.Team;
import de.thpeetz.kontor.views.tysc.TeamForm;
import de.thpeetz.kontor.views.tysc.TeamView;
@SpringBootTest @SpringBootTest
class TeamViewTest { class TeamViewTest {
@@ -14,8 +14,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import de.thpeetz.kontor.data.tysc.Vendor; import de.thpeetz.kontor.data.tysc.Vendor;
import de.thpeetz.kontor.views.tysc.VendorForm;
import de.thpeetz.kontor.views.tysc.VendorView;
@SpringBootTest @SpringBootTest
class VendorViewTest { class VendorViewTest {
@@ -1,15 +1,28 @@
package de.thpeetz.kontor; package de.thpeetz.kontor;
import org.apache.camel.CamelContext;
import org.apache.camel.component.micrometer.MicrometerConstants;
import org.apache.camel.component.micrometer.messagehistory.MicrometerMessageHistoryFactory;
import org.apache.camel.component.micrometer.routepolicy.MicrometerRoutePolicyFactory;
import org.apache.camel.spring.boot.CamelContextConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.vaadin.flow.component.page.AppShellConfigurator; import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.server.PWA; import com.vaadin.flow.server.PWA;
import com.vaadin.flow.theme.Theme; import com.vaadin.flow.theme.Theme;
import io.micrometer.core.instrument.Clock;
import io.micrometer.prometheus.PrometheusConfig;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import io.prometheus.client.CollectorRegistry;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@Slf4j @Slf4j
@EnableJpaAuditing @EnableJpaAuditing
@SpringBootApplication @SpringBootApplication
@@ -17,6 +30,27 @@ import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@PWA(name = "Vaadin Kontor", shortName = "Kontor", offlinePath = "offline.html", offlineResources = { "images/offline.png" }) @PWA(name = "Vaadin Kontor", shortName = "Kontor", offlinePath = "offline.html", offlineResources = { "images/offline.png" })
public class Application implements AppShellConfigurator { public class Application implements AppShellConfigurator {
@Bean(name = { MicrometerConstants.METRICS_REGISTRY_NAME, "prometheusMeterRegistry" })
public PrometheusMeterRegistry prometheusMeterRegistry(
PrometheusConfig prometheusConfig, CollectorRegistry collectorRegistry, Clock clock) {
return new PrometheusMeterRegistry(prometheusConfig, collectorRegistry, clock);
}
@Bean
public CamelContextConfiguration camelContextConfiguration(@Autowired PrometheusMeterRegistry registry) {
return new CamelContextConfiguration() {
@Override
public void beforeApplicationStart(CamelContext camelContext) {
camelContext.addRoutePolicyFactory(new MicrometerRoutePolicyFactory());
camelContext.setMessageHistoryFactory(new MicrometerMessageHistoryFactory());
}
@Override
public void afterApplicationStart(CamelContext camelContext) {
}
};
}
public static void main(String[] args) { public static void main(String[] args) {
log.info("Starting Kontor application"); log.info("Starting Kontor application");
SpringApplication.run(Application.class); SpringApplication.run(Application.class);
@@ -6,6 +6,7 @@ import com.vaadin.flow.component.sidenav.SideNavItem;
import de.thpeetz.kontor.views.media.MediaActorView; import de.thpeetz.kontor.views.media.MediaActorView;
import de.thpeetz.kontor.views.media.MediaArticleView; import de.thpeetz.kontor.views.media.MediaArticleView;
import de.thpeetz.kontor.views.media.MediaFileView; import de.thpeetz.kontor.views.media.MediaFileView;
import de.thpeetz.kontor.views.media.MediaLofiView;
import de.thpeetz.kontor.views.media.MediaVideoView; import de.thpeetz.kontor.views.media.MediaVideoView;
import java.util.ArrayList; import java.util.ArrayList;
@@ -15,6 +16,7 @@ public class MediaConstants {
public static final String MEDIA = "Media"; public static final String MEDIA = "Media";
public static final String MEDIAFILE_ROUTE = "media/mediafile"; public static final String MEDIAFILE_ROUTE = "media/mediafile";
public static final String MEDIAVIDEO_ROUTE = "media/mediavideo"; public static final String MEDIAVIDEO_ROUTE = "media/mediavideo";
public static final String MEDIALOFI_ROUTE = "media/medialofi";
public static final String MEDIAARTICLE_ROUTE = "media/mediaarticle"; public static final String MEDIAARTICLE_ROUTE = "media/mediaarticle";
public static final String MEDIA_ROLE = "ROLE_MEDIA"; public static final String MEDIA_ROLE = "ROLE_MEDIA";
public static final String MEDIAACTOR_ROUTE = "media/mediaactor"; public static final String MEDIAACTOR_ROUTE = "media/mediaactor";
@@ -22,12 +24,20 @@ public class MediaConstants {
public static final String MEDIAACTORFILE = "Media Actor Files"; public static final String MEDIAACTORFILE = "Media Actor Files";
private static final String MEDIAFILE = "Media Files"; private static final String MEDIAFILE = "Media Files";
private static final String MEDIAVIDEO = "Media Videos"; private static final String MEDIAVIDEO = "Media Videos";
private static final String MEDIALOFI = "Media Lofi";
private static final String MEDIAARTICLE = "Media Article"; private static final String MEDIAARTICLE = "Media Article";
private static final String MEDIAACTOR = "Media Actor"; private static final String MEDIAACTOR = "Media Actor";
public static final String URL = "url";
public static final String LINKTITLE = "linkTitle";
public static final String LOFI_ID = "lofi_id";
public static final String FILE_ID = "file_id";
public static final String VIDEO_ID = "video_id";
public static SideNavItem getMediaNavigation(ArrayList<String> roles) { public static SideNavItem getMediaNavigation(ArrayList<String> roles) {
SideNavItem media = new SideNavItem(MEDIA, MEDIAFILE_ROUTE, VaadinIcon.VIMEO.create()); SideNavItem media = new SideNavItem(MEDIA, MEDIAFILE_ROUTE, VaadinIcon.VIMEO.create());
media.addItem(new SideNavItem(MEDIAVIDEO, MediaVideoView.class)); media.addItem(new SideNavItem(MEDIAVIDEO, MediaVideoView.class));
media.addItem(new SideNavItem(MEDIALOFI, MediaLofiView.class));
media.addItem(new SideNavItem(MEDIAARTICLE, MediaArticleView.class)); media.addItem(new SideNavItem(MEDIAARTICLE, MediaArticleView.class));
if (roles.contains(MEDIA_ROLE)) { if (roles.contains(MEDIA_ROLE)) {
media.addItem(new SideNavItem(MEDIAFILE, MediaFileView.class)); media.addItem(new SideNavItem(MEDIAFILE, MediaFileView.class));
@@ -1,6 +1,5 @@
package de.thpeetz.kontor.data.common; package de.thpeetz.kontor.data.common;
import jakarta.persistence.*;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@@ -9,6 +8,13 @@ import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener; import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.Version;
import java.util.Date; import java.util.Date;
@Slf4j @Slf4j
@@ -27,6 +27,7 @@ public class MediaFile extends AbstractEntity {
private boolean shouldDownload; private boolean shouldDownload;
@Nullable @Nullable
@Column(length = 300)
private String title; private String title;
@Nullable @Nullable
@@ -0,0 +1,32 @@
package de.thpeetz.kontor.data.media;
import de.thpeetz.kontor.data.common.AbstractEntity;
import jakarta.annotation.Nullable;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Getter
@Setter
@EqualsAndHashCode(callSuper = false)
@Entity
@Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "url" }) })
public class MediaLofi extends AbstractEntity {
private String url;
private boolean review;
private boolean shouldDownload;
@Nullable
private String title;
@Nullable
private String fileName;
}
@@ -0,0 +1,39 @@
package de.thpeetz.kontor.integration.routes;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import de.thpeetz.kontor.constants.MediaConstants;
import de.thpeetz.kontor.integration.services.CheckLinkProcessor;
import de.thpeetz.kontor.services.MediaFileService;
@Component
public class QueueMediaLink extends RouteBuilder {
@Autowired
private final MediaFileService mediaFileService;
@Autowired
public QueueMediaLink(MediaFileService mediaFileService) {
this.mediaFileService = mediaFileService;
}
@Override
public void configure() throws Exception {
from("jms:queue:media.link")
.errorHandler(deadLetterChannel("jms:queue:DLQ")
.maximumRedeliveries(0)
.useOriginalMessage()
.onPrepareFailure(exchange -> {
exchange.getIn().setHeader("FailureReason", "processing failed");
}))
.routeId("media.link")
.log("${body}")
.trace(true)
.process(new CheckLinkProcessor(mediaFileService))
.choice()
.when(header(MediaConstants.FILE_ID).isNotNull()).to("jms:queue:media.link.duplicate")
.otherwise().to("jms:queue:media.link.add");
}
}
@@ -1,9 +1,11 @@
package de.thpeetz.kontor.integration.routes; package de.thpeetz.kontor.integration.routes;
import org.apache.camel.builder.RouteBuilder; import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import de.thpeetz.kontor.integration.services.AddLinkProcessor; import de.thpeetz.kontor.integration.services.AddLinkProcessor;
import de.thpeetz.kontor.integration.services.UrlTitleProcessor;
import de.thpeetz.kontor.services.MediaFileService; import de.thpeetz.kontor.services.MediaFileService;
@Component @Component
@@ -20,11 +22,11 @@ public class QueueMediaLinkAdd extends RouteBuilder {
@Override @Override
public void configure() throws Exception { public void configure() throws Exception {
from("jms:queue:media.link.add") from("jms:queue:media.link.add")
.routeId("read-queue-media-link-add") .routeId("media.link.add")
.log("${body}") .log("${body}")
.trace(true) .trace(true)
.process(new UrlTitleProcessor())
.process(new AddLinkProcessor(mediaFileService)) .process(new AddLinkProcessor(mediaFileService))
.to("jms:queue:media.link.update_title")
.to("jms:queue:media.link.add.processed"); .to("jms:queue:media.link.add.processed");
} }
} }
@@ -0,0 +1,40 @@
package de.thpeetz.kontor.integration.routes;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import de.thpeetz.kontor.constants.MediaConstants;
import de.thpeetz.kontor.integration.services.CheckLoFiProcessor;
import de.thpeetz.kontor.services.MediaLofiService;
@Component
public class QueueMediaLoFi extends RouteBuilder {
@Autowired
private final MediaLofiService mediaLofiService;
@Autowired
public QueueMediaLoFi(MediaLofiService mediaLofiService) {
this.mediaLofiService = mediaLofiService;
}
@Override
public void configure() throws Exception {
from("jms:queue:media.lofi")
.errorHandler(deadLetterChannel("jms:queue:DLQ")
.maximumRedeliveries(0)
.useOriginalMessage()
.onPrepareFailure(exchange -> {
exchange.getIn().setHeader("FailureReason", "processing failed");
}))
.routeId("media.lofi")
.log("${body}")
.trace(true)
.process(new CheckLoFiProcessor(mediaLofiService))
.to("jms:queue:media.lofi.processed")
.choice()
.when(header(MediaConstants.LOFI_ID).isNotNull()).to("jms:queue:media.lofi.duplicate")
.otherwise().to("jms:queue:media.lofi.add");
}
}
@@ -4,24 +4,28 @@ import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import de.thpeetz.kontor.services.MediaFileService; import de.thpeetz.kontor.integration.services.AddLofiProcessor;
import de.thpeetz.kontor.integration.services.UrlTitleProcessor;
import de.thpeetz.kontor.services.MediaLofiService;
@Component @Component
public class QueueMediaLoFiAdd extends RouteBuilder { public class QueueMediaLoFiAdd extends RouteBuilder {
@Autowired @Autowired
private final MediaFileService mediaFileService; private final MediaLofiService mediaLofiService;
@Autowired @Autowired
public QueueMediaLoFiAdd(MediaFileService mediaFileService) { public QueueMediaLoFiAdd(MediaLofiService mediaLofiService) {
this.mediaFileService = mediaFileService; this.mediaLofiService = mediaLofiService;
} }
@Override @Override
public void configure() throws Exception { public void configure() throws Exception {
from("jms:queue:media.lofi.add") from("jms:queue:media.lofi.add")
.routeId("read-queue-media-lofi-add") .routeId("media.lofi.add")
.log("${body}") .log("${body}")
.process(new UrlTitleProcessor())
.process(new AddLofiProcessor(mediaLofiService))
.to("jms:queue:media.lofi.add.processed"); .to("jms:queue:media.lofi.add.processed");
} }
} }
@@ -0,0 +1,39 @@
package de.thpeetz.kontor.integration.routes;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import de.thpeetz.kontor.constants.MediaConstants;
import de.thpeetz.kontor.integration.services.CheckVideoProcessor;
import de.thpeetz.kontor.services.MediaVideoService;
@Component
public class QueueMediaVideo extends RouteBuilder {
@Autowired
private final MediaVideoService mediaVideoService;
@Autowired
public QueueMediaVideo(MediaVideoService mediaVideoService) {
this.mediaVideoService = mediaVideoService;
}
@Override
public void configure() throws Exception {
from("jms:queue:media.video")
.errorHandler(deadLetterChannel("jms:queue:DLQ")
.maximumRedeliveries(0)
.useOriginalMessage()
.onPrepareFailure(exchange -> {
exchange.getIn().setHeader("FailureReason", "processing failed");
}))
.routeId("media.video")
.log("${body}")
.trace(true)
.process(new CheckVideoProcessor(mediaVideoService))
.choice()
.when(header(MediaConstants.VIDEO_ID).isNotNull()).to("jms:queue:media.video.duplicate")
.otherwise().to("jms:queue:media.video.add");
}
}
@@ -4,24 +4,30 @@ import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import de.thpeetz.kontor.services.MediaFileService; import de.thpeetz.kontor.integration.services.AddVideoProcessor;
import de.thpeetz.kontor.integration.services.UrlTitleProcessor;
import de.thpeetz.kontor.services.MediaVideoService;
@Component @Component
public class QueueMediaVideoAdd extends RouteBuilder { public class QueueMediaVideoAdd extends RouteBuilder {
@SuppressWarnings("unused")
@Autowired @Autowired
private final MediaFileService mediaFileService; private final MediaVideoService mediaVideoService;
@Autowired @Autowired
public QueueMediaVideoAdd(MediaFileService mediaFileService) { public QueueMediaVideoAdd(MediaVideoService mediaVideoService) {
this.mediaFileService = mediaFileService; this.mediaVideoService = mediaVideoService;
} }
@Override @Override
public void configure() throws Exception { public void configure() throws Exception {
from("jms:queue:media.video.add") from("jms:queue:media.video.add")
.routeId("read-queue-media-video-add") .routeId("media.video.add")
.log("${body}") .log("${body}")
.trace(true)
.process(new UrlTitleProcessor())
.process(new AddVideoProcessor(mediaVideoService))
.to("jms:queue:media.video.add.processed"); .to("jms:queue:media.video.add.processed");
} }
} }
@@ -1,16 +1,14 @@
package de.thpeetz.kontor.integration.services; package de.thpeetz.kontor.integration.services;
import com.fasterxml.jackson.core.type.TypeReference; import de.thpeetz.kontor.constants.MediaConstants;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.thpeetz.kontor.data.media.MediaFile; import de.thpeetz.kontor.data.media.MediaFile;
import de.thpeetz.kontor.services.MediaFileService; import de.thpeetz.kontor.services.MediaFileService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.camel.Exchange; import org.apache.camel.Exchange;
import org.apache.camel.Processor; import org.apache.camel.Processor;
import org.json.simple.JSONObject;
import java.util.HashMap; import org.json.simple.parser.JSONParser;
import java.util.Map; import org.json.simple.parser.ParseException;
@Slf4j @Slf4j
public class AddLinkProcessor implements Processor { public class AddLinkProcessor implements Processor {
@@ -23,32 +21,33 @@ public class AddLinkProcessor implements Processor {
@Override @Override
public void process(Exchange exchange) throws Exception { public void process(Exchange exchange) throws Exception {
ObjectMapper objectMapper = new ObjectMapper(); String messageBody = exchange.getIn().getBody(String.class);
HashMap<String, String> myMap = objectMapper.readValue(exchange.getIn().getBody().toString(), log.info("MediaFile URL to add: {}", messageBody);
new TypeReference<HashMap<String, String>>() { String title = exchange.getIn().getHeader(MediaConstants.LINKTITLE).toString();
});
String url = myMap.get("url"); JSONParser parser = new JSONParser();
log.info("found url: {}", url); try {
MediaFile mediaFile = mediaFileService.findAllMediaFilesByUrl(url); JSONObject jsonObject = (JSONObject) parser.parse(messageBody);
if (mediaFile == null) { String url = (String) jsonObject.get(MediaConstants.URL);
log.info("URL not found, create MediaFile"); MediaFile mediaFile = new MediaFile();
mediaFile = new MediaFile();
mediaFile.setUrl(url); mediaFile.setUrl(url);
mediaFile.setPath(""); mediaFile.setPath("");
mediaFile.setCloudLink(""); mediaFile.setCloudLink("");
mediaFile.setFileName(""); mediaFile.setFileName("");
mediaFile.setTitle(""); mediaFile.setTitle(title);
mediaFile.setReview(true); mediaFile.setReview(true);
mediaFile.setShouldDownload(true); mediaFile.setShouldDownload(true);
MediaFile mediaFileResult = mediaFileService.saveMediaFile(mediaFile); MediaFile mediaFileResult = mediaFileService.saveMediaFile(mediaFile);
log.info("created MediaFile with {}", mediaFileResult.getId()); if (mediaFileResult != null) {
exchange.getMessage().getHeaders().put("mediafile_id", mediaFileResult.getId()); log.info("MediaFile saved: {}", mediaFileResult.toString());
exchange.getIn().setHeader(MediaConstants.FILE_ID, mediaFileResult.getId());
} else { } else {
log.info("found MediaFile with {}", mediaFile.getId()); log.info("MediaFile could not saved: {}", url);
exchange.getMessage().getHeaders().put("mediafile_id", mediaFile.getId()); exchange.getIn().setHeader(MediaConstants.FILE_ID, null);
}
} catch (ParseException pe) {
log.info("parse exception: {}", pe.toString());
exchange.getIn().setHeader(MediaConstants.FILE_ID, null);
} }
log.info("found MediaFile: {}", mediaFile);
Map<String, Object> map = exchange.getMessage().getHeaders();
log.info("Headers: {}", map);
} }
} }
@@ -1,22 +0,0 @@
package de.thpeetz.kontor.integration.services;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashMap;
@Service
@Slf4j
public class AddLinkService {
public void fromQueue(String messageBody) throws JsonProcessingException {
log.info("get body: {}", messageBody);
ObjectMapper objectMapper = new ObjectMapper();
HashMap<String,String> myMap = objectMapper.readValue(messageBody, new TypeReference<HashMap<String,String>>() {});
String url = myMap.get("url");
log.info("found url: {}", url);
}
}
@@ -0,0 +1,52 @@
package de.thpeetz.kontor.integration.services;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import de.thpeetz.kontor.constants.MediaConstants;
import de.thpeetz.kontor.data.media.MediaLofi;
import de.thpeetz.kontor.services.MediaLofiService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class AddLofiProcessor implements Processor {
private MediaLofiService mediaLofiService;
public AddLofiProcessor(MediaLofiService medialLofiService) {
this.mediaLofiService = medialLofiService;
}
@Override
public void process(Exchange exchange) throws Exception {
String messageBody = exchange.getIn().getBody(String.class);
log.info("LoFi URL to add: {}", messageBody);
String title = exchange.getIn().getHeader(MediaConstants.LINKTITLE).toString();
JSONParser parser = new JSONParser();
try {
JSONObject jsonObject = (JSONObject) parser.parse(messageBody);
String url = (String) jsonObject.get(MediaConstants.URL);
MediaLofi mediaLofi = new MediaLofi();
mediaLofi.setUrl(url);
mediaLofi.setTitle(title);
mediaLofi.setFileName("");
mediaLofi.setReview(false);
mediaLofi.setShouldDownload(false);
mediaLofi = this.mediaLofiService.saveMediaLofi(mediaLofi);
if (mediaLofi != null) {
log.info("MediaLofi saved: {}", mediaLofi.toString());
exchange.getIn().setHeader(MediaConstants.LOFI_ID, mediaLofi.getId());
} else {
log.info("MediaLofi could not saved: {}", url);
exchange.getIn().setHeader(MediaConstants.LOFI_ID, null);
}
} catch (ParseException pe) {
log.info("parse exception: {}", pe.toString());
exchange.getIn().setHeader(MediaConstants.LOFI_ID, null);
}
}
}
@@ -0,0 +1,54 @@
package de.thpeetz.kontor.integration.services;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import de.thpeetz.kontor.constants.MediaConstants;
import de.thpeetz.kontor.data.media.MediaVideo;
import de.thpeetz.kontor.services.MediaVideoService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class AddVideoProcessor implements Processor {
private final MediaVideoService mediaVideoService;
public AddVideoProcessor(MediaVideoService mediaVideoService) {
this.mediaVideoService = mediaVideoService;
}
@Override
public void process(Exchange exchange) throws Exception {
String messageBody = exchange.getIn().getBody(String.class);
log.info("MediaVideo URL to add: {}", messageBody);
String title = exchange.getIn().getHeader(MediaConstants.LINKTITLE).toString();
JSONParser parser = new JSONParser();
try {
JSONObject jsonObject = (JSONObject) parser.parse(messageBody);
String url = (String) jsonObject.get(MediaConstants.URL);
MediaVideo mediaVideo = new MediaVideo();
mediaVideo.setUrl(url);
mediaVideo.setPath("");
mediaVideo.setCloudLink("");
mediaVideo.setFileName("");
mediaVideo.setTitle(title);
mediaVideo.setReview(true);
mediaVideo.setShouldDownload(true);
MediaVideo mediaVideoResult = mediaVideoService.saveMediaVideo(mediaVideo);
if (mediaVideoResult != null) {
log.info("MediaVideo saved: {}", mediaVideoResult.toString());
exchange.getIn().setHeader(MediaConstants.VIDEO_ID, mediaVideoResult.getId());
} else {
log.info("MediaFile could not saved: {}", url);
exchange.getIn().setHeader(MediaConstants.VIDEO_ID, null);
}
} catch (ParseException pe) {
log.info("parse exception: {}", pe.toString());
exchange.getIn().setHeader(MediaConstants.VIDEO_ID, null);
}
}
}
@@ -0,0 +1,45 @@
package de.thpeetz.kontor.integration.services;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import de.thpeetz.kontor.constants.MediaConstants;
import de.thpeetz.kontor.data.media.MediaFile;
import de.thpeetz.kontor.services.MediaFileService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class CheckLinkProcessor implements Processor {
private final MediaFileService mediaFileService;
public CheckLinkProcessor(MediaFileService mediaFileService) {
this.mediaFileService = mediaFileService;
}
@Override
public void process(Exchange exchange) throws Exception {
String messageBody = exchange.getIn().getBody(String.class);
log.info("message body: {}", messageBody);
JSONParser parser = new JSONParser();
try {
JSONObject jsonObject = (JSONObject) parser.parse(messageBody);
String url = (String) jsonObject.get(MediaConstants.URL);
MediaFile mediaFile = mediaFileService.findAllMediaFilesByUrl(url);
if (mediaFile != null) {
log.info("found url: {}", url);
exchange.getIn().setHeader(MediaConstants.FILE_ID, mediaFile.getId());
} else {
log.info("url not found: {}", url);
exchange.getIn().setHeader(MediaConstants.FILE_ID, null);
}
} catch (ParseException pe) {
log.info("parse exception: {}", pe.toString());
exchange.getIn().setHeader(MediaConstants.FILE_ID, null);
}
}
}
@@ -0,0 +1,45 @@
package de.thpeetz.kontor.integration.services;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import de.thpeetz.kontor.constants.MediaConstants;
import de.thpeetz.kontor.data.media.MediaLofi;
import de.thpeetz.kontor.services.MediaLofiService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class CheckLoFiProcessor implements Processor {
private final MediaLofiService medialLofiService;
public CheckLoFiProcessor(MediaLofiService medialLofiService) {
this.medialLofiService = medialLofiService;
}
@Override
public void process(Exchange exchange) throws Exception {
String messageBody = exchange.getIn().getBody(String.class);
log.info("message body: {}", messageBody);
JSONParser parser = new JSONParser();
try {
JSONObject jsonObject = (JSONObject) parser.parse(messageBody);
String url = (String) jsonObject.get(MediaConstants.URL);
MediaLofi mediaLofi = medialLofiService.findAllMediaLofiByUrl(url);
if (mediaLofi != null) {
log.info("found url: {}", url);
exchange.getIn().setHeader(MediaConstants.LOFI_ID, mediaLofi.getId());
} else {
log.info("url not found: {}", url);
exchange.getIn().setHeader(MediaConstants.LOFI_ID, null);
}
} catch (ParseException pe) {
log.info("parse exception: {}", pe.toString());
exchange.getIn().setHeader(MediaConstants.LOFI_ID, null);
}
}
}
@@ -0,0 +1,38 @@
package de.thpeetz.kontor.integration.services;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import de.thpeetz.kontor.services.MediaVideoService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class CheckVideoProcessor implements Processor {
@SuppressWarnings("unused")
private final MediaVideoService mediaVideoService;
public CheckVideoProcessor(MediaVideoService mediaVideoService) {
this.mediaVideoService = mediaVideoService;
}
@Override
public void process(Exchange exchange) throws Exception {
String messageBody = exchange.getIn().getBody(String.class);
log.info("message body: {}", messageBody);
JSONParser parser = new JSONParser();
try {
JSONObject jsonObject = (JSONObject) parser.parse(messageBody);
String url = (String) jsonObject.get("url");
log.info("found url: {}", url);
exchange.getIn().setHeader("linkId", null);
} catch (ParseException pe) {
log.info("parse exception: {}", pe.toString());
exchange.getIn().setHeader("linkId", null);
}
}
}
@@ -0,0 +1,40 @@
package de.thpeetz.kontor.integration.services;
import java.io.IOException;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import de.thpeetz.kontor.constants.MediaConstants;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class UrlTitleProcessor implements Processor {
@Override
public void process(Exchange exchange) throws Exception {
String messageBody = exchange.getIn().getBody(String.class);
log.info("URL to check: {}", messageBody);
JSONParser parser = new JSONParser();
try {
JSONObject jsonObject = (JSONObject) parser.parse(messageBody);
String url = (String) jsonObject.get(MediaConstants.URL);
Document doc = Jsoup.connect(url).get();
String title = doc.title();
log.info("URL Title: {}", title);
exchange.getIn().setHeader(MediaConstants.LINKTITLE, title);
} catch (IOException io) {
log.info("IOException: {}", io.toString());
exchange.getIn().setHeader(MediaConstants.LINKTITLE, "");
} catch (ParseException pe) {
log.info("parse exception: {}", pe.toString());
exchange.getIn().setHeader(MediaConstants.LINKTITLE, "");
}
}
}
@@ -0,0 +1,33 @@
package de.thpeetz.kontor.repository.media;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import de.thpeetz.kontor.data.media.MediaLofi;
public interface MediaLofiRepository extends JpaRepository<MediaLofi, String> {
@Query("select m from MediaLofi m " +
"where lower(m.url) like lower(concat('%', :searchTerm, '%')) or lower(m.title) like lower(concat('%', :searchTerm, '%'))")
List<MediaLofi> search(@Param("searchTerm") String searchTerm);
List<MediaLofi> findByShouldDownload(Boolean shouldDownload);
List<MediaLofi> findByReview(Boolean review);
List<MediaLofi> findByReviewAndShouldDownload(Boolean review, Boolean shouldDownload);
MediaLofi findByUrl(String url);
@Query("select m from MediaLofi m " +
"where lower(m.url) like lower(concat('%', :searchTerm, '%')) or lower(m.title) like lower(concat('%', :searchTerm, '%')) "
+
"AND m.review=:review AND m.shouldDownload=:download")
List<MediaLofi> search(
@Param("searchTerm") String searchTerm,
@Param("review") boolean searchReview,
@Param("download") boolean searchDownload);
}
@@ -96,7 +96,9 @@ public class ComicService {
if (searchFilter == null) return comicRepository.findAll(); if (searchFilter == null) return comicRepository.findAll();
if (searchFilter.getFilterOptions().isEmpty()) return comicRepository.search(searchFilter.getSearchTerm()); if (searchFilter.getFilterOptions().isEmpty()) return comicRepository.search(searchFilter.getSearchTerm());
if (searchFilter.getFilterOptions().size() == 1) { if (searchFilter.getFilterOptions().size() == 1) {
FilterOption option = searchFilter.getFilterOptions().getFirst(); //TODO use with Java 21
//FilterOption option = searchFilter.getFilterOptions().getFirst();
FilterOption option = searchFilter.getFilterOptions().get(0);
if (searchFilter.getSearchTerm() != null && !searchFilter.getSearchTerm().isEmpty()) { if (searchFilter.getSearchTerm() != null && !searchFilter.getSearchTerm().isEmpty()) {
switch (option.getName()) { switch (option.getName()) {
case "Bestellung": case "Bestellung":
@@ -0,0 +1,86 @@
package de.thpeetz.kontor.services;
import java.util.List;
import org.springframework.stereotype.Service;
import de.thpeetz.kontor.data.media.MediaLofi;
import de.thpeetz.kontor.repository.media.MediaLofiRepository;
import de.thpeetz.kontor.views.common.SearchFilter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class MediaLofiService {
private final MediaLofiRepository mediaLofiRepository;
public MediaLofiService(MediaLofiRepository mediaLofiRepository) {
this.mediaLofiRepository = mediaLofiRepository;
}
public List<MediaLofi> findAllMediaLofisByString(String stringFilter) {
List<MediaLofi> results;
if (stringFilter == null || stringFilter.isEmpty()) {
results = mediaLofiRepository.findAll();
} else {
results = mediaLofiRepository.search(stringFilter);
}
log.debug("Found " + results.size() + " entries");
return results;
}
public MediaLofi findAllMediaLofiByUrl(String url) {
return mediaLofiRepository.findByUrl(url);
}
public List<MediaLofi> findAllMediaLofis(SearchFilter searchFilter) {
if (searchFilter == null) {
return mediaLofiRepository.findAll();
} else {
if (searchFilter.getSearchTerm() != null && searchFilter.getFilterOptions().isEmpty()) {
log.info("find MediaFiles by using searchTerm: {}", searchFilter.getSearchTerm());
List<MediaLofi> results = mediaLofiRepository.search(searchFilter.getSearchTerm());
log.info("found {} entries", results.size());
return results;
}
if (searchFilter.getFilterOptions().size() == 1) {
log.info("using searchFilter: {}", searchFilter);
String filter = searchFilter.getFilterOptions().get(0).getName();
Boolean filterValue = searchFilter.getFilterOptions().get(0).getValue();
if (filter == "Überprüfung") {
List<MediaLofi> results = mediaLofiRepository.findByReview(filterValue);
log.info("found {} entries", results.size());
return results;
}
if (filter == "Download") {
List<MediaLofi> results = mediaLofiRepository.findByShouldDownload(filterValue);
log.info("found {} entries", results.size());
return results;
}
}
if (searchFilter.getFilterOptions().size() == 2) {
log.info("using searchFilter: {}", searchFilter);
List<MediaLofi> results = mediaLofiRepository.search(searchFilter.getSearchTerm(),
searchFilter.getFilterOptions().get(0).getValue(),
searchFilter.getFilterOptions().get(1).getValue());
log.info("found {} entries", results.size());
return results;
}
}
log.info("noch filter used");
return mediaLofiRepository.findAll();
}
public MediaLofi saveMediaLofi(MediaLofi mediaLofi) {
if (mediaLofi == null) {
log.warn("MediaLofi is null. Are you sure you have connected your form to the application?");
return null;
}
return mediaLofiRepository.save(mediaLofi);
}
public void deleteMediaLofi(MediaLofi mediaLofi) {
mediaLofiRepository.delete(mediaLofi);
}
}
@@ -25,12 +25,12 @@ public class MediaVideoService {
} }
} }
public void saveMediaVideo(MediaVideo mediaVideo) { public MediaVideo saveMediaVideo(MediaVideo mediaVideo) {
if (mediaVideo == null) { if (mediaVideo == null) {
log.warn("MediaFile is null. Are you sure you have connected your form to the application?"); log.warn("MediaFile is null. Are you sure you have connected your form to the application?");
return; return null;
} }
mediaVideoRepository.save(mediaVideo); return mediaVideoRepository.save(mediaVideo);
} }
public void deleteMediaVideo(MediaVideo mediaVideo) { public void deleteMediaVideo(MediaVideo mediaVideo) {
@@ -9,6 +9,7 @@ import de.thpeetz.kontor.security.SecurityService;
import de.thpeetz.kontor.services.AdminService; import de.thpeetz.kontor.services.AdminService;
import de.thpeetz.kontor.views.common.KontorLayoutUtil; import de.thpeetz.kontor.views.common.KontorLayoutUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.info.BuildProperties;
@Slf4j @Slf4j
public class AdminLayout extends AppLayout { public class AdminLayout extends AppLayout {
@@ -19,11 +20,15 @@ public class AdminLayout extends AppLayout {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final SecurityService securityService; private final SecurityService securityService;
public AdminLayout(AdminService adminService, SecurityService securityService) { @SuppressWarnings("unused")
private final BuildProperties buildProperties;
public AdminLayout(AdminService adminService, SecurityService securityService, BuildProperties buildProperties) {
this.adminService = adminService; this.adminService = adminService;
this.securityService = securityService; this.securityService = securityService;
this.buildProperties = buildProperties;
KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService); KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService, buildProperties);
layout.setSecondaryNavigation(getSecondaryNavigation()); layout.setSecondaryNavigation(getSecondaryNavigation());
layout.createHeader(AdminConstants.ADMIN_TITLE); layout.createHeader(AdminConstants.ADMIN_TITLE);
} }
@@ -19,13 +19,15 @@ import jakarta.annotation.security.PermitAll;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
@Route(value="user/profile", layout = MainLayout.class) @Route(value = "user/profile", layout = MainLayout.class)
@PermitAll @PermitAll
@PageTitle("Profile | User | Kontor") @PageTitle("Profile | User | Kontor")
public class UserProfileView extends VerticalLayout { public class UserProfileView extends VerticalLayout {
@SuppressWarnings("unused")
private SecurityService securityService; private SecurityService securityService;
@SuppressWarnings("unused")
private AdminService adminService; private AdminService adminService;
TextField firstName = new TextField("First name"); TextField firstName = new TextField("First name");
@@ -8,6 +8,7 @@ import de.thpeetz.kontor.constants.BookshelfConstants;
import de.thpeetz.kontor.security.SecurityService; import de.thpeetz.kontor.security.SecurityService;
import de.thpeetz.kontor.services.AdminService; import de.thpeetz.kontor.services.AdminService;
import de.thpeetz.kontor.views.common.KontorLayoutUtil; import de.thpeetz.kontor.views.common.KontorLayoutUtil;
import org.springframework.boot.info.BuildProperties;
public class BookshelfLayout extends AppLayout { public class BookshelfLayout extends AppLayout {
@@ -17,11 +18,15 @@ public class BookshelfLayout extends AppLayout {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final SecurityService securityService; private final SecurityService securityService;
public BookshelfLayout(AdminService adminService, SecurityService securityService) { @SuppressWarnings("unused")
private final BuildProperties buildProperties;
public BookshelfLayout(AdminService adminService, SecurityService securityService, BuildProperties buildProperties) {
this.adminService = adminService; this.adminService = adminService;
this.securityService = securityService; this.securityService = securityService;
this.buildProperties = buildProperties;
KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService); KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService, buildProperties);
layout.setSecondaryNavigation(getSecondaryNavigation()); layout.setSecondaryNavigation(getSecondaryNavigation());
layout.createHeader(BookshelfConstants.BOOKSHELF); layout.createHeader(BookshelfConstants.BOOKSHELF);
} }
@@ -22,12 +22,12 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class ArtistForm extends FormLayout { public class ArtistForm extends FormLayout {
TextField name = new TextField("Name"); public TextField name = new TextField("Name");
TextField weblink = new TextField("Link"); TextField weblink = new TextField("Link");
Grid<ComicWork> comicWorks = new Grid<>(ComicWork.class); Grid<ComicWork> comicWorks = new Grid<>(ComicWork.class);
Button save = new Button("Save"); public Button save = new Button("Save");
Button delete = new Button("Delete"); public Button delete = new Button("Delete");
Button close = new Button("Cancel"); Button close = new Button("Cancel");
Binder<Artist> binder = new BeanValidationBinder<>(Artist.class); Binder<Artist> binder = new BeanValidationBinder<>(Artist.class);
@@ -28,7 +28,7 @@ public class ComicForm extends FormLayout {
private static final Logger log = LoggerFactory.getLogger(ComicForm.class); private static final Logger log = LoggerFactory.getLogger(ComicForm.class);
TextField title = new TextField("Title"); public TextField title = new TextField("Title");
ComboBox<Publisher> publisher = new ComboBox<>("Publisher"); ComboBox<Publisher> publisher = new ComboBox<>("Publisher");
TextField weblink = new TextField("Link"); TextField weblink = new TextField("Link");
Checkbox currentOrder = new Checkbox("Current order"); Checkbox currentOrder = new Checkbox("Current order");
@@ -9,6 +9,7 @@ import de.thpeetz.kontor.security.SecurityService;
import de.thpeetz.kontor.services.AdminService; import de.thpeetz.kontor.services.AdminService;
import de.thpeetz.kontor.views.common.KontorLayoutUtil; import de.thpeetz.kontor.views.common.KontorLayoutUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.info.BuildProperties;
/** /**
* Represents a custom layout for the comic view in the application. * Represents a custom layout for the comic view in the application.
@@ -17,15 +18,21 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class ComicLayout extends AppLayout { public class ComicLayout extends AppLayout {
@SuppressWarnings("unused")
private final AdminService adminService; private final AdminService adminService;
@SuppressWarnings("unused")
private final SecurityService securityService; private final SecurityService securityService;
public ComicLayout(AdminService adminService, SecurityService securityService) { @SuppressWarnings("unused")
private final BuildProperties buildProperties;
public ComicLayout(AdminService adminService, SecurityService securityService, BuildProperties buildProperties) {
this.adminService = adminService; this.adminService = adminService;
this.securityService = securityService; this.securityService = securityService;
this.buildProperties = buildProperties;
KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService); KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService, buildProperties);
layout.setSecondaryNavigation(getSecondaryNavigation()); layout.setSecondaryNavigation(getSecondaryNavigation());
layout.createHeader(ComicConstants.COMICS); layout.createHeader(ComicConstants.COMICS);
} }
@@ -40,4 +47,3 @@ public class ComicLayout extends AppLayout {
return navigation; return navigation;
} }
} }
@@ -19,7 +19,7 @@ import de.thpeetz.kontor.data.comics.ComicWork;
import de.thpeetz.kontor.data.comics.Worktype; import de.thpeetz.kontor.data.comics.Worktype;
public class ComicWorkForm extends FormLayout { public class ComicWorkForm extends FormLayout {
ComboBox<Comic> comic = new ComboBox<>("Comic"); public ComboBox<Comic> comic = new ComboBox<>("Comic");
ComboBox<Artist> artist = new ComboBox<>("Artist"); ComboBox<Artist> artist = new ComboBox<>("Artist");
ComboBox<Worktype> workType = new ComboBox<>("Worktype"); ComboBox<Worktype> workType = new ComboBox<>("Worktype");
@@ -29,7 +29,7 @@ public class IssueForm extends FormLayout {
ComboBox<Comic> comic = new ComboBox<>("Comic"); ComboBox<Comic> comic = new ComboBox<>("Comic");
ComboBox<Volume> volume = new ComboBox<>("Volume"); ComboBox<Volume> volume = new ComboBox<>("Volume");
TextField issueNumber = new TextField("Issue number"); public TextField issueNumber = new TextField("Issue number");
TextField title = new TextField("Full Title"); TextField title = new TextField("Full Title");
YearMonthField publishedOn = new YearMonthField(); YearMonthField publishedOn = new YearMonthField();
Checkbox isRead = new Checkbox("Read"); Checkbox isRead = new Checkbox("Read");
@@ -61,7 +61,7 @@ public class IssueForm extends FormLayout {
issueWorks.getColumnByKey("workType.name").setHeader("Work type"); issueWorks.getColumnByKey("workType.name").setHeader("Work type");
issueWorks.getColumnByKey("artist.name").setHeader("Artist"); issueWorks.getColumnByKey("artist.name").setHeader("Artist");
issueWorks.getColumns().forEach(col -> col.setAutoWidth(true)); issueWorks.getColumns().forEach(col -> col.setAutoWidth(true));
add(comic, volume, issueNumber, title, publishedOn, isRead, inStock,issueWorks, createButtonsLayout()); add(comic, volume, issueNumber, title, publishedOn, isRead, inStock, issueWorks, createButtonsLayout());
} }
private HorizontalLayout createButtonsLayout() { private HorizontalLayout createButtonsLayout() {
@@ -20,8 +20,6 @@ import de.thpeetz.kontor.constants.ComicConstants;
import de.thpeetz.kontor.data.comics.Comic; import de.thpeetz.kontor.data.comics.Comic;
import de.thpeetz.kontor.data.comics.Issue; import de.thpeetz.kontor.data.comics.Issue;
import de.thpeetz.kontor.services.ComicService; import de.thpeetz.kontor.services.ComicService;
import de.thpeetz.kontor.views.comics.IssueForm.DeleteEvent;
import de.thpeetz.kontor.views.comics.IssueForm.SaveEvent;
import de.thpeetz.kontor.views.common.ColumnToggleContextMenu; import de.thpeetz.kontor.views.common.ColumnToggleContextMenu;
import de.thpeetz.kontor.views.common.MainLayout; import de.thpeetz.kontor.views.common.MainLayout;
import de.thpeetz.kontor.views.common.StatusIcon; import de.thpeetz.kontor.views.common.StatusIcon;
@@ -62,7 +60,8 @@ public class IssueView extends VerticalLayout {
.setHeader("Published").setResizable(true).setSortable(true); .setHeader("Published").setResizable(true).setSortable(true);
Grid.Column<Issue> isReadColumn = grid.addComponentColumn(issueColumn -> StatusIcon.create(issueColumn.getIsRead())) Grid.Column<Issue> isReadColumn = grid.addComponentColumn(issueColumn -> StatusIcon.create(issueColumn.getIsRead()))
.setHeader("Gelesen?").setWidth("6rem").setSortable(true); .setHeader("Gelesen?").setWidth("6rem").setSortable(true);
Grid.Column<Issue> inStockColumn = grid.addComponentColumn(issueColumn -> StatusIcon.create(issueColumn.getInStock())) Grid.Column<Issue> inStockColumn = grid
.addComponentColumn(issueColumn -> StatusIcon.create(issueColumn.getInStock()))
.setHeader("Im Bestand?").setWidth("6rem").setSortable(true); .setHeader("Im Bestand?").setWidth("6rem").setSortable(true);
ComboBox<Comic> comicFilter = new ComboBox<>("Comic"); ComboBox<Comic> comicFilter = new ComboBox<>("Comic");
@Getter @Getter
@@ -20,7 +20,7 @@ import java.util.List;
public class StoryArcForm extends FormLayout { public class StoryArcForm extends FormLayout {
ComboBox<Comic> comic = new ComboBox<>("Comic"); ComboBox<Comic> comic = new ComboBox<>("Comic");
TextField name = new TextField("Story Arc Name"); public TextField name = new TextField("Story Arc Name");
Button save = new Button("Save"); Button save = new Button("Save");
Button delete = new Button("Delete"); Button delete = new Button("Delete");
@@ -44,7 +44,7 @@ public class StoryArcView extends VerticalLayout {
updateList(); updateList();
} }
StoryArcForm getForm() { public StoryArcForm getForm() {
return form; return form;
} }
@@ -18,7 +18,7 @@ import de.thpeetz.kontor.data.comics.Comic;
import de.thpeetz.kontor.data.comics.TradePaperback; import de.thpeetz.kontor.data.comics.TradePaperback;
public class TradePaperBackForm extends FormLayout { public class TradePaperBackForm extends FormLayout {
TextField name = new TextField("Name"); public TextField name = new TextField("Name");
ComboBox<Comic> comic = new ComboBox<>("Comic"); ComboBox<Comic> comic = new ComboBox<>("Comic");
TextField issueStart = new TextField("Issue Start"); TextField issueStart = new TextField("Issue Start");
TextField issueEnd = new TextField("Issue End"); TextField issueEnd = new TextField("Issue End");
@@ -44,7 +44,7 @@ public class VolumeView extends VerticalLayout {
updateList(); updateList();
} }
VolumeForm getForm() { public VolumeForm getForm() {
return form; return form;
} }
@@ -24,7 +24,7 @@ public class WorktypeForm extends FormLayout {
private static final Logger log = LoggerFactory.getLogger(WorktypeForm.class); private static final Logger log = LoggerFactory.getLogger(WorktypeForm.class);
TextField name = new TextField("Name"); public TextField name = new TextField("Name");
Grid<ComicWork> comicWorks = new Grid<>(ComicWork.class); Grid<ComicWork> comicWorks = new Grid<>(ComicWork.class);
Button save = new Button("Save"); Button save = new Button("Save");
@@ -12,6 +12,7 @@ import de.thpeetz.kontor.security.SecurityService;
import de.thpeetz.kontor.services.AdminService; import de.thpeetz.kontor.services.AdminService;
import de.thpeetz.kontor.views.admin.UserProfileView; import de.thpeetz.kontor.views.admin.UserProfileView;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.info.BuildProperties;
@Slf4j @Slf4j
@Route("avatar-menu-bar") @Route("avatar-menu-bar")
@@ -21,9 +22,12 @@ public class AvatarMenuBar extends Div {
final AdminService adminService; final AdminService adminService;
public AvatarMenuBar(SecurityService securityService, AdminService adminService) { private final BuildProperties buildProperties;
public AvatarMenuBar(SecurityService securityService, AdminService adminService, BuildProperties buildProperties) {
this.adminService = adminService; this.adminService = adminService;
this.securityService = securityService; this.securityService = securityService;
this.buildProperties = buildProperties;
Avatar avatar = new Avatar(); Avatar avatar = new Avatar();
securityService.getAuthenticatedUser().ifPresent(user -> { securityService.getAuthenticatedUser().ifPresent(user -> {
@@ -45,6 +49,10 @@ public class AvatarMenuBar extends Div {
profileItem.addClickListener(e -> profileItem.getUI().ifPresent(ui -> ui.navigate(UserProfileView.class))); profileItem.addClickListener(e -> profileItem.getUI().ifPresent(ui -> ui.navigate(UserProfileView.class)));
subMenu.addItem("Settings"); subMenu.addItem("Settings");
subMenu.addItem("Help"); subMenu.addItem("Help");
subMenu.addSeparator();
subMenu.addItem("Version");
subMenu.addItem(this.buildProperties.getVersion());
subMenu.addItem(this.buildProperties.getTime().toString());
add(menuBar); add(menuBar);
} }
} }
@@ -21,6 +21,7 @@ import de.thpeetz.kontor.security.SecurityService;
import de.thpeetz.kontor.services.AdminService; import de.thpeetz.kontor.services.AdminService;
import lombok.*; import lombok.*;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.info.BuildProperties;
@Slf4j @Slf4j
public class KontorLayoutUtil { public class KontorLayoutUtil {
@@ -33,9 +34,12 @@ public class KontorLayoutUtil {
private final SecurityService securityService; private final SecurityService securityService;
public KontorLayoutUtil(AppLayout layout, AdminService adminService, SecurityService securityService) { private final BuildProperties buildProperties;
public KontorLayoutUtil(AppLayout layout, AdminService adminService, SecurityService securityService, BuildProperties buildProperties) {
this.adminService = adminService; this.adminService = adminService;
this.securityService = securityService; this.securityService = securityService;
this.buildProperties = buildProperties;
this.appLayout = layout; this.appLayout = layout;
} }
@@ -65,7 +69,7 @@ public class KontorLayoutUtil {
viewTitle.addClassNames(LumoUtility.FontSize.LARGE, LumoUtility.Margin.NONE); viewTitle.addClassNames(LumoUtility.FontSize.LARGE, LumoUtility.Margin.NONE);
HorizontalLayout subViews = this.secondaryNavigation; HorizontalLayout subViews = this.secondaryNavigation;
AvatarMenuBar avatar = new AvatarMenuBar(securityService, adminService); AvatarMenuBar avatar = new AvatarMenuBar(securityService, adminService, buildProperties);
HorizontalLayout wrapper = new HorizontalLayout(toggle, viewTitle, avatar); HorizontalLayout wrapper = new HorizontalLayout(toggle, viewTitle, avatar);
wrapper.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER); wrapper.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER);
wrapper.expand(viewTitle); wrapper.expand(viewTitle);
@@ -24,6 +24,7 @@ import de.thpeetz.kontor.services.AdminService;
import de.thpeetz.kontor.views.DataManagementView; import de.thpeetz.kontor.views.DataManagementView;
import de.thpeetz.kontor.views.EmailView; import de.thpeetz.kontor.views.EmailView;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.info.BuildProperties;
import java.util.ArrayList; import java.util.ArrayList;
@@ -34,9 +35,12 @@ public class MainLayout extends AppLayout {
private final SecurityService securityService; private final SecurityService securityService;
public MainLayout(AdminService adminService, SecurityService securityService) { private final BuildProperties buildProperties;
public MainLayout(AdminService adminService, SecurityService securityService, BuildProperties buildProperties) {
this.adminService = adminService; this.adminService = adminService;
this.securityService = securityService; this.securityService = securityService;
this.buildProperties = buildProperties;
createHeader("Kontor"); createHeader("Kontor");
createDrawer(); createDrawer();
@@ -57,7 +61,7 @@ public class MainLayout extends AppLayout {
H2 viewTitle = new H2(titleName); H2 viewTitle = new H2(titleName);
viewTitle.addClassNames(LumoUtility.FontSize.LARGE, LumoUtility.Margin.NONE); viewTitle.addClassNames(LumoUtility.FontSize.LARGE, LumoUtility.Margin.NONE);
AvatarMenuBar avatar = new AvatarMenuBar(securityService, adminService); AvatarMenuBar avatar = new AvatarMenuBar(securityService, adminService, buildProperties);
HorizontalLayout wrapper = new HorizontalLayout(toggle, viewTitle, avatar); HorizontalLayout wrapper = new HorizontalLayout(toggle, viewTitle, avatar);
wrapper.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER); wrapper.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER);
wrapper.expand(viewTitle); wrapper.expand(viewTitle);
@@ -3,15 +3,16 @@ package de.thpeetz.kontor.views.common;
import com.vaadin.flow.component.applayout.AppLayout; import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.theme.lumo.LumoUtility; import com.vaadin.flow.theme.lumo.LumoUtility;
import org.springframework.boot.info.BuildProperties;
import de.thpeetz.kontor.security.SecurityService; import de.thpeetz.kontor.security.SecurityService;
import de.thpeetz.kontor.services.AdminService; import de.thpeetz.kontor.services.AdminService;
public class SeparateMainLayout extends AppLayout { public class SeparateMainLayout extends AppLayout {
public SeparateMainLayout(AdminService adminService, SecurityService securityService) { public SeparateMainLayout(AdminService adminService, SecurityService securityService, BuildProperties buildProperties) {
KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService); KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService, buildProperties);
layout.setSecondaryNavigation(getSecondaryNavigation()); layout.setSecondaryNavigation(getSecondaryNavigation());
layout.createHeader("Kontor"); layout.createHeader("Kontor");
} }
@@ -0,0 +1,113 @@
package de.thpeetz.kontor.views.media;
import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.Key;
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.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 de.thpeetz.kontor.data.media.MediaLofi;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MediaLofiForm extends FormLayout {
TextField url = new TextField("URL");
TextField title = new TextField("Title");
TextField fileName = new TextField("Dateiname");
Checkbox review = new Checkbox("Review");
Checkbox shouldDownload = new Checkbox("Download");
Button save = new Button("Save");
Button delete = new Button("Delete");
Button close = new Button("Cancel");
Binder<MediaLofi> binder = new BeanValidationBinder<>(MediaLofi.class);
public MediaLofiForm() {
addClassName("medialofi-form");
binder.bindInstanceFields(this);
add(url, 2);
add(title, 2);
add(fileName, 2);
add(review, shouldDownload, createButtonsLayout());
}
private HorizontalLayout createButtonsLayout() {
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
save.addClickShortcut(Key.ENTER);
close.addClickShortcut(Key.ESCAPE);
save.addClickListener(event -> validateAndSave());
delete.addClickListener(event -> fireEvent(new DeleteEvent(this, binder.getBean())));
close.addClickListener(event -> fireEvent(new CloseEvent(this)));
binder.addStatusChangeListener(event -> {
save.setEnabled(event.getBinder().isValid());
});
return new HorizontalLayout(save, delete, close);
}
private void validateAndSave() {
if (binder.isValid()) {
fireEvent(new SaveEvent(this, binder.getBean()));
}
}
public void setMediaLofi(MediaLofi mediaLofi) {
binder.setBean(mediaLofi);
}
public abstract static class MediaLofiFormEvent extends ComponentEvent<MediaLofiForm> {
private MediaLofi mediaLofi;
protected MediaLofiFormEvent(MediaLofiForm source, MediaLofi mediaLofi) {
super(source, false);
this.mediaLofi = mediaLofi;
}
public MediaLofi getMediaLofi() {
return mediaLofi;
}
}
public static class SaveEvent extends MediaLofiFormEvent {
SaveEvent(MediaLofiForm source, MediaLofi mediaLofi) {
super(source, mediaLofi);
}
}
public static class DeleteEvent extends MediaLofiFormEvent {
DeleteEvent(MediaLofiForm source, MediaLofi mediaLofi) {
super(source, mediaLofi);
}
}
public static class CloseEvent extends MediaLofiFormEvent {
CloseEvent(MediaLofiForm source) {
super(source, null);
}
}
public void addDeleteListener(ComponentEventListener<DeleteEvent> listener) {
addListener(DeleteEvent.class, listener);
}
public void addSaveListener(ComponentEventListener<SaveEvent> listener) {
addListener(SaveEvent.class, listener);
}
public void addCloseListener(ComponentEventListener<CloseEvent> listener) {
addListener(CloseEvent.class, listener);
}
}
@@ -0,0 +1,144 @@
package de.thpeetz.kontor.views.media;
import org.springframework.context.annotation.Scope;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.spring.annotation.SpringComponent;
import de.thpeetz.kontor.constants.MediaConstants;
import de.thpeetz.kontor.data.media.MediaLofi;
import de.thpeetz.kontor.services.MediaLofiService;
import de.thpeetz.kontor.views.common.ColumnToggleContextMenu;
import de.thpeetz.kontor.views.common.MainLayout;
import de.thpeetz.kontor.views.common.SearchFilterField;
import de.thpeetz.kontor.views.common.StatusIcon;
import jakarta.annotation.security.PermitAll;
import lombok.Getter;
@SpringComponent
@Scope("prototype")
@PermitAll
@Route(value = MediaConstants.MEDIALOFI_ROUTE, layout = MainLayout.class)
@PageTitle("MediaLoFi | Media | Kontor")
public class MediaLofiView extends VerticalLayout {
@Getter
Grid<MediaLofi> grid = new Grid<>(MediaLofi.class, false);
Grid.Column<MediaLofi> idColumn = grid.addColumn(MediaLofi::getId).setHeader("ID").setResizable(true);
Grid.Column<MediaLofi> urlColumn = grid.addColumn(MediaLofi::getUrl).setHeader("URL").setResizable(true).setSortable(true);
Grid.Column<MediaLofi> titleColumn = grid.addColumn(MediaLofi::getTitle).setHeader("Titel").setResizable(true).setSortable(true);
Grid.Column<MediaLofi> fileNameColumn = grid.addColumn(MediaLofi::getFileName).setHeader("Dateiname").setResizable(true).setSortable(true);
Grid.Column<MediaLofi> reviewColumn = grid.addComponentColumn(mediaLofi -> StatusIcon.create(mediaLofi.isReview()))
.setHeader("Überprüfung")
.setWidth("6rem");
Grid.Column<MediaLofi> shouldDownloadColumn = grid.addComponentColumn(mediaLofi -> StatusIcon.create(mediaLofi.isShouldDownload()))
.setHeader("Download?")
.setWidth("6rem");
SearchFilterField searchFilterField = new SearchFilterField();
@Getter
MediaLofiForm form;
MediaLofiService service;
public MediaLofiView(MediaLofiService service) {
this.service = service;
addClassName("medialofi-view");
setSizeFull();
configureGrid();
configureForm();
add(getToolbar(), getContent());
updateList();
}
private void configureGrid() {
grid.addClassName("mediavideo-grid");
grid.setSizeFull();
grid.getColumns().forEach(col -> col.setAutoWidth(true));
idColumn.setVisible(false);
grid.asSingleSelect().addValueChangeListener(event -> editMediaLofi(event.getValue()));
}
private void configureForm() {
form = new MediaLofiForm();
form.setWidth("75em");
form.setVisible(false);
form.addSaveListener(this::saveMediaVideo);
form.addDeleteListener(this::deleteMediaLofi);
form.addCloseListener(e -> closeEditor());
}
private void saveMediaVideo(MediaLofiForm.SaveEvent event) {
service.saveMediaLofi(event.getMediaLofi());
updateList();
closeEditor();
}
private void deleteMediaLofi(MediaLofiForm.DeleteEvent event) {
service.deleteMediaLofi(event.getMediaLofi());
updateList();
closeEditor();
}
private Component getContent() {
HorizontalLayout content = new HorizontalLayout(grid, form);
content.setFlexGrow(2, grid);
content.setFlexGrow(1, form);
content.addClassName("content");
content.setSizeFull();
return content;
}
private HorizontalLayout getToolbar() {
searchFilterField.addFilter("Überprüfung");
searchFilterField.addFilter("Download");
searchFilterField.addValueChangeListener(e -> updateList());
Button addMediaLofiButton = new Button("Add MediaLofi");
addMediaLofiButton.addClickListener(click -> addMediaLofi());
Button menuButton = new Button("Show/Hide Columns");
menuButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
ColumnToggleContextMenu<MediaLofi> columnToggleContextMenu = new ColumnToggleContextMenu<>(menuButton);
columnToggleContextMenu.addColumnToggleItem(idColumn);
columnToggleContextMenu.addColumnToggleItem(urlColumn);
columnToggleContextMenu.addColumnToggleItem(titleColumn);
columnToggleContextMenu.addColumnToggleItem(fileNameColumn);
columnToggleContextMenu.addColumnToggleItem(reviewColumn);
columnToggleContextMenu.addColumnToggleItem(shouldDownloadColumn);
HorizontalLayout toolbar = new HorizontalLayout(searchFilterField, addMediaLofiButton, menuButton);
toolbar.addClassName("toolbar");
return toolbar;
}
public void editMediaLofi(MediaLofi mediaLofi) {
if (mediaLofi == null) {
closeEditor();
} else {
form.setMediaLofi(mediaLofi);
form.setVisible(true);
addClassName("editing");
}
}
private void closeEditor() {
form.setMediaLofi(null);
form.setVisible(false);
removeClassName("editing");
}
private void addMediaLofi() {
grid.asSingleSelect().clear();
editMediaLofi(new MediaLofi());
}
public void updateList() {
grid.setItems(service.findAllMediaLofis(searchFilterField.getValue()));
}
}
@@ -9,6 +9,7 @@ import de.thpeetz.kontor.security.SecurityService;
import de.thpeetz.kontor.services.AdminService; import de.thpeetz.kontor.services.AdminService;
import de.thpeetz.kontor.views.common.KontorLayoutUtil; import de.thpeetz.kontor.views.common.KontorLayoutUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.info.BuildProperties;
/** /**
* Represents a custom layout for the comic view in the application. * Represents a custom layout for the comic view in the application.
@@ -21,11 +22,14 @@ public class TyscLayout extends AppLayout {
private final SecurityService securityService; private final SecurityService securityService;
public TyscLayout(AdminService adminService, SecurityService securityService) { private final BuildProperties buildProperties;
public TyscLayout(AdminService adminService, SecurityService securityService, BuildProperties buildProperties) {
this.adminService = adminService; this.adminService = adminService;
this.securityService = securityService; this.securityService = securityService;
this.buildProperties = buildProperties;
KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService); KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService, buildProperties);
layout.setSecondaryNavigation(getSecondaryNavigation()); layout.setSecondaryNavigation(getSecondaryNavigation());
layout.createHeader(TyscConstants.TYSC); layout.createHeader(TyscConstants.TYSC);
} }
@@ -1,7 +1,7 @@
app: app:
name: 'Kontor' name: "Kontor"
shortName: 'Kontor' shortName: "Kontor"
description: 'Kontor is a Spring Boot application' description: "Kontor is a Spring Boot application"
spring: spring:
profiles: profiles:
active: local,dev,test,prod active: local,dev,test,prod
@@ -25,6 +25,9 @@ spring:
max-file-size: 10MB max-file-size: 10MB
max-request-size: 10MB max-request-size: 10MB
camel: camel:
component:
metrics:
metric-registry: prometheusMeterRegistry
cloud: cloud:
enabled: true enabled: true
springboot: springboot:
@@ -36,6 +39,9 @@ management:
web: web:
exposure: exposure:
include: health,info,metrics,prometheus,camelroutes include: health,info,metrics,prometheus,camelroutes
info:
git:
mode: full
endpoint: endpoint:
health: health:
show-details: always show-details: always
@@ -59,13 +65,13 @@ logging:
controllers: DEBUG controllers: DEBUG
jwt: jwt:
auth: auth:
secret: 'J6GOtcwC2NJI1l0VkHu20PacPFGTxpirBxWwynoHjsc=' secret: "J6GOtcwC2NJI1l0VkHu20PacPFGTxpirBxWwynoHjsc="
mail: mail:
protocol: 'imap' protocol: "imap"
host: 'corky.svpdata.eu' host: "corky.svpdata.eu"
port: 143 port: 143
userName: 'thomas.peetz@thpeetz.de' userName: "thomas.peetz@thpeetz.de"
password: 'fS9f4JYDIO7A' password: "fS9f4JYDIO7A"
starttls: true starttls: true
--- ---
spring: spring:
@@ -74,8 +80,8 @@ spring:
on-profile: prod on-profile: prod
datasource: datasource:
url: jdbc:postgresql://postgres:5432/kontor url: jdbc:postgresql://postgres:5432/kontor
username: 'kontor' username: "kontor"
password: 'kontor' password: "kontor"
artemis: artemis:
mode: native mode: native
broker-url: tcp://activemq:61616 broker-url: tcp://activemq:61616
+1 -1
View File
@@ -9,7 +9,7 @@ cd "$(dirname "$0")/.."
echo " => Baue Image localhost/kontor-spring:0.3.0" echo " => Baue Image localhost/kontor-spring:0.3.0"
buildah build -t kontor-spring:0.3.0 kontor-spring buildah build -t kontor-spring:0.3.0 kontor-spring
echo " => Baue Image localhost/kontor-api:0.3.0" echo " => Baue Image localhost/kontor-api:0.3.0"
buildah build --volume /home/tpeetz/projects/kontor/kontor-model:/container/kontor-model kontor-api:0.3.0 kontor-api buildah build --volume /home/tpeetz/projects/kontor/kontor-model:/container/kontor-model -t kontor-api:0.3.0 kontor-api
echo " => Baue Image localhost/kontor-quarkus:0.3.0" echo " => Baue Image localhost/kontor-quarkus:0.3.0"
buildah build -t kontor-quarkus:0.3.0 kontor-quarkus buildah build -t kontor-quarkus:0.3.0 kontor-quarkus
echo " => Baue Image localhost/kontor-echo:0.3.0" echo " => Baue Image localhost/kontor-echo:0.3.0"