initial commit
This commit is contained in:
16
src/main/java/nl/veenm/ExampleResource.java
Normal file
16
src/main/java/nl/veenm/ExampleResource.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package nl.veenm;
|
||||
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
@Path("/hello")
|
||||
public class ExampleResource {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
public String hello() {
|
||||
return "Hello from Quarkus REST";
|
||||
}
|
||||
}
|
||||
29
src/main/java/nl/veenm/MyEntity.java
Normal file
29
src/main/java/nl/veenm/MyEntity.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package nl.veenm;
|
||||
|
||||
import io.quarkus.hibernate.orm.panache.PanacheEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
|
||||
/**
|
||||
* Example JPA entity defined as a Panache Entity.
|
||||
* An ID field of Long type is provided, if you want to define your own ID field extends <code>PanacheEntityBase</code> instead.
|
||||
* <p>
|
||||
* This uses the active record pattern, you can also use the repository pattern instead:
|
||||
* .
|
||||
* <p>
|
||||
* Usage (more example on the documentation)
|
||||
* <p>
|
||||
* {@code
|
||||
* public void doSomething() {
|
||||
* MyEntity entity1 = new MyEntity();
|
||||
* entity1.field = "field-1";
|
||||
* entity1.persist();
|
||||
* <p>
|
||||
* List<MyEntity> entities = MyEntity.listAll();
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
@Entity
|
||||
public class MyEntity extends PanacheEntity {
|
||||
public String field;
|
||||
}
|
||||
87
src/main/java/nl/veenm/paypoint/domain/AppUser.java
Normal file
87
src/main/java/nl/veenm/paypoint/domain/AppUser.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package nl.veenm.paypoint.domain;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class AppUser {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
private String username;
|
||||
private String email;
|
||||
private String password; // Versleuteld wachtwoord
|
||||
private String role;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setRole(String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AppUser{" +
|
||||
"id=" + id +
|
||||
", username='" + username + '\'' +
|
||||
", email='" + email + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
", role='" + role + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
135
src/main/java/nl/veenm/paypoint/domain/Appointment.java
Normal file
135
src/main/java/nl/veenm/paypoint/domain/Appointment.java
Normal file
@@ -0,0 +1,135 @@
|
||||
package nl.veenm.paypoint.domain;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
public class Appointment {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
private String title;
|
||||
private String description;
|
||||
private LocalDateTime startDate;
|
||||
private int startHour;
|
||||
private int startMinute;
|
||||
private int endHour;
|
||||
private int endMinute;
|
||||
private int durationInMinutes;
|
||||
|
||||
@ManyToOne
|
||||
private Customer customer;
|
||||
|
||||
public Appointment(Long id, String title, String description, LocalDateTime startDate, int startHour, int startMinute, int endHour, int endMinute, int durationInMinutes) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.startDate = startDate;
|
||||
this.startHour = startHour;
|
||||
this.startMinute = startMinute;
|
||||
this.endHour = endHour;
|
||||
this.endMinute = endMinute;
|
||||
this.durationInMinutes = durationInMinutes;
|
||||
}
|
||||
|
||||
public Appointment() {
|
||||
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public LocalDateTime getStartDate() {
|
||||
return startDate;
|
||||
}
|
||||
|
||||
public void setStartDate(LocalDateTime startDate) {
|
||||
this.startDate = startDate;
|
||||
}
|
||||
|
||||
public int getStartHour() {
|
||||
return startHour;
|
||||
}
|
||||
|
||||
public void setStartHour(int startHour) {
|
||||
this.startHour = startHour;
|
||||
}
|
||||
|
||||
public int getStartMinute() {
|
||||
return startMinute;
|
||||
}
|
||||
|
||||
public void setStartMinute(int startMinute) {
|
||||
this.startMinute = startMinute;
|
||||
}
|
||||
|
||||
public int getEndHour() {
|
||||
return endHour;
|
||||
}
|
||||
|
||||
public void setEndHour(int endHour) {
|
||||
this.endHour = endHour;
|
||||
}
|
||||
|
||||
public int getEndMinute() {
|
||||
return endMinute;
|
||||
}
|
||||
|
||||
public void setEndMinute(int endMinute) {
|
||||
this.endMinute = endMinute;
|
||||
}
|
||||
|
||||
public int getDurationInMinutes() {
|
||||
return durationInMinutes;
|
||||
}
|
||||
|
||||
public void setDurationInMinutes(int durationInMinutes) {
|
||||
this.durationInMinutes = durationInMinutes;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Appointment{" +
|
||||
"id=" + id +
|
||||
", title='" + title + '\'' +
|
||||
", description='" + description + '\'' +
|
||||
", date=" + startDate +
|
||||
", startHour=" + startHour +
|
||||
", startMinute=" + startMinute +
|
||||
", endHour=" + endHour +
|
||||
", endMinute=" + endMinute +
|
||||
", durationInMinutes=" + durationInMinutes +
|
||||
", customer=" + customer +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
22
src/main/java/nl/veenm/paypoint/domain/AuthDTO.java
Normal file
22
src/main/java/nl/veenm/paypoint/domain/AuthDTO.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package nl.veenm.paypoint.domain;
|
||||
|
||||
public class AuthDTO {
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
58
src/main/java/nl/veenm/paypoint/domain/Customer.java
Normal file
58
src/main/java/nl/veenm/paypoint/domain/Customer.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package nl.veenm.paypoint.domain;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Customer {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private String email;
|
||||
|
||||
public Customer(Long id, String firstName, String lastName, String email) {
|
||||
this.id = id;
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
}
|
||||
40
src/main/java/nl/veenm/paypoint/domain/UserDTO.java
Normal file
40
src/main/java/nl/veenm/paypoint/domain/UserDTO.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package nl.veenm.paypoint.domain;
|
||||
|
||||
public class UserDTO {
|
||||
String username;
|
||||
String fullName;
|
||||
String email;
|
||||
String token;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
public void setFullName(String fullName) {
|
||||
this.fullName = fullName;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
26
src/main/java/nl/veenm/paypoint/helper/EmailHelper.java
Normal file
26
src/main/java/nl/veenm/paypoint/helper/EmailHelper.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package nl.veenm.paypoint.helper;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class EmailHelper {
|
||||
public static String getIcs(String dtStamp, LocalDate date, String formattedTime, String formattedEndTime, String location) {
|
||||
String formatted = """
|
||||
BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:-//PayPoint//Afspraak//NL
|
||||
BEGIN:VEVENT
|
||||
ORGANIZER;CN=Hairstyling By Daan:mailto:danielle@hairstylingbydaan.nl
|
||||
UID:12345
|
||||
DTSTAMP:%s
|
||||
DTSTART:%sT%s00
|
||||
DTEND:%sT%s00
|
||||
SUMMARY:Afspraak bij Hairstyling By Daan
|
||||
LOCATION:%s
|
||||
DESCRIPTION:Bevestiging van uw afspraak bij Hairstyling By Daan
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
""".formatted(dtStamp, date.toString().replace("-", ""), formattedTime.replace(":", ""), date.toString().replace("-", ""), formattedEndTime.replace(":", ""), location.replace("<br>", " "));
|
||||
System.out.println(formatted);
|
||||
return formatted;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package nl.veenm.paypoint.repository;
|
||||
|
||||
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import nl.veenm.paypoint.domain.Appointment;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
|
||||
@ApplicationScoped
|
||||
public class AppointmentRepository implements PanacheRepository<Appointment> {
|
||||
public Optional<Appointment> findMostRecentByUserId(Long userId) {
|
||||
LocalDateTime now = LocalDateTime.now().minusDays(1);
|
||||
|
||||
|
||||
return find("customer = ?1 AND startDate >= ?2 ORDER BY startDate ASC",
|
||||
userId, now)
|
||||
.firstResultOptional();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package nl.veenm.paypoint.repository;
|
||||
|
||||
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import nl.veenm.paypoint.domain.Customer;
|
||||
|
||||
@ApplicationScoped
|
||||
public class CustomerRepository implements PanacheRepository<Customer> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package nl.veenm.paypoint.repository;
|
||||
|
||||
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import nl.veenm.paypoint.domain.AppUser;
|
||||
|
||||
@ApplicationScoped
|
||||
public class UserRepository implements PanacheRepository<AppUser> {
|
||||
|
||||
public AppUser findByUsername(String username) {
|
||||
return find("username", username).firstResult();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package nl.veenm.paypoint.resource;
|
||||
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import nl.veenm.paypoint.domain.Appointment;
|
||||
import nl.veenm.paypoint.service.AppointmentService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Path("/api/appointments")
|
||||
@RolesAllowed({"ADMIN", "USER"})
|
||||
public class AppointmentResource {
|
||||
|
||||
@Inject
|
||||
AppointmentService appointmentService;
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<Appointment> getAppointments() {
|
||||
return appointmentService.getAllAppointments();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("/date")
|
||||
public List<Appointment> getAppointmentsByDate(@QueryParam("start") String start) {
|
||||
return appointmentService.getAppointmentsByDate(start);
|
||||
}
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("/recent/{id}")
|
||||
public Appointment getMostRecentAppointment(@PathParam("id") Long userId) {
|
||||
return appointmentService.getMostRecentByUserId(userId);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("/{id}")
|
||||
public Appointment getAppointmentById(@PathParam("id") Long id) {
|
||||
return appointmentService.getAppointment(id);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response addAppointment(Appointment appointment) {
|
||||
System.out.println(appointment);
|
||||
appointmentService.add(appointment);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response deleteAppointment(@QueryParam("id") Long id) {
|
||||
appointmentService.delete(id);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response updateAppointment(Appointment appointment) {
|
||||
appointmentService.update(appointment);
|
||||
return Response.ok().build();
|
||||
}
|
||||
}
|
||||
64
src/main/java/nl/veenm/paypoint/resource/AuthResource.java
Normal file
64
src/main/java/nl/veenm/paypoint/resource/AuthResource.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package nl.veenm.paypoint.resource;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import nl.veenm.paypoint.domain.AppUser;
|
||||
import nl.veenm.paypoint.domain.UserDTO;
|
||||
import nl.veenm.paypoint.service.TokenService;
|
||||
import nl.veenm.paypoint.service.UserService;
|
||||
|
||||
@Path("/auth")
|
||||
public class AuthResource {
|
||||
|
||||
@Inject
|
||||
TokenService tokenService;
|
||||
|
||||
@Inject
|
||||
UserService userService;
|
||||
|
||||
@POST
|
||||
@Path("/register")
|
||||
public Response register(AppUser appUser) {
|
||||
userService.registerUser(appUser);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
// @POST
|
||||
// @Path("/login")
|
||||
// @PermitAll
|
||||
// @Consumes(MediaType.APPLICATION_JSON)
|
||||
// public Response login(AuthDTO user) {
|
||||
// System.out.println(user);
|
||||
// System.out.println("admin".equals(user.getUsername()) && "password".equals(user.getPassword()));
|
||||
// if ("admin".equals(user.getUsername()) && "password".equals(user.getPassword())) {
|
||||
// UserDTO userDTO = new UserDTO();
|
||||
// userDTO.setUsername(user.getUsername());
|
||||
// userDTO.setEmail("vanveenmel11@gmail.com");
|
||||
// userDTO.setFullName("Mel van Veen");
|
||||
// userDTO.setToken(tokenService.generateToken(user.getUsername()));
|
||||
// return Response.ok(userDTO).build();
|
||||
// }
|
||||
// return Response.status(Response.Status.UNAUTHORIZED).build();
|
||||
// }
|
||||
|
||||
@POST
|
||||
@Path("/login")
|
||||
public Response login(AppUser user) {
|
||||
AppUser authenticated = userService.authenticate(user.getUsername(), user.getPassword());
|
||||
if (authenticated != null) {
|
||||
String token = tokenService.generateToken(authenticated);
|
||||
UserDTO userDTO = new UserDTO();
|
||||
userDTO.setUsername(authenticated.getUsername());
|
||||
userDTO.setEmail(authenticated.getEmail());
|
||||
userDTO.setFullName(authenticated.getFirstName() + " " + authenticated.getLastName());
|
||||
userDTO.setToken(token);
|
||||
return Response.ok(userDTO).build();
|
||||
} else {
|
||||
return Response.status(Response.Status.UNAUTHORIZED).entity("Invalid credentials").build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package nl.veenm.paypoint.resource;
|
||||
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import nl.veenm.paypoint.domain.Customer;
|
||||
import nl.veenm.paypoint.service.CustomerService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Path("/api/customers")
|
||||
@PermitAll()
|
||||
public class CustomerResource {
|
||||
@Inject
|
||||
CustomerService customerService;
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<Customer> getCustomers() {
|
||||
return customerService.getCustomers();
|
||||
}
|
||||
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response addCustomer(Customer customer) {
|
||||
customerService.addCustomer(customer);
|
||||
return Response.ok().build();
|
||||
}
|
||||
}
|
||||
102
src/main/java/nl/veenm/paypoint/service/AppointmentService.java
Normal file
102
src/main/java/nl/veenm/paypoint/service/AppointmentService.java
Normal file
@@ -0,0 +1,102 @@
|
||||
package nl.veenm.paypoint.service;
|
||||
|
||||
import io.quarkus.scheduler.Scheduled;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.Transactional;
|
||||
import nl.veenm.paypoint.domain.Appointment;
|
||||
import nl.veenm.paypoint.repository.AppointmentRepository;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ApplicationScoped
|
||||
public class AppointmentService {
|
||||
@Inject
|
||||
AppointmentRepository appointmentRepository;
|
||||
|
||||
@Inject
|
||||
EmailService emailService;
|
||||
|
||||
private List<Appointment> appointments;
|
||||
|
||||
public AppointmentService() {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
appointments = new ArrayList<>();
|
||||
appointments.add(new Appointment(1L, "Knippen Mel", "", now, 12, 0, 13, 0, 60));
|
||||
appointments.add(new Appointment(2L, "Knippen Mel", "", now, 14, 0, 15, 0, 60));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Appointment> getAllAppointments() {
|
||||
return appointmentRepository.listAll();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void add(Appointment appointment) {
|
||||
// appointment.setStartDate(appointment.getStartDate().plusDays(1));
|
||||
appointmentRepository.persist(appointment);
|
||||
emailService.stuurBevestiging(appointment);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Appointment> getAppointmentsByDate(String start) {
|
||||
LocalDate date = LocalDate.parse(start);
|
||||
|
||||
LocalDateTime startOfDay = date.atStartOfDay(); // 00:00:00
|
||||
LocalDateTime endOfDay = date.atTime(23, 59, 59); // 23:59:59
|
||||
|
||||
return appointmentRepository.find("startDate BETWEEN ?1 AND ?2", startOfDay, endOfDay).list();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void delete(Long id) {
|
||||
emailService.stuurVerwijdering(appointmentRepository.findById(id));
|
||||
appointmentRepository.deleteById(id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void update(Appointment appointment) {
|
||||
Appointment appointmentToUpdate = appointmentRepository.findById(appointment.getId());
|
||||
appointmentToUpdate.setTitle(appointment.getTitle());
|
||||
appointmentToUpdate.setStartDate(appointment.getStartDate());
|
||||
appointmentToUpdate.setDescription(appointment.getDescription());
|
||||
appointmentToUpdate.setStartHour(appointment.getStartHour());
|
||||
appointmentToUpdate.setStartMinute(appointment.getStartMinute());
|
||||
appointmentToUpdate.setEndHour(appointment.getEndHour());
|
||||
appointmentToUpdate.setEndMinute(appointment.getEndMinute());
|
||||
appointmentToUpdate.setCustomer(appointment.getCustomer());
|
||||
appointmentToUpdate.setDurationInMinutes(appointment.getDurationInMinutes());
|
||||
appointmentRepository.persist(appointmentToUpdate);
|
||||
emailService.stuurBewerking(appointmentToUpdate);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Appointment getAppointment(Long id) {
|
||||
return appointmentRepository.findById(id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Scheduled(cron = "0 0 0 * * ?")
|
||||
public void sendReminder() {
|
||||
LocalDate date = LocalDate.now();
|
||||
date = date.plusDays(1);
|
||||
|
||||
LocalDateTime startOfDay = date.atStartOfDay(); // 00:00:00
|
||||
LocalDateTime endOfDay = date.atTime(23, 59, 59); // 23:59:59
|
||||
|
||||
|
||||
List<Appointment> allAppointments = appointmentRepository.find("date BETWEEN ?1 AND ?2", startOfDay, endOfDay).list();
|
||||
|
||||
allAppointments.forEach(appointment -> {
|
||||
emailService.stuurHerinnering(appointment);
|
||||
});
|
||||
}
|
||||
|
||||
public Appointment getMostRecentByUserId(Long userId) {
|
||||
return appointmentRepository.findMostRecentByUserId(userId).orElse(null);
|
||||
}
|
||||
|
||||
}
|
||||
34
src/main/java/nl/veenm/paypoint/service/CustomerService.java
Normal file
34
src/main/java/nl/veenm/paypoint/service/CustomerService.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package nl.veenm.paypoint.service;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.Transactional;
|
||||
import nl.veenm.paypoint.domain.Customer;
|
||||
import nl.veenm.paypoint.repository.CustomerRepository;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ApplicationScoped
|
||||
public class CustomerService {
|
||||
|
||||
@Inject
|
||||
CustomerRepository customerRepository;
|
||||
|
||||
public CustomerService() {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Customer> getCustomers() {
|
||||
List<Customer> customers = customerRepository.listAll();
|
||||
return customers.stream()
|
||||
.sorted(Comparator.comparing(Customer::getFirstName))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void addCustomer(Customer customer) {
|
||||
customerRepository.persist(customer);
|
||||
}
|
||||
}
|
||||
381
src/main/java/nl/veenm/paypoint/service/EmailService.java
Normal file
381
src/main/java/nl/veenm/paypoint/service/EmailService.java
Normal file
@@ -0,0 +1,381 @@
|
||||
package nl.veenm.paypoint.service;
|
||||
|
||||
import io.quarkus.mailer.Mail;
|
||||
import io.quarkus.mailer.Mailer;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import nl.veenm.paypoint.domain.Appointment;
|
||||
import nl.veenm.paypoint.helper.EmailHelper;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
|
||||
@ApplicationScoped
|
||||
public class EmailService {
|
||||
|
||||
private final Mailer mailer;
|
||||
|
||||
public EmailService(Mailer mailer) {
|
||||
this.mailer = mailer;
|
||||
}
|
||||
|
||||
public void stuurBevestiging(Appointment appointment) {
|
||||
|
||||
String location = "<br>Groenestraat 29<br>6681DW Bemmel";
|
||||
String imageUrl = "https://hairstylingbydaan.nl/assets/img/Logo.png";
|
||||
String formattedDate = appointment.getStartDate().toLocalDate().format(DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.forLanguageTag("nl")));
|
||||
|
||||
String formattedHour = String.valueOf(appointment.getStartHour()).length() == 1 ? "0" + appointment.getStartHour() : String.valueOf(appointment.getStartHour());
|
||||
String formattedMinute = String.valueOf(appointment.getStartMinute()).length() == 1 ? "0" + appointment.getStartMinute() : String.valueOf(appointment.getStartMinute());
|
||||
String formattedTime = formattedHour + ":" + formattedMinute;
|
||||
|
||||
String formattedEndHour = String.valueOf(appointment.getEndHour()).length() == 1 ? "0" + appointment.getEndHour() : String.valueOf(appointment.getEndHour());
|
||||
String formattedEndMinute = String.valueOf(appointment.getEndMinute()).length() == 1 ? "0" + appointment.getEndMinute() : String.valueOf(appointment.getEndMinute());
|
||||
String formattedEndTime = formattedEndHour + ":" + formattedEndMinute;
|
||||
|
||||
// Bouw de HTML-inhoud van de e-mail
|
||||
String emailBody = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Afspraakbevestiging</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
width: 80%%;
|
||||
max-width: 600px;
|
||||
background-color: #ffffff;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.header {
|
||||
background-color: #3c3c3c;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
.content {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.image {
|
||||
height: 128px;
|
||||
width: auto;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">Bevestiging van uw afspraak</div>
|
||||
<div class="content">
|
||||
<h4>Beste %s,</h4>
|
||||
<h4>Uw afspraak is succesvol ingepland!</h4>
|
||||
<h4><strong>Datum:</strong> %s<br>
|
||||
<strong>Tijd:</strong> %s<br><br>
|
||||
<strong>Locatie:</strong> %s</h4>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<img src="%s" alt="Afspraak bevestiging" class="image">
|
||||
<h4>Met vriendelijke groet,<br>Danielle<br>Hairstyling By Daan</h4>
|
||||
<p>© 2025 PayPoint. Alle rechten voorbehouden.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
""".formatted(appointment.getCustomer().getFirstName(), formattedDate, formattedTime,
|
||||
location, imageUrl);
|
||||
|
||||
String subject = String.format(" Afspraak bevestigd: %s", formattedDate);
|
||||
String recipient = appointment.getCustomer().getEmail();
|
||||
LocalDateTime date = appointment.getStartDate();
|
||||
date = date.withHour(appointment.getStartHour()).withMinute(appointment.getStartMinute());
|
||||
|
||||
String dtStamp = date.format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
|
||||
|
||||
mailer.send(Mail.withHtml(recipient, subject, emailBody)
|
||||
.setFrom("Hairstyling By Daan <paypoint@melvanveen.nl>")
|
||||
.addAttachment("afspraak.ics", EmailHelper.getIcs(dtStamp, date.toLocalDate(), formattedTime, formattedEndTime, location).getBytes(), "text/calendar"));
|
||||
}
|
||||
|
||||
public void stuurVerwijdering(Appointment appointment) {
|
||||
|
||||
String imageUrl = "https://hairstylingbydaan.nl/assets/img/Logo.png";
|
||||
String formattedDate = appointment.getStartDate().toLocalDate().format(DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.forLanguageTag("nl")));
|
||||
|
||||
|
||||
// Bouw de HTML-inhoud van de e-mail
|
||||
String emailBody = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Afspraakbevestiging</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
width: 80%%;
|
||||
max-width: 600px;
|
||||
background-color: #ffffff;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.header {
|
||||
background-color: #3c3c3c;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
.content {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.image {
|
||||
height: 128px;
|
||||
width: auto;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">Annulering van uw afspraak</div>
|
||||
<div class="content">
|
||||
<h4>Beste %s,</h4>
|
||||
<h4>Uw afspraak op %s is geannuleerd.</h4>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<img src="%s" alt="Afspraak bevestiging" class="image">
|
||||
<h4>Met vriendelijke groet,<br>Danielle<br>Hairstyling By Daan</h4>
|
||||
<p>© 2025 PayPoint. Alle rechten voorbehouden.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
""".formatted(appointment.getCustomer().getFirstName(), formattedDate, imageUrl);
|
||||
|
||||
String subject = String.format(" Afspraak geannuleerd: %s", formattedDate);
|
||||
String recipient = appointment.getCustomer().getEmail();
|
||||
|
||||
mailer.send(Mail.withHtml(recipient, subject, emailBody).setFrom("Hairstyling By Daan <paypoint@melvanveen.nl>"));
|
||||
}
|
||||
|
||||
public void stuurBewerking(Appointment appointment) {
|
||||
|
||||
String location = "<br>Groenestraat 29<br>6681DW Bemmel";
|
||||
String imageUrl = "https://hairstylingbydaan.nl/assets/img/Logo.png";
|
||||
String formattedDate = appointment.getStartDate().toLocalDate().format(DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.forLanguageTag("nl")));
|
||||
|
||||
String formattedTime = String.format("%s:%s", appointment.getStartHour(), String.valueOf(appointment.getStartMinute()).length() == 1 ? "0" + appointment.getStartMinute() : appointment.getStartMinute());
|
||||
|
||||
|
||||
// Bouw de HTML-inhoud van de e-mail
|
||||
String emailBody = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Afspraakbevestiging</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
width: 80%%;
|
||||
max-width: 600px;
|
||||
background-color: #ffffff;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.header {
|
||||
background-color: #3c3c3c;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
.content {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.image {
|
||||
height: 128px;
|
||||
width: auto;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">Wijziging van uw afspraak</div>
|
||||
<div class="content">
|
||||
<h4>Beste %s,</h4>
|
||||
<h4>Uw afspraak op %s is gewijzigd.</h4>
|
||||
<h4><strong>Datum:</strong> %s<br>
|
||||
<strong>Tijd:</strong> %s<br><br>
|
||||
<strong>Locatie:</strong> %s</h4>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<img src="%s" alt="Afspraak bevestiging" class="image">
|
||||
<h4>Met vriendelijke groet,<br>Danielle<br>Hairstyling By Daan</h4>
|
||||
<p>© 2025 PayPoint. Alle rechten voorbehouden.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
""".formatted(appointment.getCustomer().getFirstName(), formattedDate, formattedDate, formattedTime,
|
||||
location, imageUrl);
|
||||
|
||||
String subject = String.format(" Afspraak gewijzigd: %s", formattedDate);
|
||||
String recipient = appointment.getCustomer().getEmail();
|
||||
|
||||
mailer.send(Mail.withHtml(recipient, subject, emailBody).setFrom("Hairstyling By Daan <paypoint@melvanveen.nl>"));
|
||||
}
|
||||
|
||||
public void stuurHerinnering(Appointment appointment) {
|
||||
|
||||
String location = "<br>Groenestraat 29<br>6681DW Bemmel";
|
||||
String imageUrl = "https://hairstylingbydaan.nl/assets/img/Logo.png";
|
||||
String formattedDate = appointment.getStartDate().toLocalDate().format(DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.forLanguageTag("nl")));
|
||||
|
||||
String formattedTime = String.format("%s:%s", appointment.getStartHour(), String.valueOf(appointment.getStartMinute()).length() == 1 ? "0" + appointment.getStartMinute() : appointment.getStartMinute());
|
||||
|
||||
|
||||
// Bouw de HTML-inhoud van de e-mail
|
||||
String emailBody = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Afspraakbevestiging</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
width: 80%%;
|
||||
max-width: 600px;
|
||||
background-color: #ffffff;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.header {
|
||||
background-color: #3c3c3c;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
.content {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.image {
|
||||
height: 128px;
|
||||
width: auto;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">Herinnering van uw afspraak</div>
|
||||
<div class="content">
|
||||
<h4>Beste %s,</h4>
|
||||
<h4>U heeft morgen een afspraak.</h4>
|
||||
<h4><strong>Datum:</strong> %s<br>
|
||||
<strong>Tijd:</strong> %s<br><br>
|
||||
<strong>Locatie:</strong> %s</h4>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<img src="%s" alt="Afspraak bevestiging" class="image">
|
||||
<h4>Met vriendelijke groet,<br>Danielle<br>Hairstyling By Daan</h4>
|
||||
<p>© 2025 PayPoint. Alle rechten voorbehouden.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
""".formatted(appointment.getCustomer().getFirstName(), formattedDate, formattedTime,
|
||||
location, imageUrl);
|
||||
|
||||
String subject = String.format("Herinnering afspraak: %s", formattedDate);
|
||||
String recipient = appointment.getCustomer().getEmail();
|
||||
|
||||
mailer.send(Mail.withHtml(recipient, subject, emailBody).setFrom("Hairstyling By Daan <paypoint@melvanveen.nl>"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
11
src/main/java/nl/veenm/paypoint/service/PasswordService.java
Normal file
11
src/main/java/nl/veenm/paypoint/service/PasswordService.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package nl.veenm.paypoint.service;
|
||||
|
||||
import at.favre.lib.crypto.bcrypt.BCrypt;
|
||||
|
||||
public class PasswordService {
|
||||
|
||||
public static String hashPassword(String plainPassword) {
|
||||
return BCrypt.withDefaults().hashToString(12, plainPassword.toCharArray());
|
||||
}
|
||||
}
|
||||
|
||||
24
src/main/java/nl/veenm/paypoint/service/TokenService.java
Normal file
24
src/main/java/nl/veenm/paypoint/service/TokenService.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package nl.veenm.paypoint.service;
|
||||
|
||||
import io.smallrye.jwt.build.Jwt;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import nl.veenm.paypoint.domain.AppUser;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@ApplicationScoped
|
||||
public class TokenService {
|
||||
|
||||
public String generateToken(AppUser appUser) {
|
||||
return Jwt.issuer("PayPoint")
|
||||
.subject(appUser.getUsername())
|
||||
.expiresIn(Duration.ofHours(1))
|
||||
.claim("username", appUser.getUsername())
|
||||
.claim("firstName", appUser.getFirstName())
|
||||
.claim("lastName", appUser.getLastName())
|
||||
.claim("email", appUser.getEmail())
|
||||
.claim("groups", appUser.getRole())
|
||||
.sign();
|
||||
}
|
||||
}
|
||||
|
||||
33
src/main/java/nl/veenm/paypoint/service/UserService.java
Normal file
33
src/main/java/nl/veenm/paypoint/service/UserService.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package nl.veenm.paypoint.service;
|
||||
|
||||
import at.favre.lib.crypto.bcrypt.BCrypt;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.Transactional;
|
||||
import nl.veenm.paypoint.domain.AppUser;
|
||||
import nl.veenm.paypoint.repository.UserRepository;
|
||||
|
||||
@ApplicationScoped
|
||||
public class UserService {
|
||||
|
||||
@Inject
|
||||
UserRepository userRepository;
|
||||
|
||||
@Transactional
|
||||
public void registerUser(AppUser appUser) {
|
||||
appUser.setPassword(PasswordService.hashPassword(appUser.getPassword()));
|
||||
userRepository.persist(appUser);
|
||||
}
|
||||
|
||||
public AppUser authenticate(String username, String password) {
|
||||
AppUser user = userRepository.findByUsername(username);
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (BCrypt.verifyer().verify(password.toCharArray(), user.getPassword()).verified) {
|
||||
return user;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user