Update:
All checks were successful
Docker Image CI / build-and-push (push) Successful in 11m9s
Docker Image CI / deploy (push) Successful in 27s
Docker Image CI / notify-failure (push) Has been skipped

-delen van agenda toegevoegd
-popup aangepast
-accepteren van uitnodiging toegevoegd
-koppelen van gebruiker aan bedrijf
-versturen van uitnodiging via mail
This commit is contained in:
2025-04-18 22:41:17 +02:00
parent ebce9820d2
commit a497b8162b
28 changed files with 908 additions and 55 deletions

View File

@@ -0,0 +1,65 @@
package nl.veenm.paypoint.service;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.core.Response;
import nl.veenm.paypoint.domain.InviteEntity;
import nl.veenm.paypoint.domain.InviteRequest;
import nl.veenm.paypoint.repository.InviteRepository;
import java.security.SecureRandom;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Base64;
@ApplicationScoped
public class AgendaService {
@Inject
EmailService emailService;
@Inject
InviteRepository inviteRepository;
public void sendInvite(String email, String url) {
this.emailService.stuurUitnodiging(email, url);
}
@Transactional
public InviteEntity createInvite(InviteRequest inviteRequest) {
String token = generateSecureToken(); // zoals eerder besproken
InviteEntity invite = new InviteEntity();
invite.setCompany_id(inviteRequest.companyId);
invite.setEmail(inviteRequest.email);
invite.setToken(token);
invite.setUsed(false);
invite.setCreatedAt(Instant.now());
invite.setExpiresAt(Instant.now().plus(1, ChronoUnit.HOURS)); // 1u geldig
inviteRepository.persist(invite);
return invite;
}
public String generateSecureToken() {
byte[] randomBytes = new byte[24];
new SecureRandom().nextBytes(randomBytes);
return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes);
}
public Response verifyInvite(String token) {
InviteEntity invite = inviteRepository.findByToken(token);
if (invite == null || invite.isUsed()) {
return Response.status(Response.Status.BAD_REQUEST).entity("Ongeldige of reeds gebruikte uitnodiging").build();
}
if (invite.getExpiresAt().isBefore(Instant.now())) {
return Response.status(Response.Status.GONE).entity("Deze uitnodiging is verlopen").build();
}
return Response.ok(invite).build();
}
}

View File

@@ -7,6 +7,10 @@ import jakarta.transaction.Transactional;
import nl.veenm.paypoint.domain.AppUser;
import nl.veenm.paypoint.domain.Appointment;
import nl.veenm.paypoint.domain.Company;
import nl.veenm.paypoint.domain.dto.AppUserDTO;
import nl.veenm.paypoint.domain.dto.CompanyDTO;
import nl.veenm.paypoint.domain.dto.UserCompanyDTO;
import nl.veenm.paypoint.domain.mapper.AppUserMapper;
import nl.veenm.paypoint.repository.AppointmentRepository;
import nl.veenm.paypoint.repository.CompanyRepository;
import nl.veenm.paypoint.repository.UserRepository;
@@ -14,6 +18,8 @@ import nl.veenm.paypoint.repository.UserRepository;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@ApplicationScoped
public class AppointmentService {
@@ -52,12 +58,19 @@ public class AppointmentService {
public List<Appointment> getAppointmentsByDate(String start, String username) {
LocalDate date = LocalDate.parse(start);
AppUser user = userRepository.findByUsername(username);
System.out.println("user " + user);
AppUserDTO appUserDTO = AppUserMapper.toDTO(user);
System.out.println("appUserDTO " + appUserDTO);
Set<Long> companies = appUserDTO.getCompanies().stream().map(UserCompanyDTO::getCompany).map(CompanyDTO::getId).collect(Collectors.toSet());
System.out.println("companies " + companies);
LocalDateTime startOfDay = date.atStartOfDay();
LocalDateTime endOfDay = date.atTime(23, 59, 59);
return appointmentRepository.findAppointmentsForCompanies(user.getCompanies(), startOfDay, endOfDay);
List<Appointment> appointmentsForCompanies = appointmentRepository.findAppointmentsForCompanies(companies, startOfDay, endOfDay);
System.out.println(appointmentsForCompanies);
return appointmentsForCompanies;
}
@Transactional

View File

@@ -3,38 +3,53 @@ package nl.veenm.paypoint.service;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import nl.veenm.paypoint.domain.AppUser;
import nl.veenm.paypoint.domain.Company;
import nl.veenm.paypoint.domain.*;
import nl.veenm.paypoint.domain.dto.CompanyDTO;
import nl.veenm.paypoint.domain.mapper.CompanyMapper;
import nl.veenm.paypoint.repository.CompanyRepository;
import nl.veenm.paypoint.repository.InviteRepository;
import nl.veenm.paypoint.repository.UserCompanyRepository;
import nl.veenm.paypoint.repository.UserRepository;
import java.util.Set;
import java.util.List;
@ApplicationScoped
public class CompanyService {
@Inject
CompanyRepository companyRepository;
@Inject
UserCompanyRepository userCompanyRepository;
@Inject
UserRepository userRepository;
public Set<Company> getCompanies(String username) {
AppUser user = this.userRepository.findByUsername(username);
return user.getCompanies();
@Inject
InviteRepository inviteRepository;
public List<UserCompany> getCompanies(String username) {
AppUser user = userRepository.findByUsername(username);
return userCompanyRepository.getAllByUserId(user);
}
public CompanyDTO getCompanyById(Long id) {
return CompanyMapper.toDto(companyRepository.findById(id));
}
@Transactional
public void linkCompany(Long userId, Long companyId) {
AppUser user = this.userRepository.findById(userId);
Company company = this.companyRepository.findById(companyId);
public void linkCompany(Long userId, String token) {
AppUser user = userRepository.findById(userId);
InviteEntity invite = inviteRepository.findByToken(token);
Company company = companyRepository.findById(invite.company_id);
System.out.println(user.getCompanies());
user.getCompanies().add(company);
company.getUsers().add(user);
UserCompany userCompany = new UserCompany();
userCompany.setUser(user);
userCompany.setCompany(company);
userCompany.setAccessLevel(AccessLevel.USER);
userCompanyRepository.persist(userCompany);
System.out.println(user.getCompanies());
invite.used = true;
inviteRepository.persist(invite);
userRepository.persist(user);
companyRepository.persist(company);
}
}

View File

@@ -3,6 +3,7 @@ package nl.veenm.paypoint.service;
import io.quarkus.mailer.Mail;
import io.quarkus.mailer.Mailer;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import nl.veenm.paypoint.domain.AppUser;
import nl.veenm.paypoint.domain.Appointment;
import nl.veenm.paypoint.domain.Company;
@@ -11,12 +12,16 @@ import nl.veenm.paypoint.helper.EmailHelper;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Map;
@ApplicationScoped
public class EmailService {
private final Mailer mailer;
@Inject
EmailTemplateService emailTemplateService;
public EmailService(Mailer mailer) {
this.mailer = mailer;
}
@@ -378,7 +383,18 @@ public class EmailService {
mailer.send(Mail.withHtml(recipient, subject, emailBody).setFrom("Hairstyling By Daan <paypoint@melvanveen.nl>").setReplyTo(company.getEmail()));
}
public void stuurUitnodiging(String recipient, String agendaLink) {
Map<String, String> replacements = Map.of(
"link", agendaLink
);
String templatePath = "src/main/resources/templates/agenda-invite.html";
String htmlBody = emailTemplateService.loadTemplate(templatePath, replacements);
mailer.send(Mail.withHtml(recipient, "Uitnodiging om agenda te bekijken", htmlBody).setFrom("PayPoint <paypoint@melvanveen.nl>"));
}
}

View File

@@ -0,0 +1,28 @@
package nl.veenm.paypoint.service;
import jakarta.enterprise.context.ApplicationScoped;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
@ApplicationScoped
public class EmailTemplateService {
public String loadTemplate(String templatePath, Map<String, String> replacements) {
try {
String content = Files.readString(Path.of(templatePath), StandardCharsets.UTF_8);
for (Map.Entry<String, String> entry : replacements.entrySet()) {
content = content.replace("{{" + entry.getKey() + "}}", entry.getValue());
}
return content;
} catch (IOException e) {
throw new RuntimeException("Kon e-mailtemplate niet inladen: " + templatePath, e);
}
}
}