basic contact overview
This commit is contained in:
1 parent
94bec47d4d
commit
9fe9555853
73 files changed
+996
-1488
No files matched your search
+4
-11
@@ -14,23 +14,16 @@
|
|||||||
</classpathentry>
|
</classpathentry>
|
||||||
<classpathentry kind="src" output="bin/test" path="src/test/java">
|
<classpathentry kind="src" output="bin/test" path="src/test/java">
|
||||||
<attributes>
|
<attributes>
|
||||||
|
<attribute name="test" value="true"/>
|
||||||
<attribute name="gradle_scope" value="test"/>
|
<attribute name="gradle_scope" value="test"/>
|
||||||
<attribute name="gradle_used_by_scope" value="test"/>
|
<attribute name="gradle_used_by_scope" value="test"/>
|
||||||
<attribute name="test" value="true"/>
|
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
<classpathentry kind="src" output="bin/main" path="src/main/webapp">
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/">
|
||||||
<attributes>
|
<attributes>
|
||||||
<attribute name="gradle_scope" value="main"/>
|
<attribute name="module" value="true"/>
|
||||||
<attribute name="gradle_used_by_scope" value="main,test"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/"/>
|
|
||||||
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
|
|
||||||
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer">
|
|
||||||
<attributes>
|
|
||||||
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
|
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
|
||||||
<classpathentry kind="output" path="bin/default"/>
|
<classpathentry kind="output" path="bin/default"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
@@ -10,6 +10,11 @@
|
|||||||
<arguments>
|
<arguments>
|
||||||
</arguments>
|
</arguments>
|
||||||
</buildCommand>
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
<buildCommand>
|
<buildCommand>
|
||||||
<name>org.eclipse.wst.common.project.facet.core.builder</name>
|
<name>org.eclipse.wst.common.project.facet.core.builder</name>
|
||||||
<arguments>
|
<arguments>
|
||||||
@@ -20,11 +25,6 @@
|
|||||||
<arguments>
|
<arguments>
|
||||||
</arguments>
|
</arguments>
|
||||||
</buildCommand>
|
</buildCommand>
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
</buildSpec>
|
</buildSpec>
|
||||||
<natures>
|
<natures>
|
||||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
|
||||||
<project-modules id="moduleCoreId" project-version="1.5.0">
|
|
||||||
<wb-module deploy-name="timetrack">
|
<wb-module deploy-name="timetrack">
|
||||||
<property name="context-root" value="timetrack"/>
|
|
||||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/resources"/>
|
<property name="context-root" value="timetrack"/>
|
||||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/webapp"/>
|
|
||||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/java"/>
|
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/resources"/>
|
||||||
<wb-resource deploy-path="/" source-path="src/main/webapp"/>
|
|
||||||
</wb-module>
|
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/webapp"/>
|
||||||
|
|
||||||
|
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/java"/>
|
||||||
|
|
||||||
|
<wb-resource deploy-path="/" source-path="src/main/webapp"/>
|
||||||
|
|
||||||
|
</wb-module>
|
||||||
|
|
||||||
</project-modules>
|
</project-modules>
|
||||||
+45
-52
@@ -1,77 +1,70 @@
|
|||||||
buildscript {
|
plugins {
|
||||||
repositories {
|
id 'org.springframework.boot' version '2.6.5'
|
||||||
mavenLocal()
|
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
|
||||||
mavenCentral()
|
id 'java'
|
||||||
maven { url "https://repo.maven.apache.org/maven2" }
|
|
||||||
maven { url "https://plugins.gradle.org/m2/" }
|
|
||||||
maven {
|
|
||||||
url "https://gitlab.com/jottyfan/libs/-/raw/main"
|
|
||||||
}
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.google.code.gson:gson:2.8.6'
|
|
||||||
classpath 'org.postgresql:postgresql:42.2.19'
|
|
||||||
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:latest.release'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'java'
|
group = 'de.jottyfan'
|
||||||
apply plugin: 'maven-publish'
|
version = '1.2.0'
|
||||||
apply plugin: 'war'
|
sourceCompatibility = '11'
|
||||||
apply plugin: 'eclipse'
|
|
||||||
|
|
||||||
group = 'jottyfan'
|
ext['spring-framework.version'] = '5.3.18'
|
||||||
version = '1.1.9.1'
|
|
||||||
|
|
||||||
description = """timetrack"""
|
description = """timetrack"""
|
||||||
|
|
||||||
sourceCompatibility = 11
|
sourceCompatibility = 11
|
||||||
targetCompatibility = 11
|
targetCompatibility = 11
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main.java.srcDirs = ['src/main/java']
|
|
||||||
main.resources.srcDirs = ['src/main/resources', 'src/main/webapp']
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
|
||||||
options.encoding = 'UTF-8'
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven { url "https://www.jottyfan.de/mvnrepo" }
|
maven { url "https://www.jottyfan.de/mvnrepo" }
|
||||||
maven { url "https://repo.maven.apache.org/maven2" }
|
maven { url "https://repo.maven.apache.org/maven2" }
|
||||||
|
// maven { url "https://gitlab.com/jottyfan/libs/-/raw/main" }
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencyManagement {
|
||||||
|
imports {
|
||||||
|
mavenBom 'org.keycloak.bom:keycloak-adapter-bom:17.0.1'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.jboss.weld.servlet:weld-servlet:2.4.8.Final'
|
implementation 'org.apache.logging.log4j:log4j-api:2.17.1'
|
||||||
|
implementation 'org.apache.logging.log4j:log4j-core:2.17.1'
|
||||||
|
implementation 'org.apache.logging.log4j:log4j-to-slf4j:2.17.1'
|
||||||
|
|
||||||
implementation 'de.jottyfan:timetrackjooq:0.1.0'
|
implementation 'org.webjars:bootstrap:5.1.3'
|
||||||
|
implementation 'org.webjars:font-awesome:5.15.4'
|
||||||
|
implementation 'org.webjars:jquery:3.6.0'
|
||||||
|
implementation 'org.webjars:popper.js:2.9.3'
|
||||||
|
implementation 'org.webjars:datatables:1.11.3'
|
||||||
|
implementation 'org.webjars:jquery-ui:1.13.0'
|
||||||
|
|
||||||
implementation 'org.apache.myfaces.core:myfaces-api:2.3.8'
|
implementation 'org.webjars.bowergithub.datatables:datatables:1.10.21'
|
||||||
implementation 'org.apache.myfaces.core:myfaces-impl:2.3.8'
|
|
||||||
implementation 'net.bootsfaces:bootsfaces:1.5.0'
|
|
||||||
implementation 'org.postgresql:postgresql:42.2.19'
|
|
||||||
implementation 'org.jooq:jooq:3.14.4'
|
|
||||||
implementation 'com.google.code.gson:gson:2.8.6'
|
|
||||||
implementation 'org.jasypt:jasypt:1.9.3'
|
|
||||||
implementation 'javax.servlet:javax.servlet-api:4.0.1'
|
|
||||||
implementation 'org.apache.logging.log4j:log4j-core:2.16.0'
|
|
||||||
implementation 'org.apache.logging.log4j:log4j-api:2.16.0'
|
|
||||||
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.0-M1'
|
implementation 'org.keycloak:keycloak-spring-boot-starter:17.0.1'
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.0-M1'
|
|
||||||
|
|
||||||
implementation 'org.postgresql:postgresql:42.2.19'
|
implementation 'org.springframework.boot:spring-boot-starter-jooq'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||||
|
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
|
||||||
|
implementation 'de.jottyfan:timetrackjooq:0.1.0'
|
||||||
|
|
||||||
|
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:3.0.0'
|
||||||
|
|
||||||
|
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||||
|
runtimeOnly 'org.postgresql:postgresql'
|
||||||
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
|
testImplementation 'org.springframework.security:spring-security-test'
|
||||||
}
|
}
|
||||||
|
|
||||||
war {
|
test {
|
||||||
archiveName 'timetrack.war'
|
useJUnitPlatform()
|
||||||
manifest {
|
|
||||||
attributes('Implementation-Version': project.version)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add version to manifest
|
||||||
|
springBoot {
|
||||||
|
buildInfo()
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
mkdir -p timetrack/var/lib
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
./gradlew clean build
|
||||||
|
|
||||||
|
G=$(grep "^version =" build.gradle | sed -e "s/version = //g" | sed -e "s/'//g")
|
||||||
|
|
||||||
|
echo "found version $G"
|
||||||
|
|
||||||
|
cp -v build/libs/timetrack-$G.jar debian/timetrack/var/lib/timetrack.jar
|
||||||
|
|
||||||
|
cd debian
|
||||||
|
|
||||||
|
sed -i timetrack/DEBIAN/control -e "s/Version: 0.0.0/Version: $G/"
|
||||||
|
|
||||||
|
V=$(grep "Version" timetrack/DEBIAN/control | sed -e "s/Version: //g")
|
||||||
|
|
||||||
|
fakeroot dpkg -b timetrack timetrack_$V.deb
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
/etc/timetrack.properties
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
Package: timetrack
|
||||||
|
Version: 0.0.0
|
||||||
|
Architecture: amd64
|
||||||
|
Maintainer: Jörg Henke <jottyfan@gmx.de>
|
||||||
|
Depends: default-jdk
|
||||||
|
Section: ship
|
||||||
|
Priority: optional
|
||||||
|
Description: timetrack application to track work times
|
||||||
|
Timetrack is a web application to track my work times for my daily reporting.
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
mkdir -p /var/run/timetrack
|
||||||
|
groupadd timetrack || true
|
||||||
|
useradd -r -g timetrack -d /etc/timetrack -s /sbin/nologin timetrack || true
|
||||||
|
chown timetrack:timetrack -R /etc/timetrack || true
|
||||||
|
chown timetrack:timetrack -R /var/run/timetrack || true
|
||||||
|
chown timetrack:timetrack /usr/bin/timetrack || true
|
||||||
|
cd /var/lib
|
||||||
|
|
||||||
|
systemctl daemon-reload || true
|
||||||
|
systemctl enable timetrack || true
|
||||||
|
|
||||||
|
echo "+------------------------------------------------------------------------------+"
|
||||||
|
echo "| configure timetrack in /etc/timetrack.properties; consider a port change... |"
|
||||||
|
echo "| start timetrack by calling sudo systemctl restart timetrack |"
|
||||||
|
echo "+------------------------------------------------------------------------------+"
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Timetrack
|
||||||
|
After=syslog.target network.target
|
||||||
|
Before=httpd.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=timetack
|
||||||
|
Group=timetrack
|
||||||
|
PIDFile=/var/run/timetrack/timetrack.pid
|
||||||
|
ExecStart=/usr/bin/timetrack
|
||||||
|
StandardOutput=null
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
java -Dspring.config.location=/etc/timetrack.properties -jar /var/lib/timetrack.jar
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
package de.jooqfaces;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author henkej
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public enum EJooqFacesApplicationScope {
|
|
||||||
/**
|
|
||||||
* jooqFacesUrl
|
|
||||||
*/
|
|
||||||
JOOQ_FACES_URL("jooqFacesUrl"),
|
|
||||||
/**
|
|
||||||
* jooqFacesDriver
|
|
||||||
*/
|
|
||||||
JOOQ_FACES_DRIVER("jooqFacesDriver"),
|
|
||||||
/**
|
|
||||||
* jooqFacesSqldialect
|
|
||||||
*/
|
|
||||||
JOOQ_FACES_SQLDIALECT("jooqFacesSqldialect"),
|
|
||||||
/**
|
|
||||||
* jooqFacesProperties
|
|
||||||
*/
|
|
||||||
JOOQ_FACES_PROPERTIES("jooqFacesProperties"),
|
|
||||||
/**
|
|
||||||
* jooqFacesConnectionPool
|
|
||||||
*/
|
|
||||||
JOOQ_FACES_CONNECTIONPOOL("jooqFacesConnectionPool"),
|
|
||||||
/**
|
|
||||||
* jooqFacesMaxPoolSize
|
|
||||||
*/
|
|
||||||
JOOQ_FACES_MAXPOOLSIZE("jooqFacesMaxPoolSize"),
|
|
||||||
/**
|
|
||||||
* jooqFacesParamAutocommit
|
|
||||||
*/
|
|
||||||
JOOQ_FACES_PARAM_AUTOCOMMIT("jooqFacesParamAutocommit");
|
|
||||||
|
|
||||||
private final String s;
|
|
||||||
|
|
||||||
private EJooqFacesApplicationScope(String s) {
|
|
||||||
this.s = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the value
|
|
||||||
*/
|
|
||||||
public final String get() {
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package de.jooqfaces;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author jotty
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public enum EJooqFacesConnectionPool {
|
|
||||||
CP_HIKARI("hikari");
|
|
||||||
|
|
||||||
private final String value;
|
|
||||||
|
|
||||||
private EJooqFacesConnectionPool(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String get() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String getHikari() {
|
|
||||||
return CP_HIKARI.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package de.jooqfaces;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author henkej
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public enum EJooqFacesSessionScope {
|
|
||||||
CONNECTION("connection");
|
|
||||||
|
|
||||||
private final String value;
|
|
||||||
|
|
||||||
private EJooqFacesSessionScope(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String get() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,350 +0,0 @@
|
|||||||
package de.jooqfaces;
|
|
||||||
|
|
||||||
import java.sql.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import javax.faces.application.*;
|
|
||||||
import javax.faces.application.FacesMessage.*;
|
|
||||||
import javax.faces.component.*;
|
|
||||||
import javax.faces.context.*;
|
|
||||||
import javax.faces.render.*;
|
|
||||||
import javax.servlet.*;
|
|
||||||
import javax.sql.*;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.*;
|
|
||||||
import org.jooq.*;
|
|
||||||
import org.jooq.impl.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author jotty
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class JooqFacesContext extends FacesContext {
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(JooqFacesContext.class);
|
|
||||||
private FacesContext facesContext;
|
|
||||||
private Connection connection;
|
|
||||||
|
|
||||||
public JooqFacesContext(FacesContext facesContext) {
|
|
||||||
this.facesContext = facesContext;
|
|
||||||
setCurrentInstance(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the jooq dsl context from the faces context session map<br />
|
|
||||||
* <br />
|
|
||||||
* <b>Always</b> call getJooq() within a <b>try-catch closure</b>, as the DSLContext is a closure; if not, your
|
|
||||||
* connections might run out
|
|
||||||
*
|
|
||||||
* @return the jooq context
|
|
||||||
* @throws ClassNotFoundException
|
|
||||||
* on driver errors; check if you have attached the correct jdbc driver class
|
|
||||||
* @throws SQLException
|
|
||||||
* on sql errors
|
|
||||||
*/
|
|
||||||
public CloseableDSLContext getJooq() throws ClassNotFoundException, SQLException {
|
|
||||||
ExternalContext externalContext = facesContext.getExternalContext();
|
|
||||||
if (externalContext == null) {
|
|
||||||
throw new JooqFacesException("external context of current faces context is null");
|
|
||||||
}
|
|
||||||
ServletContext servletContext = (ServletContext) externalContext.getContext();
|
|
||||||
if (servletContext == null) {
|
|
||||||
throw new JooqFacesException("servlet context of current faces context is null");
|
|
||||||
}
|
|
||||||
SQLDialect dialect = getSqlDialect(servletContext);
|
|
||||||
createConnectionIfNull(externalContext, servletContext);
|
|
||||||
return new DefaultCloseableDSLContext(new DefaultConnectionProvider(connection), dialect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the database connection from the session map; if not found, create a new one and add it to the session map
|
|
||||||
*
|
|
||||||
* @param sessionMap
|
|
||||||
* the session map
|
|
||||||
* @param externalContext
|
|
||||||
* the external context
|
|
||||||
* @param servletContext
|
|
||||||
* the servlet context
|
|
||||||
* @return the connection
|
|
||||||
* @throws ClassNotFoundException
|
|
||||||
* on driver errors (e.g. missing jdbc lib)
|
|
||||||
* @throws SQLException
|
|
||||||
* on sql errors
|
|
||||||
*/
|
|
||||||
private void createConnectionIfNull(ExternalContext externalContext, ServletContext servletContext)
|
|
||||||
throws ClassNotFoundException, SQLException {
|
|
||||||
if (connection == null) { // caching the connection within the faces context makes it faster on the jsf life cycle
|
|
||||||
Map<String, Object> sessionMap = externalContext.getSessionMap();
|
|
||||||
if (sessionMap == null) {
|
|
||||||
throw new JooqFacesException("session map of current faces context is null");
|
|
||||||
}
|
|
||||||
DataSource dataSource = (DataSource) sessionMap.get(EJooqFacesSessionScope.CONNECTION.get());
|
|
||||||
if (dataSource == null || dataSource.getConnection() == null || dataSource.getConnection().isClosed()) {
|
|
||||||
LOGGER.debug("creating new connection pool");
|
|
||||||
dataSource = getDataSourceFromServletContext(servletContext);
|
|
||||||
externalContext.getSessionMap().put(EJooqFacesSessionScope.CONNECTION.get(), dataSource);
|
|
||||||
}
|
|
||||||
connection = dataSource.getConnection();
|
|
||||||
String autoCommit = servletContext.getInitParameter(EJooqFacesApplicationScope.JOOQ_FACES_PARAM_AUTOCOMMIT.get());
|
|
||||||
connection.setAutoCommit("true".equals(autoCommit)); // default false for postgreSQL, the database of my choice
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get data source from connection pool if defined in servlet context (see
|
|
||||||
* EJooqFacesApplicationScope.CONNECTION_POOL); if not defined, return a plain data source
|
|
||||||
*
|
|
||||||
* @param servletContext
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private static final DataSource getDataSourceFromServletContext(ServletContext servletContext)
|
|
||||||
throws ClassNotFoundException {
|
|
||||||
String driver = getDriver(servletContext);
|
|
||||||
if (driver == null) {
|
|
||||||
throw new JooqFacesException(
|
|
||||||
"undefined driver in application scope, define it in your web.xml's context-param on name "
|
|
||||||
+ EJooqFacesApplicationScope.JOOQ_FACES_DRIVER.get());
|
|
||||||
}
|
|
||||||
String url = getUrl(servletContext);
|
|
||||||
if (url == null) {
|
|
||||||
throw new JooqFacesException(
|
|
||||||
"undefined connection data url in application scope, define it in your web.xml's context-param on name "
|
|
||||||
+ EJooqFacesApplicationScope.JOOQ_FACES_URL.get());
|
|
||||||
}
|
|
||||||
Integer maxPoolSize = getMaxPoolSize(servletContext);
|
|
||||||
if (maxPoolSize == null) {
|
|
||||||
LOGGER.debug("maxPoolSize not set, setting it to 20");
|
|
||||||
maxPoolSize = 20;
|
|
||||||
}
|
|
||||||
String connectionPool = getConnectionPool(servletContext);
|
|
||||||
if (connectionPool == null) {
|
|
||||||
LOGGER.warn(
|
|
||||||
"no connection pool set in servlet context (see EJooqFacesApplicationScope.JOOQ_FACES_CONNECTIONPOOL), using plain connection");
|
|
||||||
}
|
|
||||||
return new PoollessDataSource(driver, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the connection from the servlet context
|
|
||||||
*
|
|
||||||
* @param servletContext
|
|
||||||
* the servlet context
|
|
||||||
* @return the connection
|
|
||||||
* @throws ClassNotFoundException
|
|
||||||
* on driver errors (e.g. missing jdbc lib)
|
|
||||||
* @throws SQLException
|
|
||||||
* on sql errors
|
|
||||||
*/
|
|
||||||
private static final Connection getConnectionFromServletContext(ServletContext servletContext)
|
|
||||||
throws ClassNotFoundException, SQLException {
|
|
||||||
DataSource dataSource = getDataSourceFromServletContext(servletContext);
|
|
||||||
return dataSource.getConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get a jooq connection from servlet context (for such cases as the deployment phase where the faces context is still
|
|
||||||
* not available)
|
|
||||||
*
|
|
||||||
* @param servletContext
|
|
||||||
* the servlet context
|
|
||||||
* @return a jooq connection
|
|
||||||
* @throws ClassNotFoundException
|
|
||||||
* on driver errors (e.g. missing jdbc lib)
|
|
||||||
* @throws SQLException
|
|
||||||
* on sql errors
|
|
||||||
*/
|
|
||||||
public static final DSLContext getJooqFromServletContext(ServletContext servletContext)
|
|
||||||
throws ClassNotFoundException, SQLException {
|
|
||||||
SQLDialect dialect = getSqlDialect(servletContext);
|
|
||||||
Connection con = getConnectionFromServletContext(servletContext);
|
|
||||||
return DSL.using(con, dialect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addMessage(String clientId, FacesMessage message) {
|
|
||||||
facesContext.addMessage(clientId, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Application getApplication() {
|
|
||||||
return facesContext.getApplication();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<String> getClientIdsWithMessages() {
|
|
||||||
return facesContext.getClientIdsWithMessages();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ExternalContext getExternalContext() {
|
|
||||||
return facesContext.getExternalContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Severity getMaximumSeverity() {
|
|
||||||
return facesContext.getMaximumSeverity();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<FacesMessage> getMessages() {
|
|
||||||
return facesContext.getMessages();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<FacesMessage> getMessages(String clientId) {
|
|
||||||
return facesContext.getMessages(clientId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RenderKit getRenderKit() {
|
|
||||||
return facesContext.getRenderKit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getRenderResponse() {
|
|
||||||
return facesContext.getRenderResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getResponseComplete() {
|
|
||||||
|
|
||||||
return facesContext.getResponseComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResponseStream getResponseStream() {
|
|
||||||
return facesContext.getResponseStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResponseWriter getResponseWriter() {
|
|
||||||
return facesContext.getResponseWriter();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UIViewRoot getViewRoot() {
|
|
||||||
return facesContext.getViewRoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void release() {
|
|
||||||
facesContext.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderResponse() {
|
|
||||||
facesContext.renderResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void responseComplete() {
|
|
||||||
facesContext.responseComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setResponseStream(ResponseStream responseStream) {
|
|
||||||
facesContext.setResponseStream(responseStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setResponseWriter(ResponseWriter responseWriter) {
|
|
||||||
facesContext.setResponseWriter(responseWriter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setViewRoot(UIViewRoot root) {
|
|
||||||
facesContext.setViewRoot(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the connection pool from initial context
|
|
||||||
*
|
|
||||||
* @param servletContext
|
|
||||||
* the context
|
|
||||||
* @return the connection pool string or null
|
|
||||||
*/
|
|
||||||
private static final String getConnectionPool(ServletContext servletContext) {
|
|
||||||
return servletContext.getInitParameter(EJooqFacesApplicationScope.JOOQ_FACES_CONNECTIONPOOL.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the max pool size from initial context if any
|
|
||||||
*
|
|
||||||
* @param servletContext
|
|
||||||
* the context of this function call
|
|
||||||
* @return the max pool size or null
|
|
||||||
*/
|
|
||||||
private static final Integer getMaxPoolSize(ServletContext servletContext) {
|
|
||||||
String maxPoolSize = servletContext.getInitParameter(EJooqFacesApplicationScope.JOOQ_FACES_MAXPOOLSIZE.get());
|
|
||||||
return maxPoolSize == null ? null : Integer.valueOf(maxPoolSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get driver from initial context
|
|
||||||
*
|
|
||||||
* @param servletContext
|
|
||||||
* the context of this function call
|
|
||||||
* @return the parameter value of the jooq faces driver
|
|
||||||
*/
|
|
||||||
private static final String getDriver(ServletContext servletContext) {
|
|
||||||
return servletContext.getInitParameter(EJooqFacesApplicationScope.JOOQ_FACES_DRIVER.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get driver connection url from initial context
|
|
||||||
*
|
|
||||||
* @param servletContext
|
|
||||||
* the context of this function call
|
|
||||||
* @return the parameter value of the jooq faces url
|
|
||||||
*/
|
|
||||||
private static final String getUrl(ServletContext servletContext) {
|
|
||||||
return servletContext.getInitParameter(EJooqFacesApplicationScope.JOOQ_FACES_URL.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* find jooq sql dialect class for dialectName
|
|
||||||
*
|
|
||||||
* @param dialectName
|
|
||||||
* name of dialect
|
|
||||||
* @return SQLDialect if found, null otherwise
|
|
||||||
*/
|
|
||||||
private static final SQLDialect findDialect(String dialectName) {
|
|
||||||
if (dialectName == null) {
|
|
||||||
LOGGER.error("Sql dialect name is null");
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
for (SQLDialect dialect : SQLDialect.values()) {
|
|
||||||
LOGGER.trace("Sql dialect comparing: dialectName={}, loopDialect={}", dialectName, dialect);
|
|
||||||
if (dialectName.equalsIgnoreCase(dialect.name())) {
|
|
||||||
LOGGER.debug("Sql dialect found: dialectName={}, foundDialect={}", dialectName, dialect);
|
|
||||||
return dialect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOGGER.error("Sql dialect not found: dialectName={}", dialectName);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get jooq sql dialect from initial context
|
|
||||||
*
|
|
||||||
* @param servletContext
|
|
||||||
* the context of this function call
|
|
||||||
* @return the dialect or null
|
|
||||||
*/
|
|
||||||
private static final SQLDialect getSqlDialect(ServletContext servletContext) {
|
|
||||||
String dialectName = servletContext.getInitParameter(EJooqFacesApplicationScope.JOOQ_FACES_SQLDIALECT.get());
|
|
||||||
return getSqlDialect(dialectName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get sql dialect from name
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* the dialect name
|
|
||||||
* @return the dialect or null
|
|
||||||
*/
|
|
||||||
public static final SQLDialect getSqlDialect(String name) {
|
|
||||||
return findDialect(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package de.jooqfaces;
|
|
||||||
|
|
||||||
import javax.faces.*;
|
|
||||||
import javax.faces.context.*;
|
|
||||||
import javax.faces.lifecycle.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author jotty
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class JooqFacesContextFactory extends FacesContextFactory {
|
|
||||||
|
|
||||||
private FacesContextFactory facesContextFactory;
|
|
||||||
|
|
||||||
public JooqFacesContextFactory(FacesContextFactory facesContextFactory) {
|
|
||||||
this.facesContextFactory = facesContextFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FacesContext getFacesContext(Object context, Object request, Object response, Lifecycle lifecycle)
|
|
||||||
throws FacesException {
|
|
||||||
FacesContext facesContext = facesContextFactory.getFacesContext(context, request, response, lifecycle);
|
|
||||||
return new JooqFacesContext(facesContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package de.jooqfaces;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author jotty
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class JooqFacesException extends RuntimeException {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public JooqFacesException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JooqFacesException(Exception e) {
|
|
||||||
super(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package de.jooqfaces;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.sql.*;
|
|
||||||
import java.util.logging.*;
|
|
||||||
|
|
||||||
import javax.sql.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author jotty
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class PoollessDataSource implements DataSource {
|
|
||||||
|
|
||||||
private final String driver;
|
|
||||||
private final String url;
|
|
||||||
|
|
||||||
public PoollessDataSource(String driver, String url) {
|
|
||||||
this.driver = driver;
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PrintWriter getLogWriter() throws SQLException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLoginTimeout() throws SQLException {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setLogWriter(PrintWriter out) throws SQLException {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setLoginTimeout(int seconds) throws SQLException {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isWrapperFor(Class<?> iface) throws SQLException {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Connection getConnection() throws SQLException {
|
|
||||||
try {
|
|
||||||
Class.forName(driver);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
throw new SQLException(e);
|
|
||||||
}
|
|
||||||
return DriverManager.getConnection(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Connection getConnection(String username, String password) throws SQLException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
package de.jooqfaces;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.sql.*;
|
|
||||||
import java.util.*;import javax.servlet.*;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author henkej
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class PropertiesDeploymentListener implements ServletContextListener {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(PropertiesDeploymentListener.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void contextDestroyed(ServletContextEvent event) {
|
|
||||||
try {
|
|
||||||
Enumeration<Driver> drivers = DriverManager.getDrivers();
|
|
||||||
while (drivers.hasMoreElements()) {
|
|
||||||
DriverManager.deregisterDriver(drivers.nextElement());
|
|
||||||
}
|
|
||||||
} catch (SQLException | SecurityException e) {
|
|
||||||
LOGGER.error("Error deregistering drivers", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void contextInitialized(ServletContextEvent event) {
|
|
||||||
try {
|
|
||||||
ServletContext ctx = event.getServletContext();
|
|
||||||
beforeInitialization(ctx);
|
|
||||||
String propertiesFileName = (String) ctx.getInitParameter(EJooqFacesApplicationScope.JOOQ_FACES_PROPERTIES.get());
|
|
||||||
if (propertiesFileName == null) {
|
|
||||||
throw new IOException(
|
|
||||||
"undefined properties file name in application scope, define it in your web.xml's context-param on name "
|
|
||||||
+ EJooqFacesApplicationScope.JOOQ_FACES_PROPERTIES.get());
|
|
||||||
}
|
|
||||||
Properties properties = new Properties();
|
|
||||||
properties.load(new FileInputStream(propertiesFileName));
|
|
||||||
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
|
|
||||||
String key = (String) entry.getKey();
|
|
||||||
String value = (String) entry.getValue();
|
|
||||||
ctx.setInitParameter(key, value);
|
|
||||||
}
|
|
||||||
// ensure to have all needed parameters loaded
|
|
||||||
if (ctx.getInitParameter(EJooqFacesApplicationScope.JOOQ_FACES_SQLDIALECT.get()) == null) {
|
|
||||||
throw new IOException("no " + EJooqFacesApplicationScope.JOOQ_FACES_SQLDIALECT.get()
|
|
||||||
+ " defined in your properties file " + propertiesFileName);
|
|
||||||
}
|
|
||||||
if (ctx.getInitParameter(EJooqFacesApplicationScope.JOOQ_FACES_URL.get()) == null) {
|
|
||||||
throw new IOException("no " + EJooqFacesApplicationScope.JOOQ_FACES_URL.get() + " defined in your properties file "
|
|
||||||
+ propertiesFileName);
|
|
||||||
}
|
|
||||||
if (ctx.getInitParameter(EJooqFacesApplicationScope.JOOQ_FACES_DRIVER.get()) == null) {
|
|
||||||
throw new IOException("no " + EJooqFacesApplicationScope.JOOQ_FACES_DRIVER.get()
|
|
||||||
+ " defined in your properties file " + propertiesFileName);
|
|
||||||
}
|
|
||||||
afterInitialization(ctx);
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.error("Error loading needed parameters from properties file", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* executed directly after initialization if no exception is thrown
|
|
||||||
*
|
|
||||||
* @param ctx
|
|
||||||
* the context to use
|
|
||||||
* @throws IOException
|
|
||||||
* for input output exceptions
|
|
||||||
*/
|
|
||||||
public void afterInitialization(ServletContext ctx) throws IOException {
|
|
||||||
// to be implemented in extending classes
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* executed directly before initialization after getting the context from the servlet
|
|
||||||
*
|
|
||||||
* @param ctx
|
|
||||||
* the context to use
|
|
||||||
* @throws IOException
|
|
||||||
* for input output exceptions
|
|
||||||
*/
|
|
||||||
public void beforeInitialization(ServletContext ctx) throws IOException {
|
|
||||||
// to be implemented in extending classes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package de.jottyfan.timetrack;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableTransactionManagement
|
||||||
|
public class TimetrackApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(TimetrackApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package de.jottyfan.timetrack.config;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.jooq.SQLDialect;
|
||||||
|
import org.jooq.impl.DataSourceConnectionProvider;
|
||||||
|
import org.jooq.impl.DefaultConfiguration;
|
||||||
|
import org.jooq.impl.DefaultDSLContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author henkej
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class InitialConfiguration {
|
||||||
|
@Autowired
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSourceConnectionProvider connectionProvider() {
|
||||||
|
return new DataSourceConnectionProvider(new TransactionAwareDataSourceProxy(dataSource));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DefaultDSLContext dsl() {
|
||||||
|
return new DefaultDSLContext(configuration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultConfiguration configuration() {
|
||||||
|
DefaultConfiguration jooqConfiguration = new DefaultConfiguration();
|
||||||
|
jooqConfiguration.set(connectionProvider());
|
||||||
|
jooqConfiguration.set(SQLDialect.POSTGRES);
|
||||||
|
// jooqConfiguration.set(new DefaultExecuteListenerProvider(exceptionTransformer()));
|
||||||
|
return jooqConfiguration;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package de.jottyfan.timetrack.config;
|
||||||
|
|
||||||
|
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
|
||||||
|
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
|
||||||
|
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
|
||||||
|
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
|
||||||
|
import org.keycloak.adapters.springsecurity.management.HttpSessionManager;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
|
||||||
|
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||||
|
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
|
||||||
|
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||||
|
|
||||||
|
@KeycloakConfiguration
|
||||||
|
@ComponentScan(basePackageClasses = KeycloakSpringBootConfigResolver.class)
|
||||||
|
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
|
||||||
|
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
|
||||||
|
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
|
||||||
|
auth.authenticationProvider(keycloakAuthenticationProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
|
||||||
|
return new KeycloakSpringBootConfigResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Override
|
||||||
|
@ConditionalOnMissingBean(HttpSessionManager.class)
|
||||||
|
protected HttpSessionManager httpSessionManager() {
|
||||||
|
return new HttpSessionManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Override
|
||||||
|
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
|
||||||
|
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
super.configure(http);
|
||||||
|
http.authorizeRequests().antMatchers("/public/**").permitAll();
|
||||||
|
http.csrf().disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.help;
|
|
||||||
|
|
||||||
public enum Application
|
|
||||||
{
|
|
||||||
CONNECTION("connection");
|
|
||||||
|
|
||||||
private final String value;
|
|
||||||
|
|
||||||
private Application(String value)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String get()
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.help;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
import javax.servlet.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author henkej
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class EncodingFilter implements Filter
|
|
||||||
{
|
|
||||||
private String encoding;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
|
|
||||||
{
|
|
||||||
servletRequest.setCharacterEncoding(encoding);
|
|
||||||
filterChain.doFilter(servletRequest, servletResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(FilterConfig filterConfig) throws ServletException
|
|
||||||
{
|
|
||||||
encoding = filterConfig.getInitParameter("encoding");
|
|
||||||
if (encoding == null)
|
|
||||||
{
|
|
||||||
encoding = "UTF-8";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.help;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
|
|
||||||
import javax.faces.component.UIComponent;
|
|
||||||
import javax.faces.context.FacesContext;
|
|
||||||
import javax.faces.convert.Converter;
|
|
||||||
import javax.faces.convert.ConverterException;
|
|
||||||
import javax.faces.convert.FacesConverter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author jotty
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@FacesConverter("de.jottyfan.timetrack.help.LocalDateConverter")
|
|
||||||
public class LocalDateConverter implements Converter<LocalDate> {
|
|
||||||
|
|
||||||
protected final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd.MM.yyyy");
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LocalDate getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException {
|
|
||||||
return LocalDate.from(dtf.parse(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAsString(FacesContext context, UIComponent component, LocalDate value) throws ConverterException {
|
|
||||||
return value.format(dtf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package de.jottyfan.timetrack.help;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.info.BuildProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author henkej
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ManifestBean {
|
||||||
|
|
||||||
|
@Value("${server.servlet.context-path:}")
|
||||||
|
private String contextPath;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private BuildProperties buildProperties;
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
buf.append("Version ");
|
||||||
|
buf.append(buildProperties == null ? "?" : buildProperties.getVersion());
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContextPath() {
|
||||||
|
return (contextPath != null && !contextPath.isBlank()) ? String.format("/%s/", contextPath) : "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.help;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author henkej
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public abstract class Navigation
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* navigate to page referenced by p
|
|
||||||
*
|
|
||||||
* @param p
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String navigateTo(Pages p)
|
|
||||||
{
|
|
||||||
return p.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.help;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author henkej
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public enum Pages
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* contact list
|
|
||||||
*/
|
|
||||||
CONTACT_LIST("/pages/contact/list.jsf"),
|
|
||||||
/**
|
|
||||||
* contact item
|
|
||||||
*/
|
|
||||||
CONTACT_ITEM("/pages/contact/item.jsf"),
|
|
||||||
/**
|
|
||||||
* note list
|
|
||||||
*/
|
|
||||||
NOTE_LIST("/pages/note/list.jsf"),
|
|
||||||
/**
|
|
||||||
* note item
|
|
||||||
*/
|
|
||||||
NOTE_ITEM("/pages/note/item.jsf"),
|
|
||||||
/**
|
|
||||||
* todo list
|
|
||||||
*/
|
|
||||||
TODO_LIST("/pages/todo/list.jsf"),
|
|
||||||
/**
|
|
||||||
* todo item
|
|
||||||
*/
|
|
||||||
TODO_ITEM("/pages/todo/item.jsf"),
|
|
||||||
/**
|
|
||||||
* done init
|
|
||||||
*/
|
|
||||||
DONE_INIT("/pages/done/init.jsf"),
|
|
||||||
/**
|
|
||||||
* done edit
|
|
||||||
*/
|
|
||||||
DONE_EDIT("/pages/done/edit.jsf"),
|
|
||||||
/**
|
|
||||||
* done delete
|
|
||||||
*/
|
|
||||||
DONE_DELETE("/pages/done/delete.jsf"),
|
|
||||||
/**
|
|
||||||
* done add
|
|
||||||
*/
|
|
||||||
DONE_ADD("/pages/done/add.jsf"),
|
|
||||||
/**
|
|
||||||
* done clear
|
|
||||||
*/
|
|
||||||
DONE_CLEAR("/pages/done/clear.jsf"),
|
|
||||||
/**
|
|
||||||
* done read
|
|
||||||
*/
|
|
||||||
DONE_READ("/pages/done/read.jsf"),
|
|
||||||
/**
|
|
||||||
* organize init
|
|
||||||
*/
|
|
||||||
ORGANIZE_LIST("/pages/organize/list.jsf"),
|
|
||||||
/**
|
|
||||||
* organize week
|
|
||||||
*/
|
|
||||||
ORGANIZE_WEEK("/pages/organize/week.jsf"),
|
|
||||||
/**
|
|
||||||
* organize delete
|
|
||||||
*/
|
|
||||||
ORGANIZE_DELETE("/pages/organize/delete.jsf"),
|
|
||||||
/**
|
|
||||||
* organize add
|
|
||||||
*/
|
|
||||||
ORGANIZE_ADD("/pages/organize/add.jsf"),
|
|
||||||
/**
|
|
||||||
* organize edit
|
|
||||||
*/
|
|
||||||
ORGANIZE_EDIT("/pages/organize/edit.jsf"),
|
|
||||||
/**
|
|
||||||
* start
|
|
||||||
*/
|
|
||||||
START("/pages/start.jsf");
|
|
||||||
|
|
||||||
private final String value;
|
|
||||||
|
|
||||||
private Pages(String value)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String get()
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.help;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.enterprise.context.SessionScoped;
|
|
||||||
import javax.inject.Named;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author henkej
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Named
|
|
||||||
@SessionScoped
|
|
||||||
public class ThemeBean implements Serializable
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private String currentTheme;
|
|
||||||
|
|
||||||
public List<String> getValidThemes(){
|
|
||||||
List<String> list = new ArrayList<>();
|
|
||||||
list.add("cerulean");
|
|
||||||
list.add("cosmo");
|
|
||||||
list.add("cyborg");
|
|
||||||
list.add("darkly");
|
|
||||||
list.add("default");
|
|
||||||
list.add("flatly");
|
|
||||||
list.add("journal");
|
|
||||||
list.add("lumen");
|
|
||||||
list.add("other");
|
|
||||||
list.add("paper");
|
|
||||||
list.add("patternfly");
|
|
||||||
list.add("readable");
|
|
||||||
list.add("sandstone");
|
|
||||||
list.add("simplex");
|
|
||||||
list.add("slate");
|
|
||||||
list.add("spacelab");
|
|
||||||
list.add("superhero");
|
|
||||||
list.add("united");
|
|
||||||
list.add("yeti");
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCurrentTheme(String currentTheme)
|
|
||||||
{
|
|
||||||
this.currentTheme = currentTheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* contains current theme for web.xml's theme chooser
|
|
||||||
*
|
|
||||||
* @return current theme
|
|
||||||
*/
|
|
||||||
public String getCurrentTheme()
|
|
||||||
{
|
|
||||||
return currentTheme == null ? "default" : (getValidThemes().contains(currentTheme) ? currentTheme : "default");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.modules.contact;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
|
||||||
import javax.faces.context.FacesContext;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
|
||||||
|
|
||||||
import de.jooqfaces.JooqFacesContext;
|
|
||||||
import de.jottyfan.timetrack.help.Navigation;
|
|
||||||
import de.jottyfan.timetrack.help.Pages;
|
|
||||||
import de.jottyfan.timetrack.modules.ControlInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author jotty
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Named
|
|
||||||
@RequestScoped
|
|
||||||
public class ContactControl extends Navigation implements ControlInterface, Serializable {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
@Named("contactModel")
|
|
||||||
private ContactModel model;
|
|
||||||
|
|
||||||
public String toStart() {
|
|
||||||
return navigateTo(Pages.START);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toList() {
|
|
||||||
boolean ready = model.init((JooqFacesContext) FacesContext.getCurrentInstance());
|
|
||||||
return ready ? navigateTo(Pages.CONTACT_LIST) : toStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toItem(ContactBean bean) {
|
|
||||||
model.setBean(bean);
|
|
||||||
return navigateTo(Pages.CONTACT_ITEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toItem() {
|
|
||||||
model.setBean(new ContactBean(null));
|
|
||||||
return navigateTo(Pages.CONTACT_ITEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String doAdd() {
|
|
||||||
boolean ready = model.add((JooqFacesContext) FacesContext.getCurrentInstance());
|
|
||||||
return ready ? toList() : navigateTo(Pages.CONTACT_ITEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String doUpdate() {
|
|
||||||
boolean ready = model.update((JooqFacesContext) FacesContext.getCurrentInstance());
|
|
||||||
return ready ? toList() : navigateTo(Pages.CONTACT_ITEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String doDelete() {
|
|
||||||
boolean ready = model.delete((JooqFacesContext) FacesContext.getCurrentInstance());
|
|
||||||
return ready ? toList() : navigateTo(Pages.CONTACT_ITEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getAmount() {
|
|
||||||
return model.getAmount((JooqFacesContext) FacesContext.getCurrentInstance());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.modules.contact;
|
|
||||||
|
|
||||||
import static de.jottyfan.timetrack.db.contact.Tables.T_CONTACT;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.jooq.CloseableDSLContext;
|
|
||||||
import org.jooq.DeleteConditionStep;
|
|
||||||
import org.jooq.InsertValuesStep4;
|
|
||||||
import org.jooq.Record1;
|
|
||||||
import org.jooq.Record5;
|
|
||||||
import org.jooq.SelectJoinStep;
|
|
||||||
import org.jooq.UpdateConditionStep;
|
|
||||||
import org.jooq.exception.DataAccessException;
|
|
||||||
import org.jooq.impl.DSL;
|
|
||||||
|
|
||||||
import de.jooqfaces.JooqFacesContext;
|
|
||||||
import de.jottyfan.timetrack.db.contact.enums.EnumContacttype;
|
|
||||||
import de.jottyfan.timetrack.db.contact.tables.records.TContactRecord;
|
|
||||||
import de.jottyfan.timetrack.modules.JooqGateway;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author jotty
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ContactGateway extends JooqGateway {
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(ContactGateway.class);
|
|
||||||
|
|
||||||
public ContactGateway(JooqFacesContext facesContext) {
|
|
||||||
super(facesContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get sorted list of contacts
|
|
||||||
*
|
|
||||||
* @return a list (an empty one at least)
|
|
||||||
* @throws SQLException
|
|
||||||
* @throws ClassNotFoundException
|
|
||||||
* @throws DataAccessException
|
|
||||||
*/
|
|
||||||
public List<ContactBean> getAll() throws DataAccessException, ClassNotFoundException, SQLException {
|
|
||||||
try (CloseableDSLContext jooq = getJooq()) {
|
|
||||||
SelectJoinStep<Record5<Integer, String, String, String, EnumContacttype>> sql = jooq
|
|
||||||
// @formatter:off
|
|
||||||
.select(T_CONTACT.PK,
|
|
||||||
T_CONTACT.FORENAME,
|
|
||||||
T_CONTACT.SURNAME,
|
|
||||||
T_CONTACT.CONTACT,
|
|
||||||
T_CONTACT.TYPE)
|
|
||||||
.from(T_CONTACT);
|
|
||||||
// @formatter:on
|
|
||||||
LOGGER.debug("{}", sql.toString());
|
|
||||||
List<ContactBean> list = new ArrayList<>();
|
|
||||||
for (Record5<Integer, String, String, String, EnumContacttype> r : sql.fetch()) {
|
|
||||||
ContactBean bean = new ContactBean(r.get(T_CONTACT.PK));
|
|
||||||
bean.setForename(r.get(T_CONTACT.FORENAME));
|
|
||||||
bean.setSurname(r.get(T_CONTACT.SURNAME));
|
|
||||||
bean.setContact(r.get(T_CONTACT.CONTACT));
|
|
||||||
bean.setType(r.get(T_CONTACT.TYPE));
|
|
||||||
list.add(bean);
|
|
||||||
}
|
|
||||||
list.sort((o1, o2) -> o1 == null ? 0 : o1.compareTo(o2));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* delete a contact from the database
|
|
||||||
*
|
|
||||||
* @param pk
|
|
||||||
* the id of the contact
|
|
||||||
* @return the number of affected database rows, should be 1
|
|
||||||
* @throws SQLException
|
|
||||||
* @throws ClassNotFoundException
|
|
||||||
* @throws DataAccessException
|
|
||||||
*/
|
|
||||||
public Integer delete(Integer pk) throws DataAccessException, ClassNotFoundException, SQLException {
|
|
||||||
try (CloseableDSLContext jooq = getJooq()) {
|
|
||||||
DeleteConditionStep<TContactRecord> sql = jooq
|
|
||||||
// @formatter:off
|
|
||||||
.deleteFrom(T_CONTACT)
|
|
||||||
.where(T_CONTACT.PK.eq(pk));
|
|
||||||
// @formatter:on
|
|
||||||
LOGGER.debug("{}", sql.toString());
|
|
||||||
return sql.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* add a contact to the database
|
|
||||||
*
|
|
||||||
* @param bean
|
|
||||||
* the contact information
|
|
||||||
* @return the number of affected database rows, should be 1
|
|
||||||
* @throws SQLException
|
|
||||||
* @throws ClassNotFoundException
|
|
||||||
* @throws DataAccessException
|
|
||||||
*/
|
|
||||||
public Integer add(ContactBean bean) throws DataAccessException, ClassNotFoundException, SQLException {
|
|
||||||
try (CloseableDSLContext jooq = getJooq()) {
|
|
||||||
InsertValuesStep4<TContactRecord, String, String, String, EnumContacttype> sql = jooq
|
|
||||||
// @formatter:off
|
|
||||||
.insertInto(T_CONTACT,
|
|
||||||
T_CONTACT.FORENAME,
|
|
||||||
T_CONTACT.SURNAME,
|
|
||||||
T_CONTACT.CONTACT,
|
|
||||||
T_CONTACT.TYPE)
|
|
||||||
.values(bean.getForename(), bean.getSurname(), bean.getContact(), bean.getType());
|
|
||||||
// @formatter:on
|
|
||||||
LOGGER.debug("{}", sql.toString());
|
|
||||||
return sql.execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* update a contact in the database, referencing its pk
|
|
||||||
*
|
|
||||||
* @param bean
|
|
||||||
* the contact information
|
|
||||||
* @return the number of affected database rows, should be 1
|
|
||||||
* @throws SQLException
|
|
||||||
* @throws ClassNotFoundException
|
|
||||||
* @throws DataAccessException
|
|
||||||
*/
|
|
||||||
public Integer update(ContactBean bean) throws DataAccessException, ClassNotFoundException, SQLException {
|
|
||||||
try (CloseableDSLContext jooq = getJooq()) {
|
|
||||||
UpdateConditionStep<TContactRecord> sql = jooq
|
|
||||||
// @formatter:off
|
|
||||||
.update(T_CONTACT)
|
|
||||||
.set(T_CONTACT.FORENAME, bean.getForename())
|
|
||||||
.set(T_CONTACT.SURNAME, bean.getSurname())
|
|
||||||
.set(T_CONTACT.CONTACT, bean.getContact())
|
|
||||||
.set(T_CONTACT.TYPE, bean.getType())
|
|
||||||
.where(T_CONTACT.PK.eq(bean.getPk()));
|
|
||||||
// @formatter:on
|
|
||||||
LOGGER.debug("{}", sql.toString());
|
|
||||||
return sql.execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get number of entries in t_contact
|
|
||||||
*
|
|
||||||
* @return number of entries
|
|
||||||
* @throws SQLException
|
|
||||||
* @throws ClassNotFoundException
|
|
||||||
* @throws DataAccessException
|
|
||||||
*/
|
|
||||||
public Integer getAmount() throws DataAccessException, ClassNotFoundException, SQLException {
|
|
||||||
try (CloseableDSLContext jooq = getJooq()) {
|
|
||||||
SelectJoinStep<Record1<Integer>> sql = jooq
|
|
||||||
// @formatter:off
|
|
||||||
.selectCount()
|
|
||||||
.from(T_CONTACT);
|
|
||||||
// @formatter:on
|
|
||||||
LOGGER.debug("{}", sql.toString());
|
|
||||||
return sql.fetchOne(DSL.count());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get all enum types
|
|
||||||
*
|
|
||||||
* @return list of enum types
|
|
||||||
*/
|
|
||||||
public List<EnumContacttype> getTypes() {
|
|
||||||
return new ArrayList<>(Arrays.asList(EnumContacttype.values()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.modules.contact;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.enterprise.context.SessionScoped;
|
|
||||||
import javax.faces.application.FacesMessage;
|
|
||||||
import javax.inject.Named;
|
|
||||||
|
|
||||||
import org.jooq.exception.DataAccessException;
|
|
||||||
|
|
||||||
import de.jooqfaces.JooqFacesContext;
|
|
||||||
import de.jottyfan.timetrack.db.contact.enums.EnumContacttype;
|
|
||||||
import de.jottyfan.timetrack.modules.Model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author jotty
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Named
|
|
||||||
@SessionScoped
|
|
||||||
public class ContactModel implements Model, Serializable {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private ContactBean bean;
|
|
||||||
private List<ContactBean> list;
|
|
||||||
private List<EnumContacttype> types;
|
|
||||||
|
|
||||||
public boolean init(JooqFacesContext facesContext) {
|
|
||||||
bean = new ContactBean(null);
|
|
||||||
try {
|
|
||||||
ContactGateway gw = new ContactGateway(facesContext);
|
|
||||||
list = gw.getAll();
|
|
||||||
types = gw.getTypes();
|
|
||||||
return true;
|
|
||||||
} catch (DataAccessException | ClassNotFoundException | SQLException e) {
|
|
||||||
facesContext.addMessage(null,
|
|
||||||
new FacesMessage(FacesMessage.SEVERITY_ERROR, "error on loading data from db", e.getMessage()));
|
|
||||||
list = new ArrayList<>();
|
|
||||||
types = new ArrayList<>();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean delete(JooqFacesContext facesContext) {
|
|
||||||
try {
|
|
||||||
Integer affected = new ContactGateway(facesContext).delete(bean.getPk());
|
|
||||||
return affected.equals(1);
|
|
||||||
} catch (DataAccessException | ClassNotFoundException | SQLException e) {
|
|
||||||
facesContext.addMessage(null,
|
|
||||||
new FacesMessage(FacesMessage.SEVERITY_ERROR, "error on deleting data from db", e.getMessage()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(JooqFacesContext facesContext) {
|
|
||||||
try {
|
|
||||||
Integer affected = new ContactGateway(facesContext).add(bean);
|
|
||||||
return affected.equals(1);
|
|
||||||
} catch (DataAccessException | ClassNotFoundException | SQLException e) {
|
|
||||||
facesContext.addMessage(null,
|
|
||||||
new FacesMessage(FacesMessage.SEVERITY_ERROR, "error on adding data to db", e.getMessage()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean update(JooqFacesContext facesContext) {
|
|
||||||
try {
|
|
||||||
Integer affected = new ContactGateway(facesContext).update(bean);
|
|
||||||
return affected.equals(1);
|
|
||||||
} catch (DataAccessException | ClassNotFoundException | SQLException e) {
|
|
||||||
facesContext.addMessage(null,
|
|
||||||
new FacesMessage(FacesMessage.SEVERITY_ERROR, "error on updating data to db", e.getMessage()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getAmount(JooqFacesContext facesContext) {
|
|
||||||
try {
|
|
||||||
return new ContactGateway(facesContext).getAmount();
|
|
||||||
} catch (DataAccessException | ClassNotFoundException | SQLException e) {
|
|
||||||
facesContext.addMessage(null,
|
|
||||||
new FacesMessage(FacesMessage.SEVERITY_ERROR, "error on getting size of contacts", e.getMessage()));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ContactBean> getList() {
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBean(ContactBean bean) {
|
|
||||||
this.bean = bean;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ContactBean getBean() {
|
|
||||||
return bean;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<EnumContacttype> getTypes() {
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTypes(List<EnumContacttype> types) {
|
|
||||||
this.types = types;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-3
@@ -1,16 +1,15 @@
|
|||||||
package de.jottyfan.timetrack.modules.contact;
|
package de.jottyfan.timetrack.spring.contact;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import de.jottyfan.timetrack.db.contact.enums.EnumContacttype;
|
import de.jottyfan.timetrack.db.contact.enums.EnumContacttype;
|
||||||
import de.jottyfan.timetrack.modules.Bean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author jotty
|
* @author jotty
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class ContactBean implements Bean, Serializable, Comparable<ContactBean> {
|
public class ContactBean implements Serializable, Comparable<ContactBean> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final Integer pk;
|
private final Integer pk;
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package de.jottyfan.timetrack.spring.contact;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.security.RolesAllowed;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author henkej
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
public class ContactController {
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(ContactController.class);
|
||||||
|
|
||||||
|
private final HttpServletRequest request;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IContactService contactService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ContactController(HttpServletRequest request) {
|
||||||
|
this.request = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/logout")
|
||||||
|
public String getLogout(HttpServletRequest request) throws ServletException {
|
||||||
|
request.logout();
|
||||||
|
return "redirect:/";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/")
|
||||||
|
public String getIndex() {
|
||||||
|
return "public/index";
|
||||||
|
}
|
||||||
|
|
||||||
|
@ModelAttribute("currentUser")
|
||||||
|
@ResponseBody
|
||||||
|
public String getCurrentUser() {
|
||||||
|
return contactService.getCurrentUser(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("timetrack_user")
|
||||||
|
@RequestMapping(value = "/contact/contacts")
|
||||||
|
public String getList(Model model, @ModelAttribute ContactBean bean) {
|
||||||
|
List<ContactBean> list = contactService.toList();
|
||||||
|
model.addAttribute("contactList", list);
|
||||||
|
return "contact/contacts";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("timetrack_user")
|
||||||
|
@RequestMapping(value = "/contact/add/")
|
||||||
|
public String toAdd(Model model) {
|
||||||
|
return "contact/item";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("timetrack_user")
|
||||||
|
@RequestMapping(value = "/contact/insert", method = RequestMethod.POST)
|
||||||
|
public String doInsert(Model model, @ModelAttribute ContactBean bean) {
|
||||||
|
Integer amount = contactService.doInsert(bean);
|
||||||
|
return amount.equals(1) ? "contact/contacts" : "concact/item";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("timetrack_user")
|
||||||
|
@GetMapping("/contact/edit/{id}")
|
||||||
|
public String toEdit(@PathVariable Integer id, Model model) {
|
||||||
|
return "not yet implemented";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("timetrack_user")
|
||||||
|
@RequestMapping(value = "/contact/delete/")
|
||||||
|
public String doDelete(Model model, @ModelAttribute ContactBean bean) {
|
||||||
|
Integer amount = contactService.doDelete(bean.getPk());
|
||||||
|
return amount.equals(1) ? "contact/contacts" : "contact/contacts";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package de.jottyfan.timetrack.spring.contact;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author henkej
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface IContactService {
|
||||||
|
public List<ContactBean> toList();
|
||||||
|
public Integer doInsert(ContactBean bean);
|
||||||
|
public Integer doUdate(ContactBean bean);
|
||||||
|
public Integer doDelete(Integer pk);
|
||||||
|
public Integer getAmount();
|
||||||
|
public String getCurrentUser(HttpServletRequest request);
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
package de.jottyfan.timetrack.spring.contact.impl;
|
||||||
|
|
||||||
|
import static de.jottyfan.timetrack.db.contact.Tables.T_CONTACT;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.jooq.DSLContext;
|
||||||
|
import org.jooq.DeleteConditionStep;
|
||||||
|
import org.jooq.InsertValuesStep4;
|
||||||
|
import org.jooq.Record1;
|
||||||
|
import org.jooq.Record5;
|
||||||
|
import org.jooq.SelectJoinStep;
|
||||||
|
import org.jooq.UpdateConditionStep;
|
||||||
|
import org.jooq.exception.DataAccessException;
|
||||||
|
import org.jooq.impl.DSL;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import de.jottyfan.timetrack.db.contact.enums.EnumContacttype;
|
||||||
|
import de.jottyfan.timetrack.db.contact.tables.records.TContactRecord;
|
||||||
|
import de.jottyfan.timetrack.spring.contact.ContactBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public class ContactGateway {
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(ContactGateway.class);
|
||||||
|
private final DSLContext jooq;
|
||||||
|
|
||||||
|
public ContactGateway(@Autowired DSLContext jooq) throws Exception {
|
||||||
|
this.jooq = jooq;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DSLContext getJooq() {
|
||||||
|
return this.jooq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get sorted list of contacts
|
||||||
|
*
|
||||||
|
* @return a list (an empty one at least)
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
* @throws DataAccessException
|
||||||
|
*/
|
||||||
|
public List<ContactBean> getAll() throws DataAccessException, ClassNotFoundException, SQLException {
|
||||||
|
SelectJoinStep<Record5<Integer, String, String, String, EnumContacttype>> sql = getJooq()
|
||||||
|
// @formatter:off
|
||||||
|
.select(T_CONTACT.PK,
|
||||||
|
T_CONTACT.FORENAME,
|
||||||
|
T_CONTACT.SURNAME,
|
||||||
|
T_CONTACT.CONTACT,
|
||||||
|
T_CONTACT.TYPE)
|
||||||
|
.from(T_CONTACT);
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql.toString());
|
||||||
|
List<ContactBean> list = new ArrayList<>();
|
||||||
|
for (Record5<Integer, String, String, String, EnumContacttype> r : sql.fetch()) {
|
||||||
|
ContactBean bean = new ContactBean(r.get(T_CONTACT.PK));
|
||||||
|
bean.setForename(r.get(T_CONTACT.FORENAME));
|
||||||
|
bean.setSurname(r.get(T_CONTACT.SURNAME));
|
||||||
|
bean.setContact(r.get(T_CONTACT.CONTACT));
|
||||||
|
bean.setType(r.get(T_CONTACT.TYPE));
|
||||||
|
list.add(bean);
|
||||||
|
}
|
||||||
|
list.sort((o1, o2) -> o1 == null ? 0 : o1.compareTo(o2));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete a contact from the database
|
||||||
|
*
|
||||||
|
* @param pk the id of the contact
|
||||||
|
* @return the number of affected database rows, should be 1
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
* @throws DataAccessException
|
||||||
|
*/
|
||||||
|
public Integer delete(Integer pk) throws DataAccessException, ClassNotFoundException, SQLException {
|
||||||
|
DeleteConditionStep<TContactRecord> sql = getJooq()
|
||||||
|
// @formatter:off
|
||||||
|
.deleteFrom(T_CONTACT)
|
||||||
|
.where(T_CONTACT.PK.eq(pk));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql.toString());
|
||||||
|
return sql.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add a contact to the database
|
||||||
|
*
|
||||||
|
* @param bean the contact information
|
||||||
|
* @return the number of affected database rows, should be 1
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
* @throws DataAccessException
|
||||||
|
*/
|
||||||
|
public Integer add(ContactBean bean) throws DataAccessException, ClassNotFoundException, SQLException {
|
||||||
|
InsertValuesStep4<TContactRecord, String, String, String, EnumContacttype> sql = getJooq()
|
||||||
|
// @formatter:off
|
||||||
|
.insertInto(T_CONTACT,
|
||||||
|
T_CONTACT.FORENAME,
|
||||||
|
T_CONTACT.SURNAME,
|
||||||
|
T_CONTACT.CONTACT,
|
||||||
|
T_CONTACT.TYPE)
|
||||||
|
.values(bean.getForename(), bean.getSurname(), bean.getContact(), bean.getType());
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql.toString());
|
||||||
|
return sql.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update a contact in the database, referencing its pk
|
||||||
|
*
|
||||||
|
* @param bean the contact information
|
||||||
|
* @return the number of affected database rows, should be 1
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
* @throws DataAccessException
|
||||||
|
*/
|
||||||
|
public Integer update(ContactBean bean) throws DataAccessException, ClassNotFoundException, SQLException {
|
||||||
|
UpdateConditionStep<TContactRecord> sql = getJooq()
|
||||||
|
// @formatter:off
|
||||||
|
.update(T_CONTACT)
|
||||||
|
.set(T_CONTACT.FORENAME, bean.getForename())
|
||||||
|
.set(T_CONTACT.SURNAME, bean.getSurname())
|
||||||
|
.set(T_CONTACT.CONTACT, bean.getContact())
|
||||||
|
.set(T_CONTACT.TYPE, bean.getType())
|
||||||
|
.where(T_CONTACT.PK.eq(bean.getPk()));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql.toString());
|
||||||
|
return sql.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get number of entries in t_contact
|
||||||
|
*
|
||||||
|
* @return number of entries
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
* @throws DataAccessException
|
||||||
|
*/
|
||||||
|
public Integer getAmount() throws DataAccessException, ClassNotFoundException, SQLException {
|
||||||
|
SelectJoinStep<Record1<Integer>> sql = getJooq()
|
||||||
|
// @formatter:off
|
||||||
|
.selectCount()
|
||||||
|
.from(T_CONTACT);
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.debug("{}", sql.toString());
|
||||||
|
return sql.fetchOne(DSL.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all enum types
|
||||||
|
*
|
||||||
|
* @return list of enum types
|
||||||
|
*/
|
||||||
|
public List<EnumContacttype> getTypes() {
|
||||||
|
return new ArrayList<>(Arrays.asList(EnumContacttype.values()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package de.jottyfan.timetrack.spring.contact.impl;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.jooq.DSLContext;
|
||||||
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import de.jottyfan.timetrack.spring.contact.ContactBean;
|
||||||
|
import de.jottyfan.timetrack.spring.contact.IContactService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author henkej
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Transactional(transactionManager = "transactionManager")
|
||||||
|
public class ContactService implements IContactService {
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(ContactService.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DSLContext dsl;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCurrentUser(HttpServletRequest request) {
|
||||||
|
KeycloakSecurityContext ksc = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
|
||||||
|
return ksc == null ? "" : ksc.getIdToken().getPreferredUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ContactBean> toList() {
|
||||||
|
try {
|
||||||
|
return new ContactGateway(dsl).getAll();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error(e);
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer doInsert(ContactBean bean) {
|
||||||
|
try {
|
||||||
|
return new ContactGateway(dsl).add(bean);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error(e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer doUdate(ContactBean bean) {
|
||||||
|
try {
|
||||||
|
return new ContactGateway(dsl).update(bean);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error(e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer doDelete(Integer pk) {
|
||||||
|
try {
|
||||||
|
return new ContactGateway(dsl).delete(pk);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error(e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getAmount() {
|
||||||
|
return toList().size();
|
||||||
|
}
|
||||||
|
}
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,181 @@
|
|||||||
|
package de.jottyfan.timetrack.modules;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.security.RolesAllowed;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author henkej
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
public class TimetrackController {
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(TimetrackController.class);
|
||||||
|
|
||||||
|
private final HttpServletRequest request;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ITimetrackService fuelService;
|
||||||
|
|
||||||
|
private List<FuelBean> cachedFuels;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public TimetrackController(HttpServletRequest request) {
|
||||||
|
this.request = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/logout")
|
||||||
|
public String getLogout(HttpServletRequest request) throws ServletException {
|
||||||
|
request.logout();
|
||||||
|
return "redirect:/";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("car_user")
|
||||||
|
@GetMapping("/secure/welcome")
|
||||||
|
public String getWelcome() {
|
||||||
|
return "secure/welcome";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/")
|
||||||
|
public String getIndex() {
|
||||||
|
this.cachedFuels = null;
|
||||||
|
return "public/index";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("car_user")
|
||||||
|
@GetMapping("/secure/to_table")
|
||||||
|
public String getTable() {
|
||||||
|
this.cachedFuels = null;
|
||||||
|
return "secure/table";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("car_user")
|
||||||
|
@RequestMapping(value = "/secure/to_bean", method = RequestMethod.GET)
|
||||||
|
public String getBean(Model model) {
|
||||||
|
FuelBean bean = model.containsAttribute("fuelBean") ? (FuelBean) model.getAttribute("fuelBean") : new FuelBean();
|
||||||
|
model.addAttribute("fuelBean", bean);
|
||||||
|
return "secure/bean";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("car_user")
|
||||||
|
@RequestMapping(value = "/secure/to_existing_bean/{fkFuelBean}", method = RequestMethod.GET)
|
||||||
|
public String getBean(Model model, @PathVariable Integer fkFuelBean) throws Exception {
|
||||||
|
FuelBean bean = getFuelBean(fkFuelBean);
|
||||||
|
model.addAttribute("fuelBean", bean);
|
||||||
|
return "secure/bean";
|
||||||
|
}
|
||||||
|
|
||||||
|
private FuelBean getFuelBean(Integer fkFuelBean) throws Exception {
|
||||||
|
for (FuelBean bean : getFuels()) {
|
||||||
|
if (bean.getPk().equals(fkFuelBean)) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception("bean not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("car_user")
|
||||||
|
@RequestMapping(value = "/secure/do_upsert", method = RequestMethod.POST)
|
||||||
|
public String getUpsert(Model model, @ModelAttribute FuelBean fuelBean) {
|
||||||
|
Integer affected = fuelService.upsert(fuelBean);
|
||||||
|
model.addAttribute("fuelBean", fuelBean);
|
||||||
|
LOGGER.info("affected rows: {}", affected);
|
||||||
|
return affected > 0 ? getTable() : getBean(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("car_user")
|
||||||
|
@GetMapping("/secure/jsonfuels")
|
||||||
|
@ResponseBody
|
||||||
|
public List<FuelBean> getJsonFuels() {
|
||||||
|
List<FuelBean> fuels = fuelService.findAll();
|
||||||
|
return fuels;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ModelAttribute("fuels")
|
||||||
|
public List<FuelBean> getFuels() {
|
||||||
|
if (cachedFuels == null || cachedFuels.size() < 1) {
|
||||||
|
cachedFuels = fuelService.findAll();
|
||||||
|
}
|
||||||
|
return cachedFuels;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ModelAttribute("currentUser")
|
||||||
|
@ResponseBody
|
||||||
|
public String getCurrentUser() {
|
||||||
|
return fuelService.getCurrentUser(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ModelAttribute("averagelkm")
|
||||||
|
@ResponseBody
|
||||||
|
public BigDecimal getAverageLiterPerKm() {
|
||||||
|
List<FuelBean> fuels = getFuels();
|
||||||
|
Integer minMileage = 1000000; // my car won't even reach this milestone :)
|
||||||
|
Integer maxMileage = 0;
|
||||||
|
BigDecimal summedAmount = new BigDecimal(0);
|
||||||
|
for (FuelBean bean : fuels) {
|
||||||
|
summedAmount = summedAmount.add(bean.getAmount());
|
||||||
|
minMileage = bean.getMileage() < minMileage ? bean.getMileage() : minMileage;
|
||||||
|
maxMileage = bean.getMileage() > maxMileage ? bean.getMileage() : maxMileage;
|
||||||
|
}
|
||||||
|
BigDecimal totalMileage = new BigDecimal(maxMileage - minMileage);
|
||||||
|
BigDecimal calculated = totalMileage.intValue() != 0
|
||||||
|
? new BigDecimal((summedAmount.doubleValue() / totalMileage.doubleValue()) * 100d)
|
||||||
|
: new BigDecimal(0);
|
||||||
|
return calculated;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ModelAttribute("averageel")
|
||||||
|
@ResponseBody
|
||||||
|
public BigDecimal getAverageEuroPerLiter() {
|
||||||
|
List<FuelBean> fuels = getFuels();
|
||||||
|
BigDecimal summedLiter = new BigDecimal(0);
|
||||||
|
BigDecimal summedEuro = new BigDecimal(0);
|
||||||
|
for (FuelBean bean : fuels) {
|
||||||
|
summedLiter = summedLiter.add(bean.getAmount());
|
||||||
|
summedEuro = summedEuro.add(bean.getPrice());
|
||||||
|
}
|
||||||
|
BigDecimal calculated = summedLiter.intValue() != 0
|
||||||
|
? new BigDecimal(summedEuro.doubleValue() / summedLiter.doubleValue())
|
||||||
|
: new BigDecimal(0);
|
||||||
|
return calculated;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ModelAttribute("chartjsdata")
|
||||||
|
@ResponseBody
|
||||||
|
public List<BigDecimal> getChartjsData() {
|
||||||
|
List<FuelBean> fuels = getFuels();
|
||||||
|
List<BigDecimal> list = new ArrayList<>();
|
||||||
|
for (FuelBean bean : fuels) {
|
||||||
|
list.add(bean.getEuro_per_l());
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ModelAttribute("chartjslabel")
|
||||||
|
@ResponseBody
|
||||||
|
public List<Integer> getChartjsLabel() {
|
||||||
|
List<FuelBean> fuels = getFuels();
|
||||||
|
List<Integer> list = new ArrayList<>();
|
||||||
|
for (FuelBean bean : fuels) {
|
||||||
|
list.add(bean.getMileage());
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,21 @@
|
|||||||
|
# jooq
|
||||||
|
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||||
|
spring.datasource.url=jdbc:postgresql://localhost:5432/timetrack
|
||||||
|
spring.datasource.username=timetrack
|
||||||
|
spring.datasource.password=timetrack
|
||||||
|
|
||||||
|
# application
|
||||||
|
server.port = 8083
|
||||||
|
|
||||||
|
server.servlet.context-path=/timetrack
|
||||||
|
|
||||||
|
# keycloak
|
||||||
|
keycloak.auth-server-url = http://localhost:8080/
|
||||||
|
keycloak.realm = jottyfan
|
||||||
|
keycloak.resource = timetrack
|
||||||
|
keycloak.public-client = true
|
||||||
|
keycloak.security-constraints[0].authRoles[0] = timetrack_user
|
||||||
|
keycloak.security-constraints[0].securityCollections[0].patterns[0] = /*
|
||||||
|
#keycloak.credentia
|
||||||
|
keycloak.use-resource-role-mappings=true
|
||||||
|
#keycloak.bearer-only=true
|
||||||
@@ -1,3 +1,12 @@
|
|||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #eee;
|
||||||
|
height: calc(100% - 76px);
|
||||||
|
}
|
||||||
|
|
||||||
.body {
|
.body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -7,7 +16,8 @@
|
|||||||
.page {
|
.page {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-image: linear-gradient(to bottom, #ffffff 10%, #afffff 40%)
|
padding-bottom: 12px;
|
||||||
|
background-image: linear-gradient(to bottom, #eee, #777)
|
||||||
!important;
|
!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
xmlns:sec="http://www.thymeleaf.org/extras/spring-security" layout:decorate="~{layout/main.html}">
|
||||||
|
<head>
|
||||||
|
<title>Kontakte</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ul layout:fragment="menu">
|
||||||
|
<li class="nav-item" sec:authorize="hasRole('timetrack_user')"><a class="nav-link" th:href="@{/contact/add}">Neuen
|
||||||
|
Kontakt anlegen</a></li>
|
||||||
|
</ul>
|
||||||
|
<main layout:fragment="content">
|
||||||
|
<div class="row row-cols-12 ro-cols-lg-4 ro-cols-md-3 ro-cols-sd-2 g-4" style="margin: 8px">
|
||||||
|
<div class="col" th:each="contact : ${contactList}">
|
||||||
|
<div class="card text-dark bg-light shadow" style="width: 18rem">
|
||||||
|
<div class="card-header text-center">
|
||||||
|
<font th:text="${contact.forename} + ' ' + ${contact.surname}" style="font-size: larger"></font>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex justify-content-center align-items-center">
|
||||||
|
<span th:text="${contact.type} + ': ' + ${contact.contact}"></span> <a th:href="@{/contact/edit/{id}(id=${contact.pk})}"
|
||||||
|
sec:authorize="hasRole('timetrack_user')" style="margin-left: 8px;"> <i class="fa fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
xmlns:sec="http://www.thymeleaf.org/extras/spring-security" layout:decorate="~{layout/main.html}">
|
||||||
|
<head>
|
||||||
|
<title>Kontakt aktualisieren</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ul layout:fragment="menu">
|
||||||
|
<li class="nav-item" sec:authorize="hasRole('timetrack_user')"><a class="nav-link" th:href="@{/contact/contacts}">abbrechen</a></li>
|
||||||
|
</ul>
|
||||||
|
<main layout:fragment="content">
|
||||||
|
<div class="container">
|
||||||
|
<form th:action="@{/contact/insert}" th:object="${contactBean}" method="post">
|
||||||
|
<p>
|
||||||
|
Inhalt von Eintrag <span th:text="*{pk}"></span>:
|
||||||
|
</p>
|
||||||
|
<input type="hidden" th:field="*{pk}" />
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Vorname</label> <input type="text" th:field="*{forename}" class="form-control" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Nachname</label> <input type="text" th:field="*{surname}" class="form-control" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Kontakt</label> <input type="text" th:field="*{contact}" class="form-control" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Typ</label> <input type="text" th:field="*{type}" class="form-control" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
xmlns:sec="http://www.thymeleaf.org/extras/spring-security" layout:decorate="~{layout/main.html}">
|
||||||
|
<head>
|
||||||
|
<title>Timetrack</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ul layout:fragment="menu">
|
||||||
|
</ul>
|
||||||
|
<main layout:fragment="content">
|
||||||
|
<div style="margin: 10vh">
|
||||||
|
<div class="alert alert-danger" role="alert" style="vertical-align: middle; align: center">
|
||||||
|
<p>Es ist ein Fehler aufgetreten.</p>
|
||||||
|
<a th:href="@{/}" class="alert-link">Ach, Mist...</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" th:href="@{/webjars/bootstrap/5.1.3/css/bootstrap.min.css}" />
|
||||||
|
<link rel="stylesheet" type="text/css" th:href="@{/webjars/datatables/1.11.3/css/dataTables.bootstrap5.min.css}" />
|
||||||
|
<link rel="stylesheet" type="text/css" th:href="@{/webjars/font-awesome/5.15.4/css/all.min.css}">
|
||||||
|
<link rel="stylesheet" type="text/css" th:href="@{/css/style.css}">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" th:href="@{/png/favicon/favicon-32x32.png}">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" th:href="@{/png/favicon/favicon-16x16.png}">
|
||||||
|
|
||||||
|
<script th:src="@{/webjars/jquery/3.6.0/jquery.min.js}"></script>
|
||||||
|
<script th:src="@{/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js}"></script>
|
||||||
|
<script th:src="@{/webjars/datatables/1.11.3/js/jquery.dataTables.min.js}"></script>
|
||||||
|
<script th:src="@{/webjars/datatables/1.11.3/js/dataTables.bootstrap5.min.js}"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Navigation -->
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-light static-top">
|
||||||
|
<div class="container-fluid" style="width: 98%">
|
||||||
|
<a class="navbar-brand" th:href="@{/}"> <i class="fa fa-calendar-alt"></i> Timetrack
|
||||||
|
<div class="version" th:text="${@manifestBean.getVersion()}"></div>
|
||||||
|
</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive"
|
||||||
|
aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||||
|
<ul class="navbar-nav ml-auto">
|
||||||
|
<li class="nav-item dropdown"><a class="nav-link dropdown-toggle" href="#" id="navbarScrollingDropdown" role="button"
|
||||||
|
data-bs-toggle="dropdown" aria-expanded="false"> Module </a>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-light" aria-labelledby="navbarScrollingDropdown">
|
||||||
|
<li><a class="dropdown-item" th:href="@{/contact/contacts}">Kontakte</a></li>
|
||||||
|
<li><hr /></li>
|
||||||
|
<li><a class="dropdown-item" th:href="@{/logout}">[[${currentUser}]] abmelden</a></li>
|
||||||
|
</ul></li>
|
||||||
|
<li layout:fragment="menu" style="list-style-type: none"></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<main layout:fragment="content" class="page body"></main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
xmlns:sec="http://www.thymeleaf.org/extras/spring-security" layout:decorate="~{layout/main.html}">
|
||||||
|
<head>
|
||||||
|
<title>Timetrack</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ul layout:fragment="menu">
|
||||||
|
</ul>
|
||||||
|
<main layout:fragment="content"></main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.help;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author jotty
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class TestLocalDateConverter {
|
|
||||||
@Test
|
|
||||||
public void testGetAsObject() {
|
|
||||||
String now = new SimpleDateFormat("dd.MM.yyyy").format(new Date());
|
|
||||||
assertEquals(LocalDate.now(), new LocalDateConverter().getAsObject(null, null, now));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetAsString() {
|
|
||||||
String now = new SimpleDateFormat("dd.MM.yyyy").format(new Date());
|
|
||||||
assertEquals(now, new LocalDateConverter().getAsString(null, null, LocalDate.now()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.moduls.done;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
||||||
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import de.jottyfan.timetrack.modules.done.DoneBean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author henkej
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class TestDoneBean {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetLocalDateTimeFromHHmm() {
|
|
||||||
LocalDateTime ldt = LocalDateTime.now();
|
|
||||||
ldt = ldt.withSecond(0).withNano(0);
|
|
||||||
assertEquals(ldt.withHour(0).withMinute(0), new DoneBean().getLocalDateTimeFromHHmm("0:0", LocalDateTime.now()));
|
|
||||||
assertEquals(ldt.withHour(0).withMinute(5), new DoneBean().getLocalDateTimeFromHHmm("0:5", LocalDateTime.now()));
|
|
||||||
assertEquals(ldt.withHour(3).withMinute(2), new DoneBean().getLocalDateTimeFromHHmm("3:2", LocalDateTime.now()));
|
|
||||||
assertEquals(ldt.withHour(3).withMinute(2), new DoneBean().getLocalDateTimeFromHHmm("03:2", LocalDateTime.now()));
|
|
||||||
assertEquals(ldt.withHour(10).withMinute(2), new DoneBean().getLocalDateTimeFromHHmm("10:2", LocalDateTime.now()));
|
|
||||||
assertEquals(ldt.withHour(12).withMinute(2), new DoneBean().getLocalDateTimeFromHHmm("12:02", LocalDateTime.now()));
|
|
||||||
assertEquals(ldt.withHour(12).withMinute(20), new DoneBean().getLocalDateTimeFromHHmm("12:20", LocalDateTime.now()));
|
|
||||||
assertEquals(null, new DoneBean().getLocalDateTimeFromHHmm(null, LocalDateTime.now()));
|
|
||||||
assertEquals(null, new DoneBean().getLocalDateTimeFromHHmm("", LocalDateTime.now()));
|
|
||||||
assertEquals(null, new DoneBean().getLocalDateTimeFromHHmm(" ", LocalDateTime.now()));
|
|
||||||
assertEquals(ldt.withHour(0).withMinute(0), new DoneBean().getLocalDateTimeFromHHmm("0", LocalDateTime.now()));
|
|
||||||
assertEquals(ldt.withHour(1).withMinute(0), new DoneBean().getLocalDateTimeFromHHmm("1", LocalDateTime.now()));
|
|
||||||
assertEquals(ldt.withHour(5).withMinute(0), new DoneBean().getLocalDateTimeFromHHmm("5", LocalDateTime.now()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetDay() throws ParseException {
|
|
||||||
String today = new SimpleDateFormat("dd.MM.yyyy").format(new Date());
|
|
||||||
DateTimeFormatter sdf = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
|
|
||||||
DateTimeFormatter sd = DateTimeFormatter.ofPattern("dd.MM.yyyy");
|
|
||||||
|
|
||||||
DoneBean bean = new DoneBean();
|
|
||||||
bean.setDay(new Date());
|
|
||||||
assertNull(bean.getTimeFrom());
|
|
||||||
assertNull(bean.getTimeUntil());
|
|
||||||
|
|
||||||
bean.setTimeFromString("08:00");
|
|
||||||
LocalDateTime ts1 = bean.getTimeFrom();
|
|
||||||
assertEquals(today.concat(" 08:00"), ts1.format(sdf));
|
|
||||||
bean.setDay(new SimpleDateFormat("dd.MM.yyyy").parse("01.01.2001"));
|
|
||||||
assertEquals("01.01.2001", bean.getTimeFrom().format(sd));
|
|
||||||
assertNull(bean.getTimeUntil());
|
|
||||||
|
|
||||||
bean.setTimeUntilString("10:00");
|
|
||||||
LocalDateTime ts2 = bean.getTimeUntil();
|
|
||||||
assertEquals(today.concat(" 10:00"), ts2.format(sdf));
|
|
||||||
bean.setDay(new SimpleDateFormat("dd.MM.yyyy").parse("01.01.2001"));
|
|
||||||
assertEquals("01.01.2001", sd.format(bean.getTimeFrom()));
|
|
||||||
assertEquals("01.01.2001", sd.format(bean.getTimeUntil()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.moduls.done;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import de.jottyfan.timetrack.modules.done.RgbColor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author henkej
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class TestRgbColor {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDetermineRgbColor() {
|
|
||||||
RgbColor c = new RgbColor();
|
|
||||||
assertEquals("rgb(146,204,204)", c.determineRgbColor(null, null, null));
|
|
||||||
assertEquals("rgb(61,66,66)", c.determineRgbColor("Ship", "alles", "Mail"));
|
|
||||||
assertEquals("rgb(43,85,85)", c.determineRgbColor("Square", "Entwicklung_Programmierung", "alles"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.moduls.done;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import de.jottyfan.timetrack.modules.done.WholeDaySummaryBean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author henkej
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class TestWholeDaySummaryBean {
|
|
||||||
@Test
|
|
||||||
public void testGetOvertime() {
|
|
||||||
assertEquals("00:00", new WholeDaySummaryBean("", "", "07:48", "", 468).getOvertime());
|
|
||||||
assertEquals("00:12", new WholeDaySummaryBean("", "", "08:00", "", 468).getOvertime());
|
|
||||||
assertEquals("-00:48", new WholeDaySummaryBean("", "", "07:00", "", 468).getOvertime());
|
|
||||||
assertEquals("-07:48", new WholeDaySummaryBean("", "", "00:00", "", 468).getOvertime());
|
|
||||||
assertEquals("-07:48", new WholeDaySummaryBean("", "", "", "", 468).getOvertime());
|
|
||||||
assertEquals("", new WholeDaySummaryBean("", "", "a:b", "", 468).getOvertime());
|
|
||||||
assertEquals("00:00", new WholeDaySummaryBean("", "", "08:00", "", 480).getOvertime());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user