Update:
-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:
7
src/main/java/nl/veenm/paypoint/domain/AccessLevel.java
Normal file
7
src/main/java/nl/veenm/paypoint/domain/AccessLevel.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package nl.veenm.paypoint.domain;
|
||||
|
||||
public enum AccessLevel {
|
||||
READ_ONLY,
|
||||
USER
|
||||
}
|
||||
|
||||
@@ -17,13 +17,8 @@ public class AppUser {
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(
|
||||
name = "user_company",
|
||||
joinColumns = @JoinColumn(name = "user_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "company_id")
|
||||
)
|
||||
private Set<Company> companies = new HashSet<>();
|
||||
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private Set<UserCompany> userCompanies = new HashSet<>();
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
@@ -81,12 +76,12 @@ public class AppUser {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Set<Company> getCompanies() {
|
||||
return companies;
|
||||
public Set<UserCompany> getUserCompanies() {
|
||||
return userCompanies;
|
||||
}
|
||||
|
||||
public void setCompanies(Set<Company> companies) {
|
||||
this.companies = companies;
|
||||
public void setUserCompanies(Set<UserCompany> userCompanies) {
|
||||
this.userCompanies = userCompanies;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package nl.veenm.paypoint.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -18,9 +17,8 @@ public class Company {
|
||||
private String postal_code;
|
||||
private String city;
|
||||
|
||||
@ManyToMany(mappedBy = "companies")
|
||||
@JsonIgnore
|
||||
private Set<AppUser> users = new HashSet<>();
|
||||
@OneToMany(mappedBy = "company", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private Set<UserCompany> userCompanies = new HashSet<>();
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
@@ -78,11 +76,11 @@ public class Company {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public Set<AppUser> getUsers() {
|
||||
return users;
|
||||
public Set<UserCompany> getUserCompanies() {
|
||||
return userCompanies;
|
||||
}
|
||||
|
||||
public void setUsers(Set<AppUser> users) {
|
||||
this.users = users;
|
||||
public void setUserCompanies(Set<UserCompany> userCompanies) {
|
||||
this.userCompanies = userCompanies;
|
||||
}
|
||||
}
|
||||
|
||||
100
src/main/java/nl/veenm/paypoint/domain/InviteEntity.java
Normal file
100
src/main/java/nl/veenm/paypoint/domain/InviteEntity.java
Normal file
@@ -0,0 +1,100 @@
|
||||
package nl.veenm.paypoint.domain;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
public class InviteEntity {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
public UUID id;
|
||||
public Long company_id;
|
||||
public String email;
|
||||
public String token;
|
||||
public Instant expiresAt;
|
||||
public boolean used;
|
||||
public Instant createdAt;
|
||||
|
||||
public InviteEntity() {
|
||||
}
|
||||
|
||||
public InviteEntity(UUID id, Long company_id, String email, String token, Instant expiresAt, boolean used, Instant createdAt) {
|
||||
this.id = id;
|
||||
this.company_id = company_id;
|
||||
this.email = email;
|
||||
this.token = token;
|
||||
this.expiresAt = expiresAt;
|
||||
this.used = used;
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getCompany_id() {
|
||||
return company_id;
|
||||
}
|
||||
|
||||
public void setCompany_id(Long company_id) {
|
||||
this.company_id = company_id;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public Instant getExpiresAt() {
|
||||
return expiresAt;
|
||||
}
|
||||
|
||||
public void setExpiresAt(Instant expires_at) {
|
||||
this.expiresAt = expires_at;
|
||||
}
|
||||
|
||||
public boolean isUsed() {
|
||||
return used;
|
||||
}
|
||||
|
||||
public void setUsed(boolean used) {
|
||||
this.used = used;
|
||||
}
|
||||
|
||||
public Instant getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(Instant created_at) {
|
||||
this.createdAt = created_at;
|
||||
}
|
||||
}
|
||||
|
||||
//Kolom | Type | Beschrijving
|
||||
//id | UUID (PK) | Uniek ID
|
||||
//bedrijf_id | Long | ID van het bedrijf/agenda
|
||||
//email | String | Ontvanger
|
||||
//token | String (uniek) | Token (bijv. Base64 of UUID)
|
||||
//expires_at | Timestamp | Expiratietijd (bijv. 24u geldig)
|
||||
//used | Boolean | Of de uitnodiging al geaccepteerd is
|
||||
//created_at | Timestamp | Voor logging/audit
|
||||
@@ -0,0 +1,7 @@
|
||||
package nl.veenm.paypoint.domain;
|
||||
|
||||
public class InviteRequest {
|
||||
public Long companyId;
|
||||
public String email;
|
||||
}
|
||||
|
||||
5
src/main/java/nl/veenm/paypoint/domain/UrlRequest.java
Normal file
5
src/main/java/nl/veenm/paypoint/domain/UrlRequest.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package nl.veenm.paypoint.domain;
|
||||
|
||||
public class UrlRequest {
|
||||
public String url;
|
||||
}
|
||||
60
src/main/java/nl/veenm/paypoint/domain/UserCompany.java
Normal file
60
src/main/java/nl/veenm/paypoint/domain/UserCompany.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package nl.veenm.paypoint.domain;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "user_company")
|
||||
public class UserCompany {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private UUID id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "user_id")
|
||||
private AppUser user;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "company_id")
|
||||
private Company company;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "access_level")
|
||||
private AccessLevel accessLevel;
|
||||
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public AppUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(AppUser user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public Company getCompany() {
|
||||
return company;
|
||||
}
|
||||
|
||||
public void setCompany(Company company) {
|
||||
this.company = company;
|
||||
}
|
||||
|
||||
public AccessLevel getAccessLevel() {
|
||||
return accessLevel;
|
||||
}
|
||||
|
||||
public void setAccessLevel(AccessLevel accessLevel) {
|
||||
this.accessLevel = accessLevel;
|
||||
}
|
||||
}
|
||||
|
||||
78
src/main/java/nl/veenm/paypoint/domain/dto/AppUserDTO.java
Normal file
78
src/main/java/nl/veenm/paypoint/domain/dto/AppUserDTO.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package nl.veenm.paypoint.domain.dto;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class AppUserDTO {
|
||||
private Long id;
|
||||
private String username;
|
||||
private String email;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private String role;
|
||||
private String token;
|
||||
private Set<UserCompanyDTO> companies;
|
||||
|
||||
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 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 getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setRole(String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public Set<UserCompanyDTO> getCompanies() {
|
||||
return companies;
|
||||
}
|
||||
|
||||
public void setCompanies(Set<UserCompanyDTO> companies) {
|
||||
this.companies = companies;
|
||||
}
|
||||
}
|
||||
67
src/main/java/nl/veenm/paypoint/domain/dto/CompanyDTO.java
Normal file
67
src/main/java/nl/veenm/paypoint/domain/dto/CompanyDTO.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package nl.veenm.paypoint.domain.dto;
|
||||
|
||||
public class CompanyDTO {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String email;
|
||||
private String address;
|
||||
private String postalCode;
|
||||
private String city;
|
||||
private String imgHref;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getPostalCode() {
|
||||
return postalCode;
|
||||
}
|
||||
|
||||
public void setPostalCode(String postalCode) {
|
||||
this.postalCode = postalCode;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getImgHref() {
|
||||
return imgHref;
|
||||
}
|
||||
|
||||
public void setImgHref(String imgHref) {
|
||||
this.imgHref = imgHref;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package nl.veenm.paypoint.domain.dto;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class UserCompanyDTO {
|
||||
private UUID id;
|
||||
private String accessLevel;
|
||||
private CompanyDTO company;
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getAccessLevel() {
|
||||
return accessLevel;
|
||||
}
|
||||
|
||||
public void setAccessLevel(String accessLevel) {
|
||||
this.accessLevel = accessLevel;
|
||||
}
|
||||
|
||||
public CompanyDTO getCompany() {
|
||||
return company;
|
||||
}
|
||||
|
||||
public void setCompany(CompanyDTO company) {
|
||||
this.company = company;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package nl.veenm.paypoint.domain.mapper;
|
||||
|
||||
import nl.veenm.paypoint.domain.AppUser;
|
||||
import nl.veenm.paypoint.domain.Company;
|
||||
import nl.veenm.paypoint.domain.UserCompany;
|
||||
import nl.veenm.paypoint.domain.dto.AppUserDTO;
|
||||
import nl.veenm.paypoint.domain.dto.CompanyDTO;
|
||||
import nl.veenm.paypoint.domain.dto.UserCompanyDTO;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AppUserMapper {
|
||||
|
||||
public static AppUserDTO toDTO(AppUser user, String token) {
|
||||
AppUserDTO dto = toDTO(user);
|
||||
dto.setToken(token);
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
public static AppUserDTO toDTO(AppUser user) {
|
||||
AppUserDTO dto = new AppUserDTO();
|
||||
dto.setId(user.getId());
|
||||
dto.setUsername(user.getUsername());
|
||||
dto.setEmail(user.getEmail());
|
||||
dto.setFirstName(user.getFirstName());
|
||||
dto.setLastName(user.getLastName());
|
||||
dto.setRole(user.getRole());
|
||||
|
||||
if (user.getUserCompanies() != null) {
|
||||
Set<UserCompanyDTO> companyDTOs = user.getUserCompanies()
|
||||
.stream()
|
||||
.map(AppUserMapper::toUserCompanyDTO)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
dto.setCompanies(companyDTOs);
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
private static UserCompanyDTO toUserCompanyDTO(UserCompany uc) {
|
||||
UserCompanyDTO dto = new UserCompanyDTO();
|
||||
dto.setId(uc.getId());
|
||||
dto.setAccessLevel(uc.getAccessLevel().name());
|
||||
|
||||
Company company = uc.getCompany();
|
||||
CompanyDTO companyDTO = CompanyMapper.toDto(company);
|
||||
|
||||
dto.setCompany(companyDTO);
|
||||
return dto;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package nl.veenm.paypoint.domain.mapper;
|
||||
|
||||
import nl.veenm.paypoint.domain.Company;
|
||||
import nl.veenm.paypoint.domain.dto.CompanyDTO;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CompanyMapper {
|
||||
|
||||
public static CompanyDTO toDto(Company company) {
|
||||
if (company == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CompanyDTO dto = new CompanyDTO();
|
||||
dto.setId(company.getId());
|
||||
dto.setName(company.getName());
|
||||
dto.setEmail(company.getEmail());
|
||||
dto.setAddress(company.getAddress());
|
||||
dto.setPostalCode(company.getPostal_code());
|
||||
dto.setCity(company.getCity());
|
||||
dto.setImgHref(company.getImg_href());
|
||||
return dto;
|
||||
}
|
||||
|
||||
public static List<CompanyDTO> toDtoList(Collection<Company> companies) {
|
||||
if (companies == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return companies.stream()
|
||||
.map(CompanyMapper::toDto)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,9 @@ public class AppointmentRepository implements PanacheRepository<Appointment> {
|
||||
return find("company = ?1", company).list();
|
||||
}
|
||||
|
||||
public List<Appointment> findAppointmentsForCompanies(Set<Company> companies, LocalDateTime startDate, LocalDateTime endDate) {
|
||||
return find("SELECT a FROM Appointment a WHERE a.company IN :companies AND a.startDate BETWEEN :start AND :end",
|
||||
Parameters.with("companies", companies).and("start", startDate).and("end", endDate))
|
||||
public List<Appointment> findAppointmentsForCompanies(Set<Long> companyIds, LocalDateTime startDate, LocalDateTime endDate) {
|
||||
return find("SELECT a FROM Appointment a WHERE a.company.id IN :companyIds AND a.startDate BETWEEN :start AND :end",
|
||||
Parameters.with("companyIds", companyIds).and("start", startDate).and("end", endDate))
|
||||
.list();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package nl.veenm.paypoint.repository;
|
||||
|
||||
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import nl.veenm.paypoint.domain.InviteEntity;
|
||||
|
||||
@ApplicationScoped
|
||||
public class InviteRepository implements PanacheRepository<InviteEntity> {
|
||||
public InviteEntity findByToken(String token) {
|
||||
return find("token", token).firstResult();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package nl.veenm.paypoint.repository;
|
||||
|
||||
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import nl.veenm.paypoint.domain.AppUser;
|
||||
import nl.veenm.paypoint.domain.UserCompany;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ApplicationScoped
|
||||
public class UserCompanyRepository implements PanacheRepository<UserCompany> {
|
||||
public List<UserCompany> getAllByUserId(AppUser user) {
|
||||
return find("user", user).list();
|
||||
}
|
||||
}
|
||||
40
src/main/java/nl/veenm/paypoint/resource/AgendaResource.java
Normal file
40
src/main/java/nl/veenm/paypoint/resource/AgendaResource.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package nl.veenm.paypoint.resource;
|
||||
|
||||
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.InviteEntity;
|
||||
import nl.veenm.paypoint.domain.InviteRequest;
|
||||
import nl.veenm.paypoint.domain.UrlRequest;
|
||||
import nl.veenm.paypoint.service.AgendaService;
|
||||
|
||||
@Path("/agenda")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class AgendaResource {
|
||||
|
||||
@Inject
|
||||
AgendaService agendaService;
|
||||
|
||||
@POST
|
||||
@Path("/{email}")
|
||||
public void sendInvite(@PathParam("email") String email, UrlRequest urlRequest) {
|
||||
agendaService.sendInvite(email, urlRequest.url);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/verify")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response verifyInvite(@QueryParam("token") String token) {
|
||||
return agendaService.verifyInvite(token);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/createinvite")
|
||||
public InviteEntity createInvite(InviteRequest inviteRequest) {
|
||||
return agendaService.createInvite(inviteRequest);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -31,7 +31,9 @@ public class AppointmentResource {
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("/date")
|
||||
public List<Appointment> getAppointmentsByDate(@QueryParam("start") String start) {
|
||||
System.out.println("getting appointments from " + start);
|
||||
String user = jwt.getClaim("username");
|
||||
System.out.println("user " + user);
|
||||
return appointmentService.getAppointmentsByDate(start, user);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ 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.domain.dto.AppUserDTO;
|
||||
import nl.veenm.paypoint.domain.mapper.AppUserMapper;
|
||||
import nl.veenm.paypoint.service.TokenService;
|
||||
import nl.veenm.paypoint.service.UserService;
|
||||
|
||||
@@ -46,15 +47,12 @@ public class AuthResource {
|
||||
@POST
|
||||
@Path("/login")
|
||||
public Response login(AppUser user) {
|
||||
System.out.println("login");
|
||||
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();
|
||||
AppUserDTO authenticatedDTO = AppUserMapper.toDTO(authenticated, token);
|
||||
return Response.ok(authenticatedDTO).build();
|
||||
} else {
|
||||
return Response.status(Response.Status.UNAUTHORIZED).entity("Invalid credentials").build();
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@ package nl.veenm.paypoint.resource;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import nl.veenm.paypoint.domain.Company;
|
||||
import nl.veenm.paypoint.domain.UserCompany;
|
||||
import nl.veenm.paypoint.domain.dto.CompanyDTO;
|
||||
import nl.veenm.paypoint.service.CompanyService;
|
||||
import org.eclipse.microprofile.jwt.JsonWebToken;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.List;
|
||||
|
||||
@Path("/company")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@@ -21,14 +22,19 @@ public class CompanyResource {
|
||||
JsonWebToken jwt;
|
||||
|
||||
@GET
|
||||
public Set<Company> getCompanies() {
|
||||
public List<UserCompany> getCompanies() {
|
||||
return this.companyService.getCompanies(this.jwt.getClaim("username"));
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
public CompanyDTO getCompanyById(@PathParam("id") Long id) {
|
||||
return this.companyService.getCompanyById(id);
|
||||
}
|
||||
|
||||
@POST
|
||||
public void linkCompany(@QueryParam("user") Long userId, @QueryParam("company") Long companyId) {
|
||||
System.out.println(userId);
|
||||
System.out.println(companyId);
|
||||
this.companyService.linkCompany(userId, companyId);
|
||||
@Path("/link")
|
||||
public void linkCompany(@QueryParam("user") Long userId, @QueryParam("token") String token) {
|
||||
this.companyService.linkCompany(userId, token);
|
||||
}
|
||||
}
|
||||
|
||||
65
src/main/java/nl/veenm/paypoint/service/AgendaService.java
Normal file
65
src/main/java/nl/veenm/paypoint/service/AgendaService.java
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
66
src/main/resources/templates/agenda-invite.html
Normal file
66
src/main/resources/templates/agenda-invite.html
Normal file
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="nl">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>Agenda-uitnodiging</title>
|
||||
</head>
|
||||
<body style="margin:0;padding:0;background-color:#f4f4f4;">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="background-color:#f4f4f4;padding:20px 0;">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table width="600" cellpadding="0" cellspacing="0"
|
||||
style="background-color:#ffffff;border-radius:8px;padding:30px;font-family:sans-serif;">
|
||||
|
||||
<!-- Logo -->
|
||||
<tr>
|
||||
<td style="text-align:center;padding-bottom:20px;">
|
||||
<img
|
||||
src="https://paypoint.melvanveen.nl/assets/logo-minimal.png"
|
||||
alt="Agenda logo"
|
||||
style="max-width:200px;height:auto;margin-bottom:10px;"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Titel -->
|
||||
<tr>
|
||||
<td style="text-align:center;padding-bottom:20px;">
|
||||
<h2 style="margin:0;color:#1f2937;">Uitnodiging om een agenda te bekijken</h2>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Inhoud -->
|
||||
<tr>
|
||||
<td style="font-size:16px;color:#374151;line-height:1.6;text-align: center;">
|
||||
<p>
|
||||
Je bent uitgenodigd om een agenda te bekijken of eraan deel te nemen.
|
||||
</p>
|
||||
<p>
|
||||
Klik op onderstaande knop om toegang te krijgen:
|
||||
</p>
|
||||
|
||||
<p style="text-align:center;margin:30px 0;">
|
||||
<a
|
||||
href="{{link}}"
|
||||
style="background-color:#3b82f6;color:#ffffff;padding:12px 24px;border-radius:6px;text-decoration:none;display:inline-block;font-weight:bold;"
|
||||
>
|
||||
Bekijk de agenda
|
||||
</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Footer -->
|
||||
<tr>
|
||||
<td style="font-size:12px;text-align:center;color:#9ca3af;padding-top:30px;">
|
||||
Als je deze uitnodiging niet verwachtte, kun je deze e-mail negeren.
|
||||
<p>© 2025 PayPoint. Alle rechten voorbehouden.</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user