Erweiterungen
This commit is contained in:
5
pom.xml
5
pom.xml
@@ -87,6 +87,11 @@
|
|||||||
<artifactId>openpdf</artifactId>
|
<artifactId>openpdf</artifactId>
|
||||||
<version>1.3.30</version>
|
<version>1.3.30</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.mail</groupId>
|
||||||
|
<artifactId>jakarta.mail</artifactId>
|
||||||
|
<version>2.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ public class AppUser {
|
|||||||
@Field("app_device_id")
|
@Field("app_device_id")
|
||||||
private ObjectId appDeviceId;
|
private ObjectId appDeviceId;
|
||||||
|
|
||||||
|
@Field("owner")
|
||||||
|
private ObjectId owner;
|
||||||
|
|
||||||
@Field("erstellt_am")
|
@Field("erstellt_am")
|
||||||
private LocalDateTime erstelltAm;
|
private LocalDateTime erstelltAm;
|
||||||
|
|
||||||
|
|||||||
@@ -98,9 +98,9 @@ public final class MainLayout extends AppLayout {
|
|||||||
userContent.setSpacing(true);
|
userContent.setSpacing(true);
|
||||||
|
|
||||||
// Create navigation items for the collapsible list
|
// Create navigation items for the collapsible list
|
||||||
SideNavItem profile = new SideNavItem("Mein Profil", "7", new Icon(VaadinIcon.COG));
|
SideNavItem profile = new SideNavItem("Mein Profil", "edit-profile", new Icon(VaadinIcon.USER));
|
||||||
SideNavItem myInvoices = new SideNavItem("Meine Rechnungen", "8", new Icon(VaadinIcon.COG));
|
SideNavItem myInvoices = new SideNavItem("Meine Rechnungen", "8", new Icon(VaadinIcon.COG));
|
||||||
SideNavItem imprint = new SideNavItem("Impressum", "9", new Icon(VaadinIcon.COG));
|
SideNavItem imprint = new SideNavItem("Impressum", "impressum", new Icon(VaadinIcon.INFO_CIRCLE));
|
||||||
|
|
||||||
userContent.add(profile, myInvoices, imprint);
|
userContent.add(profile, myInvoices, imprint);
|
||||||
userDetails.add(userContent);
|
userDetails.add(userContent);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public class AppUserService {
|
|||||||
ObjectId currentUserId = securityService.getCurrentUserId();
|
ObjectId currentUserId = securityService.getCurrentUserId();
|
||||||
appUser.setErstelltVon(currentUserId);
|
appUser.setErstelltVon(currentUserId);
|
||||||
appUser.setAktualisiertVon(currentUserId);
|
appUser.setAktualisiertVon(currentUserId);
|
||||||
|
appUser.setOwner(currentUserId);
|
||||||
|
|
||||||
return appUserRepository.save(appUser);
|
return appUserRepository.save(appUser);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,7 @@ import com.vaadin.flow.router.PageTitle;
|
|||||||
import com.vaadin.flow.router.Route;
|
import com.vaadin.flow.router.Route;
|
||||||
import de.assecutor.votianlt.model.AppUser;
|
import de.assecutor.votianlt.model.AppUser;
|
||||||
import de.assecutor.votianlt.pages.service.AppUserService;
|
import de.assecutor.votianlt.pages.service.AppUserService;
|
||||||
import de.assecutor.votianlt.model.AppDevice;
|
|
||||||
import de.assecutor.votianlt.pages.service.AppDeviceService;
|
|
||||||
import jakarta.annotation.security.RolesAllowed;
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
@PageTitle("App-Nutzer")
|
@PageTitle("App-Nutzer")
|
||||||
@Route(value = "app-user", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
|
@Route(value = "app-user", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
|
||||||
@@ -25,12 +22,9 @@ public class AppUserView extends VerticalLayout {
|
|||||||
|
|
||||||
private final AppUserService appUserService;
|
private final AppUserService appUserService;
|
||||||
private final Grid<AppUser> appUserGrid;
|
private final Grid<AppUser> appUserGrid;
|
||||||
private final AppDeviceService appDeviceService;
|
|
||||||
|
|
||||||
@Autowired
|
public AppUserView(AppUserService appUserService) {
|
||||||
public AppUserView(AppUserService appUserService, AppDeviceService appDeviceService) {
|
|
||||||
this.appUserService = appUserService;
|
this.appUserService = appUserService;
|
||||||
this.appDeviceService = appDeviceService;
|
|
||||||
|
|
||||||
setSizeFull();
|
setSizeFull();
|
||||||
setPadding(true);
|
setPadding(true);
|
||||||
@@ -63,13 +57,7 @@ public class AppUserView extends VerticalLayout {
|
|||||||
appUserGrid.addColumn(AppUser::getTelefon).setHeader("Telefon").setAutoWidth(true);
|
appUserGrid.addColumn(AppUser::getTelefon).setHeader("Telefon").setAutoWidth(true);
|
||||||
appUserGrid.addColumn(AppUser::getAppCode).setHeader("App-Code").setAutoWidth(true);
|
appUserGrid.addColumn(AppUser::getAppCode).setHeader("App-Code").setAutoWidth(true);
|
||||||
appUserGrid.addColumn(AppUser::getEmail).setHeader("E-Mail").setAutoWidth(true);
|
appUserGrid.addColumn(AppUser::getEmail).setHeader("E-Mail").setAutoWidth(true);
|
||||||
appUserGrid.addColumn(appUser -> {
|
appUserGrid.addColumn(AppUser::getGeraet).setHeader("Gerät").setAutoWidth(true);
|
||||||
if (appUser.getAppDeviceId() != null) {
|
|
||||||
AppDevice device = appDeviceService.findById(appUser.getAppDeviceId());
|
|
||||||
return device != null ? device.getName() : "Unbekannt";
|
|
||||||
}
|
|
||||||
return "Nicht zugeordnet";
|
|
||||||
}).setHeader("Gerät").setAutoWidth(true);
|
|
||||||
|
|
||||||
// Make grid rows clickable
|
// Make grid rows clickable
|
||||||
appUserGrid.setSelectionMode(Grid.SelectionMode.SINGLE);
|
appUserGrid.setSelectionMode(Grid.SelectionMode.SINGLE);
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
package de.assecutor.votianlt.pages.view;
|
||||||
|
|
||||||
|
import com.vaadin.flow.component.button.Button;
|
||||||
|
import com.vaadin.flow.component.button.ButtonVariant;
|
||||||
|
import com.vaadin.flow.component.checkbox.Checkbox;
|
||||||
|
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||||
|
import com.vaadin.flow.component.html.Div;
|
||||||
|
import com.vaadin.flow.component.html.H2;
|
||||||
|
import com.vaadin.flow.component.html.Label;
|
||||||
|
import com.vaadin.flow.component.html.Paragraph;
|
||||||
|
import com.vaadin.flow.component.icon.Icon;
|
||||||
|
import com.vaadin.flow.component.icon.VaadinIcon;
|
||||||
|
import com.vaadin.flow.component.notification.Notification;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.FlexComponent;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.component.textfield.EmailField;
|
||||||
|
import com.vaadin.flow.component.textfield.TextField;
|
||||||
|
import com.vaadin.flow.component.textfield.NumberField;
|
||||||
|
import com.vaadin.flow.router.PageTitle;
|
||||||
|
import com.vaadin.flow.router.Route;
|
||||||
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
|
|
||||||
|
@PageTitle("Profil bearbeiten")
|
||||||
|
@Route(value = "edit-profile", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
|
||||||
|
@RolesAllowed({"USER","ADMIN"})
|
||||||
|
public class EditProfileView extends HorizontalLayout {
|
||||||
|
public EditProfileView() {
|
||||||
|
setSizeFull();
|
||||||
|
setPadding(true);
|
||||||
|
setSpacing(true);
|
||||||
|
setJustifyContentMode(JustifyContentMode.CENTER);
|
||||||
|
setAlignItems(Alignment.START);
|
||||||
|
|
||||||
|
// Linke Spalte: Formular
|
||||||
|
VerticalLayout formColumn = new VerticalLayout();
|
||||||
|
formColumn.setWidth("500px");
|
||||||
|
formColumn.setPadding(false);
|
||||||
|
formColumn.setSpacing(false);
|
||||||
|
|
||||||
|
FormLayout form = new FormLayout();
|
||||||
|
form.setWidthFull();
|
||||||
|
form.setResponsiveSteps(new FormLayout.ResponsiveStep("0", 2));
|
||||||
|
|
||||||
|
// Firmenfelder
|
||||||
|
TextField companyField = new TextField("Firma*");
|
||||||
|
TextField companyAddField = new TextField("Firmenzusatz");
|
||||||
|
TextField firstnameField = new TextField("Vorname*");
|
||||||
|
TextField lastnameField = new TextField("Nachname*");
|
||||||
|
TextField phoneField = new TextField("Telefonnummer*");
|
||||||
|
TextField faxField = new TextField("Telefon (Fax)");
|
||||||
|
TextField mobileField = new TextField("Telefon (Mobil)");
|
||||||
|
EmailField emailField = new EmailField("E-Mail-Adresse (Login)*");
|
||||||
|
TextField streetField = new TextField("Straße*");
|
||||||
|
TextField houseNumberField = new TextField("Hausnr*");
|
||||||
|
TextField addressAddField = new TextField("Adresszusatz");
|
||||||
|
TextField zipField = new TextField("Postleitzahl*");
|
||||||
|
TextField cityField = new TextField("Stadt*");
|
||||||
|
|
||||||
|
// Pflichtfeldhinweis
|
||||||
|
Paragraph pflichtHinweis = new Paragraph("Die mit (*) gekennzeichneten Felder sind Pflichtfelder.");
|
||||||
|
pflichtHinweis.getStyle().set("color", "#d32f2f").set("fontWeight", "bold");
|
||||||
|
|
||||||
|
// Abweichende Rechnungsadresse
|
||||||
|
Checkbox diffInvoiceAddress = new Checkbox("Abweichende Rechnungsadresse");
|
||||||
|
diffInvoiceAddress.getStyle().set("marginTop", "1em");
|
||||||
|
// Rechnungsadresse Felder (disabled by default)
|
||||||
|
TextField invCompanyField = new TextField("Firma*");
|
||||||
|
TextField invCompanyAddField = new TextField("Firmenzusatz");
|
||||||
|
TextField invFirstnameField = new TextField("Vorname*");
|
||||||
|
TextField invLastnameField = new TextField("Nachname*");
|
||||||
|
TextField invStreetField = new TextField("Straße*");
|
||||||
|
TextField invHouseNumberField = new TextField("Hausnr*");
|
||||||
|
TextField invAddressAddField = new TextField("Adresszusatz");
|
||||||
|
TextField invZipField = new TextField("Postleitzahl*");
|
||||||
|
TextField invCityField = new TextField("Stadt*");
|
||||||
|
invCompanyField.setEnabled(false);
|
||||||
|
invCompanyAddField.setEnabled(false);
|
||||||
|
invFirstnameField.setEnabled(false);
|
||||||
|
invLastnameField.setEnabled(false);
|
||||||
|
invStreetField.setEnabled(false);
|
||||||
|
invHouseNumberField.setEnabled(false);
|
||||||
|
invAddressAddField.setEnabled(false);
|
||||||
|
invZipField.setEnabled(false);
|
||||||
|
invCityField.setEnabled(false);
|
||||||
|
diffInvoiceAddress.addValueChangeListener(e -> {
|
||||||
|
boolean enabled = e.getValue();
|
||||||
|
invCompanyField.setEnabled(enabled);
|
||||||
|
invCompanyAddField.setEnabled(enabled);
|
||||||
|
invFirstnameField.setEnabled(enabled);
|
||||||
|
invLastnameField.setEnabled(enabled);
|
||||||
|
invStreetField.setEnabled(enabled);
|
||||||
|
invHouseNumberField.setEnabled(enabled);
|
||||||
|
invAddressAddField.setEnabled(enabled);
|
||||||
|
invZipField.setEnabled(enabled);
|
||||||
|
invCityField.setEnabled(enabled);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Formularfelder hinzufügen
|
||||||
|
form.add(companyField, 2);
|
||||||
|
form.add(companyAddField, 2);
|
||||||
|
form.add(firstnameField, lastnameField);
|
||||||
|
form.add(phoneField, faxField);
|
||||||
|
form.add(mobileField, 2);
|
||||||
|
form.add(emailField, 2);
|
||||||
|
form.add(streetField, houseNumberField);
|
||||||
|
form.add(addressAddField, 2);
|
||||||
|
form.add(zipField, cityField);
|
||||||
|
form.add(diffInvoiceAddress, 2);
|
||||||
|
form.add(invCompanyField, 2);
|
||||||
|
form.add(invCompanyAddField, 2);
|
||||||
|
form.add(invFirstnameField, invLastnameField);
|
||||||
|
form.add(invStreetField, invHouseNumberField);
|
||||||
|
form.add(invAddressAddField, 2);
|
||||||
|
form.add(invZipField, invCityField);
|
||||||
|
|
||||||
|
formColumn.add(form, pflichtHinweis);
|
||||||
|
|
||||||
|
// Schalter
|
||||||
|
Checkbox locateAppUser = new Checkbox("App-Nutzer orten");
|
||||||
|
Checkbox digitalProcess = new Checkbox("Digitale Abwicklung");
|
||||||
|
Checkbox invoiceViaVotianlt = new Checkbox("Rechnungslegung über votianlt");
|
||||||
|
formColumn.add(locateAppUser, digitalProcess, invoiceViaVotianlt);
|
||||||
|
|
||||||
|
// Rechte Spalte: Karte und Aktionen
|
||||||
|
VerticalLayout rightColumn = new VerticalLayout();
|
||||||
|
rightColumn.setWidth("100%");
|
||||||
|
rightColumn.setAlignItems(Alignment.CENTER);
|
||||||
|
rightColumn.setSpacing(true);
|
||||||
|
rightColumn.setPadding(false);
|
||||||
|
|
||||||
|
// Koordinatenanzeige
|
||||||
|
Label coordsLabel = new Label("53°36'25.1\"N 10°06'46.9\"E");
|
||||||
|
coordsLabel.getStyle().set("fontWeight", "bold").set("marginTop", "1em");
|
||||||
|
rightColumn.add(coordsLabel);
|
||||||
|
|
||||||
|
// Google Maps Platzhalter (iFrame)
|
||||||
|
Div mapDiv = new Div();
|
||||||
|
mapDiv.setWidth("400px");
|
||||||
|
mapDiv.setHeight("400px");
|
||||||
|
mapDiv.getElement().setProperty("innerHTML",
|
||||||
|
"<iframe width='100%' height='100%' frameborder='0' style='border:0' " +
|
||||||
|
"src='https://www.google.com/maps/embed/v1/place?key=AIzaSyDnbitL06iLp3elmj-WtPudCykX9xvXcVE&q=53.6070,10.1125' allowfullscreen></iframe>");
|
||||||
|
rightColumn.add(mapDiv);
|
||||||
|
|
||||||
|
// 2-Faktor Auth
|
||||||
|
Checkbox twoFactor = new Checkbox("2-Faktor-Authentifizierung");
|
||||||
|
Icon twoFactorInfo = VaadinIcon.QUESTION_CIRCLE_O.create();
|
||||||
|
twoFactorInfo.getStyle().set("marginLeft", "0.3em");
|
||||||
|
HorizontalLayout twoFactorLayout = new HorizontalLayout(twoFactor, twoFactorInfo);
|
||||||
|
twoFactorLayout.setAlignItems(Alignment.CENTER);
|
||||||
|
rightColumn.add(twoFactorLayout);
|
||||||
|
|
||||||
|
// Passwort ändern Button
|
||||||
|
Button changePassword = new Button("Passwort ändern");
|
||||||
|
changePassword.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||||
|
rightColumn.add(changePassword);
|
||||||
|
|
||||||
|
// Benutzerkonto löschen Button
|
||||||
|
Button deleteAccount = new Button("Benutzerkonto löschen");
|
||||||
|
deleteAccount.addThemeVariants(ButtonVariant.LUMO_ERROR);
|
||||||
|
rightColumn.add(deleteAccount);
|
||||||
|
|
||||||
|
// Profil speichern Button (unten rechts)
|
||||||
|
Button saveProfile = new Button("Profiländerungen speichern");
|
||||||
|
saveProfile.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||||
|
saveProfile.getStyle().set("position", "absolute").set("right", "2em").set("bottom", "2em");
|
||||||
|
add(formColumn, rightColumn, saveProfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package de.assecutor.votianlt.pages.view;
|
||||||
|
|
||||||
|
import com.vaadin.flow.component.html.H2;
|
||||||
|
import com.vaadin.flow.component.html.Paragraph;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.router.PageTitle;
|
||||||
|
import com.vaadin.flow.router.Route;
|
||||||
|
import jakarta.annotation.security.PermitAll;
|
||||||
|
|
||||||
|
@PageTitle("Impressum")
|
||||||
|
@Route(value = "impressum", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
|
||||||
|
@PermitAll
|
||||||
|
public class ImprintView extends VerticalLayout {
|
||||||
|
public ImprintView() {
|
||||||
|
setSizeFull();
|
||||||
|
setPadding(true);
|
||||||
|
setSpacing(true);
|
||||||
|
setAlignItems(Alignment.CENTER);
|
||||||
|
|
||||||
|
H2 title = new H2("Impressum");
|
||||||
|
add(title);
|
||||||
|
|
||||||
|
Paragraph p1 = new Paragraph("Max Mustermann\nMusterstraße 1\n12345 Musterstadt\nDeutschland");
|
||||||
|
Paragraph p2 = new Paragraph("Telefon: +49 123 456789\nE-Mail: info@example.com");
|
||||||
|
Paragraph p3 = new Paragraph("Umsatzsteuer-ID: DE123456789\nHandelsregister: Amtsgericht Musterstadt, HRB 12345");
|
||||||
|
Paragraph p4 = new Paragraph("Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV: Max Mustermann");
|
||||||
|
|
||||||
|
add(p1, p2, p3, p4);
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/main/java/de/assecutor/votianlt/util/MailUtil.java
Normal file
41
src/main/java/de/assecutor/votianlt/util/MailUtil.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package de.assecutor.votianlt.util;
|
||||||
|
|
||||||
|
import jakarta.mail.Message;
|
||||||
|
import jakarta.mail.MessagingException;
|
||||||
|
import jakarta.mail.PasswordAuthentication;
|
||||||
|
import jakarta.mail.Session;
|
||||||
|
import jakarta.mail.Transport;
|
||||||
|
import jakarta.mail.internet.InternetAddress;
|
||||||
|
import jakarta.mail.internet.MimeMessage;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class MailUtil {
|
||||||
|
public static void sendMail(String to, String subject, String body) throws MessagingException {
|
||||||
|
// SMTP-Konfiguration (hier Beispiel für Gmail, anpassen für Produktivsystem!)
|
||||||
|
final String username = "your-email@gmail.com"; // TODO: ersetzen
|
||||||
|
final String password = "your-password"; // TODO: ersetzen
|
||||||
|
final String host = "smtp.gmail.com";
|
||||||
|
final int port = 587;
|
||||||
|
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.put("mail.smtp.auth", "true");
|
||||||
|
props.put("mail.smtp.starttls.enable", "true");
|
||||||
|
props.put("mail.smtp.host", host);
|
||||||
|
props.put("mail.smtp.port", String.valueOf(port));
|
||||||
|
|
||||||
|
Session session = Session.getInstance(props, new jakarta.mail.Authenticator() {
|
||||||
|
@Override
|
||||||
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
|
return new PasswordAuthentication(username, password);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Message message = new MimeMessage(session);
|
||||||
|
message.setFrom(new InternetAddress(username));
|
||||||
|
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
|
||||||
|
message.setSubject(subject);
|
||||||
|
message.setText(body);
|
||||||
|
|
||||||
|
Transport.send(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user