Erweiterungen
This commit is contained in:
@@ -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.");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
42
src/main/java/de/assecutor/votianlt/model/Job.java
Normal file
42
src/main/java/de/assecutor/votianlt/model/Job.java
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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<String> roles;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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<String> customerSelection;
|
||||
private Button preloadAddressButton;
|
||||
|
||||
// Required fields notice
|
||||
private Span requiredFieldsNotice;
|
||||
|
||||
// Pickup address fields
|
||||
private TextField pickupCompany;
|
||||
private ComboBox<String> 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<String> 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<String> appUser;
|
||||
|
||||
// Submit button
|
||||
private Button submitButton;
|
||||
|
||||
private final Binder<Job> 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");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -12,5 +12,5 @@ public interface LoginRepository extends MongoRepository<User, String> {
|
||||
// If you don't need a total row count, Slice is better than Page.
|
||||
Slice<User> findAllBy(Pageable pageable);
|
||||
|
||||
Optional<User> findByEmailAndPassword(String email, String password);
|
||||
Optional<User> findByEmail(String email);
|
||||
}
|
||||
|
||||
@@ -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<User> findUser(String mail, String password) {
|
||||
var user = loginRepository.findByEmailAndPassword(mail, password);
|
||||
public Optional<User> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<User, String> {
|
||||
|
||||
// If you don't need a total row count, Slice is better than Page.
|
||||
Slice<User> findAllBy(Pageable pageable);
|
||||
public interface RegisterRepository extends UserRepository {
|
||||
// Erbt alle Methoden von UserRepository
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> 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<String> 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");
|
||||
}
|
||||
}
|
||||
|
||||
23
src/main/java/de/assecutor/votianlt/pages/test/TestView.java
Normal file
23
src/main/java/de/assecutor/votianlt/pages/test/TestView.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<User, String> {
|
||||
|
||||
Optional<User> findByEmail(String email);
|
||||
|
||||
boolean existsByEmail(String email);
|
||||
|
||||
void deleteByEmail(String email);
|
||||
}
|
||||
@@ -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")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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<UserDetails> 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);
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
spring.data.mongodb.uri=mongodb://192.168.180.25:27017/votianlt
|
||||
Reference in New Issue
Block a user