diff --git a/pom.xml b/pom.xml
index e1c3f1f..d43a0b5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,6 +12,9 @@
21
+ 21
+ 21
+ 21
24.7.0
1.3.0
@@ -67,10 +70,16 @@
spring-boot-starter-data-mongodb
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
org.projectlombok
lombok
- 1.18.30
+ 1.18.38
provided
@@ -82,6 +91,23 @@
org.springframework.boot
spring-boot-maven-plugin
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ 21
+ 21
+ 21
+
+
+ org.projectlombok
+ lombok
+ 1.18.38
+
+
+
+
com.diffplug.spotless
spotless-maven-plugin
diff --git a/src/main/java/de/assecutor/votianlt/config/DataInitializer.java b/src/main/java/de/assecutor/votianlt/config/DataInitializer.java
new file mode 100644
index 0000000..2d1c076
--- /dev/null
+++ b/src/main/java/de/assecutor/votianlt/config/DataInitializer.java
@@ -0,0 +1,88 @@
+package de.assecutor.votianlt.config;
+
+import de.assecutor.votianlt.model.User;
+import de.assecutor.votianlt.repository.UserRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.util.Set;
+
+@Component
+public class DataInitializer implements CommandLineRunner {
+
+ private static final Logger log = LoggerFactory.getLogger(DataInitializer.class);
+
+ private final UserRepository userRepository;
+ private final PasswordEncoder passwordEncoder;
+
+ public DataInitializer(UserRepository userRepository, PasswordEncoder passwordEncoder) {
+ this.userRepository = userRepository;
+ this.passwordEncoder = passwordEncoder;
+ }
+
+ @Override
+ public void run(String... args) throws Exception {
+ initializeTestUsers();
+ }
+
+ private void initializeTestUsers() {
+ log.info("Initializing test users...");
+
+ // Admin User
+ if (!userRepository.existsByEmail("admin@votianlt.de")) {
+ User adminUser = new User();
+ adminUser.setEmail("admin@votianlt.de");
+ adminUser.setPassword(passwordEncoder.encode("admin123"));
+ adminUser.setName("Administrator");
+ adminUser.setFirstname("Admin");
+ adminUser.setIsActivated((byte) 1);
+ adminUser.setIsEmailConfirmed((byte) 1);
+ adminUser.setCreatedAt(LocalDateTime.now());
+ adminUser.setUpdatedAt(LocalDateTime.now());
+ adminUser.setRoles(Set.of("USER", "ADMIN"));
+
+ userRepository.save(adminUser);
+ log.info("Created admin user: admin@votianlt.de / admin123");
+ }
+
+ // Test User
+ if (!userRepository.existsByEmail("test@votianlt.de")) {
+ User testUser = new User();
+ testUser.setEmail("test@votianlt.de");
+ testUser.setPassword(passwordEncoder.encode("test123"));
+ testUser.setName("Testmann");
+ testUser.setFirstname("Test");
+ testUser.setIsActivated((byte) 1);
+ testUser.setIsEmailConfirmed((byte) 1);
+ testUser.setCreatedAt(LocalDateTime.now());
+ testUser.setUpdatedAt(LocalDateTime.now());
+ testUser.setRoles(Set.of("USER"));
+
+ userRepository.save(testUser);
+ log.info("Created test user: test@votianlt.de / test123");
+ }
+
+ // Demo User
+ if (!userRepository.existsByEmail("demo@votianlt.de")) {
+ User demoUser = new User();
+ demoUser.setEmail("demo@votianlt.de");
+ demoUser.setPassword(passwordEncoder.encode("demo123"));
+ demoUser.setName("Demouser");
+ demoUser.setFirstname("Demo");
+ demoUser.setIsActivated((byte) 1);
+ demoUser.setIsEmailConfirmed((byte) 1);
+ demoUser.setCreatedAt(LocalDateTime.now());
+ demoUser.setUpdatedAt(LocalDateTime.now());
+ demoUser.setRoles(Set.of("USER"));
+
+ userRepository.save(demoUser);
+ log.info("Created demo user: demo@votianlt.de / demo123");
+ }
+
+ log.info("Test users initialization completed.");
+ }
+}
diff --git a/src/main/java/de/assecutor/votianlt/model/Company.java b/src/main/java/de/assecutor/votianlt/model/Company.java
index 62f9b7b..e05e762 100644
--- a/src/main/java/de/assecutor/votianlt/model/Company.java
+++ b/src/main/java/de/assecutor/votianlt/model/Company.java
@@ -6,12 +6,12 @@ import org.bson.types.ObjectId;
@Data
public class Company
{
- public ObjectId id;
+ private ObjectId id;
- public String name;
- public String street;
- public String houseNumber;
- public String addressAddition;
- public String zip;
- public String city;
+ private String name;
+ private String street;
+ private String houseNumber;
+ private String addressAddition;
+ private String zip;
+ private String city;
}
\ No newline at end of file
diff --git a/src/main/java/de/assecutor/votianlt/model/Customer.java b/src/main/java/de/assecutor/votianlt/model/Customer.java
index c54fa29..ef34f2f 100644
--- a/src/main/java/de/assecutor/votianlt/model/Customer.java
+++ b/src/main/java/de/assecutor/votianlt/model/Customer.java
@@ -7,17 +7,16 @@ import org.bson.types.ObjectId;
public class Customer
{
private ObjectId id;
-
- public String title;
- public String companyName;
- public String firstname;
- public String lastName;
- public String telephone;
- public String fax;
- public String mail;
- public String street;
- public String houseNumber;
- public String addressAddition;
- public String zip;
- public String city;
+ private String title;
+ private String companyName;
+ private String firstname;
+ private String lastName;
+ private String telephone;
+ private String fax;
+ private String mail;
+ private String street;
+ private String houseNumber;
+ private String addressAddition;
+ private String zip;
+ private String city;
}
\ No newline at end of file
diff --git a/src/main/java/de/assecutor/votianlt/model/Job.java b/src/main/java/de/assecutor/votianlt/model/Job.java
new file mode 100644
index 0000000..a371aff
--- /dev/null
+++ b/src/main/java/de/assecutor/votianlt/model/Job.java
@@ -0,0 +1,42 @@
+package de.assecutor.votianlt.model;
+
+import lombok.Data;
+import org.bson.types.ObjectId;
+
+@Data
+public class Job {
+ private ObjectId id;
+
+ // Auftraggeber/Rechnungsempfänger
+ private String customerSelection; // Kunde01 | KOTVor K01Nach
+
+ // Abholadresse
+ private String pickupCompany;
+ private String pickupSalutation;
+ private String pickupFirstName;
+ private String pickupLastName;
+ private String pickupPhone;
+ private String pickupStreet;
+ private String pickupHouseNumber;
+ private String pickupAddressAddition;
+ private String pickupZip;
+ private String pickupCity;
+ private boolean savePickupAddress;
+
+ // Lieferadresse
+ private String deliveryCompany;
+ private String deliverySalutation;
+ private String deliveryFirstName;
+ private String deliveryLastName;
+ private String deliveryPhone;
+ private String deliveryStreet;
+ private String deliveryHouseNumber;
+ private String deliveryAddressAddition;
+ private String deliveryZip;
+ private String deliveryCity;
+ private boolean saveDeliveryAddress;
+
+ // Digitale Abwicklung per App
+ private boolean digitalProcessing;
+ private String appUser;
+}
diff --git a/src/main/java/de/assecutor/votianlt/model/User.java b/src/main/java/de/assecutor/votianlt/model/User.java
index 9c5c0c6..c95405d 100644
--- a/src/main/java/de/assecutor/votianlt/model/User.java
+++ b/src/main/java/de/assecutor/votianlt/model/User.java
@@ -1,28 +1,45 @@
package de.assecutor.votianlt.model;
import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.index.Indexed;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.Set;
@Data
-public class User
-{
- public int usrId;
- public int hqId;
- public short type;
- public String title;
- public String name;
- public String firstname;
- public java.sql.Date birthdate;
- public String email;
- public String invitationEmail;
- public String phone;
- public String phone2;
- public String fax;
- public String password;
- public byte isActivated;
- public String activationCode;
- public byte isEmailConfirmed;
- public byte isPasswordLost;
- public String passwordCode;
- public int passwordTimestamp;
- public long activationDate;
+@Document(collection = "users")
+public class User {
+
+ @Id
+ private String id;
+
+ private int usrId;
+ private int hqId;
+ private short type;
+ private String title;
+ private String name;
+ private String firstname;
+ private LocalDate birthdate;
+
+ @Indexed(unique = true)
+ private String email;
+
+ private String invitationEmail;
+ private String phone;
+ private String phone2;
+ private String fax;
+ private String password;
+ private byte isActivated;
+ private String activationCode;
+ private byte isEmailConfirmed;
+ private byte isPasswordLost;
+ private String passwordCode;
+ private LocalDateTime passwordTimestamp;
+ private LocalDateTime activationDate;
+ private LocalDateTime createdAt;
+ private LocalDateTime updatedAt;
+ private Set roles;
}
\ No newline at end of file
diff --git a/src/main/java/de/assecutor/votianlt/pages/add_company/ui/view/AddCompanyView.java b/src/main/java/de/assecutor/votianlt/pages/add_company/ui/view/AddCompanyView.java
index 4355b87..24b5ac1 100644
--- a/src/main/java/de/assecutor/votianlt/pages/add_company/ui/view/AddCompanyView.java
+++ b/src/main/java/de/assecutor/votianlt/pages/add_company/ui/view/AddCompanyView.java
@@ -16,11 +16,13 @@ import de.assecutor.votianlt.model.Company;
import de.assecutor.votianlt.pages.add_company.service.AddCompanyService;
import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
+import jakarta.annotation.security.RolesAllowed;
import java.time.Clock;
-@Route("add_company")
+@Route(value = "add_company", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
@PageTitle("Neuen Firma anlegen")
@Menu(order = 0, icon = "vaadin:clipboard-check", title = "Neue Firma anlegen")
+@RolesAllowed("USER")
public class AddCompanyView extends Main {
private final AddCompanyService addCompanyService;
@@ -82,7 +84,7 @@ public class AddCompanyView extends Main {
private void submit() {
Company company = new Company();
- company.name = companyName.getValue();
+ company.setName(companyName.getValue());
try {
binder.writeBean(company);
diff --git a/src/main/java/de/assecutor/votianlt/pages/add_customer/ui/view/AddCustomerView.java b/src/main/java/de/assecutor/votianlt/pages/add_customer/ui/view/AddCustomerView.java
index 04cb50a..88dd259 100644
--- a/src/main/java/de/assecutor/votianlt/pages/add_customer/ui/view/AddCustomerView.java
+++ b/src/main/java/de/assecutor/votianlt/pages/add_customer/ui/view/AddCustomerView.java
@@ -16,11 +16,13 @@ import de.assecutor.votianlt.model.Customer;
import de.assecutor.votianlt.pages.add_customer.service.AddCustomerService;
import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
+import jakarta.annotation.security.RolesAllowed;
import java.time.Clock;
-@Route("add_customer")
+@Route(value = "add_customer", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
@PageTitle("Neuen Kunden anlegen")
@Menu(order = 0, icon = "vaadin:clipboard-check", title = "Neuen Kunden anlegen")
+@RolesAllowed("USER")
public class AddCustomerView extends Main {
private final AddCustomerService addCustomerService;
@@ -82,7 +84,7 @@ public class AddCustomerView extends Main {
private void submit() {
Customer customer = new Customer();
- customer.companyName = companyName.getValue();
+ customer.setCompanyName(companyName.getValue());
try {
binder.writeBean(customer);
diff --git a/src/main/java/de/assecutor/votianlt/pages/add_job/service/AddJobService.java b/src/main/java/de/assecutor/votianlt/pages/add_job/service/AddJobService.java
new file mode 100644
index 0000000..f99bba4
--- /dev/null
+++ b/src/main/java/de/assecutor/votianlt/pages/add_job/service/AddJobService.java
@@ -0,0 +1,13 @@
+package de.assecutor.votianlt.pages.add_job.service;
+
+import de.assecutor.votianlt.model.Job;
+import org.springframework.stereotype.Service;
+
+@Service
+public class AddJobService {
+
+ public void addJob(Job job) {
+ // TODO: Implement job persistence logic
+ System.out.println("Job would be saved: " + job.toString());
+ }
+}
diff --git a/src/main/java/de/assecutor/votianlt/pages/add_job/ui/view/AddJobView.java b/src/main/java/de/assecutor/votianlt/pages/add_job/ui/view/AddJobView.java
new file mode 100644
index 0000000..1d93983
--- /dev/null
+++ b/src/main/java/de/assecutor/votianlt/pages/add_job/ui/view/AddJobView.java
@@ -0,0 +1,353 @@
+package de.assecutor.votianlt.pages.add_job.ui.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.combobox.ComboBox;
+import com.vaadin.flow.component.html.Div;
+import com.vaadin.flow.component.html.H3;
+import com.vaadin.flow.component.html.Main;
+import com.vaadin.flow.component.html.Span;
+import com.vaadin.flow.component.icon.Icon;
+import com.vaadin.flow.component.icon.VaadinIcon;
+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.TextField;
+import com.vaadin.flow.data.binder.Binder;
+import com.vaadin.flow.data.binder.ValidationException;
+import com.vaadin.flow.router.Menu;
+import com.vaadin.flow.router.PageTitle;
+import com.vaadin.flow.router.Route;
+import com.vaadin.flow.theme.lumo.LumoUtility;
+import de.assecutor.votianlt.model.Job;
+import de.assecutor.votianlt.pages.add_job.service.AddJobService;
+import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
+
+import jakarta.annotation.security.RolesAllowed;
+
+@Route(value = "add_job", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
+@PageTitle("Neuen Auftrag anlegen")
+@Menu(order = 0, icon = "vaadin:clipboard-check", title = "Neuen Auftrag anlegen")
+@RolesAllowed("USER")
+public class AddJobView extends Main {
+
+ private final AddJobService addJobService;
+
+ // Customer selection
+ private ComboBox customerSelection;
+ private Button preloadAddressButton;
+
+ // Required fields notice
+ private Span requiredFieldsNotice;
+
+ // Pickup address fields
+ private TextField pickupCompany;
+ private ComboBox pickupSalutation;
+ private TextField pickupFirstName;
+ private TextField pickupLastName;
+ private TextField pickupPhone;
+ private TextField pickupStreet;
+ private TextField pickupHouseNumber;
+ private TextField pickupAddressAddition;
+ private TextField pickupZip;
+ private TextField pickupCity;
+ private Checkbox savePickupAddress;
+
+ // Delivery address fields
+ private TextField deliveryCompany;
+ private ComboBox deliverySalutation;
+ private TextField deliveryFirstName;
+ private TextField deliveryLastName;
+ private TextField deliveryPhone;
+ private TextField deliveryStreet;
+ private TextField deliveryHouseNumber;
+ private TextField deliveryAddressAddition;
+ private TextField deliveryZip;
+ private TextField deliveryCity;
+ private Checkbox saveDeliveryAddress;
+
+ // Digital processing
+ private Checkbox digitalProcessing;
+ private ComboBox appUser;
+
+ // Submit button
+ private Button submitButton;
+
+ private final Binder binder = new Binder<>(Job.class);
+
+ public AddJobView(AddJobService addJobService) {
+ this.addJobService = addJobService;
+ initializeComponents();
+ setupLayout();
+ setupValidation();
+ }
+
+ private void initializeComponents() {
+ // Customer selection
+ customerSelection = new ComboBox<>("Auftraggeber/Rechnungsempfänger");
+ customerSelection.setItems("Kunde01 | KOTVor K01Nach");
+ customerSelection.setValue("Kunde01 | KOTVor K01Nach");
+ customerSelection.setWidthFull();
+
+ preloadAddressButton = new Button("Vorbelegte Adressfelder leeren");
+ preloadAddressButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
+ preloadAddressButton.setIcon(new Icon(VaadinIcon.QUESTION_CIRCLE));
+
+ // Required fields notice
+ requiredFieldsNotice = new Span("Die mit (*) gekennzeichneten Felder sind Pflichtfelder.");
+ requiredFieldsNotice.getStyle().set("color", "red");
+ requiredFieldsNotice.getStyle().set("font-size", "14px");
+
+ // Pickup address
+ pickupCompany = new TextField("Firma");
+ pickupCompany.setValue("Kunde01");
+ pickupSalutation = new ComboBox<>("Anrede");
+ pickupSalutation.setItems("Herr", "Frau", "Divers");
+ pickupFirstName = new TextField("Vorname*");
+ pickupFirstName.setValue("K01Vor");
+ pickupFirstName.setRequiredIndicatorVisible(true);
+ pickupLastName = new TextField("Nachname*");
+ pickupLastName.setValue("K01Nach");
+ pickupLastName.setRequiredIndicatorVisible(true);
+ pickupPhone = new TextField("Telefonnummer");
+ pickupPhone.setValue("01");
+ pickupStreet = new TextField("Straße*");
+ pickupStreet.setValue("Ottensener Str.");
+ pickupStreet.setRequiredIndicatorVisible(true);
+ pickupHouseNumber = new TextField("Hausnr*");
+ pickupHouseNumber.setValue("8");
+ pickupHouseNumber.setRequiredIndicatorVisible(true);
+ pickupAddressAddition = new TextField("Adresszusatz");
+ pickupZip = new TextField("Postleitzahl*");
+ pickupZip.setValue("22525");
+ pickupZip.setRequiredIndicatorVisible(true);
+ pickupCity = new TextField("Ort*");
+ pickupCity.setValue("Hamburg");
+ pickupCity.setRequiredIndicatorVisible(true);
+ savePickupAddress = new Checkbox("Die Adresse für zukünftige Aufträge speichern.");
+
+ // Delivery address
+ deliveryCompany = new TextField("Firma");
+ deliverySalutation = new ComboBox<>("Anrede");
+ deliverySalutation.setItems("Herr", "Frau", "Divers");
+ deliveryFirstName = new TextField("Vorname*");
+ deliveryFirstName.setRequiredIndicatorVisible(true);
+ deliveryLastName = new TextField("Nachname*");
+ deliveryLastName.setRequiredIndicatorVisible(true);
+ deliveryPhone = new TextField("Telefonnummer");
+ deliveryStreet = new TextField("Straße*");
+ deliveryStreet.setRequiredIndicatorVisible(true);
+ deliveryHouseNumber = new TextField("Hausnr*");
+ deliveryHouseNumber.setRequiredIndicatorVisible(true);
+ deliveryAddressAddition = new TextField("Adresszusatz");
+ deliveryZip = new TextField("Postleitzahl*");
+ deliveryZip.setRequiredIndicatorVisible(true);
+ deliveryCity = new TextField("Ort*");
+ deliveryCity.setRequiredIndicatorVisible(true);
+ saveDeliveryAddress = new Checkbox("Die Adresse für zukünftige Aufträge speichern.");
+ saveDeliveryAddress.setValue(true);
+
+ // Digital processing
+ digitalProcessing = new Checkbox("Digitale Abwicklung per App");
+ digitalProcessing.setValue(true);
+ appUser = new ComboBox<>("App-Nutzer");
+ appUser.setItems("App-Nutzer");
+
+ // Submit button
+ submitButton = new Button("Auftrag anlegen", event -> submit());
+ submitButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
+ }
+
+ private void setupLayout() {
+ setSizeFull();
+ addClassNames(LumoUtility.BoxSizing.BORDER, LumoUtility.Display.FLEX,
+ LumoUtility.FlexDirection.COLUMN, LumoUtility.Padding.MEDIUM,
+ LumoUtility.Gap.SMALL);
+
+ add(new ViewToolbar("Neuen Auftrag anlegen"));
+
+ // Customer selection section
+ HorizontalLayout customerLayout = new HorizontalLayout();
+ customerLayout.setWidthFull();
+ customerLayout.setAlignItems(FlexComponent.Alignment.END);
+ customerLayout.add(customerSelection, preloadAddressButton);
+ customerSelection.setWidth("70%");
+ preloadAddressButton.setWidth("30%");
+
+ add(customerLayout);
+ add(requiredFieldsNotice);
+
+ // Main content layout with two equal columns (50% each)
+ HorizontalLayout mainLayout = new HorizontalLayout();
+ mainLayout.setWidthFull();
+ mainLayout.setSpacing(true);
+ mainLayout.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.START);
+
+ // Left column (50%) - Pickup address section
+ VerticalLayout leftColumn = createPickupSection();
+ leftColumn.setWidth("50%");
+
+ // Right column (50%) - Delivery address section
+ VerticalLayout rightColumn = createDeliverySection();
+ rightColumn.setWidth("50%");
+
+ // Add copy button to the right column at the top
+ Button copyButton = new Button("Abholadresse kopieren");
+ copyButton.setIcon(new Icon(VaadinIcon.ARROW_RIGHT));
+ copyButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
+ copyButton.addClickListener(e -> copyPickupToDelivery());
+ copyButton.getStyle().set("margin-bottom", "var(--lumo-space-m)");
+
+ // Insert copy button at the beginning of right column
+ rightColumn.addComponentAsFirst(copyButton);
+
+ mainLayout.add(leftColumn, rightColumn);
+
+ add(mainLayout);
+
+ // Digital processing section
+ VerticalLayout digitalSection = new VerticalLayout();
+ digitalSection.setSpacing(false);
+ digitalSection.add(digitalProcessing, appUser);
+ add(digitalSection);
+
+ // Submit button
+ HorizontalLayout submitLayout = new HorizontalLayout();
+ submitLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
+ submitLayout.add(submitButton);
+ add(submitLayout);
+ }
+
+ private VerticalLayout createPickupSection() {
+ VerticalLayout section = new VerticalLayout();
+ section.setSpacing(true);
+ section.setPadding(false);
+
+ H3 title = new H3("Abholadresse");
+ title.getStyle().set("margin", "0");
+ title.getStyle().set("display", "flex");
+ title.getStyle().set("align-items", "center");
+ Icon helpIcon = new Icon(VaadinIcon.QUESTION_CIRCLE);
+ helpIcon.getStyle().set("margin-left", "8px");
+ title.add(helpIcon);
+
+ section.add(title);
+ section.add(pickupCompany);
+ section.add(pickupSalutation);
+ section.add(pickupFirstName);
+ section.add(pickupLastName);
+ section.add(pickupPhone);
+
+ HorizontalLayout streetLayout = new HorizontalLayout();
+ streetLayout.setWidthFull();
+ streetLayout.add(pickupStreet, pickupHouseNumber);
+ pickupStreet.setWidth("70%");
+ pickupHouseNumber.setWidth("30%");
+ section.add(streetLayout);
+
+ section.add(pickupAddressAddition);
+
+ HorizontalLayout zipCityLayout = new HorizontalLayout();
+ zipCityLayout.setWidthFull();
+ zipCityLayout.add(pickupZip, pickupCity);
+ pickupZip.setWidth("30%");
+ pickupCity.setWidth("70%");
+ section.add(zipCityLayout);
+
+ section.add(savePickupAddress);
+
+ return section;
+ }
+
+ private VerticalLayout createDeliverySection() {
+ VerticalLayout section = new VerticalLayout();
+ section.setSpacing(true);
+ section.setPadding(false);
+
+ H3 title = new H3("Lieferadresse");
+ title.getStyle().set("margin", "0");
+
+ section.add(title);
+ section.add(deliveryCompany);
+ section.add(deliverySalutation);
+ section.add(deliveryFirstName);
+ section.add(deliveryLastName);
+ section.add(deliveryPhone);
+
+ HorizontalLayout streetLayout = new HorizontalLayout();
+ streetLayout.setWidthFull();
+ streetLayout.add(deliveryStreet, deliveryHouseNumber);
+ deliveryStreet.setWidth("70%");
+ deliveryHouseNumber.setWidth("30%");
+ section.add(streetLayout);
+
+ section.add(deliveryAddressAddition);
+
+ HorizontalLayout zipCityLayout = new HorizontalLayout();
+ zipCityLayout.setWidthFull();
+ zipCityLayout.add(deliveryZip, deliveryCity);
+ deliveryZip.setWidth("30%");
+ deliveryCity.setWidth("70%");
+ section.add(zipCityLayout);
+
+ section.add(saveDeliveryAddress);
+
+ return section;
+ }
+
+ private void copyPickupToDelivery() {
+ deliveryCompany.setValue(pickupCompany.getValue());
+ deliverySalutation.setValue(pickupSalutation.getValue());
+ deliveryFirstName.setValue(pickupFirstName.getValue());
+ deliveryLastName.setValue(pickupLastName.getValue());
+ deliveryPhone.setValue(pickupPhone.getValue());
+ deliveryStreet.setValue(pickupStreet.getValue());
+ deliveryHouseNumber.setValue(pickupHouseNumber.getValue());
+ deliveryAddressAddition.setValue(pickupAddressAddition.getValue());
+ deliveryZip.setValue(pickupZip.getValue());
+ deliveryCity.setValue(pickupCity.getValue());
+ }
+
+ private void setupValidation() {
+ // Basic validation setup - detailed validation can be added later
+ }
+
+ private void submit() {
+ Job job = new Job();
+
+ // Set pickup address
+ job.setPickupCompany(pickupCompany.getValue());
+ job.setPickupSalutation(pickupSalutation.getValue());
+ job.setPickupFirstName(pickupFirstName.getValue());
+ job.setPickupLastName(pickupLastName.getValue());
+ job.setPickupPhone(pickupPhone.getValue());
+ job.setPickupStreet(pickupStreet.getValue());
+ job.setPickupHouseNumber(pickupHouseNumber.getValue());
+ job.setPickupAddressAddition(pickupAddressAddition.getValue());
+ job.setPickupZip(pickupZip.getValue());
+ job.setPickupCity(pickupCity.getValue());
+ job.setSavePickupAddress(savePickupAddress.getValue());
+
+ // Set delivery address
+ job.setDeliveryCompany(deliveryCompany.getValue());
+ job.setDeliverySalutation(deliverySalutation.getValue());
+ job.setDeliveryFirstName(deliveryFirstName.getValue());
+ job.setDeliveryLastName(deliveryLastName.getValue());
+ job.setDeliveryPhone(deliveryPhone.getValue());
+ job.setDeliveryStreet(deliveryStreet.getValue());
+ job.setDeliveryHouseNumber(deliveryHouseNumber.getValue());
+ job.setDeliveryAddressAddition(deliveryAddressAddition.getValue());
+ job.setDeliveryZip(deliveryZip.getValue());
+ job.setDeliveryCity(deliveryCity.getValue());
+ job.setSaveDeliveryAddress(saveDeliveryAddress.getValue());
+
+ // Set digital processing
+ job.setDigitalProcessing(digitalProcessing.getValue());
+ job.setAppUser(appUser.getValue());
+ job.setCustomerSelection(customerSelection.getValue());
+
+ addJobService.addJob(job);
+ System.out.println("Job created successfully");
+ }
+}
diff --git a/src/main/java/de/assecutor/votianlt/pages/base/ui/view/MainLayout.java b/src/main/java/de/assecutor/votianlt/pages/base/ui/view/MainLayout.java
index 01331af..23f0ff7 100644
--- a/src/main/java/de/assecutor/votianlt/pages/base/ui/view/MainLayout.java
+++ b/src/main/java/de/assecutor/votianlt/pages/base/ui/view/MainLayout.java
@@ -16,13 +16,16 @@ import com.vaadin.flow.component.sidenav.SideNavItem;
import com.vaadin.flow.router.Layout;
import com.vaadin.flow.server.menu.MenuConfiguration;
import com.vaadin.flow.server.menu.MenuEntry;
+import de.assecutor.votianlt.security.SecurityService;
import static com.vaadin.flow.theme.lumo.LumoUtility.*;
-@Layout
public final class MainLayout extends AppLayout {
- public MainLayout() {
+ private final SecurityService securityService;
+
+ public MainLayout(SecurityService securityService) {
+ this.securityService = securityService;
setPrimarySection(Section.DRAWER);
addToDrawer(createHeader(), new Scroller(createSideNav()), createUserMenu());
@@ -58,8 +61,9 @@ public final class MainLayout extends AppLayout {
}
private Component createUserMenu() {
- // TODO Replace with real user information and actions
- var avatar = new Avatar("John Smith");
+ String currentUser = securityService.getCurrentUsername();
+
+ var avatar = new Avatar(currentUser);
avatar.addThemeVariants(AvatarVariant.LUMO_XSMALL);
avatar.addClassNames(Margin.Right.SMALL);
avatar.setColorIndex(5);
@@ -69,10 +73,10 @@ public final class MainLayout extends AppLayout {
userMenu.addClassNames(Margin.MEDIUM);
var userMenuItem = userMenu.addItem(avatar);
- userMenuItem.add("John Smith");
- userMenuItem.getSubMenu().addItem("View Profile");
- userMenuItem.getSubMenu().addItem("Manage Settings");
- userMenuItem.getSubMenu().addItem("Logout");
+ userMenuItem.add(currentUser);
+ userMenuItem.getSubMenu().addItem("Profil anzeigen");
+ userMenuItem.getSubMenu().addItem("Einstellungen");
+ userMenuItem.getSubMenu().addItem("Abmelden", e -> securityService.logout());
return userMenu;
}
diff --git a/src/main/java/de/assecutor/votianlt/pages/customers/ui/view/CustomersView.java b/src/main/java/de/assecutor/votianlt/pages/customers/ui/view/CustomersView.java
index cf72eb1..95cbb7a 100644
--- a/src/main/java/de/assecutor/votianlt/pages/customers/ui/view/CustomersView.java
+++ b/src/main/java/de/assecutor/votianlt/pages/customers/ui/view/CustomersView.java
@@ -18,7 +18,7 @@ import java.time.Clock;
import static com.vaadin.flow.spring.data.VaadinSpringDataHelpers.toSpringPageRequest;
-@Route("customer")
+@Route(value = "customer", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
@PageTitle("Kunden")
@Menu(order = 0, icon = "vaadin:clipboard-check", title = "Kunden")
public class CustomersView extends Main {
diff --git a/src/main/java/de/assecutor/votianlt/pages/login/domain/LoginRepository.java b/src/main/java/de/assecutor/votianlt/pages/login/domain/LoginRepository.java
index c66c79c..b302182 100644
--- a/src/main/java/de/assecutor/votianlt/pages/login/domain/LoginRepository.java
+++ b/src/main/java/de/assecutor/votianlt/pages/login/domain/LoginRepository.java
@@ -12,5 +12,5 @@ public interface LoginRepository extends MongoRepository {
// If you don't need a total row count, Slice is better than Page.
Slice findAllBy(Pageable pageable);
- Optional findByEmailAndPassword(String email, String password);
+ Optional findByEmail(String email);
}
diff --git a/src/main/java/de/assecutor/votianlt/pages/login/service/LoginService.java b/src/main/java/de/assecutor/votianlt/pages/login/service/LoginService.java
index 1a7168a..0f24e36 100644
--- a/src/main/java/de/assecutor/votianlt/pages/login/service/LoginService.java
+++ b/src/main/java/de/assecutor/votianlt/pages/login/service/LoginService.java
@@ -3,6 +3,7 @@ package de.assecutor.votianlt.pages.login.service;
import com.vaadin.flow.component.notification.Notification;
import de.assecutor.votianlt.model.User;
import de.assecutor.votianlt.pages.login.domain.LoginRepository;
+import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@@ -15,18 +16,25 @@ import java.util.Optional;
public class LoginService {
private final LoginRepository loginRepository;
+ private final PasswordEncoder passwordEncoder;
- LoginService(LoginRepository loginRepository, Clock clock) {
+ LoginService(LoginRepository loginRepository, PasswordEncoder passwordEncoder, Clock clock) {
this.loginRepository = loginRepository;
+ this.passwordEncoder = passwordEncoder;
}
- public Optional findUser(String mail, String password) {
- var user = loginRepository.findByEmailAndPassword(mail, password);
+ public Optional findUser(String email, String password) {
+ var userOpt = loginRepository.findByEmail(email);
- if (user.isEmpty()) {
- Notification.show("Login failed", 3000, Notification.Position.BOTTOM_END);
+ if (userOpt.isPresent()) {
+ User user = userOpt.get();
+ // Prüfe das Passwort mit BCrypt
+ if (passwordEncoder.matches(password, user.getPassword())) {
+ return Optional.of(user);
+ }
}
- return user;
+ Notification.show("Login failed", 3000, Notification.Position.BOTTOM_END);
+ return Optional.empty();
}
}
diff --git a/src/main/java/de/assecutor/votianlt/pages/login/ui/view/LoginView.java b/src/main/java/de/assecutor/votianlt/pages/login/ui/view/LoginView.java
index 327021b..aaa7100 100644
--- a/src/main/java/de/assecutor/votianlt/pages/login/ui/view/LoginView.java
+++ b/src/main/java/de/assecutor/votianlt/pages/login/ui/view/LoginView.java
@@ -3,64 +3,58 @@ package de.assecutor.votianlt.pages.login.ui.view;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
+import com.vaadin.flow.component.html.Anchor;
+import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Main;
-import com.vaadin.flow.component.notification.Notification;
-import com.vaadin.flow.component.notification.NotificationVariant;
+import com.vaadin.flow.component.login.LoginForm;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
-import com.vaadin.flow.component.textfield.TextField;
+import com.vaadin.flow.router.BeforeEnterEvent;
+import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
-import com.vaadin.flow.theme.lumo.LumoUtility;
-import de.assecutor.votianlt.pages.login.service.LoginService;
-import de.assecutor.votianlt.pages.register.service.RegisterService;
-import de.assecutor.votianlt.util.Util;
-
-import java.io.Console;
-import java.time.Clock;
+import com.vaadin.flow.server.auth.AnonymousAllowed;
@Route("login")
@PageTitle("Bei VotianLT anmelden")
-//@Menu(order = 0, icon = "vaadin:clipboard-check", title = "Bei VotianLT registrieren")
-public class LoginView extends Main {
- private final LoginService loginService;
+@AnonymousAllowed
+public class LoginView extends VerticalLayout implements BeforeEnterObserver {
- TextField usernameField = new TextField("E-Mail-Adresse");
- TextField password1Field = new TextField("Passwort");
- Button submitButton = new Button("Registrieren");
-
- public LoginView(LoginService loginService, Clock clock) {
- this.loginService = loginService;
-
- // Setze den Button als primär
- submitButton = new Button("Anmelden", event -> login());
- submitButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
-
- // Erstelle ein Div als Container (oder direkt ein Layout)
- VerticalLayout formLayout = new VerticalLayout();
- formLayout.add(usernameField, password1Field, submitButton);
-
- // Zentriere die Inhalte vertikal und horizontal
- formLayout.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
- formLayout.setSpacing(true);
- formLayout.setSizeUndefined(); // Inhalt eng setzen
+ private final LoginForm loginForm = new LoginForm();
+ public LoginView() {
+ addClassName("login-view");
setSizeFull();
- addClassNames(LumoUtility.BoxSizing.BORDER, LumoUtility.Display.FLEX, LumoUtility.FlexDirection.COLUMN,
- LumoUtility.Padding.MEDIUM, LumoUtility.Gap.SMALL);
- add(formLayout);
+ setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
+ setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
+
+ loginForm.setAction("login");
+
+ H1 title = new H1("VotianLT");
+ title.getStyle().set("color", "var(--lumo-primary-color)");
+
+ Button registerButton = new Button("Noch kein Konto? Registrieren",
+ e -> UI.getCurrent().navigate("register"));
+ registerButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
+
+ VerticalLayout loginLayout = new VerticalLayout();
+ loginLayout.setAlignItems(FlexComponent.Alignment.CENTER);
+ loginLayout.add(title, loginForm, registerButton);
+ loginLayout.setMaxWidth("400px");
+ loginLayout.setPadding(true);
+
+ add(loginLayout);
}
- private void login() {
- var user = loginService.findUser(usernameField.getValue(), password1Field.getValue());
-
- if (user.isPresent()) {
- UI.getCurrent().navigate("customer");
+ @Override
+ public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
+ // Zeige Fehlermeldung bei fehlgeschlagener Anmeldung
+ if (beforeEnterEvent.getLocation()
+ .getQueryParameters()
+ .getParameters()
+ .containsKey("error")) {
+ loginForm.setError(true);
}
}
-
- private void submit() {
- Util.changeDrawerState(true);
- }
}
diff --git a/src/main/java/de/assecutor/votianlt/pages/register/domain/RegisterRepository.java b/src/main/java/de/assecutor/votianlt/pages/register/domain/RegisterRepository.java
index ffb80a8..fb5a98c 100644
--- a/src/main/java/de/assecutor/votianlt/pages/register/domain/RegisterRepository.java
+++ b/src/main/java/de/assecutor/votianlt/pages/register/domain/RegisterRepository.java
@@ -1,12 +1,7 @@
package de.assecutor.votianlt.pages.register.domain;
-import de.assecutor.votianlt.model.User;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Slice;
-import org.springframework.data.mongodb.repository.MongoRepository;
+import de.assecutor.votianlt.repository.UserRepository;
-public interface RegisterRepository extends MongoRepository {
-
- // If you don't need a total row count, Slice is better than Page.
- Slice findAllBy(Pageable pageable);
+public interface RegisterRepository extends UserRepository {
+ // Erbt alle Methoden von UserRepository
}
diff --git a/src/main/java/de/assecutor/votianlt/pages/register/service/UserService.java b/src/main/java/de/assecutor/votianlt/pages/register/service/UserService.java
new file mode 100644
index 0000000..d62b53f
--- /dev/null
+++ b/src/main/java/de/assecutor/votianlt/pages/register/service/UserService.java
@@ -0,0 +1,59 @@
+package de.assecutor.votianlt.pages.register.service;
+
+import de.assecutor.votianlt.model.User;
+import de.assecutor.votianlt.repository.UserRepository;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+
+@Service
+public class UserService {
+
+ private final PasswordEncoder passwordEncoder;
+ private final UserRepository userRepository;
+
+ public UserService(PasswordEncoder passwordEncoder, UserRepository userRepository) {
+ this.passwordEncoder = passwordEncoder;
+ this.userRepository = userRepository;
+ }
+
+ public User findByEmail(String email) {
+ return userRepository.findByEmail(email).orElse(null);
+ }
+
+ public User save(User user) {
+ if (user.getPassword() != null && !user.getPassword().startsWith("$2a$")) {
+ // Passwort verschlüsseln, falls noch nicht verschlüsselt
+ user.setPassword(passwordEncoder.encode(user.getPassword()));
+ }
+
+ // Timestamps setzen
+ if (user.getCreatedAt() == null) {
+ user.setCreatedAt(LocalDateTime.now());
+ }
+ user.setUpdatedAt(LocalDateTime.now());
+
+ return userRepository.save(user);
+ }
+
+ public boolean existsByEmail(String email) {
+ return userRepository.existsByEmail(email);
+ }
+
+ public User createUser(String email, String password, String firstName, String lastName) {
+ if (existsByEmail(email)) {
+ throw new RuntimeException("User with email " + email + " already exists");
+ }
+
+ User user = new User();
+ user.setEmail(email);
+ user.setPassword(password); // wird in save() verschlüsselt
+ user.setFirstname(firstName);
+ user.setName(lastName);
+ user.setIsActivated((byte) 1);
+ user.setIsEmailConfirmed((byte) 1);
+
+ return save(user);
+ }
+}
diff --git a/src/main/java/de/assecutor/votianlt/pages/register/ui/view/RegisterView.java b/src/main/java/de/assecutor/votianlt/pages/register/ui/view/RegisterView.java
index 2c778ff..086cd66 100644
--- a/src/main/java/de/assecutor/votianlt/pages/register/ui/view/RegisterView.java
+++ b/src/main/java/de/assecutor/votianlt/pages/register/ui/view/RegisterView.java
@@ -2,61 +2,162 @@ package de.assecutor.votianlt.pages.register.ui.view;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
-import com.vaadin.flow.component.html.Main;
+import com.vaadin.flow.component.html.H1;
+import com.vaadin.flow.component.html.H2;
+import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
+import com.vaadin.flow.component.textfield.PasswordField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
-import com.vaadin.flow.theme.lumo.LumoUtility;
-import de.assecutor.votianlt.model.User;
+import com.vaadin.flow.server.auth.AnonymousAllowed;
import de.assecutor.votianlt.pages.register.service.RegisterService;
-import de.assecutor.votianlt.util.Util;
+import de.assecutor.votianlt.pages.register.service.UserService;
import java.time.Clock;
@Route("register")
-@PageTitle("Bei VotianLT anmelden")
-//@Menu(order = 0, icon = "vaadin:clipboard-check", title = "Bei VotianLT registrieren")
-public class RegisterView extends Main {
+@PageTitle("Bei VotianLT registrieren")
+@AnonymousAllowed
+public class RegisterView extends VerticalLayout {
private final RegisterService registerService;
+ private final UserService userService;
- TextField mail = new TextField("E-Mail-Adresse");
- TextField password1Field = new TextField("Passwort");
- TextField password2Field = new TextField("Passwort wiederholen");
- Button submitButton = new Button("Registrieren");
+ private TextField emailField;
+ private PasswordField passwordField;
+ private PasswordField confirmPasswordField;
+ private Button submitButton;
- public RegisterView(RegisterService registerService, Clock clock) {
+ public RegisterView(RegisterService registerService, UserService userService, Clock clock) {
this.registerService = registerService;
+ this.userService = userService;
- // Setze den Button als primär
- submitButton = new Button("Registrieren", event -> registerUser());
- submitButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
-
- // Erstelle ein Div als Container (oder direkt ein Layout)
- VerticalLayout formLayout = new VerticalLayout();
- formLayout.add(mail, password1Field, password2Field, submitButton);
-
- // Zentriere die Inhalte vertikal und horizontal
- formLayout.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
- formLayout.setSpacing(true);
- formLayout.setSizeUndefined(); // Inhalt eng setzen
-
+ // Layout-Konfiguration für vollständige Zentrierung
setSizeFull();
- addClassNames(LumoUtility.BoxSizing.BORDER, LumoUtility.Display.FLEX, LumoUtility.FlexDirection.COLUMN, LumoUtility.Padding.MEDIUM, LumoUtility.Gap.SMALL);
+ setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
+ setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
+ setPadding(true);
+ setSpacing(false);
- add(formLayout);
+ // Hauptcontainer für das Formular
+ VerticalLayout formContainer = createFormContainer();
+ add(formContainer);
+ }
+
+ private VerticalLayout createFormContainer() {
+ VerticalLayout container = new VerticalLayout();
+ container.setWidth("400px");
+ container.setPadding(true);
+ container.setSpacing(true);
+ container.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);
+
+ // Styling für den Container
+ container.getStyle().set("background-color", "var(--lumo-base-color)");
+ container.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
+ container.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
+ container.getStyle().set("box-shadow", "var(--lumo-box-shadow-s)");
+
+ // Titel
+ H1 title = new H1("Registrierung");
+ title.getStyle().set("text-align", "center");
+ title.getStyle().set("color", "var(--lumo-primary-color)");
+ title.getStyle().set("margin-top", "0");
+
+ H2 subtitle = new H2("Erstellen Sie Ihr VotianLT-Konto");
+ subtitle.getStyle().set("text-align", "center");
+ subtitle.getStyle().set("color", "var(--lumo-secondary-text-color)");
+ subtitle.getStyle().set("font-size", "var(--lumo-font-size-l)");
+ subtitle.getStyle().set("font-weight", "normal");
+ subtitle.getStyle().set("margin-bottom", "var(--lumo-space-l)");
+
+ // Formularfelder
+ emailField = new TextField("E-Mail-Adresse");
+ emailField.setWidthFull();
+ emailField.setRequired(true);
+ emailField.setPlaceholder("ihre.email@beispiel.de");
+
+ passwordField = new PasswordField("Passwort");
+ passwordField.setWidthFull();
+ passwordField.setRequired(true);
+ passwordField.setPlaceholder("Mindestens 6 Zeichen");
+
+ confirmPasswordField = new PasswordField("Passwort bestätigen");
+ confirmPasswordField.setWidthFull();
+ confirmPasswordField.setRequired(true);
+ confirmPasswordField.setPlaceholder("Passwort wiederholen");
+
+ // Submit Button
+ submitButton = new Button("Registrieren", event -> registerUser());
+ submitButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_LARGE);
+ submitButton.setWidthFull();
+
+ // Zurück-Link
+ Button backButton = new Button("Zurück zur Startseite", event ->
+ getUI().ifPresent(ui -> ui.navigate("")));
+ backButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
+ backButton.setWidthFull();
+
+ container.add(title, subtitle, emailField, passwordField, confirmPasswordField, submitButton, backButton);
+ return container;
}
private void registerUser() {
- var mail = this.mail.getValue();
- var password = password1Field.getValue();
+ var email = emailField.getValue().trim();
+ var password = passwordField.getValue();
+ var confirmPassword = confirmPasswordField.getValue();
- User user = new User();
- user.setEmail(mail);
- user.setPassword(password);
+ // Validierung
+ if (email.isEmpty()) {
+ Notification.show("Bitte geben Sie eine E-Mail-Adresse ein.", 3000, Notification.Position.MIDDLE);
+ emailField.focus();
+ return;
+ }
- registerService.registerUser(user);
+ if (!email.contains("@") || !email.contains(".")) {
+ Notification.show("Bitte geben Sie eine gültige E-Mail-Adresse ein.", 3000, Notification.Position.MIDDLE);
+ emailField.focus();
+ return;
+ }
+
+ if (password.isEmpty()) {
+ Notification.show("Bitte geben Sie ein Passwort ein.", 3000, Notification.Position.MIDDLE);
+ passwordField.focus();
+ return;
+ }
+
+ if (password.length() < 6) {
+ Notification.show("Das Passwort muss mindestens 6 Zeichen lang sein.", 3000, Notification.Position.MIDDLE);
+ passwordField.focus();
+ return;
+ }
+
+ if (!password.equals(confirmPassword)) {
+ Notification.show("Die Passwörter stimmen nicht überein.", 3000, Notification.Position.MIDDLE);
+ confirmPasswordField.focus();
+ return;
+ }
+
+ try {
+ // Benutzer erstellen
+ userService.createUser(email, password, "Benutzer", "Name");
+
+ // Erfolgsmeldung und Weiterleitung
+ Notification.show("Registrierung erfolgreich! Sie werden zur Anmeldung weitergeleitet.",
+ 3000, Notification.Position.MIDDLE);
+
+ getUI().ifPresent(ui -> ui.navigate("login"));
+
+ } catch (RuntimeException e) {
+ if (e.getMessage().contains("already exists")) {
+ Notification.show("Ein Benutzer mit dieser E-Mail-Adresse existiert bereits.",
+ 5000, Notification.Position.MIDDLE);
+ emailField.focus();
+ } else {
+ Notification.show("Registrierung fehlgeschlagen: " + e.getMessage(),
+ 5000, Notification.Position.MIDDLE);
+ }
+ }
}
}
diff --git a/src/main/java/de/assecutor/votianlt/pages/start/ui/view/StartView.java b/src/main/java/de/assecutor/votianlt/pages/start/ui/view/StartView.java
index 5128679..c43d7b2 100644
--- a/src/main/java/de/assecutor/votianlt/pages/start/ui/view/StartView.java
+++ b/src/main/java/de/assecutor/votianlt/pages/start/ui/view/StartView.java
@@ -1,40 +1,344 @@
package de.assecutor.votianlt.pages.start.ui.view;
+import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
-import com.vaadin.flow.component.html.Main;
-import com.vaadin.flow.router.Menu;
+import com.vaadin.flow.component.combobox.ComboBox;
+import com.vaadin.flow.component.html.*;
+import com.vaadin.flow.component.icon.Icon;
+import com.vaadin.flow.component.icon.VaadinIcon;
+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.router.PageTitle;
import com.vaadin.flow.router.Route;
-import com.vaadin.flow.theme.lumo.LumoUtility;
+import com.vaadin.flow.router.RouterLayout;
+import com.vaadin.flow.server.auth.AnonymousAllowed;
+import de.assecutor.votianlt.security.SecurityService;
@Route("")
-@PageTitle("Dummy")
-@Menu(order = 0, icon = "vaadin:clipboard-check", title = "DUMMY")
-public class StartView extends Main {
+@PageTitle("VotianLT - Willkommen")
+@AnonymousAllowed
+public class StartView extends VerticalLayout {
- final Button registerBtn;
- final Button loginBtn;
-
- public StartView() {
- registerBtn = new Button("Registrieren", event -> register());
- registerBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
- add(registerBtn);
-
- loginBtn = new Button("Anmelden", event -> login());
- loginBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
- add(loginBtn);
+ private final SecurityService securityService;
+ public StartView(SecurityService securityService) {
+ this.securityService = securityService;
setSizeFull();
- addClassNames(LumoUtility.BoxSizing.BORDER, LumoUtility.Display.FLEX, LumoUtility.FlexDirection.COLUMN,
- LumoUtility.Padding.MEDIUM, LumoUtility.Gap.SMALL);
+ setPadding(false);
+ setSpacing(false);
+ setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);
+ // Header mit Navigation
+ add(createHeader());
+
+ // Hero Section
+ add(createHeroSection());
+
+ // System Section
+ add(createSystemSection());
+
+ // App Section
+ add(createAppSection());
+
+ // Footer
+ add(createFooter());
+ }
+
+ private Component createHeader() {
+ HorizontalLayout header = new HorizontalLayout();
+ header.setWidthFull();
+ header.setPadding(true);
+ header.setSpacing(true);
+ header.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER);
+ header.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
+ header.getStyle().set("background-color", "var(--lumo-contrast-5pct)");
+ header.getStyle().set("border-bottom", "1px solid var(--lumo-contrast-10pct)");
+
+ // Logo
+ H1 logo = new H1("votian LT");
+ logo.getStyle().set("color", "var(--lumo-primary-color)");
+ logo.getStyle().set("margin", "0");
+ logo.getStyle().set("font-weight", "bold");
+
+ // Navigation - abhängig vom Anmeldestatus
+ Component navigation = securityService.isUserLoggedIn()
+ ? createAuthenticatedNavigation()
+ : createAnonymousNavigation();
+
+ header.add(logo, navigation);
+
+ return header;
+ }
+
+ private Component createAnonymousNavigation() {
+ HorizontalLayout navButtons = new HorizontalLayout();
+ navButtons.setSpacing(true);
+ navButtons.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER);
+
+ Button loginBtn = new Button("Anmelden", event -> login());
+ loginBtn.addThemeVariants(ButtonVariant.LUMO_CONTRAST);
+
+ Button registerBtn = new Button("Registrieren", event -> register());
+ registerBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
+
+ navButtons.add(loginBtn, registerBtn);
+ return navButtons;
+ }
+
+ private Component createAuthenticatedNavigation() {
+ HorizontalLayout navLayout = new HorizontalLayout();
+ navLayout.setSpacing(true);
+ navLayout.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER);
+
+ // Auftragserstellung Button
+ Button createOrderBtn = new Button("Auftragserstellung", event ->
+ UI.getCurrent().navigate("add_job"));
+ createOrderBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
+
+ // Verwaltung ComboBox
+ ComboBox managementCombo = new ComboBox<>();
+ managementCombo.setPlaceholder("Verwaltung");
+ managementCombo.setItems("Kunden", "Aufträge", "Firmen");
+ managementCombo.addValueChangeListener(event -> {
+ String value = event.getValue();
+ if (value != null) {
+ switch (value) {
+ case "Kunden":
+ UI.getCurrent().navigate("customer");
+ break;
+ case "Aufträge":
+ UI.getCurrent().navigate("orders");
+ break;
+ case "Firmen":
+ UI.getCurrent().navigate("add_company");
+ break;
+ }
+ managementCombo.clear(); // Reset selection
+ }
+ });
+
+ // Benutzer ComboBox
+ String currentUser = securityService.getCurrentUsername();
+ ComboBox userCombo = new ComboBox<>();
+ userCombo.setPlaceholder(currentUser);
+ userCombo.setItems("Profil anzeigen", "Einstellungen", "Abmelden");
+ userCombo.addValueChangeListener(event -> {
+ String value = event.getValue();
+ if (value != null) {
+ switch (value) {
+ case "Profil anzeigen":
+ // TODO: Navigate to profile
+ break;
+ case "Einstellungen":
+ // TODO: Navigate to settings
+ break;
+ case "Abmelden":
+ securityService.logout();
+ break;
+ }
+ userCombo.clear(); // Reset selection
+ }
+ });
+
+ // Benachrichtigungs-Icon
+ Button notificationBtn = new Button();
+ notificationBtn.setIcon(VaadinIcon.BELL.create());
+ notificationBtn.addThemeVariants(ButtonVariant.LUMO_ICON, ButtonVariant.LUMO_TERTIARY);
+ notificationBtn.setTooltipText("Benachrichtigungen");
+ notificationBtn.addClickListener(event -> {
+ // TODO: Show notifications
+ com.vaadin.flow.component.notification.Notification.show("Keine neuen Benachrichtigungen", 3000,
+ com.vaadin.flow.component.notification.Notification.Position.TOP_END);
+ });
+
+ navLayout.add(createOrderBtn, managementCombo, userCombo, notificationBtn);
+ return navLayout;
+ }
+
+ private Component createHeroSection() {
+ VerticalLayout heroSection = new VerticalLayout();
+ heroSection.setWidthFull();
+ heroSection.setPadding(true);
+ heroSection.setSpacing(true);
+ heroSection.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
+ heroSection.getStyle().set("background", "linear-gradient(135deg, var(--lumo-primary-color-10pct), var(--lumo-primary-color-50pct))");
+ heroSection.getStyle().set("min-height", "400px");
+ heroSection.setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
+
+ // Hero Image Placeholder
+ Icon heroIcon = VaadinIcon.TRUCK.create();
+ heroIcon.setSize("120px");
+ heroIcon.getStyle().set("color", "var(--lumo-primary-color)");
+
+ H1 heroTitle = new H1("VotianLT - Ihr digitaler Transportpartner");
+ heroTitle.getStyle().set("text-align", "center");
+ heroTitle.getStyle().set("color", "var(--lumo-primary-text-color)");
+ heroTitle.getStyle().set("margin-bottom", "var(--lumo-space-l)");
+
+ Paragraph heroDescription = new Paragraph(
+ "Für Solo-Selbstständige und Kleinunternehmer im Transportgewerbe - " +
+ "volldigital und aus einem Guss. Konzentrieren Sie sich auf Ihr Geschäft, " +
+ "wir kümmern uns um die Büroarbeit."
+ );
+ heroDescription.getStyle().set("text-align", "center");
+ heroDescription.getStyle().set("max-width", "600px");
+ heroDescription.getStyle().set("font-size", "var(--lumo-font-size-l)");
+
+ Button ctaButton = new Button("Jetzt kostenlos testen", event -> register());
+ ctaButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_LARGE);
+
+ heroSection.add(heroIcon, heroTitle, heroDescription, ctaButton);
+ return heroSection;
+ }
+
+ private Component createSystemSection() {
+ VerticalLayout systemSection = new VerticalLayout();
+ systemSection.setWidthFull();
+ systemSection.setPadding(true);
+ systemSection.setSpacing(true);
+ systemSection.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
+ systemSection.getStyle().set("background-color", "var(--lumo-base-color)");
+
+ // Section Header
+ H2 systemTitle = new H2("Das System");
+ systemTitle.getStyle().set("color", "var(--lumo-primary-color)");
+ systemTitle.getStyle().set("text-align", "center");
+
+ Paragraph systemIntro = new Paragraph(
+ "Für Solo-Selbstständige und Kleinunternehmer im Transportgewerbe ist von entscheidender Bedeutung, " +
+ "dass sie sich in erster Linie auf ihr eigentliches Geschäft konzentrieren können: Kunden gewinnen und Waren von A nach B liefern."
+ );
+ systemIntro.getStyle().set("text-align", "center");
+ systemIntro.getStyle().set("max-width", "800px");
+ systemIntro.getStyle().set("margin-bottom", "var(--lumo-space-xl)");
+
+ // Features Grid
+ HorizontalLayout featuresGrid = new HorizontalLayout();
+ featuresGrid.setWidthFull();
+ featuresGrid.setSpacing(true);
+ featuresGrid.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.START);
+
+ // Feature Cards
+ featuresGrid.add(
+ createFeatureCard(VaadinIcon.COG, "Einrichtungsassistent",
+ "Mithilfe des Einrichtungsassistenten haben Sie die Möglichkeit, Ihr Nutzerprofil zu vervollständigen."),
+ createFeatureCard(VaadinIcon.USERS, "Kunden- und Auftragsverwaltung",
+ "Mit der Kunden- und Auftragsverwaltung haben Sie alle Kontaktdaten und Auftragsdetails stets im Blick."),
+ createFeatureCard(VaadinIcon.CLIPBOARD_TEXT, "Auftragserstellung",
+ "Stellen Sie mit wenigen Mausklicks Aufträge ins System ein und legen Sie fest, welcher Mitarbeiter welchen Transportauftrag abarbeiten soll.")
+ );
+
+ systemSection.add(systemTitle, systemIntro, featuresGrid);
+ return systemSection;
+ }
+
+ private Component createFeatureCard(VaadinIcon iconType, String title, String description) {
+ VerticalLayout card = new VerticalLayout();
+ card.setSpacing(true);
+ card.setPadding(true);
+ card.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
+ card.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
+ card.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
+ card.getStyle().set("background-color", "var(--lumo-base-color)");
+ card.getStyle().set("box-shadow", "var(--lumo-box-shadow-xs)");
+ card.setWidth("300px");
+
+ Icon icon = iconType.create();
+ icon.setSize("48px");
+ icon.getStyle().set("color", "var(--lumo-primary-color)");
+
+ H3 cardTitle = new H3(title);
+ cardTitle.getStyle().set("text-align", "center");
+ cardTitle.getStyle().set("margin", "var(--lumo-space-s) 0");
+
+ Paragraph cardDescription = new Paragraph(description);
+ cardDescription.getStyle().set("text-align", "center");
+ cardDescription.getStyle().set("font-size", "var(--lumo-font-size-s)");
+
+ card.add(icon, cardTitle, cardDescription);
+ return card;
+ }
+
+ private Component createAppSection() {
+ VerticalLayout appSection = new VerticalLayout();
+ appSection.setWidthFull();
+ appSection.setPadding(true);
+ appSection.setSpacing(true);
+ appSection.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
+ appSection.getStyle().set("background-color", "var(--lumo-contrast-5pct)");
+
+ H2 appTitle = new H2("Die App");
+ appTitle.getStyle().set("color", "var(--lumo-primary-color)");
+ appTitle.getStyle().set("text-align", "center");
+
+ Paragraph appDescription = new Paragraph(
+ "Jeder Auftrag kann optional über die votianLT-App abgearbeitet werden – ganz ohne \"Zettelwirtschaft\". " +
+ "So gelangen alle relevanten Auftragsinformationen direkt auf das Smartphone des Fahrers."
+ );
+ appDescription.getStyle().set("text-align", "center");
+ appDescription.getStyle().set("max-width", "800px");
+
+ Icon appIcon = VaadinIcon.MOBILE.create();
+ appIcon.setSize("80px");
+ appIcon.getStyle().set("color", "var(--lumo-primary-color)");
+
+ appSection.add(appTitle, appDescription, appIcon);
+ return appSection;
+ }
+
+ private Component createFooter() {
+ VerticalLayout footer = new VerticalLayout();
+ footer.setWidthFull();
+ footer.setPadding(true);
+ footer.setSpacing(true);
+ footer.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
+ footer.getStyle().set("background-color", "var(--lumo-contrast-10pct)");
+ footer.getStyle().set("border-top", "1px solid var(--lumo-contrast-20pct)");
+
+ // Company Info
+ H3 companyTitle = new H3("Impressum");
+ companyTitle.getStyle().set("color", "var(--lumo-primary-color)");
+ companyTitle.getStyle().set("text-align", "center");
+
+ VerticalLayout companyInfo = new VerticalLayout();
+ companyInfo.setSpacing(false);
+ companyInfo.setPadding(false);
+ companyInfo.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
+
+ companyInfo.add(
+ new Paragraph("Assecutor Data Service GmbH"),
+ new Paragraph("Ottensener Str. 8, 22525 Hamburg"),
+ new Paragraph("Telefon: +49 40 18 123 771 0"),
+ new Paragraph("E-Mail: ahoi@assecutor.de")
+ );
+
+ // Call to Action
+ Paragraph ctaText = new Paragraph(
+ "Registrieren Sie sich noch heute und nutzen den kostenfreien Probemonat, " +
+ "um das System auf Herz und Nieren zu testen."
+ );
+ ctaText.getStyle().set("text-align", "center");
+ ctaText.getStyle().set("font-weight", "bold");
+ ctaText.getStyle().set("color", "var(--lumo-primary-color)");
+ ctaText.getStyle().set("margin-top", "var(--lumo-space-l)");
+
+ Paragraph slogan = new Paragraph("Betreiben Sie Ihr Geschäft smart … mit votianLT!");
+ slogan.getStyle().set("text-align", "center");
+ slogan.getStyle().set("font-style", "italic");
+ slogan.getStyle().set("color", "var(--lumo-primary-color)");
+
+ footer.add(companyTitle, companyInfo, ctaText, slogan);
+ return footer;
}
private void register() {
UI.getCurrent().navigate("register");
}
- private void login() { UI.getCurrent().navigate("login"); }
+ private void login() {
+ UI.getCurrent().navigate("login");
+ }
}
diff --git a/src/main/java/de/assecutor/votianlt/pages/test/TestView.java b/src/main/java/de/assecutor/votianlt/pages/test/TestView.java
new file mode 100644
index 0000000..ad95123
--- /dev/null
+++ b/src/main/java/de/assecutor/votianlt/pages/test/TestView.java
@@ -0,0 +1,23 @@
+package de.assecutor.votianlt.pages.test;
+
+import com.vaadin.flow.component.html.H1;
+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 de.assecutor.votianlt.pages.base.ui.view.MainLayout;
+
+@Route(value = "test", layout = MainLayout.class)
+@PageTitle("Test Seite")
+public class TestView extends VerticalLayout {
+
+ public TestView() {
+ H1 title = new H1("Test Seite");
+ Paragraph description = new Paragraph("Diese Seite dient zum Testen der Navigation.");
+
+ add(title, description);
+
+ setPadding(true);
+ setSpacing(true);
+ }
+}
diff --git a/src/main/java/de/assecutor/votianlt/repository/UserRepository.java b/src/main/java/de/assecutor/votianlt/repository/UserRepository.java
new file mode 100644
index 0000000..bb21ab0
--- /dev/null
+++ b/src/main/java/de/assecutor/votianlt/repository/UserRepository.java
@@ -0,0 +1,17 @@
+package de.assecutor.votianlt.repository;
+
+import de.assecutor.votianlt.model.User;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface UserRepository extends MongoRepository {
+
+ Optional findByEmail(String email);
+
+ boolean existsByEmail(String email);
+
+ void deleteByEmail(String email);
+}
diff --git a/src/main/java/de/assecutor/votianlt/security/SecurityConfig.java b/src/main/java/de/assecutor/votianlt/security/SecurityConfig.java
new file mode 100644
index 0000000..3e9e8b9
--- /dev/null
+++ b/src/main/java/de/assecutor/votianlt/security/SecurityConfig.java
@@ -0,0 +1,61 @@
+package de.assecutor.votianlt.security;
+
+import com.vaadin.flow.spring.security.VaadinWebSecurity;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+
+import de.assecutor.votianlt.pages.login.ui.view.LoginView;
+
+@EnableWebSecurity
+@Configuration
+public class SecurityConfig extends VaadinWebSecurity {
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // Konfiguriere zusätzliche öffentliche Endpunkte vor der Basis-Konfiguration
+ http.authorizeHttpRequests(auth -> auth
+ // Öffentliche Endpunkte
+ .requestMatchers(
+ new AntPathRequestMatcher("/"),
+ new AntPathRequestMatcher("/register"),
+ new AntPathRequestMatcher("/login"),
+ new AntPathRequestMatcher("/images/**"),
+ new AntPathRequestMatcher("/icons/**"),
+ new AntPathRequestMatcher("/favicon.ico"),
+ new AntPathRequestMatcher("/robots.txt"),
+ new AntPathRequestMatcher("/manifest.webmanifest"),
+ new AntPathRequestMatcher("/sw.js"),
+ new AntPathRequestMatcher("/offline.html"),
+ new AntPathRequestMatcher("/frontend/**"),
+ new AntPathRequestMatcher("/webjars/**"),
+ new AntPathRequestMatcher("/h2-console/**"),
+ new AntPathRequestMatcher("/frontend-es5/**", "/frontend-es6/**")
+ ).permitAll()
+ );
+
+ // Delegiere die Basis-Konfiguration an VaadinWebSecurity
+ // Dies fügt automatisch .anyRequest().authenticated() hinzu
+ super.configure(http);
+
+ // Setze die Login-View
+ setLoginView(http, LoginView.class);
+
+ // Logout-Konfiguration
+ http.logout(logout -> logout
+ .logoutUrl("/logout")
+ .logoutSuccessUrl("/")
+ .invalidateHttpSession(true)
+ .deleteCookies("JSESSIONID")
+ );
+ }
+}
diff --git a/src/main/java/de/assecutor/votianlt/security/SecurityService.java b/src/main/java/de/assecutor/votianlt/security/SecurityService.java
new file mode 100644
index 0000000..017f5e1
--- /dev/null
+++ b/src/main/java/de/assecutor/votianlt/security/SecurityService.java
@@ -0,0 +1,42 @@
+package de.assecutor.votianlt.security;
+
+import com.vaadin.flow.spring.security.AuthenticationContext;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+@Component
+public class SecurityService {
+
+ private final AuthenticationContext authenticationContext;
+
+ public SecurityService(AuthenticationContext authenticationContext) {
+ this.authenticationContext = authenticationContext;
+ }
+
+ public Optional getAuthenticatedUser() {
+ return authenticationContext.getAuthenticatedUser(UserDetails.class);
+ }
+
+ public boolean isUserLoggedIn() {
+ return authenticationContext.isAuthenticated();
+ }
+
+ public String getCurrentUsername() {
+ return getAuthenticatedUser()
+ .map(UserDetails::getUsername)
+ .orElse("Anonymous");
+ }
+
+ public void logout() {
+ authenticationContext.logout();
+ }
+
+ public boolean hasRole(String role) {
+ return getAuthenticatedUser()
+ .map(user -> user.getAuthorities().stream()
+ .anyMatch(authority -> authority.getAuthority().equals("ROLE_" + role)))
+ .orElse(false);
+ }
+}
diff --git a/src/main/java/de/assecutor/votianlt/security/UserDetailsServiceImpl.java b/src/main/java/de/assecutor/votianlt/security/UserDetailsServiceImpl.java
new file mode 100644
index 0000000..c519d73
--- /dev/null
+++ b/src/main/java/de/assecutor/votianlt/security/UserDetailsServiceImpl.java
@@ -0,0 +1,44 @@
+package de.assecutor.votianlt.security;
+
+import de.assecutor.votianlt.model.User;
+import de.assecutor.votianlt.pages.register.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.Collections;
+
+@Service
+public class UserDetailsServiceImpl implements UserDetailsService {
+
+ @Autowired
+ private UserService userService;
+
+ @Override
+ public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
+ User user = userService.findByEmail(email);
+ if (user == null) {
+ throw new UsernameNotFoundException("User not found with email: " + email);
+ }
+
+ return new org.springframework.security.core.userdetails.User(
+ user.getEmail(),
+ user.getPassword(),
+ user.getIsActivated() == 1, // enabled
+ true, // accountNonExpired
+ true, // credentialsNonExpired
+ true, // accountNonLocked
+ getAuthorities(user)
+ );
+ }
+
+ private Collection extends GrantedAuthority> getAuthorities(User user) {
+ // Basis-Rolle für alle Benutzer
+ return Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index f06ab0a..ec44326 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -12,4 +12,4 @@ vaadin.allowed-packages=com.vaadin,org.vaadin,de.assecutor.votianlt
spring.jpa.open-in-view=false
# MongoDB
-spring.data.mongodb.uri=mongodb://192.168.180.28:27017/votianlt
\ No newline at end of file
+spring.data.mongodb.uri=mongodb://192.168.180.25:27017/votianlt
\ No newline at end of file