✨ Add membership feature
This commit is contained in:
parent
23955b33df
commit
f1751250a1
47
Jenkinsfile
vendored
Executable file
47
Jenkinsfile
vendored
Executable file
@ -0,0 +1,47 @@
|
|||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Set Image Name') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
env.TAG = "${env.BUILD_NUMBER}"
|
||||||
|
env.REFERENCE = "harbor.dinauer.dev/tavolio/iam-backend"
|
||||||
|
env.IMAGE = "${env.REFERENCE}:${env.BUILD_NUMBER}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Build Quarkus application') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
sh './gradlew build'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Build Docker Image') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
sh "docker build --no-cache -t ${env.IMAGE} -f src/main/docker/Dockerfile.jvm ."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Push Image to Docker Hub') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
withCredentials([usernamePassword(credentialsId: 'harbor', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
|
||||||
|
sh 'echo ${PASSWORD} | docker login harbor.dinauer.dev -u ${USERNAME} --password-stdin'
|
||||||
|
sh "docker push ${env.IMAGE}"
|
||||||
|
sh "docker logout"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Remove image from host') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
sh "docker image rm --force ${env.IMAGE}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
pom.xml
8
pom.xml
@ -63,6 +63,14 @@
|
|||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-hibernate-validator</artifactId>
|
<artifactId>quarkus-hibernate-validator</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-smallrye-jwt</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-smallrye-jwt-build</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-junit5</artifactId>
|
<artifactId>quarkus-junit5</artifactId>
|
||||||
|
|||||||
93
src/main/java/de/tavolio/AuthenticationService.java
Normal file
93
src/main/java/de/tavolio/AuthenticationService.java
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package de.tavolio;
|
||||||
|
|
||||||
|
import de.tavolio.account.AccountEntity;
|
||||||
|
import de.tavolio.account.AccountRepo;
|
||||||
|
import io.quarkus.security.UnauthorizedException;
|
||||||
|
import io.vertx.core.http.HttpServerRequest;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.NotFoundException;
|
||||||
|
import jakarta.ws.rs.core.HttpHeaders;
|
||||||
|
import jakarta.ws.rs.core.SecurityContext;
|
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class AuthenticationService
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
Logger LOG;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AccountRepo accountRepo;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
SecurityContext securityContext;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
HttpServerRequest request;
|
||||||
|
|
||||||
|
@ConfigProperty(name = "iam.user.name")
|
||||||
|
String superuserName;
|
||||||
|
|
||||||
|
@ConfigProperty(name = "iam.user.password")
|
||||||
|
String superuserPassword;
|
||||||
|
|
||||||
|
public boolean isSuperUser()
|
||||||
|
{
|
||||||
|
String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
|
||||||
|
if (authHeader != null && !authHeader.isBlank())
|
||||||
|
{
|
||||||
|
String[] sections = authHeader.split("\\s+");
|
||||||
|
if (sections.length == 2 && sections[0].equals("Basic"))
|
||||||
|
{
|
||||||
|
String value = new String(Base64.getDecoder().decode(sections[1]));
|
||||||
|
String[] parts = value.split(":");
|
||||||
|
if (parts.length == 2)
|
||||||
|
{
|
||||||
|
String username = parts[0];
|
||||||
|
String password = parts[1];
|
||||||
|
boolean isSuperuser = username.equals(superuserName) && password.equals(superuserPassword);
|
||||||
|
if (isSuperuser)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
LOG.errorf("Invalid username or password", getRequestPath());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG.errorf("Invalid base64 credentials %s", getRequestPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountEntity requireUser()
|
||||||
|
{
|
||||||
|
Principal principal = securityContext.getUserPrincipal();
|
||||||
|
if(principal != null)
|
||||||
|
{
|
||||||
|
AccountEntity accountEntity = accountRepo.findById(principal.getName());
|
||||||
|
if(accountEntity != null)
|
||||||
|
{
|
||||||
|
return accountEntity;
|
||||||
|
}
|
||||||
|
LOG.warnf("No account found for request %s", getRequestPath());
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
LOG.warnf("Unauthorized request %s", getRequestPath());
|
||||||
|
throw new UnauthorizedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getRequestPath()
|
||||||
|
{
|
||||||
|
return String.format("[%s, %s]", request.method().name(), request.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,10 @@
|
|||||||
package de.tavolio.account;
|
package de.tavolio.account;
|
||||||
|
|
||||||
|
import de.tavolio.member.MembershipEntity;
|
||||||
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
|
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.*;
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import jakarta.persistence.Table;
|
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -22,6 +22,12 @@ public class AccountEntity extends PanacheEntityBase
|
|||||||
|
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private AccountStatus status;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "account")
|
||||||
|
private Set<MembershipEntity> memberships;
|
||||||
|
|
||||||
public static AccountEntity init()
|
public static AccountEntity init()
|
||||||
{
|
{
|
||||||
return new AccountEntity().setId(UUID.randomUUID().toString());
|
return new AccountEntity().setId(UUID.randomUUID().toString());
|
||||||
@ -81,4 +87,26 @@ public class AccountEntity extends PanacheEntityBase
|
|||||||
this.password = password;
|
this.password = password;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<MembershipEntity> getMemberships()
|
||||||
|
{
|
||||||
|
return memberships;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountEntity setMemberships(Set<MembershipEntity> memberships)
|
||||||
|
{
|
||||||
|
this.memberships = memberships;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountStatus getStatus()
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountEntity setStatus(AccountStatus status)
|
||||||
|
{
|
||||||
|
this.status = status;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,13 +2,12 @@ package de.tavolio.account;
|
|||||||
|
|
||||||
import de.tavolio.account.dto.Account;
|
import de.tavolio.account.dto.Account;
|
||||||
import jakarta.enterprise.context.ApplicationScoped;
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
import jakarta.ws.rs.ApplicationPath;
|
|
||||||
|
|
||||||
@ApplicationScoped
|
@ApplicationScoped
|
||||||
public class AccountMapper
|
public class AccountMapper
|
||||||
{
|
{
|
||||||
public Account map(AccountEntity accountEntity)
|
public Account map(AccountEntity accountEntity)
|
||||||
{
|
{
|
||||||
return new Account(accountEntity.getId());
|
return new Account(accountEntity.getId(), accountEntity.getFirstname(), accountEntity.getLastname(), accountEntity.getEmail(), accountEntity.getStatus());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
package de.tavolio.account;
|
package de.tavolio.account;
|
||||||
|
|
||||||
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
|
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
|
||||||
|
import io.quarkus.panache.common.Parameters;
|
||||||
import jakarta.enterprise.context.ApplicationScoped;
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@ApplicationScoped
|
@ApplicationScoped
|
||||||
public class AccountRepo implements PanacheRepositoryBase<AccountEntity, String>
|
public class AccountRepo implements PanacheRepositoryBase<AccountEntity, String>
|
||||||
{
|
{
|
||||||
|
public Optional<AccountEntity> findOptionalByEmail(String email)
|
||||||
|
{
|
||||||
|
return find("email = :email", Parameters.with("email", email)).firstResultOptional();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,8 +7,8 @@ import jakarta.validation.Valid;
|
|||||||
import jakarta.ws.rs.GET;
|
import jakarta.ws.rs.GET;
|
||||||
import jakarta.ws.rs.POST;
|
import jakarta.ws.rs.POST;
|
||||||
import jakarta.ws.rs.Path;
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.PathParam;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.jboss.resteasy.reactive.common.NotImplementedYet;
|
|
||||||
|
|
||||||
@Path("/accounts")
|
@Path("/accounts")
|
||||||
public class AccountResource
|
public class AccountResource
|
||||||
@ -28,8 +28,9 @@ public class AccountResource
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
public Account get()
|
@Path("/{id}")
|
||||||
|
public Account get(@PathParam("id") String id)
|
||||||
{
|
{
|
||||||
throw new NotImplementedYet();
|
return accountService.getUser(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,30 @@
|
|||||||
package de.tavolio.account;
|
package de.tavolio.account;
|
||||||
|
|
||||||
|
import de.tavolio.AuthenticationService;
|
||||||
import de.tavolio.account.dto.Account;
|
import de.tavolio.account.dto.Account;
|
||||||
import de.tavolio.account.dto.AccountCreation;
|
import de.tavolio.account.dto.AccountCreation;
|
||||||
import io.quarkus.elytron.security.common.BcryptUtil;
|
import io.quarkus.elytron.security.common.BcryptUtil;
|
||||||
|
import io.quarkus.security.UnauthorizedException;
|
||||||
import jakarta.enterprise.context.ApplicationScoped;
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import jakarta.transaction.Transactional;
|
import jakarta.transaction.Transactional;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
@ApplicationScoped
|
@ApplicationScoped
|
||||||
public class AccountService
|
public class AccountService
|
||||||
{
|
{
|
||||||
|
@Inject
|
||||||
|
Logger LOG;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AccountRepo accountRepo;
|
AccountRepo accountRepo;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AccountMapper accountMapper;
|
AccountMapper accountMapper;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AuthenticationService authenticationService;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public Account create(AccountCreation account)
|
public Account create(AccountCreation account)
|
||||||
{
|
{
|
||||||
@ -23,8 +32,21 @@ public class AccountService
|
|||||||
accountEntity.setEmail(account.email())
|
accountEntity.setEmail(account.email())
|
||||||
.setFirstname(account.firstname())
|
.setFirstname(account.firstname())
|
||||||
.setLastname(account.lastname())
|
.setLastname(account.lastname())
|
||||||
.setPassword(BcryptUtil.bcryptHash(account.password()));
|
.setPassword(BcryptUtil.bcryptHash(account.password()))
|
||||||
|
.setStatus(AccountStatus.INIT);
|
||||||
accountRepo.persist(accountEntity);
|
accountRepo.persist(accountEntity);
|
||||||
return accountMapper.map(accountEntity);
|
return accountMapper.map(accountEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Account getUser(String id)
|
||||||
|
{
|
||||||
|
AccountEntity account = authenticationService.requireUser();
|
||||||
|
AccountEntity requestedAccount = accountRepo.findById(id);
|
||||||
|
if (requestedAccount != null && requestedAccount.getId().equals(account.getId()))
|
||||||
|
{
|
||||||
|
return accountMapper.map(authenticationService.requireUser());
|
||||||
|
}
|
||||||
|
LOG.errorf("Cannot access account");
|
||||||
|
throw new UnauthorizedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
src/main/java/de/tavolio/account/AccountStatus.java
Normal file
6
src/main/java/de/tavolio/account/AccountStatus.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package de.tavolio.account;
|
||||||
|
|
||||||
|
public enum AccountStatus
|
||||||
|
{
|
||||||
|
INIT, REGISTERED
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
package de.tavolio.account.dto;
|
package de.tavolio.account.dto;
|
||||||
|
|
||||||
public record Account(String id)
|
import de.tavolio.account.AccountStatus;
|
||||||
|
|
||||||
|
public record Account(String id, String firstname, String lastname, String email, AccountStatus status)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
package de.tavolio.member;
|
||||||
|
|
||||||
|
import de.tavolio.AuthenticationService;
|
||||||
|
import de.tavolio.account.AccountEntity;
|
||||||
|
import de.tavolio.member.dto.AccountMemberships;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
@Path("/memberships")
|
||||||
|
public class AccountMembershipResource
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
MembershipRepo membershipRepo;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AuthenticationService authenticationService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MembershipMapper membershipMapper;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
public AccountMemberships get()
|
||||||
|
{
|
||||||
|
AccountEntity account = authenticationService.requireUser();
|
||||||
|
return new AccountMemberships(
|
||||||
|
membershipMapper.map(membershipRepo.findByTenantTypeAndAccount(TenantType.ORGANISATION, account)),
|
||||||
|
membershipMapper.map(membershipRepo.findByTenantTypeAndAccount(TenantType.RESTAURANT, account))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
105
src/main/java/de/tavolio/member/MembershipEntity.java
Normal file
105
src/main/java/de/tavolio/member/MembershipEntity.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package de.tavolio.member;
|
||||||
|
|
||||||
|
import de.tavolio.account.AccountEntity;
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "membership")
|
||||||
|
public class MembershipEntity extends PanacheEntityBase
|
||||||
|
{
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column(name = "tenant_type")
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private TenantType tenantType;
|
||||||
|
|
||||||
|
@Column(name = "tenant_id")
|
||||||
|
private String tenantId;
|
||||||
|
|
||||||
|
@Column(name = "member_role")
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private MembershipRole role;
|
||||||
|
|
||||||
|
@Column(name = "member_since")
|
||||||
|
private ZonedDateTime memberSince;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "account_id")
|
||||||
|
private AccountEntity account;
|
||||||
|
|
||||||
|
public static MembershipEntity init()
|
||||||
|
{
|
||||||
|
return new MembershipEntity().setId(UUID.randomUUID().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MembershipEntity setId(String id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TenantType getTenantType()
|
||||||
|
{
|
||||||
|
return tenantType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MembershipEntity setTenantType(TenantType tenantType)
|
||||||
|
{
|
||||||
|
this.tenantType = tenantType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTenantId()
|
||||||
|
{
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MembershipEntity setTenantId(String tenantId)
|
||||||
|
{
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MembershipRole getRole()
|
||||||
|
{
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MembershipEntity setRole(MembershipRole role)
|
||||||
|
{
|
||||||
|
this.role = role;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZonedDateTime getMemberSince()
|
||||||
|
{
|
||||||
|
return memberSince;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MembershipEntity setMemberSince(ZonedDateTime memberSince)
|
||||||
|
{
|
||||||
|
this.memberSince = memberSince;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountEntity getAccount()
|
||||||
|
{
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MembershipEntity setAccount(AccountEntity account)
|
||||||
|
{
|
||||||
|
this.account = account;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/main/java/de/tavolio/member/MembershipMapper.java
Normal file
25
src/main/java/de/tavolio/member/MembershipMapper.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package de.tavolio.member;
|
||||||
|
|
||||||
|
import de.tavolio.account.AccountMapper;
|
||||||
|
import de.tavolio.member.dto.Membership;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class MembershipMapper
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
AccountMapper accountMapper;
|
||||||
|
|
||||||
|
public Membership map(MembershipEntity membership)
|
||||||
|
{
|
||||||
|
return new Membership(membership.getId(), membership.getTenantType(), membership.getTenantId(), membership.getRole(), accountMapper.map(membership.getAccount()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Membership> map(List<MembershipEntity> memberships)
|
||||||
|
{
|
||||||
|
return memberships.stream().map(this::map).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/main/java/de/tavolio/member/MembershipRepo.java
Normal file
22
src/main/java/de/tavolio/member/MembershipRepo.java
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package de.tavolio.member;
|
||||||
|
|
||||||
|
import de.tavolio.account.AccountEntity;
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
|
||||||
|
import io.quarkus.panache.common.Parameters;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class MembershipRepo implements PanacheRepositoryBase<MembershipEntity, String>
|
||||||
|
{
|
||||||
|
public List<MembershipEntity> findByTenantTypeAndAccount(TenantType tenantType, AccountEntity account)
|
||||||
|
{
|
||||||
|
return list("tenantType = :tenantType AND account = :account", Parameters.with("tenantType", tenantType).and("account", account));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MembershipEntity> findByTenantTypeAndTenantId(TenantType tenantType, String tenantId)
|
||||||
|
{
|
||||||
|
return list("tenantType = :tenantType AND tenantId = :tenantId", Parameters.with("tenantType", tenantType).and("tenantId", tenantId));
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/main/java/de/tavolio/member/MembershipRole.java
Normal file
6
src/main/java/de/tavolio/member/MembershipRole.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package de.tavolio.member;
|
||||||
|
|
||||||
|
public enum MembershipRole
|
||||||
|
{
|
||||||
|
OWNER, ADMIN, MEMBER
|
||||||
|
}
|
||||||
87
src/main/java/de/tavolio/member/MembershipService.java
Normal file
87
src/main/java/de/tavolio/member/MembershipService.java
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package de.tavolio.member;
|
||||||
|
|
||||||
|
import de.tavolio.AuthenticationService;
|
||||||
|
import de.tavolio.account.AccountEntity;
|
||||||
|
import de.tavolio.account.AccountRepo;
|
||||||
|
import de.tavolio.account.AccountStatus;
|
||||||
|
import de.tavolio.member.dto.Membership;
|
||||||
|
import de.tavolio.member.dto.MembershipCreation;
|
||||||
|
import io.quarkus.security.UnauthorizedException;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import jakarta.ws.rs.BadRequestException;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class MembershipService
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
Logger LOG;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AuthenticationService authenticationService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MembershipRepo membershipRepo;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MembershipMapper membershipMapper;
|
||||||
|
@Inject
|
||||||
|
AccountRepo accountRepo;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Membership create(TenantType tenantType, String tenantId, MembershipCreation membershipCreation)
|
||||||
|
{
|
||||||
|
switch (tenantType)
|
||||||
|
{
|
||||||
|
case ORGANISATION ->
|
||||||
|
{
|
||||||
|
if (membershipCreation.role().equals(MembershipRole.OWNER))
|
||||||
|
{
|
||||||
|
if (authenticationService.isSuperUser())
|
||||||
|
{
|
||||||
|
AccountEntity account = accountRepo.findById(membershipCreation.accountId());
|
||||||
|
|
||||||
|
MembershipEntity membership = MembershipEntity.init();
|
||||||
|
membership.setAccount(account);
|
||||||
|
membership.setRole(membershipCreation.role());
|
||||||
|
membership.setTenantType(TenantType.ORGANISATION);
|
||||||
|
membership.setTenantId(tenantId);
|
||||||
|
membership.setMemberSince(ZonedDateTime.now());
|
||||||
|
membershipRepo.persist(membership);
|
||||||
|
|
||||||
|
account.setStatus(AccountStatus.REGISTERED);
|
||||||
|
accountRepo.persist(account);
|
||||||
|
|
||||||
|
return membershipMapper.map(membership);
|
||||||
|
}
|
||||||
|
LOG.errorf("Membership with role 'Owner' cannot be created without superuser permissions");
|
||||||
|
throw new UnauthorizedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case RESTAURANT ->
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
default ->
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new BadRequestException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Membership> findByTenantType(TenantType tenantType)
|
||||||
|
{
|
||||||
|
return membershipMapper.map(membershipRepo.findByTenantTypeAndAccount(tenantType, authenticationService.requireUser()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Membership> findByTenantTypeAndTenantId(TenantType tenantType, String tenantId)
|
||||||
|
{
|
||||||
|
return membershipMapper.map(membershipRepo.findByTenantTypeAndTenantId(tenantType, tenantId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
package de.tavolio.member;
|
||||||
|
|
||||||
|
import de.tavolio.member.dto.Membership;
|
||||||
|
import de.tavolio.member.dto.MembershipCreation;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.*;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.jboss.resteasy.reactive.common.NotImplementedYet;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Path("/{tenant-type}")
|
||||||
|
public class TenantMembershipResource
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
Logger LOG;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MembershipService membershipService;
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("/{tenant-id}/memberships")
|
||||||
|
public Membership post(@PathParam("tenant-type") String tenantType, @PathParam("tenant-id") String tenantId, MembershipCreation membershipCreation)
|
||||||
|
{
|
||||||
|
switch (tenantType)
|
||||||
|
{
|
||||||
|
case "organisations" ->
|
||||||
|
{
|
||||||
|
Membership membership = membershipService.create(TenantType.ORGANISATION, tenantId, membershipCreation);
|
||||||
|
LOG.infof("Created membership for organisation %s", tenantId);
|
||||||
|
return membership;
|
||||||
|
}
|
||||||
|
case "restaurants" ->
|
||||||
|
{
|
||||||
|
Membership membership = membershipService.create(TenantType.RESTAURANT, tenantId, membershipCreation);
|
||||||
|
LOG.infof("Created membership for restaurant %s", tenantId);
|
||||||
|
return membership;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new BadRequestException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/{tenant-id}/memberships")
|
||||||
|
public List<Membership> get(@PathParam("tenant-type") String tenantType, @PathParam("tenant-id") String tenantId)
|
||||||
|
{
|
||||||
|
switch (tenantType)
|
||||||
|
{
|
||||||
|
case "organisations" ->
|
||||||
|
{
|
||||||
|
return membershipService.findByTenantTypeAndTenantId(TenantType.ORGANISATION, tenantId);
|
||||||
|
}
|
||||||
|
case "restaurants" ->
|
||||||
|
{
|
||||||
|
throw new NotImplementedYet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.errorf("Unknown tenant type %s", tenantType);
|
||||||
|
throw new BadRequestException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/memberships")
|
||||||
|
public List<Membership> get(@PathParam("tenant-type") String tenantType)
|
||||||
|
{
|
||||||
|
switch (tenantType)
|
||||||
|
{
|
||||||
|
case "organisations" ->
|
||||||
|
{
|
||||||
|
return membershipService.findByTenantType(TenantType.ORGANISATION);
|
||||||
|
}
|
||||||
|
case "restaurants" ->
|
||||||
|
{
|
||||||
|
return membershipService.findByTenantType(TenantType.RESTAURANT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.errorf("Unknown tenant type %s", tenantType);
|
||||||
|
throw new BadRequestException();
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/main/java/de/tavolio/member/TenantType.java
Normal file
6
src/main/java/de/tavolio/member/TenantType.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package de.tavolio.member;
|
||||||
|
|
||||||
|
public enum TenantType
|
||||||
|
{
|
||||||
|
ORGANISATION, RESTAURANT
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.tavolio.member.dto;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record AccountMemberships(List<Membership> organisations, List<Membership> restaurants)
|
||||||
|
{
|
||||||
|
}
|
||||||
9
src/main/java/de/tavolio/member/dto/Membership.java
Normal file
9
src/main/java/de/tavolio/member/dto/Membership.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package de.tavolio.member.dto;
|
||||||
|
|
||||||
|
import de.tavolio.account.dto.Account;
|
||||||
|
import de.tavolio.member.MembershipRole;
|
||||||
|
import de.tavolio.member.TenantType;
|
||||||
|
|
||||||
|
public record Membership(String id, TenantType tenantType, String tenantId, MembershipRole role, Account account)
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.tavolio.member.dto;
|
||||||
|
|
||||||
|
import de.tavolio.member.MembershipRole;
|
||||||
|
|
||||||
|
public record MembershipCreation(String accountId, MembershipRole role)
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -1,5 +0,0 @@
|
|||||||
package de.tavolio.organisation.member;
|
|
||||||
|
|
||||||
public class OrganisationMemberResource
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
package de.tavolio.organisation.member;
|
|
||||||
|
|
||||||
public class OrganisationMembershipRepo
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
package de.tavolio.restaurant.member;
|
|
||||||
|
|
||||||
public class OrganisationMemberResource
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
package de.tavolio.restaurant.member;
|
|
||||||
|
|
||||||
public class RestaurantMembershipRepo
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@ -1,15 +1,26 @@
|
|||||||
package de.tavolio.session;
|
package de.tavolio.session;
|
||||||
|
|
||||||
|
import de.tavolio.session.dto.SessionCreation;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import jakarta.ws.rs.POST;
|
import jakarta.ws.rs.POST;
|
||||||
import jakarta.ws.rs.Path;
|
import jakarta.ws.rs.Path;
|
||||||
import org.jboss.resteasy.reactive.common.NotImplementedYet;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
@Path("/sessions")
|
@Path("/sessions")
|
||||||
public class SessionResource
|
public class SessionResource
|
||||||
{
|
{
|
||||||
|
@Inject
|
||||||
|
Logger LOG;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
SessionService sessionService;
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
public String get()
|
public String get(@Valid SessionCreation sessionCreation)
|
||||||
{
|
{
|
||||||
throw new NotImplementedYet();
|
String token = sessionService.generateBySessionCreation(sessionCreation);
|
||||||
|
LOG.infof("Generated token for email %s", sessionCreation.email());
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/main/java/de/tavolio/session/SessionService.java
Normal file
39
src/main/java/de/tavolio/session/SessionService.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package de.tavolio.session;
|
||||||
|
|
||||||
|
import de.tavolio.account.AccountEntity;
|
||||||
|
import de.tavolio.account.AccountRepo;
|
||||||
|
import de.tavolio.session.dto.SessionCreation;
|
||||||
|
import io.quarkus.elytron.security.common.BcryptUtil;
|
||||||
|
import io.smallrye.jwt.build.Jwt;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.NotFoundException;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class SessionService
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
AccountRepo accountRepo;
|
||||||
|
|
||||||
|
public String generateBySessionCreation(SessionCreation sessionCreation)
|
||||||
|
{
|
||||||
|
Optional<AccountEntity> accountEntityOptional = accountRepo.findOptionalByEmail(sessionCreation.email());
|
||||||
|
if (accountEntityOptional.isPresent())
|
||||||
|
{
|
||||||
|
AccountEntity accountEntity = accountEntityOptional.get();
|
||||||
|
if (BcryptUtil.matches(sessionCreation.password(), accountEntity.getPassword()))
|
||||||
|
{
|
||||||
|
return generateToken(accountEntity.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateToken(String upn)
|
||||||
|
{
|
||||||
|
return Jwt.upn(upn).expiresAt(ZonedDateTime.now().plusYears(1).toInstant()).issuer("https://tavolio.de").sign();
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/main/java/de/tavolio/session/dto/SessionCreation.java
Normal file
10
src/main/java/de/tavolio/session/dto/SessionCreation.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package de.tavolio.session.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.Email;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
public record SessionCreation(
|
||||||
|
@Email String email,
|
||||||
|
@NotBlank String password)
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -5,6 +5,14 @@ quarkus.http.test-port=9089
|
|||||||
|
|
||||||
quarkus.hibernate-orm.schema-management.strategy=drop-and-create
|
quarkus.hibernate-orm.schema-management.strategy=drop-and-create
|
||||||
|
|
||||||
|
smallrye.jwt.sign.key.location=private.key
|
||||||
|
mp.jwt.verify.publickey.location=public.crt
|
||||||
|
mp.jwt.verify.issuer=https://tavolio.de
|
||||||
|
|
||||||
%dev.quarkus.datasource.username=postgres
|
%dev.quarkus.datasource.username=postgres
|
||||||
%dev.quarkus.datasource.password=${DB_PASSWORD}
|
%dev.quarkus.datasource.password=${DB_PASSWORD}
|
||||||
%dev.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/postgres?currentSchema=iam
|
%dev.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/postgres?currentSchema=iam
|
||||||
|
|
||||||
|
# IAM Superuser
|
||||||
|
%dev.iam.user.name=tavolio
|
||||||
|
%dev.iam.user.password=tavolio
|
||||||
@ -3,4 +3,10 @@
|
|||||||
-- insert into myentity (id, field) values(1, 'field-1');
|
-- insert into myentity (id, field) values(1, 'field-1');
|
||||||
-- insert into myentity (id, field) values(2, 'field-2');
|
-- insert into myentity (id, field) values(2, 'field-2');
|
||||||
-- insert into myentity (id, field) values(3, 'field-3');
|
-- insert into myentity (id, field) values(3, 'field-3');
|
||||||
-- alter sequence myentity_seq restart with 4;
|
-- alter sequence myentity_seq restart with 4;
|
||||||
|
|
||||||
|
INSERT INTO account (id, firstname, lastname, email, password, status)
|
||||||
|
VALUES ('66b261fe-4c5a-4728-9857-67717f02d4e1', 'Andreas', 'Dinauer', 'andreas.j.dinauer@gmail.com', '$2a$12$cdrzIY4sMFAXiz29uo9Ul.MPy0RN0FGS2yjVzb5BTe6bSijn4eGQy', 'REGISTERED');
|
||||||
|
|
||||||
|
INSERT INTO membership(id, tenant_type, tenant_id, member_role, member_since, account_id)
|
||||||
|
VALUES ('cd20d271-6e76-48c4-9cfb-a67f8892d46c', 'ORGANISATION', 'b3912be6-7503-4a13-b8ab-5d65af036742', 'OWNER', '2025-08-20 15:30:12.123456+02', '66b261fe-4c5a-4728-9857-67717f02d4e1');
|
||||||
@ -1,23 +1,34 @@
|
|||||||
package de.tavolio.account;
|
package de.tavolio.account;
|
||||||
|
|
||||||
import io.quarkus.deployment.dev.testing.TestConfig;
|
import de.tavolio.utils.Database;
|
||||||
|
import io.quarkus.elytron.security.common.BcryptUtil;
|
||||||
import io.quarkus.test.junit.QuarkusTest;
|
import io.quarkus.test.junit.QuarkusTest;
|
||||||
import io.restassured.RestAssured;
|
import io.quarkus.test.security.TestSecurity;
|
||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
|
import io.restassured.response.Response;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Order;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static io.restassured.RestAssured.given;
|
import static io.restassured.RestAssured.given;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static io.restassured.RestAssured.when;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
@QuarkusTest
|
@QuarkusTest
|
||||||
public class AccountResourceTest
|
public class AccountResourceTest
|
||||||
{
|
{
|
||||||
|
@Inject
|
||||||
|
Database database;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AccountRepo accountRepo;
|
AccountRepo accountRepo;
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void afterEach()
|
||||||
|
{
|
||||||
|
database.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testInsert()
|
void testInsert()
|
||||||
{
|
{
|
||||||
@ -40,4 +51,35 @@ public class AccountResourceTest
|
|||||||
|
|
||||||
assertEquals(1, accountRepo.count());
|
assertEquals(1, accountRepo.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestSecurity(user = "66609092-6c98-4466-af52-9a3e9d633108")
|
||||||
|
void testRetrieval()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
database.setup(() -> {
|
||||||
|
AccountEntity account = new AccountEntity()
|
||||||
|
.setId("66609092-6c98-4466-af52-9a3e9d633108")
|
||||||
|
.setFirstname("Andreas")
|
||||||
|
.setLastname("Dinauer")
|
||||||
|
.setEmail("andreas.j.dinauer@gmail.com")
|
||||||
|
.setPassword(BcryptUtil.bcryptHash("pw"));
|
||||||
|
accountRepo.persist(account);
|
||||||
|
});
|
||||||
|
|
||||||
|
// when
|
||||||
|
Response response = when()
|
||||||
|
.get("accounts")
|
||||||
|
.then()
|
||||||
|
.extract()
|
||||||
|
.response();
|
||||||
|
|
||||||
|
// then
|
||||||
|
String body = response.getBody().prettyPrint();
|
||||||
|
assertFalse(body.isEmpty());
|
||||||
|
assertTrue(body.contains("66609092-6c98-4466-af52-9a3e9d633108"));
|
||||||
|
assertTrue(body.contains("Andreas"));
|
||||||
|
assertTrue(body.contains("Dinauer"));
|
||||||
|
assertTrue(body.contains("andreas.j.dinauer@gmail.com"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
67
src/test/java/de/tavolio/session/SessionResourceTest.java
Normal file
67
src/test/java/de/tavolio/session/SessionResourceTest.java
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package de.tavolio.session;
|
||||||
|
|
||||||
|
import de.tavolio.account.AccountEntity;
|
||||||
|
import de.tavolio.account.AccountRepo;
|
||||||
|
import de.tavolio.utils.Database;
|
||||||
|
import io.quarkus.elytron.security.common.BcryptUtil;
|
||||||
|
import io.quarkus.test.junit.QuarkusTest;
|
||||||
|
import io.restassured.http.ContentType;
|
||||||
|
import io.restassured.response.Response;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static io.restassured.RestAssured.given;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@QuarkusTest
|
||||||
|
public class SessionResourceTest
|
||||||
|
{
|
||||||
|
@Inject
|
||||||
|
Database database;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AccountRepo accountRepo;
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void afterEach()
|
||||||
|
{
|
||||||
|
database.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGet()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
database.setup(() -> {
|
||||||
|
AccountEntity accountEntity = AccountEntity.init()
|
||||||
|
.setEmail("andreas.j.dinauer@gmail.com")
|
||||||
|
.setFirstname("Andreas")
|
||||||
|
.setLastname("Dinauer")
|
||||||
|
.setPassword(BcryptUtil.bcryptHash("pw"));
|
||||||
|
accountRepo.persist(accountEntity);
|
||||||
|
});
|
||||||
|
|
||||||
|
String loginRequest = """
|
||||||
|
{
|
||||||
|
"email": "andreas.j.dinauer@gmail.com",
|
||||||
|
"password": "pw"
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
// when
|
||||||
|
Response response = given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body(loginRequest)
|
||||||
|
.when()
|
||||||
|
.post("/sessions")
|
||||||
|
.then()
|
||||||
|
.extract()
|
||||||
|
.response();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(200, response.statusCode());
|
||||||
|
assertTrue(response.getBody().prettyPrint().startsWith("ey"));
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/test/java/de/tavolio/utils/Database.java
Normal file
67
src/test/java/de/tavolio/utils/Database.java
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package de.tavolio.utils;
|
||||||
|
|
||||||
|
import io.agroal.api.AgroalDataSource;
|
||||||
|
import io.quarkus.narayana.jta.QuarkusTransaction;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class Database {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AgroalDataSource dataSource;
|
||||||
|
|
||||||
|
public void setup(Runnable setup) {
|
||||||
|
QuarkusTransaction.begin();
|
||||||
|
setup.run();
|
||||||
|
QuarkusTransaction.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
forceForeignKeys(false);
|
||||||
|
getAllTables().forEach(this::truncateTable);
|
||||||
|
forceForeignKeys(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getAllTables() {
|
||||||
|
try(Connection connection = dataSource.getConnection()) {
|
||||||
|
ResultSet rs = connection.getMetaData().getTables(null, "public", "%", new String[] {"TABLE"});
|
||||||
|
connection.close();
|
||||||
|
List<String> tables = new LinkedList<>();
|
||||||
|
while(rs.next()) {
|
||||||
|
tables.add(rs.getString(3));
|
||||||
|
}
|
||||||
|
return tables;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forceForeignKeys(boolean force) {
|
||||||
|
if(force) {
|
||||||
|
execute("SET session_replication_role = replica");
|
||||||
|
} else {
|
||||||
|
execute("SET session_replication_role = DEFAULT");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void truncateTable(String table) {
|
||||||
|
execute("TRUNCATE TABLE public." + table + " RESTART IDENTITY CASCADE");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void execute(String sql) {
|
||||||
|
try(Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement()) {
|
||||||
|
statement.execute(sql);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
System.out.println(sql + ": Error executing SQL.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user