diff --git a/pom.xml b/pom.xml index ec34bd5..4b107ec 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ UTF-8 quarkus-universe-bom io.quarkus - 2.2.2.Final + 2.3.1.Final 3.0.0-M5 @@ -31,7 +31,7 @@ io.quarkus - quarkus-resteasy + quarkus-resteasy-jsonb io.quarkus diff --git a/src/main/java/de/mbremer/configuration/Configuration.java b/src/main/java/de/mbremer/configuration/Configuration.java index d430f1f..af4d7dd 100644 --- a/src/main/java/de/mbremer/configuration/Configuration.java +++ b/src/main/java/de/mbremer/configuration/Configuration.java @@ -1,19 +1,41 @@ package de.mbremer.configuration; import io.quarkus.hibernate.orm.panache.PanacheEntity; +import io.quarkus.hibernate.orm.panache.PanacheQuery; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import javax.persistence.Entity; +import javax.persistence.NoResultException; @Entity @Getter @Setter -@AllArgsConstructor @NoArgsConstructor +@AllArgsConstructor public class Configuration extends PanacheEntity { - String propertyName; - String value; + public static final String GOOGLE_API_KEY = "google_api_key"; + public static final String OFFICE_ADRESS_KEY = "office_address"; + + private String propertyName; + private String value; + + public static String findGooleApiKey() { + return findValueOrEmpty(GOOGLE_API_KEY); + } + + public static String findOfficeAdress() { + return findValueOrEmpty(OFFICE_ADRESS_KEY); + } + + private static String findValueOrEmpty(String key) { + PanacheQuery configuration = find("propertyName", key); + try { + return configuration.singleResult().getValue(); + } catch (NoResultException e) { + return ""; + } + } } diff --git a/src/main/java/de/mbremer/configuration/ConfigurationService.java b/src/main/java/de/mbremer/configuration/ConfigurationService.java new file mode 100644 index 0000000..767afe5 --- /dev/null +++ b/src/main/java/de/mbremer/configuration/ConfigurationService.java @@ -0,0 +1,27 @@ +package de.mbremer.configuration; + +import org.jboss.logging.Logger; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.persistence.NoResultException; +import javax.transaction.Transactional; + +@ApplicationScoped +public class ConfigurationService { + + @Inject + Logger log; + + @Transactional + public void createOrUpdate(String configurationKey, String configurationValue) { + try { + Configuration apiKeyConfig = Configuration.find("propertyName", configurationKey).singleResult(); + apiKeyConfig.setValue(configurationValue); + log.info("update " + configurationKey + ": " + configurationValue); + } catch (NoResultException e) { + new Configuration(configurationKey, configurationValue).persist(); + log.info("create " + configurationKey + ": " + configurationValue); + } + } +} diff --git a/src/main/java/de/mbremer/configuration/DatabaseConfigSource.java b/src/main/java/de/mbremer/configuration/DatabaseConfigSource.java deleted file mode 100644 index 9ca7c04..0000000 --- a/src/main/java/de/mbremer/configuration/DatabaseConfigSource.java +++ /dev/null @@ -1,40 +0,0 @@ -package de.mbremer.configuration; - -import io.quarkus.hibernate.orm.panache.PanacheQuery; -import org.eclipse.microprofile.config.spi.ConfigSource; - -import java.util.Set; -import java.util.stream.Collectors; - -public class DatabaseConfigSource implements ConfigSource { - - @Override - public Set getPropertyNames() { - try { - return Configuration.streamAll().map(c -> ((Configuration) c).getPropertyName()).collect(Collectors.toSet()); - } catch (IllegalStateException e) { - // DB in not up - return Set.of(); - } - } - - @Override - public String getValue(String propertyName) { - try { - PanacheQuery conf = Configuration.find("propertyName", propertyName); - if (conf == null) { - // DB in not up - return null; - } - return conf.singleResultOptional().map(c -> ((Configuration) c).getValue()).orElse(null); - } catch (IllegalStateException e) { - // DB in not up - return null; - } - } - - @Override - public String getName() { - return DatabaseConfigSource.class.getSimpleName(); - } -} diff --git a/src/main/java/de/mbremer/secutity/UserResource.java b/src/main/java/de/mbremer/secutity/UserResource.java index 14dd03b..de072ff 100644 --- a/src/main/java/de/mbremer/secutity/UserResource.java +++ b/src/main/java/de/mbremer/secutity/UserResource.java @@ -1,16 +1,16 @@ package de.mbremer.secutity; import de.mbremer.configuration.Configuration; +import de.mbremer.configuration.ConfigurationService; import de.mbremer.room.Room; import de.mbremer.traffic.TrafficAdminForm; import de.mbremer.traffic.TrafficUserForm; -import io.quarkus.hibernate.orm.panache.PanacheEntityBase; +import de.mbremer.traffic.TrafficWarningConfig; import io.quarkus.panache.common.Sort; import io.quarkus.qute.Location; import io.quarkus.qute.Template; import io.quarkus.qute.TemplateInstance; import io.quarkus.security.identity.SecurityIdentity; -import org.eclipse.microprofile.config.inject.ConfigProperty; import org.jboss.logging.Logger; import org.jboss.resteasy.annotations.jaxrs.PathParam; import org.jboss.resteasy.annotations.providers.multipart.MultipartForm; @@ -18,15 +18,15 @@ import org.jboss.resteasy.annotations.providers.multipart.MultipartForm; import javax.annotation.security.PermitAll; import javax.annotation.security.RolesAllowed; import javax.inject.Inject; -import javax.persistence.NoResultException; import javax.transaction.Transactional; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; import java.net.URI; -import java.util.Optional; +import static de.mbremer.configuration.Configuration.GOOGLE_API_KEY; +import static de.mbremer.configuration.Configuration.OFFICE_ADRESS_KEY; import static de.mbremer.secutity.Role.ADMIN; @Path("/user") @@ -40,29 +40,42 @@ public class UserResource { @Inject UserService userService; @Inject + ConfigurationService configurationService; + @Inject Template userinit; @Inject @Location("user.html") Template userTemplate; - // TODO: 12.10.21 -// @ConfigProperty(name = "google_api_key") -// Optional googleApiKey; @GET @Produces(MediaType.TEXT_HTML) @RolesAllowed({"USER", "ADMIN"}) public TemplateInstance getUser() { + + TrafficWarningConfig trafficWarningConfig = + (TrafficWarningConfig) TrafficWarningConfig.find("user", userService.getCurrentUser()).singleResultOptional().orElse(null); + TemplateInstance templateInstance = userTemplate .data("current_user", User.find("username", identity.getPrincipal().getName()).singleResult()); -// log.info("Google-API-Key" + googleApiKey.orElse("-")); + if (trafficWarningConfig != null) { + log.info(trafficWarningConfig.toString()); + templateInstance + .data("traffic_email", trafficWarningConfig.getEmailadress()) + .data("traffic_active", trafficWarningConfig.isActive()) + .data("traffic_address", trafficWarningConfig.getAddress()) + .data("traffic_away", trafficWarningConfig.getTimeAway()) + .data("traffic_back", trafficWarningConfig.getTimeBack()) + .data("traffic_duration", trafficWarningConfig.getThreshold()); + } if (identity.hasRole("ADMIN")) { templateInstance - .data("is_admin", true) - .data("users", User.listAll(Sort.by("username"))) - .data("rooms", Room.listAll(Sort.by("name"))); -// .data("google_api_key", googleApiKey.orElse("")); + .data("is_admin", true) + .data("users", User.listAll(Sort.by("username"))) + .data("rooms", Room.listAll(Sort.by("name"))) + .data("google_api_key", Configuration.findGooleApiKey()) + .data("office_address", Configuration.findOfficeAdress()); } return templateInstance; @@ -74,10 +87,10 @@ public class UserResource { @Path("init") @PermitAll public Response initialAdd(@MultipartForm UserForm userForm) { - if(User.count("role", ADMIN.name()) > 0) { + if (User.count("role", ADMIN.name()) > 0) { throw new BadRequestException("Only allowed on initial set up"); } - if(!ADMIN.name().equals(userForm.role)) { + if (!ADMIN.name().equals(userForm.role)) { throw new BadRequestException("Only role ADMIN"); } @@ -94,7 +107,7 @@ public class UserResource { @Path("init") @PermitAll public TemplateInstance initial() { - if(User.count("role", ADMIN.name()) > 0) { + if (User.count("role", ADMIN.name()) > 0) { throw new BadRequestException("Only allowed on initial set up"); } return userinit.instance(); @@ -107,7 +120,7 @@ public class UserResource { public Response logout() { return Response .temporaryRedirect(URI.create("/")) - .cookie(new NewCookie("quarkus-credential", null, "/", null, null, 0, false,true)) + .cookie(new NewCookie("quarkus-credential", null, "/", null, null, 0, false, true)) .build(); } @@ -165,16 +178,8 @@ public class UserResource { @Transactional @Path("/traffic/config/") public TemplateInstance configureTrafficAdmin(@MultipartForm TrafficAdminForm trafficAdminForm) { - log.info("configure traffic"); - - try { - Configuration apiKeyConfig = Configuration.find("propertyName", "google_api_key").singleResult(); - apiKeyConfig.setValue(trafficAdminForm.googleApiKey); - log.info("update API-Key: " + trafficAdminForm.googleApiKey); - } catch (NoResultException e) { - new Configuration("google_api_key", trafficAdminForm.googleApiKey).persist(); - log.info("create API-Key: " + trafficAdminForm.googleApiKey); - } + configurationService.createOrUpdate(GOOGLE_API_KEY, trafficAdminForm.googleApiKey); + configurationService.createOrUpdate(OFFICE_ADRESS_KEY, trafficAdminForm.officeAddress); return getUser(); } @@ -187,6 +192,18 @@ public class UserResource { public TemplateInstance configureTrafficUser(@PathParam("username") String username, @MultipartForm TrafficUserForm trafficUserForm) { log.info("configure traffic for " + username); + User currentUser = userService.getCurrentUser(); + TrafficWarningConfig trafficWarningConfig = (TrafficWarningConfig) TrafficWarningConfig.find("user", currentUser).singleResultOptional().orElse(null); + + if (trafficWarningConfig == null) { + log.info("create new trafficWarningConfig. user " + currentUser.getUsername()); + trafficWarningConfig = new TrafficWarningConfig(); + trafficWarningConfig.setUser(currentUser); + } + trafficWarningConfig = trafficUserForm.updateTrafficWarningConfig(trafficWarningConfig); + log.info(trafficWarningConfig.toString()); + + trafficWarningConfig.persist(); return getUser(); } } diff --git a/src/main/java/de/mbremer/traffic/LocalTimeMessageBodyReader.java b/src/main/java/de/mbremer/traffic/LocalTimeMessageBodyReader.java new file mode 100644 index 0000000..2bd3364 --- /dev/null +++ b/src/main/java/de/mbremer/traffic/LocalTimeMessageBodyReader.java @@ -0,0 +1,28 @@ +package de.mbremer.traffic; + +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.time.LocalTime; + +@Provider +@Produces(MediaType.TEXT_PLAIN) +public class LocalTimeMessageBodyReader implements MessageBodyReader { + + @Override + public boolean isReadable(Class> type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return type == LocalTime.class; + } + + @Override + public LocalTime readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { + return LocalTime.parse(new String(entityStream.readAllBytes())); + } +} diff --git a/src/main/java/de/mbremer/traffic/TrafficAdminForm.java b/src/main/java/de/mbremer/traffic/TrafficAdminForm.java index bae6230..e4c18e3 100644 --- a/src/main/java/de/mbremer/traffic/TrafficAdminForm.java +++ b/src/main/java/de/mbremer/traffic/TrafficAdminForm.java @@ -6,6 +6,6 @@ import javax.ws.rs.FormParam; public class TrafficAdminForm { public @FormParam("googleapikey") String googleApiKey; - public @FormParam("officeadress") - String officeAdress; + public @FormParam("officeaddress") + String officeAddress; } diff --git a/src/main/java/de/mbremer/traffic/TrafficUserForm.java b/src/main/java/de/mbremer/traffic/TrafficUserForm.java index 95227bf..63ae2f3 100644 --- a/src/main/java/de/mbremer/traffic/TrafficUserForm.java +++ b/src/main/java/de/mbremer/traffic/TrafficUserForm.java @@ -1,4 +1,29 @@ package de.mbremer.traffic; +import javax.ws.rs.FormParam; +import java.time.LocalTime; + public class TrafficUserForm { + public @FormParam("traffic_email") + String email; + public @FormParam("traffic_address") + String address; + public @FormParam("traffic_away") + LocalTime away; + public @FormParam("traffic_back") + LocalTime back; + public @FormParam("traffic_duration") + Integer duration; + public @FormParam("traffic_active") + boolean active; + + public TrafficWarningConfig updateTrafficWarningConfig(TrafficWarningConfig trafficWarningConfig) { + trafficWarningConfig.setEmailadress(email); + trafficWarningConfig.setAddress(address); + trafficWarningConfig.setThreshold(duration); + trafficWarningConfig.setTimeAway(away); + trafficWarningConfig.setTimeBack(back); + trafficWarningConfig.setActive(active); + return trafficWarningConfig; + } } diff --git a/src/main/java/de/mbremer/traffic/TrafficWarningConfig.java b/src/main/java/de/mbremer/traffic/TrafficWarningConfig.java new file mode 100644 index 0000000..885ca74 --- /dev/null +++ b/src/main/java/de/mbremer/traffic/TrafficWarningConfig.java @@ -0,0 +1,31 @@ +package de.mbremer.traffic; + +import de.mbremer.secutity.User; +import io.quarkus.hibernate.orm.panache.PanacheEntity; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import javax.persistence.Entity; +import javax.persistence.OneToOne; +import javax.validation.constraints.NotNull; +import java.time.LocalTime; + + +@Getter +@Setter +@Entity +@ToString(exclude = "user") +public class TrafficWarningConfig extends PanacheEntity { + @NotNull + private String emailadress; + @NotNull + private String address; + LocalTime timeAway; + LocalTime timeBack; + private Integer threshold; + private boolean active; + @NotNull + @OneToOne + private User user; +} diff --git a/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource b/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource deleted file mode 100644 index 3dfa939..0000000 --- a/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource +++ /dev/null @@ -1 +0,0 @@ -de.mbremer.configuration.DatabaseConfigSource diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index cddf87b..fcac00b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -6,7 +6,7 @@ quarkus.datasource.db-kind=postgresql quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQL95Dialect -%dev.quarkus.hibernate-orm.log.sql=true +%dev.quarkus.hibernate-orm.log.sql=false quarkus.flyway.migrate-at-start=true # theoretische soll auch 'filesystem:' funktionieren diff --git a/src/main/resources/db/migration/V0005__trafficwarning.sql b/src/main/resources/db/migration/V0005__trafficwarning.sql new file mode 100644 index 0000000..1956d57 --- /dev/null +++ b/src/main/resources/db/migration/V0005__trafficwarning.sql @@ -0,0 +1,10 @@ +create table trafficwarningconfig ( + id bigint not null primary key, + emailadress varchar not null, + address varchar not null, + timeaway time, + timeback time, + threshold integer not null, + active boolean not null, + user_id bigint unique not null references users +); diff --git a/src/main/resources/templates/user.html b/src/main/resources/templates/user.html index 51f28ac..3f6ad95 100644 --- a/src/main/resources/templates/user.html +++ b/src/main/resources/templates/user.html @@ -43,13 +43,14 @@ - + google-API-Key - + - + Büroadresse @@ -73,50 +74,57 @@ Verkehrsinfos Die Fahrzeit wird über die googlemaps-API ermittelt und bei Überschreitung des Grenzwerts via E-Mail gewarnt. - + - + E-Mail-Adresse - + Heimatadresse - + Hinfahrt - + Rückfahrt - + Grenzwert Fahrzeit - + Verkehrsinfos via google-API aktiv + + Speichern + +