Gerüst mit Form-Auth
This commit is contained in:
55
src/main/docker/Dockerfile.jvm
Normal file
55
src/main/docker/Dockerfile.jvm
Normal file
@@ -0,0 +1,55 @@
|
||||
####
|
||||
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
|
||||
#
|
||||
# Before building the container image run:
|
||||
#
|
||||
# ./mvnw package
|
||||
#
|
||||
# Then, build the image with:
|
||||
#
|
||||
# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/buerokalender-jvm .
|
||||
#
|
||||
# Then run the container using:
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/buerokalender-jvm
|
||||
#
|
||||
# If you want to include the debug port into your docker image
|
||||
# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005
|
||||
#
|
||||
# Then run the container using :
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/buerokalender-jvm
|
||||
#
|
||||
###
|
||||
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4
|
||||
|
||||
ARG JAVA_PACKAGE=java-11-openjdk-headless
|
||||
ARG RUN_JAVA_VERSION=1.3.8
|
||||
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
|
||||
# Install java and the run-java script
|
||||
# Also set up permissions for user `1001`
|
||||
RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
|
||||
&& microdnf update \
|
||||
&& microdnf clean all \
|
||||
&& mkdir /deployments \
|
||||
&& chown 1001 /deployments \
|
||||
&& chmod "g+rwX" /deployments \
|
||||
&& chown 1001:root /deployments \
|
||||
&& curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
|
||||
&& chown 1001 /deployments/run-java.sh \
|
||||
&& chmod 540 /deployments/run-java.sh \
|
||||
&& echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/conf/security/java.security
|
||||
|
||||
# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
|
||||
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
|
||||
# We make four distinct layers so if there are application changes the library layers can be re-used
|
||||
COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/
|
||||
COPY --chown=1001 target/quarkus-app/*.jar /deployments/
|
||||
COPY --chown=1001 target/quarkus-app/app/ /deployments/app/
|
||||
COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/
|
||||
|
||||
EXPOSE 8080
|
||||
USER 1001
|
||||
|
||||
ENTRYPOINT [ "/deployments/run-java.sh" ]
|
||||
|
||||
51
src/main/docker/Dockerfile.legacy-jar
Normal file
51
src/main/docker/Dockerfile.legacy-jar
Normal file
@@ -0,0 +1,51 @@
|
||||
####
|
||||
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
|
||||
#
|
||||
# Before building the container image run:
|
||||
#
|
||||
# ./mvnw package -Dquarkus.package.type=legacy-jar
|
||||
#
|
||||
# Then, build the image with:
|
||||
#
|
||||
# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/buerokalender-legacy-jar .
|
||||
#
|
||||
# Then run the container using:
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/buerokalender-legacy-jar
|
||||
#
|
||||
# If you want to include the debug port into your docker image
|
||||
# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005
|
||||
#
|
||||
# Then run the container using :
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/buerokalender-legacy-jar
|
||||
#
|
||||
###
|
||||
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4
|
||||
|
||||
ARG JAVA_PACKAGE=java-11-openjdk-headless
|
||||
ARG RUN_JAVA_VERSION=1.3.8
|
||||
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
|
||||
# Install java and the run-java script
|
||||
# Also set up permissions for user `1001`
|
||||
RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
|
||||
&& microdnf update \
|
||||
&& microdnf clean all \
|
||||
&& mkdir /deployments \
|
||||
&& chown 1001 /deployments \
|
||||
&& chmod "g+rwX" /deployments \
|
||||
&& chown 1001:root /deployments \
|
||||
&& curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
|
||||
&& chown 1001 /deployments/run-java.sh \
|
||||
&& chmod 540 /deployments/run-java.sh \
|
||||
&& echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/conf/security/java.security
|
||||
|
||||
# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
|
||||
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
|
||||
COPY target/lib/* /deployments/lib/
|
||||
COPY target/*-runner.jar /deployments/app.jar
|
||||
|
||||
EXPOSE 8080
|
||||
USER 1001
|
||||
|
||||
ENTRYPOINT [ "/deployments/run-java.sh" ]
|
||||
27
src/main/docker/Dockerfile.native
Normal file
27
src/main/docker/Dockerfile.native
Normal file
@@ -0,0 +1,27 @@
|
||||
####
|
||||
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode
|
||||
#
|
||||
# Before building the container image run:
|
||||
#
|
||||
# ./mvnw package -Pnative
|
||||
#
|
||||
# Then, build the image with:
|
||||
#
|
||||
# docker build -f src/main/docker/Dockerfile.native -t quarkus/buerokalender .
|
||||
#
|
||||
# Then run the container using:
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/buerokalender
|
||||
#
|
||||
###
|
||||
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4
|
||||
WORKDIR /work/
|
||||
RUN chown 1001 /work \
|
||||
&& chmod "g+rwX" /work \
|
||||
&& chown 1001:root /work
|
||||
COPY --chown=1001:root target/*-runner /work/application
|
||||
|
||||
EXPOSE 8080
|
||||
USER 1001
|
||||
|
||||
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
|
||||
23
src/main/docker/Dockerfile.native-distroless
Normal file
23
src/main/docker/Dockerfile.native-distroless
Normal file
@@ -0,0 +1,23 @@
|
||||
####
|
||||
# This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no JVM) mode
|
||||
#
|
||||
# Before building the container image run:
|
||||
#
|
||||
# ./mvnw package -Pnative
|
||||
#
|
||||
# Then, build the image with:
|
||||
#
|
||||
# docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/buerokalender .
|
||||
#
|
||||
# Then run the container using:
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/buerokalender
|
||||
#
|
||||
###
|
||||
FROM quay.io/quarkus/quarkus-distroless-image:1.0
|
||||
COPY target/*-runner /application
|
||||
|
||||
EXPOSE 8080
|
||||
USER nonroot
|
||||
|
||||
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
|
||||
26
src/main/java/de/mbremer/kalender/KalenderResource.java
Normal file
26
src/main/java/de/mbremer/kalender/KalenderResource.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package de.mbremer.kalender;
|
||||
|
||||
import io.quarkus.qute.Template;
|
||||
import io.quarkus.qute.TemplateInstance;
|
||||
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
@Path("/kalender")
|
||||
@RolesAllowed({"USER", "ADMIN"})
|
||||
public class KalenderResource {
|
||||
|
||||
@Inject
|
||||
Template kalender;
|
||||
|
||||
@Path("")
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
public TemplateInstance kalender() {
|
||||
return kalender.instance();
|
||||
}
|
||||
}
|
||||
20
src/main/java/de/mbremer/kalender/KalenderTag.java
Normal file
20
src/main/java/de/mbremer/kalender/KalenderTag.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package de.mbremer.kalender;
|
||||
|
||||
import de.mbremer.secutity.User;
|
||||
import io.quarkus.hibernate.orm.panache.PanacheEntity;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class KalenderTag extends PanacheEntity {
|
||||
|
||||
private LocalDate date;
|
||||
@OneToMany
|
||||
private User inOffice;
|
||||
}
|
||||
5
src/main/java/de/mbremer/secutity/Role.java
Normal file
5
src/main/java/de/mbremer/secutity/Role.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package de.mbremer.secutity;
|
||||
|
||||
public enum Role {
|
||||
ADMIN, USER
|
||||
}
|
||||
57
src/main/java/de/mbremer/secutity/User.java
Normal file
57
src/main/java/de/mbremer/secutity/User.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package de.mbremer.secutity;
|
||||
|
||||
import io.quarkus.elytron.security.common.BcryptUtil;
|
||||
import io.quarkus.hibernate.orm.panache.PanacheEntity;
|
||||
import io.quarkus.security.jpa.Password;
|
||||
import io.quarkus.security.jpa.Roles;
|
||||
import io.quarkus.security.jpa.UserDefinition;
|
||||
import io.quarkus.security.jpa.Username;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@UserDefinition
|
||||
@NoArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "users")
|
||||
public class User extends PanacheEntity {
|
||||
|
||||
@Username
|
||||
@NotBlank
|
||||
@Getter
|
||||
@Column(nullable = false)
|
||||
private String username;
|
||||
|
||||
@Password
|
||||
@NotBlank
|
||||
@Getter
|
||||
@Column(nullable = false)
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* ADMIN or USER.
|
||||
*/
|
||||
@Roles
|
||||
@Getter
|
||||
@Setter
|
||||
@Column(nullable = false)
|
||||
private String role = "USER";
|
||||
|
||||
public User setPassword(String password) {
|
||||
this.password = BcryptUtil.bcryptHash(password);
|
||||
return this;
|
||||
}
|
||||
|
||||
public User setUsername(String username) {
|
||||
this.username = username == null ? null : username.trim();
|
||||
return this;
|
||||
}
|
||||
|
||||
public User setRole(String role) {
|
||||
this.role = role == null ? role : role.toUpperCase();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
18
src/main/java/de/mbremer/secutity/UserForm.java
Normal file
18
src/main/java/de/mbremer/secutity/UserForm.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package de.mbremer.secutity;
|
||||
|
||||
import javax.ws.rs.FormParam;
|
||||
|
||||
public class UserForm {
|
||||
public @FormParam("username") String username;
|
||||
public @FormParam("password") String password;
|
||||
public @FormParam("passwordVerify") String passwordVerify;
|
||||
public @FormParam("role") String role;
|
||||
|
||||
public User getUser() {
|
||||
return new User().setUsername(username).setPassword(password).setRole(role);
|
||||
}
|
||||
|
||||
public boolean verifyPassword() {
|
||||
return password != null && password.length() > 4 && password.equals(passwordVerify);
|
||||
}
|
||||
}
|
||||
104
src/main/java/de/mbremer/secutity/UserResource.java
Normal file
104
src/main/java/de/mbremer/secutity/UserResource.java
Normal file
@@ -0,0 +1,104 @@
|
||||
package de.mbremer.secutity;
|
||||
|
||||
import io.quarkus.qute.Location;
|
||||
import io.quarkus.qute.Template;
|
||||
import io.quarkus.qute.TemplateInstance;
|
||||
import io.quarkus.security.identity.SecurityIdentity;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;
|
||||
|
||||
import javax.annotation.security.PermitAll;
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
import javax.inject.Inject;
|
||||
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 static de.mbremer.secutity.Role.ADMIN;
|
||||
|
||||
@Path("/user")
|
||||
@RolesAllowed("ADMIN")
|
||||
public class UserResource {
|
||||
|
||||
@Inject
|
||||
Logger log;
|
||||
@Inject
|
||||
SecurityIdentity identity;
|
||||
@Inject
|
||||
Template userinit;
|
||||
@Inject
|
||||
@Location("user.html")
|
||||
Template userTemplate;
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
@RolesAllowed({"USER", "ADMIN"})
|
||||
public TemplateInstance getUser() {
|
||||
return userTemplate
|
||||
.data("user_count", User.count())
|
||||
.data("current_username", identity.getPrincipal().getName())
|
||||
.data("is_admin", identity.hasRole("ADMIN"));
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Transactional
|
||||
@Path("init")
|
||||
@PermitAll
|
||||
public Response initialAdd(@MultipartForm UserForm userForm) {
|
||||
if(User.count("role", ADMIN.name()) > 0) {
|
||||
throw new BadRequestException("Only allowed on initial set up");
|
||||
}
|
||||
if(!ADMIN.name().equals(userForm.role)) {
|
||||
throw new BadRequestException("Only role ADMIN");
|
||||
}
|
||||
|
||||
User user = userForm.getUser();
|
||||
user.persist();
|
||||
|
||||
return Response.status(Response.Status.SEE_OTHER)
|
||||
.location(URI.create("/login.html"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
@Path("init")
|
||||
@PermitAll
|
||||
public TemplateInstance initial() {
|
||||
if(User.count("role", ADMIN.name()) > 0) {
|
||||
throw new BadRequestException("Only allowed on initial set up");
|
||||
}
|
||||
return userinit.instance();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
@Path("logout")
|
||||
@RolesAllowed({"USER", "ADMIN"})
|
||||
public Response logout() {
|
||||
return Response
|
||||
.temporaryRedirect(URI.create("/"))
|
||||
.cookie(new NewCookie("quarkus-credential", null, "/", null, null, 0, false,true))
|
||||
.build();
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
@Transactional
|
||||
@Path("/new")
|
||||
public TemplateInstance add(@MultipartForm UserForm userForm) {
|
||||
if (!userForm.verifyPassword()) {
|
||||
return getUser().data("error", "Das Passwort ist zu kurz oder stimmt nicht mit der Wiederholung überein.");
|
||||
}
|
||||
|
||||
User user = userForm.getUser();
|
||||
user.persist();
|
||||
|
||||
return getUser().data("info", "User angelegt.");
|
||||
}
|
||||
}
|
||||
20
src/main/resources/META-INF/resources/error.html
Normal file
20
src/main/resources/META-INF/resources/error.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/webjars/bootstrap/5.0.0/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/webjars/bootstrap-icons/1.5.0/font/bootstrap-icons.css">
|
||||
<title>Bürokalender</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-lg fs-5">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
Ups, da klappt etwas nicht!
|
||||
</div>
|
||||
<div>
|
||||
<a class="btn btn-primary" href="/" role="button">Home</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
10
src/main/resources/META-INF/resources/index.html
Normal file
10
src/main/resources/META-INF/resources/index.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Refresh" content="0; url=/kalender"/>
|
||||
<title>Bürokalender</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Weiterleitung auf die <a href="/kalender">Startseite</a></p></body>
|
||||
</html>
|
||||
33
src/main/resources/META-INF/resources/login.html
Normal file
33
src/main/resources/META-INF/resources/login.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/webjars/bootstrap/5.0.0/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/webjars/bootstrap-icons/1.5.0/font/bootstrap-icons.css">
|
||||
<title>Bürokalender</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container col-xl-10 p-3">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-3">
|
||||
<div class="navbar-brand"><i class="bi-puzzle"></i> Bürokalender</div>
|
||||
</nav>
|
||||
<div class="row align-items-center g-lg-5 py-5">
|
||||
<div class="col-md-10 mx-auto col-lg-5">
|
||||
<form class="p-4 p-md-5 border rounded-3 bg-light" action="j_security_check" method="post">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" name="j_username" class="form-control" id="floatingInput" placeholder="name@example.com">
|
||||
<label for="floatingInput">Benutzername</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="password" name="j_password" class="form-control" id="floatingPassword" placeholder="Password">
|
||||
<label for="floatingPassword">Passwort</label>
|
||||
</div>
|
||||
<button class="w-100 btn btn-lg btn-primary" type="submit">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/webjars/bootstrap/5.0.0/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
16
src/main/resources/application.properties
Normal file
16
src/main/resources/application.properties
Normal file
@@ -0,0 +1,16 @@
|
||||
# Database
|
||||
%prod.quarkus.datasource.jdbc.url = jdbc:postgresql://db:5432/buerokalender
|
||||
%prod.quarkus.datasource.username = buerokalender
|
||||
%prod.quarkus.datasource.password = buerokalender
|
||||
%prod.quarkus.datasource.jdbc.max-size=16
|
||||
quarkus.datasource.db-kind=postgresql
|
||||
|
||||
quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQL95Dialect
|
||||
|
||||
quarkus.flyway.migrate-at-start=true
|
||||
|
||||
# Security
|
||||
quarkus.http.auth.form.enabled=true
|
||||
quarkus.http.auth.session.encryption-key=zHId14V+uiyxmbzhEPCyi7VvbaI80UeEO5yu0H/hVLs=
|
||||
# 24h
|
||||
quarkus.http.auth.form.timeout=86400
|
||||
14
src/main/resources/db/migration/V0001__initial.sql
Normal file
14
src/main/resources/db/migration/V0001__initial.sql
Normal file
@@ -0,0 +1,14 @@
|
||||
create sequence hibernate_sequence start 1;
|
||||
|
||||
create table users (
|
||||
id bigint not null primary key,
|
||||
username varchar not null unique,
|
||||
password varchar not null,
|
||||
role varchar not null
|
||||
);
|
||||
|
||||
create table kalendertag (
|
||||
id bigint not null primary key,
|
||||
date date not null unique,
|
||||
inoffice_id bigint not null references users
|
||||
);
|
||||
33
src/main/resources/templates/base.html
Normal file
33
src/main/resources/templates/base.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/webjars/bootstrap/5.0.0/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/webjars/bootstrap-icons/1.5.0/font/bootstrap-icons.css">
|
||||
|
||||
<title>Bürokalender</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container col-xl-10 p-3">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-3">
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
|
||||
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="navbar-brand ml-2"><i class="bi-puzzle"></i> Bürokalender</div>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<div class="navbar-nav mr-auto">
|
||||
<a class="nav-item nav-link {#insert kalender_active}{/}" href="/kalender">Kalender</a>
|
||||
<a class="nav-item nav-link {#insert user_active}{/}" href="/user">Benutzer</a>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-outline-primary me-2" href="/user/logout">Logout</a>
|
||||
</nav>
|
||||
{#if error}<div class="alert alert-danger" role="alert">{error}</div>{/if}
|
||||
{#if info}<div class="alert alert-primary" role="alert">{info}</div>{/if}
|
||||
{#insert contents}No contents!{/}
|
||||
</div>
|
||||
<script src="/webjars/bootstrap/5.0.0/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
12
src/main/resources/templates/kalender.html
Normal file
12
src/main/resources/templates/kalender.html
Normal file
@@ -0,0 +1,12 @@
|
||||
{#include base.html}
|
||||
{#kalender_active}active{/}
|
||||
{#contents}
|
||||
|
||||
<div class="mt-2">
|
||||
aktuelle Woche<br>
|
||||
nächste Woche<br>
|
||||
übernächste Woche<br>
|
||||
</div>
|
||||
|
||||
{/contents}
|
||||
{/include}
|
||||
29
src/main/resources/templates/password-modal.html
Normal file
29
src/main/resources/templates/password-modal.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<div class="modal fade" id="passwordModal" tabindex="-1" aria-labelledby="passwordModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="userModalLabel">Passwort ändern</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<form action="/user/password" method="POST" name="userForm" enctype="multipart/form-data">
|
||||
<div class="modal-body row mb-3">
|
||||
<div class="align-items-center col-md-10 mx-auto col-lg-11">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="password" name="password" class="form-control" id="pwd" placeholder="Password" required>
|
||||
<label for="pwd">Passwort</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="password" name="passwordVerify" class="form-control" id="pwdv" placeholder="Passwort wiederholen" required>
|
||||
<label for="pwd">Passwort wiederholen</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
|
||||
<button type="submit" class="btn btn-primary">Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
40
src/main/resources/templates/user-modal.html
Normal file
40
src/main/resources/templates/user-modal.html
Normal file
@@ -0,0 +1,40 @@
|
||||
<div class="modal fade" id="userModal" tabindex="-1" aria-labelledby="userModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="userModalLabel">Benutzer anlegen</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<form action="/user/new" method="POST" name="userForm" enctype="multipart/form-data">
|
||||
<div class="modal-body row mb-3">
|
||||
<div class="align-items-center col-md-10 mx-auto col-lg-11">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" name="username" class="form-control" id="name" placeholder="Benutzername" required>
|
||||
<label for="name">Benutzername</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="password" name="password" class="form-control" id="pwd" placeholder="Password" required>
|
||||
<label for="pwd">Passwort</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="password" name="passwordVerify" class="form-control" id="pwdv" placeholder="Passwort wiederholen" required>
|
||||
<label for="pwd">Passwort wiederholen</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<select id="role" name="role" class="form-select" required>
|
||||
<option selected>USER</option>
|
||||
<option>ADMIN</option>
|
||||
</select>
|
||||
<label class="col-sm-3 col-form-label1" for="role">Rolle</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
|
||||
<button type="submit" class="btn btn-primary">Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
21
src/main/resources/templates/user.html
Normal file
21
src/main/resources/templates/user.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{#include base.html}
|
||||
{#user_active}active{/}
|
||||
{#contents}
|
||||
|
||||
<div class="mt-2">
|
||||
<h2>Hallo {current_username}</h2>
|
||||
{#if is_admin}User: {user_count}{/if}
|
||||
</div>
|
||||
|
||||
<div class="mt-2" >
|
||||
{#if is_admin}
|
||||
<a class="btn btn-primary btn" data-bs-toggle="modal" data-bs-target="#userModal" role="button">neuer Benutzer</a>
|
||||
{/if}
|
||||
<a class="btn btn-primary btn" data-bs-toggle="modal" data-bs-target="#passwordModal" role="button">Passwort ändern</a>
|
||||
{#if is_admin}
|
||||
{#include user-modal.html}{/include}
|
||||
{/if}
|
||||
{#include password-modal.html}{/include}
|
||||
</div>
|
||||
{/contents}
|
||||
{/include}
|
||||
30
src/main/resources/templates/userinit.html
Normal file
30
src/main/resources/templates/userinit.html
Normal file
@@ -0,0 +1,30 @@
|
||||
{#include base.html}
|
||||
{#contents}
|
||||
|
||||
<div class="container mt-2">
|
||||
<p>Die Anwendung kennt noch keinen Benutzer.</p>
|
||||
<p><b>Bitte lege einen Admin-Benutzer an.</b></p>
|
||||
|
||||
<form action="/user/init" method="POST" name="userForm" enctype="multipart/form-data">
|
||||
<div class="form-row align-items-center">
|
||||
<div class="col-sm-3 my-1">
|
||||
<label class="sr-only" for="name">Name</label>
|
||||
<input type="text" name="username" class="form-control" id="name" placeholder="Benutzername" required autofocus>
|
||||
</div>
|
||||
<div class="col-sm-3 my-1">
|
||||
<label class="sr-only" for="pwd">Passwort</label>
|
||||
<input type="password" name="password" class="form-control" id="pwd" placeholder="Passwort" required>
|
||||
</div>
|
||||
<div class="col-sm-3 my-1">
|
||||
<label class="sr-only" for="pwd">Rolle</label>
|
||||
<input type="text" name="role" class="form-control" id="role" value="ADMIN" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class="btn btn-primary">Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{/contents}
|
||||
{/include}
|
||||
Reference in New Issue
Block a user