diff --git a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceRepository.java b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceRepository.java index 167b53010..de1ba72b3 100644 --- a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceRepository.java +++ b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceRepository.java @@ -10,23 +10,23 @@ interface AbsenceRepository extends CrudRepository { - Optional findByTenantIdAndSourceIdAndType_Category(String tenantId, Long sourceId, AbsenceTypeCategory absenceTypeCategory); + Optional findBySourceIdAndType_Category(Long sourceId, AbsenceTypeCategory absenceTypeCategory); /** - * Finds all absences of tenantId, userId of set and intersection with interval from and toExclusive-1 + * Finds all absences of userId of set and intersection with interval from and toExclusive-1 */ - List findAllByTenantIdAndUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual( - String tenantId, List userIds, Instant toExclusive, Instant from + List findAllByUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual( + List userIds, Instant toExclusive, Instant from ); /** - * Finds all absences of tenantId and intersection with interval from and toExclusive-1 + * Finds all absences of intersection with interval from and toExclusive-1 */ - List findAllByTenantIdAndStartDateLessThanAndEndDateGreaterThanEqual( - String tenantId, Instant toExclusive, Instant from + List findAllByStartDateLessThanAndEndDateGreaterThanEqual( + Instant toExclusive, Instant from ); @Modifying @Transactional - int deleteByTenantIdAndSourceIdAndType_Category(String tenantId, Long sourceId, AbsenceTypeCategory absenceTypeCategory); + int deleteBySourceIdAndType_Category(Long sourceId, AbsenceTypeCategory absenceTypeCategory); } diff --git a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceServiceImpl.java b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceServiceImpl.java index 8dc25898c..a07826952 100644 --- a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceServiceImpl.java +++ b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceServiceImpl.java @@ -1,8 +1,6 @@ package de.focusshift.zeiterfassung.absence; import de.focusshift.zeiterfassung.CachedFunction; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import de.focusshift.zeiterfassung.user.UserId; import de.focusshift.zeiterfassung.user.UserIdComposite; import de.focusshift.zeiterfassung.user.UserSettingsProvider; @@ -46,21 +44,18 @@ class AbsenceServiceImpl implements AbsenceService { private final AbsenceRepository absenceRepository; private final AbsenceTypeService absenceTypeService; private final UserSettingsProvider userSettingsProvider; - private final TenantContextHolder tenantContextHolder; private final UserManagementService userManagementService; private final MessageSource messageSource; AbsenceServiceImpl(AbsenceRepository absenceRepository, AbsenceTypeService absenceTypeService, UserSettingsProvider userSettingsProvider, - TenantContextHolder tenantContextHolder, UserManagementService userManagementService, MessageSource messageSource) { this.absenceRepository = absenceRepository; this.absenceTypeService = absenceTypeService; this.userSettingsProvider = userSettingsProvider; - this.tenantContextHolder = tenantContextHolder; this.userManagementService = userManagementService; this.messageSource = messageSource; } @@ -69,10 +64,9 @@ class AbsenceServiceImpl implements AbsenceService { public Map> findAllAbsences(UserId userId, Instant from, Instant toExclusive) { final ZoneId zoneId = userSettingsProvider.zoneId(); - final String tenantId = tenantContextHolder.getCurrentTenantId().orElse(new TenantId("")).tenantId(); final List absenceEntities = - absenceRepository.findAllByTenantIdAndUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(tenantId, List.of(userId.value()), toExclusive, from); + absenceRepository.findAllByUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(List.of(userId.value()), toExclusive, from); final List absences = toAbsences(absenceEntities).toList(); @@ -96,7 +90,6 @@ public Map> findAllAbsences(UserId userId, Instant from public Map> getAbsencesByUserIds(List userLocalIds, LocalDate from, LocalDate toExclusive) { final InstantPeriod period = getInstantPeriod(from, toExclusive); - final String tenantId = tenantContextHolder.getCurrentTenantId().orElse(new TenantId("")).tenantId(); final List users = userManagementService.findAllUsersByLocalIds(userLocalIds); @@ -109,7 +102,7 @@ public Map> getAbsencesByUserIds(List idCompositeByUserId = users.stream().collect(toMap(User::userId, User::userIdComposite)); final List absenceEntities = - absenceRepository.findAllByTenantIdAndUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(tenantId, userIdValues, period.toExclusive, period.from); + absenceRepository.findAllByUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(userIdValues, period.toExclusive, period.from); final Map> result = toAbsences(absenceEntities) .collect(groupingBy(absence -> idCompositeByUserId.get(absence.userId()))); @@ -124,10 +117,9 @@ public Map> getAbsencesByUserIds(List> getAbsencesForAllUsers(LocalDate from, LocalDate toExclusive) { final InstantPeriod period = getInstantPeriod(from, toExclusive); - final String tenantId = tenantContextHolder.getCurrentTenantId().orElse(new TenantId("")).tenantId(); final List absenceEntities = - absenceRepository.findAllByTenantIdAndStartDateLessThanAndEndDateGreaterThanEqual(tenantId, period.toExclusive, period.from); + absenceRepository.findAllByStartDateLessThanAndEndDateGreaterThanEqual(period.toExclusive, period.from); final Map> absenceByUserId = toAbsences(absenceEntities) .collect(groupingBy(Absence::userId)); @@ -149,10 +141,8 @@ public Map> getAbsencesForAllUsers(LocalDate from public List getAbsencesByUserId(UserId userId, LocalDate from, LocalDate toExclusive) { final InstantPeriod period = getInstantPeriod(from, toExclusive); - final String tenantId = tenantContextHolder.getCurrentTenantId().orElse(new TenantId("")).tenantId(); - final List absenceEntities = - absenceRepository.findAllByTenantIdAndUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(tenantId, List.of(userId.value()), period.toExclusive, period.from); + final List absenceEntities = absenceRepository.findAllByUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(List.of(userId.value()), period.toExclusive, period.from); return toAbsences(absenceEntities).toList(); } diff --git a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeEntity.java b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeEntity.java index b5432563d..f50381608 100644 --- a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeEntity.java +++ b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeEntity.java @@ -1,6 +1,6 @@ package de.focusshift.zeiterfassung.absence; -import de.focusshift.zeiterfassung.tenancy.configuration.multi.AdminAware; +import de.focusshift.zeiterfassung.tenancy.tenant.AbstractTenantAwareEntity; import jakarta.persistence.Column; import jakarta.persistence.Convert; import jakarta.persistence.Entity; @@ -9,7 +9,6 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.SequenceGenerator; -import jakarta.validation.constraints.Size; import java.util.Locale; import java.util.Map; @@ -18,11 +17,7 @@ import static jakarta.persistence.EnumType.STRING; @Entity(name = "absence_type") -public class AbsenceTypeEntity implements AdminAware { - - @Size(max = 255) - @Column(name = "tenant_id") - private String tenantId; +public class AbsenceTypeEntity extends AbstractTenantAwareEntity { @Id @Column(name = "id", unique = true, nullable = false, updatable = false) @@ -45,15 +40,10 @@ public class AbsenceTypeEntity implements AdminAware { @Convert(converter = LabelByLocaleConverter.class) private Map labelByLocale; - public String getTenantId() { - return tenantId; - } - - public void setTenantId(String tenantId) { - this.tenantId = tenantId; + public AbsenceTypeEntity() { + super(null); } - @Override public Long getId() { return id; } @@ -110,7 +100,6 @@ public int hashCode() { @Override public String toString() { return "AbsenceTypeEntity{" + - "tenantId='" + tenantId + '\'' + ", id=" + id + ", category=" + category + ", sourceId=" + sourceId + diff --git a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeEntityEmbeddable.java b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeEntityEmbeddable.java index daa67cb98..b962ad5f3 100644 --- a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeEntityEmbeddable.java +++ b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeEntityEmbeddable.java @@ -4,12 +4,17 @@ import jakarta.persistence.Embeddable; import jakarta.persistence.Enumerated; +import java.io.Serial; +import java.io.Serializable; import java.util.Objects; import static jakarta.persistence.EnumType.STRING; @Embeddable -public class AbsenceTypeEntityEmbeddable { +public class AbsenceTypeEntityEmbeddable implements Serializable { + + @Serial + private static final long serialVersionUID = -393457998708034020L; @Column(name = "type_category", nullable = false) @Enumerated(STRING) diff --git a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeRepository.java b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeRepository.java index 3a7da8a0b..079981775 100644 --- a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeRepository.java +++ b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeRepository.java @@ -8,7 +8,7 @@ interface AbsenceTypeRepository extends CrudRepository { - Optional findByTenantIdAndSourceId(String tenantId, Long sourceId); + Optional findBySourceId(Long sourceId); - List findByTenantIdAndSourceIdIsIn(String tenantId, Collection sourceIds); + List findBySourceIdIsIn(Collection sourceIds); } diff --git a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeServiceImpl.java b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeServiceImpl.java index 7d057c842..f9e3876c7 100644 --- a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeServiceImpl.java +++ b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeServiceImpl.java @@ -1,6 +1,5 @@ package de.focusshift.zeiterfassung.absence; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import org.springframework.stereotype.Service; import java.util.Collection; @@ -11,23 +10,19 @@ class AbsenceTypeServiceImpl implements AbsenceTypeService { private final AbsenceTypeRepository repository; - private final TenantContextHolder tenantContextHolder; - AbsenceTypeServiceImpl(AbsenceTypeRepository repository, TenantContextHolder tenantContextHolder) { + AbsenceTypeServiceImpl(AbsenceTypeRepository repository) { this.repository = repository; - this.tenantContextHolder = tenantContextHolder; } @Override public void updateAbsenceType(AbsenceTypeUpdate absenceTypeUpdate) { - final String tenantId = absenceTypeUpdate.tenantId().tenantId(); final Long sourceId = absenceTypeUpdate.sourceId(); - final AbsenceTypeEntity entity = repository.findByTenantIdAndSourceId(tenantId, sourceId) + final AbsenceTypeEntity entity = repository.findBySourceId(sourceId) .orElseGet(AbsenceTypeEntity::new); - entity.setTenantId(tenantId); entity.setSourceId(sourceId); entity.setCategory(absenceTypeUpdate.category()); entity.setColor(absenceTypeUpdate.color()); @@ -38,17 +33,11 @@ public void updateAbsenceType(AbsenceTypeUpdate absenceTypeUpdate) { @Override public List findAllByAbsenceTypeSourceIds(Collection absenceTypeSourceIds) { - return repository.findByTenantIdAndSourceIdIsIn(tenantId(), absenceTypeSourceIds).stream() + return repository.findBySourceIdIsIn(absenceTypeSourceIds).stream() .map(AbsenceTypeServiceImpl::toAbsenceType) .toList(); } - private String tenantId() { - return tenantContextHolder.getCurrentTenantId() - .orElseThrow(() -> new IllegalStateException("expected tenantId to exist.")) - .tenantId(); - } - private static AbsenceType toAbsenceType(AbsenceTypeEntity entity) { return new AbsenceType( entity.getCategory(), diff --git a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeUpdate.java b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeUpdate.java index 50824bb60..59ae05522 100644 --- a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeUpdate.java +++ b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceTypeUpdate.java @@ -1,21 +1,17 @@ package de.focusshift.zeiterfassung.absence; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; - import java.util.Locale; import java.util.Map; /** * Update {@linkplain AbsenceType} to the given values. * - * @param tenantId {@linkplain TenantId} this {@linkplain AbsenceType} is linked to * @param sourceId external system source identifier of the absence type * @param category next {@linkplain AbsenceTypeCategory} * @param color next {@linkplain AbsenceColor} * @param labelByLocale next labels */ public record AbsenceTypeUpdate( - TenantId tenantId, Long sourceId, AbsenceTypeCategory category, AbsenceColor color, diff --git a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceWrite.java b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceWrite.java index c39ed1995..eb785e494 100644 --- a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceWrite.java +++ b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceWrite.java @@ -1,6 +1,5 @@ package de.focusshift.zeiterfassung.absence; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import de.focusshift.zeiterfassung.user.UserId; import jakarta.annotation.Nullable; @@ -9,7 +8,6 @@ /** * Describes the write model of an absence like holiday or sick. * - * @param tenantId * @param sourceId * @param userId * @param startDate @@ -19,7 +17,6 @@ * @param absenceTypeSourceId absence type source id or {@code null} for {@linkplain AbsenceTypeCategory#SICK} */ public record AbsenceWrite( - TenantId tenantId, Long sourceId, UserId userId, Instant startDate, @@ -32,7 +29,6 @@ public record AbsenceWrite( /** * constructor for absences without a absenceType sourceId (e.g. {@linkplain AbsenceTypeCategory#SICK}). * - * @param tenantId * @param sourceId * @param userId * @param startDate @@ -40,7 +36,7 @@ public record AbsenceWrite( * @param dayLength * @param absenceTypeCategory */ - public AbsenceWrite(TenantId tenantId, Long sourceId, UserId userId, Instant startDate, Instant endDate, DayLength dayLength, AbsenceTypeCategory absenceTypeCategory) { - this(tenantId, sourceId, userId, startDate, endDate, dayLength, absenceTypeCategory, null); + public AbsenceWrite(Long sourceId, UserId userId, Instant startDate, Instant endDate, DayLength dayLength, AbsenceTypeCategory absenceTypeCategory) { + this(sourceId, userId, startDate, endDate, dayLength, absenceTypeCategory, null); } } diff --git a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceWriteEntity.java b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceWriteEntity.java index bcff146ea..dcaa0e578 100644 --- a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceWriteEntity.java +++ b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceWriteEntity.java @@ -1,6 +1,6 @@ package de.focusshift.zeiterfassung.absence; -import de.focusshift.zeiterfassung.tenancy.configuration.multi.AdminAware; +import de.focusshift.zeiterfassung.tenancy.tenant.AbstractTenantAwareEntity; import jakarta.persistence.Column; import jakarta.persistence.Embedded; import jakarta.persistence.Entity; @@ -10,7 +10,6 @@ import jakarta.persistence.Id; import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; -import jakarta.validation.constraints.Size; import java.time.Instant; import java.util.Objects; @@ -19,11 +18,7 @@ @Entity @Table(name = "absence") -public class AbsenceWriteEntity implements AdminAware { - - @Size(max = 255) - @Column(name = "tenant_id") - private String tenantId; +public class AbsenceWriteEntity extends AbstractTenantAwareEntity { @Id @Column(name = "id", unique = true, nullable = false, updatable = false) @@ -50,12 +45,8 @@ public class AbsenceWriteEntity implements AdminAware { @Embedded private AbsenceTypeEntityEmbeddable type; - public String getTenantId() { - return tenantId; - } - - public void setTenantId(String tenantId) { - this.tenantId = tenantId; + public AbsenceWriteEntity() { + super(null); } public Long getId() { @@ -130,7 +121,6 @@ public int hashCode() { @Override public String toString() { return "AbsenceEntity{" + - "tenantId=" + tenantId + ", id=" + id + '}'; } diff --git a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceWriteServiceImpl.java b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceWriteServiceImpl.java index 9ac308897..1eb640e22 100644 --- a/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceWriteServiceImpl.java +++ b/src/main/java/de/focusshift/zeiterfassung/absence/AbsenceWriteServiceImpl.java @@ -26,7 +26,6 @@ public void addAbsence(AbsenceWrite absence) { final Optional existing = findEntity(absence); - final String tenantId = absence.tenantId().tenantId(); final Long sourceId = absence.sourceId(); final AbsenceTypeSourceId typeId = absence.absenceTypeSourceId(); @@ -34,9 +33,9 @@ public void addAbsence(AbsenceWrite absence) { final AbsenceWriteEntity entity = new AbsenceWriteEntity(); setEntityFields(entity, absence); repository.save(entity); - LOG.info("successfully persisted absence in database. tenantId={} sourceId={} type={}", tenantId, sourceId, typeId); + LOG.info("successfully persisted absence in database. sourceId={} type={}", sourceId, typeId); } else { - LOG.info("did not persist absence because it exists already. tenantId={} sourceId={} type={}", tenantId, sourceId, typeId); + LOG.info("did not persist absence because it exists already. sourceId={} type={}", sourceId, typeId); } } @@ -46,7 +45,6 @@ public void updateAbsence(AbsenceWrite absence) { final Optional existing = findEntity(absence); - final String tenantId = absence.tenantId().tenantId(); final Long sourceId = absence.sourceId(); final AbsenceTypeSourceId typeId = absence.absenceTypeSourceId(); @@ -54,9 +52,9 @@ public void updateAbsence(AbsenceWrite absence) { final AbsenceWriteEntity entity = existing.get(); setEntityFields(entity, absence); repository.save(entity); - LOG.info("successfully updated absence in database. tenantId={} sourceId={} type={}", tenantId, sourceId, typeId); + LOG.info("successfully updated absence in database. sourceId={} type={}", sourceId, typeId); } else { - LOG.info("no absence found that could be updated. tenantId={} sourceId={} type={}", tenantId, sourceId, typeId); + LOG.info("no absence found that could be updated, sourceId={} type={}", sourceId, typeId); } } @@ -64,26 +62,24 @@ public void updateAbsence(AbsenceWrite absence) { @Transactional public void deleteAbsence(AbsenceWrite absence) { - final String tenantId = absence.tenantId().tenantId(); final Long sourceId = absence.sourceId(); final AbsenceTypeSourceId typeSourceId = absence.absenceTypeSourceId(); final AbsenceTypeCategory category = absence.absenceTypeCategory(); - final int countOfDeletedAbsences = repository.deleteByTenantIdAndSourceIdAndType_Category(tenantId, sourceId, category); + final int countOfDeletedAbsences = repository.deleteBySourceIdAndType_Category(sourceId, category); if (countOfDeletedAbsences >= 1) { - LOG.info("successfully deleted {} absences. tenantId={} sourceId={} typeSourceId={} typeCategory={}", countOfDeletedAbsences, tenantId, sourceId, typeSourceId, category); + LOG.info("successfully deleted {} absences. sourceId={} typeSourceId={} typeCategory={}", countOfDeletedAbsences, sourceId, typeSourceId, category); } else { - LOG.info("did not delete absence. tenantId={} sourceId={} typeSourceId={} typeCategory={}", tenantId, sourceId, typeSourceId, category); + LOG.info("did not delete absence. sourceId={} typeSourceId={} typeCategory={}", sourceId, typeSourceId, category); } } private Optional findEntity(AbsenceWrite absence) { - return repository.findByTenantIdAndSourceIdAndType_Category(absence.tenantId().tenantId(), absence.sourceId(), absence.absenceTypeCategory()); + return repository.findBySourceIdAndType_Category(absence.sourceId(), absence.absenceTypeCategory()); } private static void setEntityFields(AbsenceWriteEntity entity, AbsenceWrite absence) { - entity.setTenantId(absence.tenantId().tenantId()); entity.setSourceId(absence.sourceId()); entity.setUserId(absence.userId().value()); entity.setStartDate(absence.startDate()); diff --git a/src/main/java/de/focusshift/zeiterfassung/importer/TenantImporterComponent.java b/src/main/java/de/focusshift/zeiterfassung/importer/TenantImporterComponent.java index 59b9c75e5..5b8d8745b 100644 --- a/src/main/java/de/focusshift/zeiterfassung/importer/TenantImporterComponent.java +++ b/src/main/java/de/focusshift/zeiterfassung/importer/TenantImporterComponent.java @@ -93,22 +93,20 @@ public void runImport() { LOG.info("Found existing tenantId={} - going to import users", tenantId.tenantId()); - try { - this.tenantContextHolder.setTenantId(tenantId); - - if (!tenantUserService.findAllUsers().isEmpty()) { - LOG.info("tenantId={} already has users, skipping import", tenantId.tenantId()); - return; + tenantContextHolder.runInTenantIdContext(tenantId, passedTenantId -> { + try { + if (!tenantUserService.findAllUsers().isEmpty()) { + LOG.info("tenantId={} already has users, skipping import", passedTenantId); + return; + } + LOG.info("tenantId={} has no users, starting import {} users!", passedTenantId, importerData.users().size()); + importerData.users().forEach(userToImport -> importUser(userToImport, new TenantId(passedTenantId))); + LOG.info("finished importing {} users of tenantId={}", importerData.users().size(), passedTenantId); + } catch (Exception e) { + LOG.error("Error occurred while importing users", e); } + }); - LOG.info("tenantId={} has no users, starting import {} users!", tenantId.tenantId(), importerData.users().size()); - importerData.users().forEach(userToImport -> importUser(userToImport, tenantId)); - LOG.info("finished importing {} users of tenantId={}", importerData.users().size(), tenantId.tenantId()); - } catch (Exception e) { - LOG.error("Error occurred while importing users", e); - } finally { - this.tenantContextHolder.clear(); - } LOG.info("Finished import for tenant={}", tenantId.tenantId()); diff --git a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationEventDtoAdapter.java b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationEventDtoAdapter.java index f8e2e1a44..e2861efed 100644 --- a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationEventDtoAdapter.java +++ b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationEventDtoAdapter.java @@ -15,7 +15,6 @@ */ class ApplicationEventDtoAdapter { - private final String tenantId; private final Long sourceId; private final ApplicationPersonDTO person; private final VacationTypeDTO vacationType; @@ -23,7 +22,6 @@ class ApplicationEventDtoAdapter { private final Set absentWorkingDays; ApplicationEventDtoAdapter(ApplicationAllowedEventDTO event) { - this.tenantId = event.getTenantId(); this.sourceId = event.getSourceId(); this.person = event.getPerson(); this.vacationType = event.getVacationType(); @@ -32,7 +30,6 @@ class ApplicationEventDtoAdapter { } ApplicationEventDtoAdapter(ApplicationCancelledEventDTO event) { - this.tenantId = event.getTenantId(); this.sourceId = event.getSourceId(); this.person = event.getPerson(); this.vacationType = event.getVacationType(); @@ -41,7 +38,6 @@ class ApplicationEventDtoAdapter { } ApplicationEventDtoAdapter(ApplicationCreatedFromSickNoteEventDTO event) { - this.tenantId = event.getTenantId(); this.sourceId = event.getSourceId(); this.person = event.getPerson(); this.vacationType = event.getVacationType(); @@ -49,10 +45,6 @@ class ApplicationEventDtoAdapter { this.absentWorkingDays = event.getAbsentWorkingDays(); } - public String getTenantId() { - return tenantId; - } - public Long getSourceId() { return sourceId; } diff --git a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationEventHandlerRabbitmq.java b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationEventHandlerRabbitmq.java index d07bca706..46b9ab47e 100644 --- a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationEventHandlerRabbitmq.java +++ b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationEventHandlerRabbitmq.java @@ -10,7 +10,7 @@ import de.focusshift.zeiterfassung.absence.AbsenceWriteService; import de.focusshift.zeiterfassung.absence.DayLength; import de.focusshift.zeiterfassung.integration.urlaubsverwaltung.RabbitMessageConsumer; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import de.focusshift.zeiterfassung.user.UserId; import org.slf4j.Logger; import org.springframework.amqp.rabbit.annotation.RabbitListener; @@ -30,39 +30,11 @@ public class ApplicationEventHandlerRabbitmq extends RabbitMessageConsumer { private static final Logger LOG = getLogger(lookup().lookupClass()); private final AbsenceWriteService absenceWriteService; + private final TenantContextHolder tenantContextHolder; - ApplicationEventHandlerRabbitmq(AbsenceWriteService absenceWriteService) { + ApplicationEventHandlerRabbitmq(AbsenceWriteService absenceWriteService, TenantContextHolder tenantContextHolder) { this.absenceWriteService = absenceWriteService; - } - - @RabbitListener(queues = {ZEITERFASSUNG_URLAUBSVERWALTUNG_APPLICATION_ALLOWED_QUEUE}) - void on(ApplicationAllowedEventDTO event) { - - LOG.info("Received ApplicationAllowedEvent id={} for person={} and tenantId={}", - event.getId(), event.getPerson(), event.getTenantId()); - - toAbsence(new ApplicationEventDtoAdapter(event)) - .ifPresentOrElse( - absenceWriteService::addAbsence, - () -> LOG.info("could not map ApplicationAllowedEvent with id={} to Absence for person={} and tenantId={} -> skip adding Absence", event.getId(), event.getPerson(), event.getTenantId())); - } - - @RabbitListener(queues = {ZEITERFASSUNG_URLAUBSVERWALTUNG_APPLICATION_CREATED_FROM_SICKNOTE_QUEUE}) - void on(ApplicationCreatedFromSickNoteEventDTO event) { - LOG.info("Received ApplicationCreatedFromSicknoteEvent for person={} and tenantId={}", event.getPerson(), event.getTenantId()); - toAbsence(new ApplicationEventDtoAdapter(event)) - .ifPresentOrElse( - absenceWriteService::addAbsence, - () -> LOG.info("could not map ApplicationCreatedFromSicknoteEvent with id={} to Absence for person={} and tenantId={} -> skip adding Absence", event.getId(), event.getPerson(), event.getTenantId())); - } - - @RabbitListener(queues = {ZEITERFASSUNG_URLAUBSVERWALTUNG_APPLICATION_CANCELLED_QUEUE}) - void on(ApplicationCancelledEventDTO event) { - LOG.info("Received ApplicationCancelledEvent for person={} and tenantId={}", event.getPerson(), event.getTenantId()); - toAbsence(new ApplicationEventDtoAdapter(event)) - .ifPresentOrElse( - absenceWriteService::deleteAbsence, - () -> LOG.info("could not map ApplicationCancelledEvent with id={} to Absence for person={} and tenantId={} -> skip adding Absence", event.getId(), event.getPerson(), event.getTenantId())); + this.tenantContextHolder = tenantContextHolder; } private static Optional toAbsence(ApplicationEventDtoAdapter event) { @@ -77,7 +49,6 @@ private static Optional toAbsence(ApplicationEventDtoAdapter event } return Optional.of(new AbsenceWrite( - new TenantId(event.getTenantId()), event.getSourceId(), new UserId(event.getPerson().getUsername()), event.getPeriod().getStartDate(), @@ -95,4 +66,38 @@ private static Optional toDayLength(de.focus_shift.urlaubsverwaltung. private static Optional toAbsenceType(VacationTypeDTO vacationType) { return mapToEnum(vacationType.getCategory(), AbsenceTypeCategory.class); } + + @RabbitListener(queues = {ZEITERFASSUNG_URLAUBSVERWALTUNG_APPLICATION_ALLOWED_QUEUE}) + void on(ApplicationAllowedEventDTO event) { + tenantContextHolder.runInTenantIdContext(event.getTenantId(), tenantId -> { + LOG.info("Received ApplicationAllowedEvent id={} for person={} and tenantId={}", + event.getId(), event.getPerson(), tenantId); + toAbsence(new ApplicationEventDtoAdapter(event)) + .ifPresentOrElse( + absenceWriteService::addAbsence, + () -> LOG.info("could not map ApplicationAllowedEvent with id={} to Absence for person={} and tenantId={} -> skip adding Absence", event.getId(), event.getPerson(), tenantId)); + }); + } + + @RabbitListener(queues = {ZEITERFASSUNG_URLAUBSVERWALTUNG_APPLICATION_CREATED_FROM_SICKNOTE_QUEUE}) + void on(ApplicationCreatedFromSickNoteEventDTO event) { + tenantContextHolder.runInTenantIdContext(event.getTenantId(), tenantId -> { + LOG.info("Received ApplicationCreatedFromSicknoteEvent for person={} and tenantId={}", event.getPerson(), tenantId); + toAbsence(new ApplicationEventDtoAdapter(event)) + .ifPresentOrElse( + absenceWriteService::addAbsence, + () -> LOG.info("could not map ApplicationCreatedFromSicknoteEvent with id={} to Absence for person={} and tenantId={} -> skip adding Absence", event.getId(), event.getPerson(), tenantId)); + }); + } + + @RabbitListener(queues = {ZEITERFASSUNG_URLAUBSVERWALTUNG_APPLICATION_CANCELLED_QUEUE}) + void on(ApplicationCancelledEventDTO event) { + tenantContextHolder.runInTenantIdContext(event.getTenantId(), tenantId -> { + LOG.info("Received ApplicationCancelledEvent for person={} and tenantId={}", event.getPerson(), tenantId); + toAbsence(new ApplicationEventDtoAdapter(event)) + .ifPresentOrElse( + absenceWriteService::deleteAbsence, + () -> LOG.info("could not map ApplicationCancelledEvent with id={} to Absence for person={} and tenantId={} -> skip adding Absence", event.getId(), event.getPerson(), tenantId)); + }); + } } diff --git a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationRabbitmqConfiguration.java b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationRabbitmqConfiguration.java index 03331cfda..c7ff62632 100644 --- a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationRabbitmqConfiguration.java +++ b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationRabbitmqConfiguration.java @@ -1,6 +1,7 @@ package de.focusshift.zeiterfassung.integration.urlaubsverwaltung.application; import de.focusshift.zeiterfassung.absence.AbsenceWriteService; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.Queue; @@ -19,8 +20,8 @@ class ApplicationRabbitmqConfiguration { static final String ZEITERFASSUNG_URLAUBSVERWALTUNG_APPLICATION_CANCELLED_QUEUE = "zeiterfassung.queue.urlaubsverwaltung.application.cancelled"; static final String ZEITERFASSUNG_URLAUBSVERWALTUNG_APPLICATION_CREATED_FROM_SICKNOTE_QUEUE = "zeiterfassung.queue.urlaubsverwaltung.application.created_from_sicknote"; @Bean - ApplicationEventHandlerRabbitmq applicationEventHandlerRabbitmq(AbsenceWriteService absenceWriteService) { - return new ApplicationEventHandlerRabbitmq(absenceWriteService); + ApplicationEventHandlerRabbitmq applicationEventHandlerRabbitmq(AbsenceWriteService absenceWriteService, TenantContextHolder tenantContextHolder) { + return new ApplicationEventHandlerRabbitmq(absenceWriteService, tenantContextHolder); } @Configuration diff --git a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteEventDtoAdapter.java b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteEventDtoAdapter.java index cd3865778..11575b7df 100644 --- a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteEventDtoAdapter.java +++ b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteEventDtoAdapter.java @@ -12,14 +12,12 @@ */ class SickNoteEventDtoAdapter { - private final String tenantId; private final Long sourceId; private final SickNotePersonDTO person; private final String type; private final SickNotePeriodDTO period; SickNoteEventDtoAdapter(SickNoteCreatedEventDTO event) { - this.tenantId = event.getTenantId(); this.sourceId = event.getSourceId(); this.person = event.getPerson(); this.type = event.getType(); @@ -27,7 +25,6 @@ class SickNoteEventDtoAdapter { } SickNoteEventDtoAdapter(SickNoteUpdatedEventDTO event) { - this.tenantId = event.getTenantId(); this.sourceId = event.getSourceId(); this.person = event.getPerson(); this.type = event.getType(); @@ -35,7 +32,6 @@ class SickNoteEventDtoAdapter { } SickNoteEventDtoAdapter(SickNoteConvertedToApplicationEventDTO event) { - this.tenantId = event.getTenantId(); this.sourceId = event.getSourceId(); this.person = event.getPerson(); this.type = event.getType(); @@ -43,17 +39,12 @@ class SickNoteEventDtoAdapter { } SickNoteEventDtoAdapter(SickNoteCancelledEventDTO event) { - this.tenantId = event.getTenantId(); this.sourceId = event.getSourceId(); this.person = event.getPerson(); this.type = event.getType(); this.period = event.getPeriod(); } - public String getTenantId() { - return tenantId; - } - public Long getSourceId() { return sourceId; } diff --git a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteEventHandlerRabbitmq.java b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteEventHandlerRabbitmq.java index d5ee0740f..b7373f724 100644 --- a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteEventHandlerRabbitmq.java +++ b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteEventHandlerRabbitmq.java @@ -9,6 +9,7 @@ import de.focusshift.zeiterfassung.absence.AbsenceWriteService; import de.focusshift.zeiterfassung.absence.DayLength; import de.focusshift.zeiterfassung.integration.urlaubsverwaltung.RabbitMessageConsumer; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import de.focusshift.zeiterfassung.user.UserId; import org.slf4j.Logger; @@ -27,55 +28,65 @@ public class SickNoteEventHandlerRabbitmq extends RabbitMessageConsumer { private static final Logger LOG = getLogger(lookup().lookupClass()); private final AbsenceWriteService absenceWriteService; + private final TenantContextHolder tenantContextHolder; - SickNoteEventHandlerRabbitmq(AbsenceWriteService absenceWriteService) { + SickNoteEventHandlerRabbitmq(AbsenceWriteService absenceWriteService, TenantContextHolder tenantContextHolder) { this.absenceWriteService = absenceWriteService; + this.tenantContextHolder = tenantContextHolder; } @RabbitListener(queues = {ZEITERFASSUNG_URLAUBSVERWALTUNG_SICKNOTE_CANCELLED_QUEUE}) void on(SickNoteCancelledEventDTO event) { - LOG.info("Received SickNoteCancelledEvent for person={} and tenantId={}", event.getPerson(), event.getTenantId()); - toAbsence(new SickNoteEventDtoAdapter(event)) - .ifPresentOrElse( - absenceWriteService::deleteAbsence, - () -> LOG.info("could not map SickNoteCancelledEvent to Absence -> could not delete Absence") - ); + tenantContextHolder.runInTenantIdContext(new TenantId(event.getTenantId()), tenantId -> { + LOG.info("Received SickNoteCancelledEvent for person={} and tenantId={}", event.getPerson(), tenantId); + toAbsence(new SickNoteEventDtoAdapter(event)) + .ifPresentOrElse( + absenceWriteService::deleteAbsence, + () -> LOG.info("could not map SickNoteCancelledEvent to Absence -> could not delete Absence") + ); + }); } @RabbitListener(queues = {ZEITERFASSUNG_URLAUBSVERWALTUNG_SICKNOTE_CREATED_QUEUE}) void on(SickNoteCreatedEventDTO event) { - LOG.info("Received SickNoteCreatedEvent for person={} and tenantId={}", event.getPerson(), event.getTenantId()); - toAbsence(new SickNoteEventDtoAdapter(event)) - .ifPresentOrElse( - absenceWriteService::addAbsence, - () -> LOG.info("could not map SickNoteCreatedEventDTO to Absence -> could not add Absence") - ); + tenantContextHolder.runInTenantIdContext(new TenantId(event.getTenantId()), tenantId -> { + LOG.info("Received SickNoteCreatedEvent for person={} and tenantId={}", event.getPerson(), tenantId); + toAbsence(new SickNoteEventDtoAdapter(event)) + .ifPresentOrElse( + absenceWriteService::addAbsence, + () -> LOG.info("could not map SickNoteCreatedEventDTO to Absence -> could not add Absence") + ); + }); } @RabbitListener(queues = {ZEITERFASSUNG_URLAUBSVERWALTUNG_SICKNOTE_UPDATED_QUEUE}) void on(SickNoteUpdatedEventDTO event) { - LOG.info("Received SickNoteUpdatedEvent for person={} and tenantId={}", event.getPerson(), event.getTenantId()); - toAbsence(new SickNoteEventDtoAdapter(event)) - .ifPresentOrElse( - absenceWriteService::updateAbsence, - () -> LOG.info("could not map SickNoteUpdatedEventDTO to Absence -> could not update Absence") - ); + tenantContextHolder.runInTenantIdContext(event.getTenantId(), tenantId -> { + LOG.info("Received SickNoteUpdatedEvent for person={} and tenantId={}", event.getPerson(), tenantId); + toAbsence(new SickNoteEventDtoAdapter(event)) + .ifPresentOrElse( + absenceWriteService::updateAbsence, + () -> LOG.info("could not map SickNoteUpdatedEventDTO to Absence -> could not update Absence") + ); + }); } @RabbitListener(queues = {ZEITERFASSUNG_URLAUBSVERWALTUNG_SICKNOTE_CONVERTED_TO_APPLICATION_QUEUE}) void on(SickNoteConvertedToApplicationEventDTO event) { - LOG.info("Received SickNoteConvertedToApplicationEvent for person={} and tenantId={}", event.getPerson(), event.getTenantId()); - toAbsence(new SickNoteEventDtoAdapter(event)) - .ifPresentOrElse( - absenceWriteService::deleteAbsence, - () -> LOG.info("could not map SickNoteConvertedToApplicationEventDTO to Absence -> could not convert SickNote to Absence") - ); + tenantContextHolder.runInTenantIdContext(new TenantId(event.getTenantId()), tenantId -> { + LOG.info("Received SickNoteConvertedToApplicationEvent for person={} and tenantId={}", event.getPerson(), tenantId); + toAbsence(new SickNoteEventDtoAdapter(event)) + .ifPresentOrElse( + absenceWriteService::deleteAbsence, + () -> LOG.info("could not map SickNoteConvertedToApplicationEventDTO to Absence -> could not convert SickNote to Absence") + ); + + }); } private static Optional toAbsence(SickNoteEventDtoAdapter event) { return toDayLength(event.getPeriod().getDayLength()) .map(dayLength -> new AbsenceWrite( - new TenantId(event.getTenantId()), event.getSourceId(), new UserId(event.getPerson().getUsername()), event.getPeriod().getStartDate(), diff --git a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteRabbitmqConfiguration.java b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteRabbitmqConfiguration.java index ef11bc64c..01d255c0c 100644 --- a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteRabbitmqConfiguration.java +++ b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteRabbitmqConfiguration.java @@ -1,6 +1,7 @@ package de.focusshift.zeiterfassung.integration.urlaubsverwaltung.sicknote; import de.focusshift.zeiterfassung.absence.AbsenceWriteService; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.Queue; @@ -23,8 +24,8 @@ class SickNoteRabbitmqConfiguration { @Bean - SickNoteEventHandlerRabbitmq sickNoteEventHandlerRabbitmq(AbsenceWriteService absenceWriteService) { - return new SickNoteEventHandlerRabbitmq(absenceWriteService); + SickNoteEventHandlerRabbitmq sickNoteEventHandlerRabbitmq(AbsenceWriteService absenceWriteService, TenantContextHolder tenantContextHolder) { + return new SickNoteEventHandlerRabbitmq(absenceWriteService, tenantContextHolder); } @Configuration diff --git a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/vacationtype/VacationTypeHandlerRabbitmq.java b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/vacationtype/VacationTypeHandlerRabbitmq.java index e91b812ca..9af1c0634 100644 --- a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/vacationtype/VacationTypeHandlerRabbitmq.java +++ b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/vacationtype/VacationTypeHandlerRabbitmq.java @@ -6,7 +6,7 @@ import de.focusshift.zeiterfassung.absence.AbsenceTypeService; import de.focusshift.zeiterfassung.absence.AbsenceTypeUpdate; import de.focusshift.zeiterfassung.integration.urlaubsverwaltung.RabbitMessageConsumer; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import org.slf4j.Logger; import org.springframework.amqp.rabbit.annotation.RabbitListener; @@ -21,21 +21,23 @@ class VacationTypeHandlerRabbitmq extends RabbitMessageConsumer { private static final Logger LOG = getLogger(lookup().lookupClass()); private final AbsenceTypeService absenceTypeService; + private final TenantContextHolder tenantContextHolder; - VacationTypeHandlerRabbitmq(AbsenceTypeService absenceTypeService) { + VacationTypeHandlerRabbitmq(AbsenceTypeService absenceTypeService, TenantContextHolder tenantContextHolder) { this.absenceTypeService = absenceTypeService; + this.tenantContextHolder = tenantContextHolder; } @RabbitListener(queues = ZEITERFASSUNG_URLAUBSVERWALTUNG_VACATIONTYPE_UPDATED_QUEUE) void on(VacationTypeUpdatedEventDTO event) { - - LOG.info("Received VacationTypeUpdatedEvent id={} for tenantId={}", event.getId(), event.getTenantId()); - - toAbsenceTypeUpdate(event) - .ifPresentOrElse( - absenceTypeService::updateAbsenceType, - () -> LOG.info("could not map VacationTypeUpdatedEvent -> could not update AbsenceType") - ); + tenantContextHolder.runInTenantIdContext(event.getTenantId(), tenantId -> { + LOG.info("Received VacationTypeUpdatedEvent id={} for tenantId={}", event.getId(), event.getTenantId()); + toAbsenceTypeUpdate(event) + .ifPresentOrElse( + absenceTypeService::updateAbsenceType, + () -> LOG.info("could not map VacationTypeUpdatedEvent -> could not update AbsenceType") + ); + }); } private Optional toAbsenceTypeUpdate(VacationTypeUpdatedEventDTO eventDTO) { @@ -44,7 +46,6 @@ private Optional toAbsenceTypeUpdate(VacationTypeUpdatedEvent toAbsenceTypeCategory(eventDTO.getCategory()) .map(category -> new AbsenceTypeUpdate( - new TenantId(eventDTO.getTenantId()), eventDTO.getSourceId(), category, color, diff --git a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/vacationtype/VacationTypeRabbitmqConfiguration.java b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/vacationtype/VacationTypeRabbitmqConfiguration.java index 4ffdf80ad..b54baddc4 100644 --- a/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/vacationtype/VacationTypeRabbitmqConfiguration.java +++ b/src/main/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/vacationtype/VacationTypeRabbitmqConfiguration.java @@ -1,6 +1,7 @@ package de.focusshift.zeiterfassung.integration.urlaubsverwaltung.vacationtype; import de.focusshift.zeiterfassung.absence.AbsenceTypeService; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.Queue; @@ -18,8 +19,8 @@ class VacationTypeRabbitmqConfiguration { static final String ZEITERFASSUNG_URLAUBSVERWALTUNG_VACATIONTYPE_UPDATED_QUEUE = "zeiterfassung.queue.urlaubsverwaltung.vacationtype.updated"; @Bean - VacationTypeHandlerRabbitmq vacationTypeHandlerRabbitmq(AbsenceTypeService absenceTypeService) { - return new VacationTypeHandlerRabbitmq(absenceTypeService); + VacationTypeHandlerRabbitmq vacationTypeHandlerRabbitmq(AbsenceTypeService absenceTypeService, TenantContextHolder tenantContextHolder) { + return new VacationTypeHandlerRabbitmq(absenceTypeService, tenantContextHolder); } @ConditionalOnProperty(value = "zeiterfassung.integration.urlaubsverwaltung.vacationtype.manage-topology", havingValue = "true") diff --git a/src/main/java/de/focusshift/zeiterfassung/settings/FederalStateSettingsRepository.java b/src/main/java/de/focusshift/zeiterfassung/settings/FederalStateSettingsRepository.java index d02d68af1..121fb0339 100644 --- a/src/main/java/de/focusshift/zeiterfassung/settings/FederalStateSettingsRepository.java +++ b/src/main/java/de/focusshift/zeiterfassung/settings/FederalStateSettingsRepository.java @@ -2,9 +2,5 @@ import org.springframework.data.repository.CrudRepository; -import java.util.Optional; - interface FederalStateSettingsRepository extends CrudRepository { - - Optional findByTenantId(String tenantId); } diff --git a/src/main/java/de/focusshift/zeiterfassung/settings/SettingsService.java b/src/main/java/de/focusshift/zeiterfassung/settings/SettingsService.java index 7523488bb..b1a29daea 100644 --- a/src/main/java/de/focusshift/zeiterfassung/settings/SettingsService.java +++ b/src/main/java/de/focusshift/zeiterfassung/settings/SettingsService.java @@ -1,21 +1,26 @@ package de.focusshift.zeiterfassung.settings; import de.focusshift.zeiterfassung.publicholiday.FederalState; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import org.springframework.stereotype.Service; import java.util.Optional; +import static java.util.stream.StreamSupport.stream; + @Service class SettingsService implements FederalStateSettingsService { private final FederalStateSettingsRepository federalStateSettingsRepository; - private final TenantContextHolder tenantContextHolder; - SettingsService(FederalStateSettingsRepository federalStateSettingsRepository, TenantContextHolder tenantContextHolder) { + SettingsService(FederalStateSettingsRepository federalStateSettingsRepository) { this.federalStateSettingsRepository = federalStateSettingsRepository; - this.tenantContextHolder = tenantContextHolder; + } + + private static FederalStateSettings toFederalStateSettings(FederalStateSettingsEntity federalStateSettingsEntity) { + return new FederalStateSettings( + federalStateSettingsEntity.getFederalState(), + federalStateSettingsEntity.isWorksOnPublicHoliday() + ); } @Override @@ -37,17 +42,9 @@ FederalStateSettings updateFederalStateSettings(FederalState federalState, boole } private Optional getFederalStateEntity() { - - final TenantId tenantId = tenantContextHolder.getCurrentTenantId() - .orElseThrow(() -> new IllegalStateException("expected a tenantId to exist.")); - - return federalStateSettingsRepository.findByTenantId(tenantId.tenantId()); - } - - private static FederalStateSettings toFederalStateSettings(FederalStateSettingsEntity federalStateSettingsEntity) { - return new FederalStateSettings( - federalStateSettingsEntity.getFederalState(), - federalStateSettingsEntity.isWorksOnPublicHoliday() - ); + // `findFirst` is sufficient as there exists only one FederalStateSettingsEntity per tenant. + // however, the tenantId is handled transparently in the background. and we only have the public API of `findAll`. + final Iterable settings = federalStateSettingsRepository.findAll(); + return stream(settings.spliterator(), false).findFirst(); } } diff --git a/src/main/java/de/focusshift/zeiterfassung/tenancy/configuration/multi/AdminAwareDatabaseConfiguration.java b/src/main/java/de/focusshift/zeiterfassung/tenancy/configuration/multi/AdminAwareDatabaseConfiguration.java index 31d2a9df3..22375cdbb 100644 --- a/src/main/java/de/focusshift/zeiterfassung/tenancy/configuration/multi/AdminAwareDatabaseConfiguration.java +++ b/src/main/java/de/focusshift/zeiterfassung/tenancy/configuration/multi/AdminAwareDatabaseConfiguration.java @@ -1,8 +1,6 @@ package de.focusshift.zeiterfassung.tenancy.configuration.multi; import com.zaxxer.hikari.HikariDataSource; -import de.focusshift.zeiterfassung.absence.AbsenceTypeEntity; -import de.focusshift.zeiterfassung.absence.AbsenceWriteEntity; import de.focusshift.zeiterfassung.security.oidc.clientregistration.OidcClientEntity; import de.focusshift.zeiterfassung.tenancy.tenant.TenantEntity; import org.springframework.beans.factory.annotation.Qualifier; @@ -27,7 +25,7 @@ @Configuration(proxyBeanMethods = false) @EnableTransactionManagement @EnableJpaRepositories( - basePackageClasses = {TenantEntity.class, OidcClientEntity.class, AbsenceWriteEntity.class, AbsenceTypeEntity.class}, + basePackageClasses = {TenantEntity.class, OidcClientEntity.class}, entityManagerFactoryRef = "adminEntityManagerFactory", transactionManagerRef = "adminTransactionManager" ) @@ -57,7 +55,7 @@ LocalContainerEntityManagerFactoryBean adminEntityManagerFactory(EntityManagerFa return builder .dataSource(adminDataSource) // List all admin related entity packages here - .packages(TenantEntity.class, OidcClientEntity.class, AbsenceWriteEntity.class, AbsenceTypeEntity.class) + .packages(TenantEntity.class, OidcClientEntity.class) .persistenceUnit("admin") .build(); } diff --git a/src/main/java/de/focusshift/zeiterfassung/tenancy/configuration/multi/TenantAwareDatabaseConfiguration.java b/src/main/java/de/focusshift/zeiterfassung/tenancy/configuration/multi/TenantAwareDatabaseConfiguration.java index ed28c7868..92261273e 100644 --- a/src/main/java/de/focusshift/zeiterfassung/tenancy/configuration/multi/TenantAwareDatabaseConfiguration.java +++ b/src/main/java/de/focusshift/zeiterfassung/tenancy/configuration/multi/TenantAwareDatabaseConfiguration.java @@ -1,6 +1,8 @@ package de.focusshift.zeiterfassung.tenancy.configuration.multi; import com.zaxxer.hikari.HikariDataSource; +import de.focusshift.zeiterfassung.absence.AbsenceTypeEntity; +import de.focusshift.zeiterfassung.absence.AbsenceWriteEntity; import de.focusshift.zeiterfassung.settings.FederalStateSettingsEntity; import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import de.focusshift.zeiterfassung.tenancy.user.TenantUserEntity; @@ -34,6 +36,8 @@ @EnableTransactionManagement @EnableJpaRepositories( basePackageClasses = { + AbsenceWriteEntity.class, + AbsenceTypeEntity.class, TimeEntryEntity.class, TimeClockEntity.class, TenantUserEntity.class, @@ -76,6 +80,8 @@ LocalContainerEntityManagerFactoryBean tenantAwareEntityManagerFactory(EntityMan .dataSource(tenantAwareDataSource) // List all tenant aware related entity packages here .packages( + AbsenceWriteEntity.class, + AbsenceTypeEntity.class, TimeEntryEntity.class, TimeClockEntity.class, TenantUserEntity.class, diff --git a/src/main/java/de/focusshift/zeiterfassung/tenancy/configuration/multi/TenantContextHolderMultiTenant.java b/src/main/java/de/focusshift/zeiterfassung/tenancy/configuration/multi/TenantContextHolderMultiTenant.java index b07df73cd..4274f120d 100644 --- a/src/main/java/de/focusshift/zeiterfassung/tenancy/configuration/multi/TenantContextHolderMultiTenant.java +++ b/src/main/java/de/focusshift/zeiterfassung/tenancy/configuration/multi/TenantContextHolderMultiTenant.java @@ -4,6 +4,7 @@ import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.MDC; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; @@ -32,12 +33,14 @@ public void setTenantId(TenantId tenantId) { } LOG.debug("Setting tenantId to {}", tenantId); + MDC.put("tenantId", tenantId.tenantId()); currentTenantId.set(tenantId); } @Override public void clear() { LOG.debug("Clearing tenantId"); + MDC.remove("tenantId"); currentTenantId.remove(); } } diff --git a/src/main/java/de/focusshift/zeiterfassung/tenancy/tenant/TenantContextHolder.java b/src/main/java/de/focusshift/zeiterfassung/tenancy/tenant/TenantContextHolder.java index 6315f2d66..52185c057 100644 --- a/src/main/java/de/focusshift/zeiterfassung/tenancy/tenant/TenantContextHolder.java +++ b/src/main/java/de/focusshift/zeiterfassung/tenancy/tenant/TenantContextHolder.java @@ -1,6 +1,7 @@ package de.focusshift.zeiterfassung.tenancy.tenant; import java.util.Optional; +import java.util.function.Consumer; public interface TenantContextHolder { @@ -15,4 +16,17 @@ default void setTenantId(TenantId tenantId) { default void clear() { } + + default void runInTenantIdContext(String tenantId, Consumer function) { + runInTenantIdContext(new TenantId(tenantId), function); + } + + default void runInTenantIdContext(TenantId tenantId, Consumer function) { + try { + setTenantId(tenantId); + function.accept(tenantId.tenantId()); + } finally { + clear(); + } + } } diff --git a/src/main/java/de/focusshift/zeiterfassung/tenancy/user/TenantUserCreatorAndUpdater.java b/src/main/java/de/focusshift/zeiterfassung/tenancy/user/TenantUserCreatorAndUpdater.java index 7625a29a3..4e421d5c2 100644 --- a/src/main/java/de/focusshift/zeiterfassung/tenancy/user/TenantUserCreatorAndUpdater.java +++ b/src/main/java/de/focusshift/zeiterfassung/tenancy/user/TenantUserCreatorAndUpdater.java @@ -34,33 +34,28 @@ class TenantUserCreatorAndUpdater { public void handle(InteractiveAuthenticationSuccessEvent event) { if (event.getAuthentication() instanceof final OAuth2AuthenticationToken oauthToken) { - try { final TenantId tenantId = new TenantId(oauthToken.getAuthorizedClientRegistrationId()); if (!tenantId.valid()) { LOG.warn("Ignoring InteractiveAuthenticationSuccessEvent for invalid tenantId={}", tenantId.tenantId()); } else { - tenantContextHolder.setTenantId(tenantId); - createOrUpdateTenantUser(tenantId, oauthToken.getPrincipal()); + tenantContextHolder.runInTenantIdContext(tenantId, passedTenantId -> createOrUpdateTenantUser(oauthToken.getPrincipal(), passedTenantId)); } - } finally { - tenantContextHolder.clear(); - } } else { LOG.warn("Ignoring InteractiveAuthenticationSuccessEvent for unexpected authentication token type={}", event.getAuthentication().getClass()); } } - private void createOrUpdateTenantUser(TenantId tenantId, OAuth2User oauth2User) { + private void createOrUpdateTenantUser(OAuth2User oauth2User, String tenantId) { if (oauth2User instanceof final DefaultOidcUser oidcUser) { final EMailAddress eMailAddress = new EMailAddress(oidcUser.getEmail()); final UserId userId = new UserId(oidcUser.getSubject()); tenantUserService.findById(userId).ifPresentOrElse(user -> { final TenantUser tenantUser = new TenantUser(user.id(), user.localId(), oidcUser.getGivenName(), oidcUser.getFamilyName(), eMailAddress, user.authorities()); - LOG.info("updating existing user={} of tenantId={} with data from oidc token", userId.value(), tenantId.tenantId()); + LOG.info("updating existing user={} of tenantId={} with data from oidc token", userId.value(), tenantId); tenantUserService.updateUser(tenantUser); }, () -> { - LOG.info("creating new user={} for tenantId={} with data from oidc token", userId.value(), tenantId.tenantId()); + LOG.info("creating new user={} for tenantId={} with data from oidc token", userId.value(), tenantId); tenantUserService.createNewUser(oidcUser.getSubject(), oidcUser.getGivenName(), oidcUser.getFamilyName(), eMailAddress, Set.of(ZEITERFASSUNG_USER)); }); } diff --git a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceIT.java b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceIT.java index f5da19e39..a2c7463c5 100644 --- a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceIT.java +++ b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceIT.java @@ -6,12 +6,16 @@ import de.focus_shift.urlaubsverwaltung.extension.api.application.VacationTypeDTO; import de.focusshift.zeiterfassung.RabbitTestConfiguration; import de.focusshift.zeiterfassung.TestContainersBase; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import de.focusshift.zeiterfassung.user.UserId; import de.focusshift.zeiterfassung.user.UserSettingsProvider; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Answers; +import org.mockito.InOrder; +import org.mockito.Mockito; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -25,6 +29,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.Function; @@ -36,6 +41,8 @@ import static java.util.Locale.GERMAN; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @SpringBootTest( @@ -59,6 +66,8 @@ class AbsenceIT extends TestContainersBase { @MockBean private UserSettingsProvider userSettingsProvider; + @MockBean(answer = Answers.CALLS_REAL_METHODS) + private TenantContextHolder tenantContextHolder; @Autowired private AbsenceService absenceService; @@ -75,6 +84,7 @@ class AbsenceIT extends TestContainersBase { @BeforeEach void setUp() { when(userSettingsProvider.zoneId()).thenReturn(ZONE_ID); + when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId(TENANT_ID))); } @AfterEach @@ -96,7 +106,6 @@ void ensureAbsenceWithAbsenceTypeInformation() { final AbsenceTypeCategory erholungsurlaubCategory = HOLIDAY; absenceTypeService.updateAbsenceType(new AbsenceTypeUpdate( - new TenantId(TENANT_ID), erholungsUrlaubSourceId, erholungsurlaubCategory, erholungsUrlaubColor, @@ -129,5 +138,11 @@ void ensureAbsenceWithAbsenceTypeInformation() { .hasSize(1) .contains(Map.entry(now, List.of(expectedAbsence))); }); + + InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(new TenantId(TENANT_ID)); + inOrder.verify(tenantContextHolder).clear(); + + verify(tenantContextHolder, times(2)).getCurrentTenantId(); } } diff --git a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceRepositoryIT.java b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceRepositoryIT.java index 3fa79ea0f..21f88b4d0 100644 --- a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceRepositoryIT.java +++ b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceRepositoryIT.java @@ -2,26 +2,35 @@ import de.focusshift.zeiterfassung.TestContainersBase; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.transaction.annotation.Transactional; import java.time.Instant; import java.util.List; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @SpringBootTest @Transactional class AbsenceRepositoryIT extends TestContainersBase { - - private static final String TENANT = "tenant"; + private static final TenantId TENANT_ID = new TenantId("default"); private static final String USER = "user-id"; @Autowired - AbsenceRepository sut; + private AbsenceRepository sut; + + @MockBean + private TenantContextHolder tenantContextHolder; /** * Tested period is KW 31 2023: 31.07.2023-06.08.2023 @@ -37,21 +46,24 @@ void findForGivenWeek() { final AbsenceWriteEntity startOnEndAndEndOutside = absence(++sourceId, "2023-08-05T22:00:00.000Z", "2023-08-06T22:00:00.000Z"); final AbsenceWriteEntity oneDayAfterRequestedWeek = absence(++sourceId, "2023-08-06T22:00:00.000Z", "2023-08-06T22:00:00.000Z"); + when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(TENANT_ID)); + sut.saveAll(List.of(oneDayBeforeRequestedWeek, startOutsideEndOnStartOfWeek, startAndEndInside, startBeforeEndAfter, startOnEndAndEndOutside, oneDayAfterRequestedWeek)); final Instant startOfWeek = Instant.parse("2023-07-30T22:00:00.000Z"); final Instant endOfWeekExclusive = Instant.parse("2023-08-06T22:00:00.000Z"); - final List matchingAbsences = sut.findAllByTenantIdAndUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(TENANT, List.of(USER), endOfWeekExclusive, startOfWeek); + final List matchingAbsences = sut.findAllByUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(List.of(USER), endOfWeekExclusive, startOfWeek); assertThat(matchingAbsences) .contains(startOutsideEndOnStartOfWeek, startAndEndInside, startBeforeEndAfter, startOnEndAndEndOutside) .doesNotContain(oneDayBeforeRequestedWeek, oneDayAfterRequestedWeek); + + verify(tenantContextHolder, times(6)).getCurrentTenantId(); } private static AbsenceWriteEntity absence(long sourceId, String start, String end) { final AbsenceWriteEntity oneDayBeforeRequestedWeek = new AbsenceWriteEntity(); - oneDayBeforeRequestedWeek.setTenantId(TENANT); oneDayBeforeRequestedWeek.setSourceId(sourceId); oneDayBeforeRequestedWeek.setUserId(USER); oneDayBeforeRequestedWeek.setStartDate(Instant.parse(start)); diff --git a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceServiceImplTest.java b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceServiceImplTest.java index 5a1d8ca02..f085f682f 100644 --- a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceServiceImplTest.java +++ b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceServiceImplTest.java @@ -1,7 +1,5 @@ package de.focusshift.zeiterfassung.absence; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import de.focusshift.zeiterfassung.tenancy.user.EMailAddress; import de.focusshift.zeiterfassung.user.UserId; import de.focusshift.zeiterfassung.user.UserIdComposite; @@ -25,7 +23,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.Function; @@ -59,15 +56,13 @@ class AbsenceServiceImplTest { @Mock private UserSettingsProvider userSettingsProvider; @Mock - private TenantContextHolder tenantContextHolder; - @Mock private UserManagementService userManagementService; @Mock private MessageSource messageSource; @BeforeEach void setUp() { - sut = new AbsenceServiceImpl(repository, absenceTypeService, userSettingsProvider, tenantContextHolder, userManagementService, messageSource); + sut = new AbsenceServiceImpl(repository, absenceTypeService, userSettingsProvider, userManagementService, messageSource); } @Test @@ -79,7 +74,6 @@ void ensureFindAllAbsences() { final ZoneId berlin = ZoneId.of("Europe/Berlin"); when(userSettingsProvider.zoneId()).thenReturn(berlin); - when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId("tenant"))); final AbsenceWriteEntity entity_1 = new AbsenceWriteEntity(); entity_1.setId(1L); @@ -97,7 +91,7 @@ void ensureFindAllAbsences() { entity_2.setDayLength(MORNING); entity_2.setType(new AbsenceTypeEntityEmbeddable(SPECIALLEAVE, 2000L)); - when(repository.findAllByTenantIdAndUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual("tenant", List.of("user"), endDateExclusive, startDate)) + when(repository.findAllByUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(List.of("user"), endDateExclusive, startDate)) .thenReturn(List.of(entity_1, entity_2)); final AbsenceType absenceType1 = new AbsenceType(HOLIDAY, 1000L, label(GERMAN, "1000-de", ENGLISH, "1000-en"), PINK); @@ -148,7 +142,6 @@ void ensureFindAllAbsencesWithLabelForDayLength(DayLength givenDayLength) { final ZoneId berlin = ZoneId.of("Europe/Berlin"); when(userSettingsProvider.zoneId()).thenReturn(berlin); - when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId("tenant"))); final AbsenceWriteEntity entity = new AbsenceWriteEntity(); entity.setId(1L); @@ -158,7 +151,7 @@ void ensureFindAllAbsencesWithLabelForDayLength(DayLength givenDayLength) { entity.setDayLength(givenDayLength); entity.setType(new AbsenceTypeEntityEmbeddable(HOLIDAY, 1000L)); - when(repository.findAllByTenantIdAndUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual("tenant", List.of("user"), endDateExclusive, startDate)) + when(repository.findAllByUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(List.of("user"), endDateExclusive, startDate)) .thenReturn(List.of(entity)); final AbsenceType absenceType = new AbsenceType(HOLIDAY, 1000L, label(GERMAN, "de", ENGLISH, "en"), PINK); @@ -187,7 +180,6 @@ void ensureFindAllAbsencesWithLabelForDayLengthAndCategorySickness(DayLength giv final ZoneId berlin = ZoneId.of("Europe/Berlin"); when(userSettingsProvider.zoneId()).thenReturn(berlin); - when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId("tenant"))); final AbsenceWriteEntity entitySickness = new AbsenceWriteEntity(); entitySickness.setId(2L); @@ -197,7 +189,7 @@ void ensureFindAllAbsencesWithLabelForDayLengthAndCategorySickness(DayLength giv entitySickness.setDayLength(givenDayLength); entitySickness.setType(new AbsenceTypeEntityEmbeddable(SICK, null)); - when(repository.findAllByTenantIdAndUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual("tenant", List.of("user"), endDateExclusive, startDate)) + when(repository.findAllByUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(List.of("user"), endDateExclusive, startDate)) .thenReturn(List.of(entitySickness)); // SupportedLanguages are GERMAN and ENGLISH right now @@ -218,7 +210,6 @@ void ensureGetAbsencesByUserIdsReturnsEmptyListForAskedUsersWithoutAbsences() { final ZoneId berlin = ZoneId.of("Europe/Berlin"); when(userSettingsProvider.zoneId()).thenReturn(berlin); - when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId("tenant"))); final LocalDate from = LocalDate.of(2023, 11, 16); final LocalDate toExclusive = LocalDate.of(2023, 11, 16); @@ -235,7 +226,7 @@ void ensureGetAbsencesByUserIdsReturnsEmptyListForAskedUsersWithoutAbsences() { final List userIdsValues = List.of(userId.value()); - when(repository.findAllByTenantIdAndUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual("tenant", userIdsValues, toExclusiveStartOfDay, fromStartOfDay)) + when(repository.findAllByUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(userIdsValues, toExclusiveStartOfDay, fromStartOfDay)) .thenReturn(List.of()); final Map> actual = sut.getAbsencesByUserIds(List.of(userLocalId), from, toExclusive); @@ -247,7 +238,6 @@ void ensureGetAbsencesByUserIds() { final ZoneId berlin = ZoneId.of("Europe/Berlin"); when(userSettingsProvider.zoneId()).thenReturn(berlin); - when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId("tenant"))); final LocalDate from = LocalDate.of(2023, 11, 1); final LocalDate toExclusive = LocalDate.of(2023, 11, 30); @@ -293,7 +283,7 @@ void ensureGetAbsencesByUserIds() { absenceEntity_2_2.setDayLength(NOON); absenceEntity_2_2.setType(new AbsenceTypeEntityEmbeddable(OTHER, 3000L)); - when(repository.findAllByTenantIdAndUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual("tenant", List.of(userId_1.value(), userId_2.value()), toExclusiveStartOfDay, fromStartOfDay)) + when(repository.findAllByUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(List.of(userId_1.value(), userId_2.value()), toExclusiveStartOfDay, fromStartOfDay)) .thenReturn(List.of(absenceEntity_1, absenceEntity_2_1, absenceEntity_2_2)); final AbsenceType absenceType1 = new AbsenceType(OTHER, 1000L, label(GERMAN, "1000-de", ENGLISH, "1000-en"), YELLOW); @@ -323,7 +313,6 @@ void ensureGetAbsencesByUserIdsLabelForDayLength(DayLength givenDayLength) { final ZoneId berlin = ZoneId.of("Europe/Berlin"); when(userSettingsProvider.zoneId()).thenReturn(berlin); - when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId("tenant"))); final LocalDate from = LocalDate.of(2023, 11, 1); final LocalDate toExclusive = LocalDate.of(2023, 11, 30); @@ -347,7 +336,7 @@ void ensureGetAbsencesByUserIdsLabelForDayLength(DayLength givenDayLength) { absenceEntity.setDayLength(givenDayLength); absenceEntity.setType(new AbsenceTypeEntityEmbeddable(OTHER, 1000L)); - when(repository.findAllByTenantIdAndUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual("tenant", List.of(userId.value()), toExclusiveStartOfDay, fromStartOfDay)) + when(repository.findAllByUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(List.of(userId.value()), toExclusiveStartOfDay, fromStartOfDay)) .thenReturn(List.of(absenceEntity)); final AbsenceType absenceType = new AbsenceType(OTHER, 1000L, label(GERMAN, "de", ENGLISH, "en"), YELLOW); @@ -370,7 +359,6 @@ void ensureGetAbsencesForAllUsersReturnsEmptyListForUsersWithoutAbsences() { final ZoneId berlin = ZoneId.of("Europe/Berlin"); when(userSettingsProvider.zoneId()).thenReturn(berlin); - when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId("tenant"))); final LocalDate from = LocalDate.of(2023, 11, 1); final LocalDate toExclusive = LocalDate.of(2023, 11, 30); @@ -383,7 +371,7 @@ void ensureGetAbsencesForAllUsersReturnsEmptyListForUsersWithoutAbsences() { final User user = new User(userIdComposite, "", "", new EMailAddress(""), Set.of()); when(userManagementService.findAllUsers()).thenReturn(List.of(user)); - when(repository.findAllByTenantIdAndStartDateLessThanAndEndDateGreaterThanEqual("tenant", toExclusiveStartOfDay, fromStartOfDay)) + when(repository.findAllByStartDateLessThanAndEndDateGreaterThanEqual(toExclusiveStartOfDay, fromStartOfDay)) .thenReturn(List.of()); final Map> actual = sut.getAbsencesForAllUsers(from, toExclusive); @@ -395,7 +383,6 @@ void ensureGetAbsencesForAllUsers() { final ZoneId berlin = ZoneId.of("Europe/Berlin"); when(userSettingsProvider.zoneId()).thenReturn(berlin); - when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId("tenant"))); final LocalDate from = LocalDate.of(2023, 11, 1); final LocalDate toExclusive = LocalDate.of(2023, 11, 30); @@ -441,7 +428,7 @@ void ensureGetAbsencesForAllUsers() { absenceEntity_2_2.setDayLength(NOON); absenceEntity_2_2.setType(new AbsenceTypeEntityEmbeddable(OTHER, 3000L)); - when(repository.findAllByTenantIdAndStartDateLessThanAndEndDateGreaterThanEqual("tenant", toExclusiveStartOfDay, fromStartOfDay)) + when(repository.findAllByStartDateLessThanAndEndDateGreaterThanEqual(toExclusiveStartOfDay, fromStartOfDay)) .thenReturn(List.of(absenceEntity_1, absenceEntity_2_1, absenceEntity_2_2)); final AbsenceType absenceType1 = new AbsenceType(OTHER, 1000L, label(GERMAN, "1000-de", ENGLISH, "1000-en"), YELLOW); @@ -471,7 +458,6 @@ void ensureGetAbsencesForAllUsersLabelForDayLength(DayLength givenDayLength) { final ZoneId berlin = ZoneId.of("Europe/Berlin"); when(userSettingsProvider.zoneId()).thenReturn(berlin); - when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId("tenant"))); final LocalDate from = LocalDate.of(2023, 11, 1); final LocalDate toExclusive = LocalDate.of(2023, 11, 30); @@ -494,7 +480,7 @@ void ensureGetAbsencesForAllUsersLabelForDayLength(DayLength givenDayLength) { absenceEntity.setDayLength(givenDayLength); absenceEntity.setType(new AbsenceTypeEntityEmbeddable(OTHER, 1000L)); - when(repository.findAllByTenantIdAndStartDateLessThanAndEndDateGreaterThanEqual("tenant", toExclusiveStartOfDay, fromStartOfDay)) + when(repository.findAllByStartDateLessThanAndEndDateGreaterThanEqual(toExclusiveStartOfDay, fromStartOfDay)) .thenReturn(List.of(absenceEntity)); final AbsenceType absenceType = new AbsenceType(OTHER, 1000L, label(GERMAN, "de", ENGLISH, "en"), YELLOW); @@ -516,15 +502,12 @@ void ensureGetAbsencesForAllUsersLabelForDayLength(DayLength givenDayLength) { void getAbsencesByUserId() { final UserId userId = new UserId("user"); - when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId("tenant"))); - final ZoneId berlin = ZoneId.of("Europe/Berlin"); final ZonedDateTime today = LocalDate.now().atStartOfDay(berlin); final Instant startDate = today.toInstant(); final Instant endDateExclusive = today.plusWeeks(1).toInstant(); when(userSettingsProvider.zoneId()).thenReturn(berlin); - when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId("tenant"))); final AbsenceWriteEntity entity_1 = new AbsenceWriteEntity(); entity_1.setId(1L); @@ -542,7 +525,7 @@ void getAbsencesByUserId() { entity_2.setDayLength(MORNING); entity_2.setType(new AbsenceTypeEntityEmbeddable(SPECIALLEAVE, 2000L)); - when(repository.findAllByTenantIdAndUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual("tenant", List.of("user"), endDateExclusive, startDate)) + when(repository.findAllByUserIdInAndStartDateLessThanAndEndDateGreaterThanEqual(List.of("user"), endDateExclusive, startDate)) .thenReturn(List.of(entity_1, entity_2)); final AbsenceType absenceType1 = new AbsenceType(HOLIDAY, 1000L, label(GERMAN, "1000-de", ENGLISH, "1000-en"), PINK); diff --git a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceTypeIT.java b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceTypeIT.java index 957cd1c35..8368866ee 100644 --- a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceTypeIT.java +++ b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceTypeIT.java @@ -3,19 +3,28 @@ import de.focus_shift.urlaubsverwaltung.extension.api.vacationtype.VacationTypeUpdatedEventDTO; import de.focusshift.zeiterfassung.RabbitTestConfiguration; import de.focusshift.zeiterfassung.TestContainersBase; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import org.junit.jupiter.api.Test; +import org.mockito.Answers; +import org.mockito.InOrder; +import org.mockito.Mockito; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import org.springframework.transaction.annotation.Transactional; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @SpringBootTest( properties = { @@ -38,12 +47,18 @@ class AbsenceTypeIT extends TestContainersBase { @Autowired private RabbitTemplate rabbitTemplate; + @MockBean(answer = Answers.CALLS_REAL_METHODS) + private TenantContextHolder tenantContextHolder; + @Test void ensureAbsenceTypeCreation() { + final TenantId tenantId = new TenantId("default"); + when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(tenantId)); + rabbitTemplate.convertAndSend("vacationtype.topic", "updated", VacationTypeUpdatedEventDTO.builder() .id(UUID.randomUUID()) - .tenantId("tenant-id") + .tenantId(tenantId.tenantId()) .sourceId(42L) .category(AbsenceTypeCategory.OTHER.name()) .requiresApprovalToApply(false) @@ -64,7 +79,7 @@ void ensureAbsenceTypeCreation() { .first() .satisfies(entity -> { assertThat(entity.getId()).isNotNull(); - assertThat(entity.getTenantId()).isEqualTo("tenant-id"); + assertThat(entity.getTenantId()).isEqualTo(tenantId.tenantId()); assertThat(entity.getSourceId()).isEqualTo(42); assertThat(entity.getCategory()).isEqualTo(AbsenceTypeCategory.OTHER); assertThat(entity.getColor()).isEqualTo(AbsenceColor.VIOLET); @@ -74,5 +89,11 @@ void ensureAbsenceTypeCreation() { )); }); }); + + final InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(tenantId); + inOrder.verify(tenantContextHolder).clear(); + + verify(tenantContextHolder).getCurrentTenantId(); } } diff --git a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceTypeServiceImplTest.java b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceTypeServiceImplTest.java index f5c8846a2..8f590ccdb 100644 --- a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceTypeServiceImplTest.java +++ b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceTypeServiceImplTest.java @@ -1,6 +1,5 @@ package de.focusshift.zeiterfassung.absence; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -28,10 +27,9 @@ class AbsenceTypeServiceImplTest { @Test void ensureCreatingNewAbsenceType() { - when(repository.findByTenantIdAndSourceId("tenant", 42L)).thenReturn(Optional.empty()); + when(repository.findBySourceId(42L)).thenReturn(Optional.empty()); final AbsenceTypeUpdate absenceTypeUpdate = new AbsenceTypeUpdate( - new TenantId("tenant"), 42L, AbsenceTypeCategory.OTHER, AbsenceColor.VIOLET, @@ -48,7 +46,7 @@ void ensureCreatingNewAbsenceType() { assertThat(captor.getValue()).satisfies(entity -> { assertThat(entity.getId()).isNull(); - assertThat(entity.getTenantId()).isEqualTo("tenant"); + assertThat(entity.getTenantId()).isNull(); assertThat(entity.getCategory()).isEqualTo(AbsenceTypeCategory.OTHER); assertThat(entity.getColor()).isEqualTo(AbsenceColor.VIOLET); assertThat(entity.getLabelByLocale()).containsExactlyInAnyOrderEntriesOf(Map.of( @@ -63,12 +61,12 @@ void ensureUpdateAbsenceType() { final AbsenceTypeEntity existingEntity = new AbsenceTypeEntity(); existingEntity.setId(1L); + existingEntity.setTenantId("tenant"); - when(repository.findByTenantIdAndSourceId("tenant", 42L)) + when(repository.findBySourceId(42L)) .thenReturn(Optional.of(existingEntity)); final AbsenceTypeUpdate absenceTypeUpdate = new AbsenceTypeUpdate( - new TenantId("tenant"), 42L, AbsenceTypeCategory.OTHER, AbsenceColor.VIOLET, diff --git a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceWriteServiceImplIT.java b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceWriteServiceImplIT.java index 4c055e47a..8ef5833ee 100644 --- a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceWriteServiceImplIT.java +++ b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceWriteServiceImplIT.java @@ -1,17 +1,23 @@ package de.focusshift.zeiterfassung.absence; import de.focusshift.zeiterfassung.TestContainersBase; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import de.focusshift.zeiterfassung.user.UserId; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.transaction.annotation.Transactional; import java.time.Instant; +import java.util.Optional; import static de.focusshift.zeiterfassung.absence.AbsenceTypeCategory.HOLIDAY; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @SpringBootTest @Transactional @@ -23,14 +29,18 @@ class AbsenceWriteServiceImplIT extends TestContainersBase { @Autowired private AbsenceRepository repository; + @MockBean + private TenantContextHolder tenantContextHolder; + @Test void ensureDeleteAbsence() { final Instant startDate = Instant.now(); final Instant endDate = Instant.now(); + when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(new TenantId("tenant"))); + final AbsenceWriteEntity existingEntity = new AbsenceWriteEntity(); - existingEntity.setTenantId("tenant"); existingEntity.setSourceId(42L); existingEntity.setUserId("user-id"); existingEntity.setStartDate(startDate); @@ -40,7 +50,6 @@ void ensureDeleteAbsence() { repository.save(existingEntity); final AbsenceWrite absence = new AbsenceWrite( - new TenantId("tenant"), 42L, new UserId("user-id"), startDate, @@ -51,39 +60,11 @@ void ensureDeleteAbsence() { assertThat(repository.findAll()).hasSize(1); + sut.deleteAbsence(absence); assertThat(repository.findAll()).isEmpty(); + verify(tenantContextHolder, times(2)).getCurrentTenantId(); } - @Test - void ensureDeleteAbsenceDoesNotDeleteWhenTenantIdIsDifferent() { - - final Instant startDate = Instant.now(); - final Instant endDate = Instant.now(); - - final AbsenceWriteEntity existingEntity = new AbsenceWriteEntity(); - existingEntity.setTenantId("tenant"); - existingEntity.setSourceId(42L); - existingEntity.setUserId("user-id"); - existingEntity.setStartDate(startDate); - existingEntity.setEndDate(endDate); - existingEntity.setDayLength(DayLength.FULL); - existingEntity.setType(new AbsenceTypeEntityEmbeddable(HOLIDAY, 1000L)); - repository.save(existingEntity); - - final AbsenceWrite absence = new AbsenceWrite( - new TenantId("tenant-2"), - 42L, - new UserId("user-id"), - startDate, - endDate, - DayLength.FULL, - HOLIDAY - ); - - sut.deleteAbsence(absence); - - assertThat(repository.findAll()).hasSize(1); - } } diff --git a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceWriteServiceImplTest.java b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceWriteServiceImplTest.java index c90300757..2efcddbcc 100644 --- a/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceWriteServiceImplTest.java +++ b/src/test/java/de/focusshift/zeiterfassung/absence/AbsenceWriteServiceImplTest.java @@ -1,6 +1,5 @@ package de.focusshift.zeiterfassung.absence; -import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import de.focusshift.zeiterfassung.user.UserId; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -37,11 +36,10 @@ void ensureAddAbsence() { final Instant startDate = Instant.now(); final Instant endDate = Instant.now(); - when(repository.findByTenantIdAndSourceIdAndType_Category("tenant-id", 42L, SPECIALLEAVE)) + when(repository.findBySourceIdAndType_Category(42L, SPECIALLEAVE)) .thenReturn(Optional.empty()); final AbsenceWrite absence = new AbsenceWrite( - new TenantId("tenant-id"), 42L, new UserId("user-id"), startDate, @@ -56,7 +54,7 @@ void ensureAddAbsence() { verify(repository).save(captor.capture()); final AbsenceWriteEntity actualPersistedEntity = captor.getValue(); - assertThat(actualPersistedEntity.getTenantId()).isEqualTo("tenant-id"); + assertThat(actualPersistedEntity.getTenantId()).isNull(); assertThat(actualPersistedEntity.getId()).isNull(); assertThat(actualPersistedEntity.getUserId()).isEqualTo("user-id"); assertThat(actualPersistedEntity.getStartDate()).isEqualTo(startDate); @@ -71,11 +69,10 @@ void ensureAddAbsenceDoesNothingWhenItExistsAlready() { final Instant startDate = Instant.now(); final Instant endDate = Instant.now(); - when(repository.findByTenantIdAndSourceIdAndType_Category("tenant-id", 42L, SPECIALLEAVE)) + when(repository.findBySourceIdAndType_Category(42L, SPECIALLEAVE)) .thenReturn(Optional.of(new AbsenceWriteEntity())); final AbsenceWrite absence = new AbsenceWrite( - new TenantId("tenant-id"), 42L, new UserId("user-id"), startDate, diff --git a/src/test/java/de/focusshift/zeiterfassung/importer/TenantImporterComponentTest.java b/src/test/java/de/focusshift/zeiterfassung/importer/TenantImporterComponentTest.java index 8d7ddb2e7..9d3542731 100644 --- a/src/test/java/de/focusshift/zeiterfassung/importer/TenantImporterComponentTest.java +++ b/src/test/java/de/focusshift/zeiterfassung/importer/TenantImporterComponentTest.java @@ -27,6 +27,7 @@ import de.focusshift.zeiterfassung.workingtime.WorkingTimeService; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; import org.mockito.InOrder; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -64,7 +65,7 @@ class TenantImporterComponentTest { @InjectMocks private TenantImporterComponent sut; - @Mock + @Mock(answer = Answers.CALLS_REAL_METHODS) private TenantContextHolder tenantContextHolder; @Mock private TenantService tenantService; diff --git a/src/test/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationEventHandlerRabbitmqTest.java b/src/test/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationEventHandlerRabbitmqTest.java index 8804c4652..9b8d7602e 100644 --- a/src/test/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationEventHandlerRabbitmqTest.java +++ b/src/test/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/application/ApplicationEventHandlerRabbitmqTest.java @@ -11,12 +11,16 @@ import de.focusshift.zeiterfassung.absence.AbsenceWrite; import de.focusshift.zeiterfassung.absence.AbsenceWriteService; import de.focusshift.zeiterfassung.absence.DayLength; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import de.focusshift.zeiterfassung.user.UserId; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; +import org.mockito.InOrder; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import java.time.Instant; @@ -36,16 +40,21 @@ class ApplicationEventHandlerRabbitmqTest { @Mock private AbsenceWriteService absenceWriteService; + @Mock(answer = Answers.CALLS_REAL_METHODS) + private TenantContextHolder tenantContextHolder; + @BeforeEach void setUp() { - sut = new ApplicationEventHandlerRabbitmq(absenceWriteService); + sut = new ApplicationEventHandlerRabbitmq(absenceWriteService, tenantContextHolder); } @Test void onApplicationAllowedEvent() { + final TenantId tenantId = new TenantId("tenantId"); + final ApplicationAllowedEventDTO event = ApplicationAllowedEventDTO.builder() .id(UUID.randomUUID()) - .tenantId("tenantId") + .tenantId(tenantId.tenantId()) .sourceId(1L) .person(ApplicationPersonDTO.builder().personId(2L).username("userId").build()) .period(ApplicationPeriodDTO.builder().startDate(Instant.ofEpochMilli(0L)).endDate(Instant.ofEpochMilli(1L)).dayLength(de.focus_shift.urlaubsverwaltung.extension.api.application.DayLength.FULL).build()) @@ -54,10 +63,10 @@ void onApplicationAllowedEvent() { .status("status") .absentWorkingDays(Set.of(LocalDate.now())) .build(); + sut.on(event); final AbsenceWrite absence = new AbsenceWrite( - new TenantId("tenantId"), 1L, new UserId("userId"), Instant.ofEpochMilli(0L), @@ -67,13 +76,19 @@ void onApplicationAllowedEvent() { new AbsenceTypeSourceId(1000L) ); verify(absenceWriteService).addAbsence(absence); + + final InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(tenantId); + inOrder.verify(tenantContextHolder).clear(); } @Test void onApplicationCreatedFromSickNoteEvent() { + final TenantId tenantId = new TenantId("tenantId"); + final ApplicationCreatedFromSickNoteEventDTO event = ApplicationCreatedFromSickNoteEventDTO.builder() .id(UUID.randomUUID()) - .tenantId("tenantId") + .tenantId(tenantId.tenantId()) .sourceId(1L) .person(ApplicationPersonDTO.builder().personId(2L).username("userId").build()) .period(ApplicationPeriodDTO.builder().startDate(Instant.ofEpochMilli(0L)).endDate(Instant.ofEpochMilli(1L)).dayLength(de.focus_shift.urlaubsverwaltung.extension.api.application.DayLength.FULL).build()) @@ -85,7 +100,6 @@ void onApplicationCreatedFromSickNoteEvent() { sut.on(event); final AbsenceWrite absence = new AbsenceWrite( - new TenantId("tenantId"), 1L, new UserId("userId"), Instant.ofEpochMilli(0L), @@ -95,13 +109,19 @@ void onApplicationCreatedFromSickNoteEvent() { new AbsenceTypeSourceId(1000L) ); verify(absenceWriteService).addAbsence(absence); + + final InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(tenantId); + inOrder.verify(tenantContextHolder).clear(); } @Test void onApplicationCancelledEvent() { + final TenantId tenantId = new TenantId("tenantId"); + final ApplicationCancelledEventDTO event = ApplicationCancelledEventDTO.builder() .id(UUID.randomUUID()) - .tenantId("tenantId") + .tenantId(tenantId.tenantId()) .sourceId(1L) .person(ApplicationPersonDTO.builder().personId(2L).username("userId").build()) .period(ApplicationPeriodDTO.builder().startDate(Instant.ofEpochMilli(0L)).endDate(Instant.ofEpochMilli(1L)).dayLength(de.focus_shift.urlaubsverwaltung.extension.api.application.DayLength.FULL).build()) @@ -113,7 +133,6 @@ void onApplicationCancelledEvent() { sut.on(event); final AbsenceWrite absence = new AbsenceWrite( - new TenantId("tenantId"), 1L, new UserId("userId"), Instant.ofEpochMilli(0L), @@ -123,13 +142,19 @@ void onApplicationCancelledEvent() { new AbsenceTypeSourceId(1000L) ); verify(absenceWriteService).deleteAbsence(absence); + + final InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(tenantId); + inOrder.verify(tenantContextHolder).clear(); } @Test void onApplicationWithAbsentWorkingDays() { + final TenantId tenantId = new TenantId("tenantId"); + final ApplicationAllowedEventDTO event = ApplicationAllowedEventDTO.builder() .id(UUID.randomUUID()) - .tenantId("tenantId") + .tenantId(tenantId.tenantId()) .sourceId(1L) .person(ApplicationPersonDTO.builder().personId(2L).username("userId").build()) .period(ApplicationPeriodDTO.builder().startDate(Instant.ofEpochMilli(0L)).endDate(Instant.ofEpochMilli(1L)).dayLength(de.focus_shift.urlaubsverwaltung.extension.api.application.DayLength.FULL).build()) @@ -141,5 +166,9 @@ void onApplicationWithAbsentWorkingDays() { sut.on(event); verifyNoInteractions(absenceWriteService); + + final InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(tenantId); + inOrder.verify(tenantContextHolder).clear(); } } diff --git a/src/test/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteEventHandlerRabbitmqIT.java b/src/test/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteEventHandlerRabbitmqIT.java index f4a5ac9fa..f6df7ecac 100644 --- a/src/test/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteEventHandlerRabbitmqIT.java +++ b/src/test/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/sicknote/SickNoteEventHandlerRabbitmqIT.java @@ -12,11 +12,15 @@ import de.focusshift.zeiterfassung.absence.AbsenceService; import de.focusshift.zeiterfassung.absence.AbsenceWrite; import de.focusshift.zeiterfassung.absence.AbsenceWriteService; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import de.focusshift.zeiterfassung.user.UserId; import de.focusshift.zeiterfassung.user.UserSettingsProvider; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Answers; +import org.mockito.InOrder; +import org.mockito.Mockito; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -30,6 +34,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.Function; @@ -69,6 +74,8 @@ class SickNoteEventHandlerRabbitmqIT extends TestContainersBase { @MockBean private UserSettingsProvider userSettingsProvider; + @MockBean(answer = Answers.CALLS_REAL_METHODS) + private TenantContextHolder tenantContextHolder; @Autowired private AbsenceService absenceService; @@ -92,6 +99,9 @@ void ensureSickNoteCreatedUpdatedDeleted() { final SickNotePersonDTO boss = SickNotePersonDTO.builder().personId(1L).username("boss").build(); + final TenantId tenantId = new TenantId(TENANT_ID); + when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(tenantId)); + // CREATE sick note absence rabbitTemplate.convertAndSend(TOPIC, CREATED_ROUTING_KEY, SickNoteCreatedEventDTO.builder() .createdAt(Instant.now()) @@ -116,6 +126,10 @@ void ensureSickNoteCreatedUpdatedDeleted() { assertThat(absences) .hasSize(1) .containsOnly(Map.entry(now, List.of(expected))); + + final InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(tenantId); + inOrder.verify(tenantContextHolder).clear(); }); // UPDATE to period of two days @@ -139,6 +153,10 @@ void ensureSickNoteCreatedUpdatedDeleted() { assertThat(absences) .hasSize(2) .containsOnly(Map.entry(now, List.of(expected)), Map.entry(now.plusDays(1), List.of(expected))); + + final InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(tenantId); + inOrder.verify(tenantContextHolder).clear(); }); // CANCEL sick note absence @@ -160,7 +178,12 @@ void ensureSickNoteCreatedUpdatedDeleted() { assertThat(absences) .hasSize(1) .containsOnly(Map.entry(now, List.of())); + + final InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(tenantId); + inOrder.verify(tenantContextHolder).clear(); }); + } @Test @@ -173,7 +196,10 @@ void ensureConvertedToApplicationDeletesSickNote() { final SickNotePersonDTO boss = SickNotePersonDTO.builder().personId(1L).username("boss").build(); final UserId userId = new UserId("boss"); - final AbsenceWrite absence = new AbsenceWrite(new TenantId(TENANT_ID), 1L, userId, startOfDay, startOfDay, FULL, SICK); + final TenantId tenantId = new TenantId(TENANT_ID); + when(tenantContextHolder.getCurrentTenantId()).thenReturn(Optional.of(tenantId)); + + final AbsenceWrite absence = new AbsenceWrite(1L, userId, startOfDay, startOfDay, FULL, SICK); absenceWriteService.addAbsence(absence); // CANCEL sick note absence @@ -196,5 +222,9 @@ void ensureConvertedToApplicationDeletesSickNote() { .hasSize(1) .containsOnly(Map.entry(now, List.of())); }); + + final InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(tenantId); + inOrder.verify(tenantContextHolder).clear(); } } diff --git a/src/test/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/vacationtype/VacationTypeHandlerRabbitmqTest.java b/src/test/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/vacationtype/VacationTypeHandlerRabbitmqTest.java index 105117353..340e31cfa 100644 --- a/src/test/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/vacationtype/VacationTypeHandlerRabbitmqTest.java +++ b/src/test/java/de/focusshift/zeiterfassung/integration/urlaubsverwaltung/vacationtype/VacationTypeHandlerRabbitmqTest.java @@ -6,14 +6,18 @@ import de.focusshift.zeiterfassung.absence.AbsenceTypeCategory; import de.focusshift.zeiterfassung.absence.AbsenceTypeService; import de.focusshift.zeiterfassung.absence.AbsenceTypeUpdate; +import de.focusshift.zeiterfassung.tenancy.tenant.TenantContextHolder; import de.focusshift.zeiterfassung.tenancy.tenant.TenantId; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Answers; +import org.mockito.InOrder; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Locale; @@ -27,18 +31,23 @@ @ExtendWith(MockitoExtension.class) class VacationTypeHandlerRabbitmqTest { + private static final TenantId TENANT_ID = new TenantId("tenant"); + @InjectMocks private VacationTypeHandlerRabbitmq sut; @Mock private AbsenceTypeService absenceTypeService; + @Mock(answer = Answers.CALLS_REAL_METHODS) + private TenantContextHolder tenantContextHolder; + @Test void ensureAbsenceTypeUpdateIsIgnoredWhenCategoryCannotBeMapped() { final VacationTypeUpdatedEventDTO eventDto = VacationTypeUpdatedEventDTO.builder() .id(UUID.randomUUID()) - .tenantId("tenant") + .tenantId(TENANT_ID.tenantId()) .sourceId(42L) .category("unknown") .color("VIOLET") @@ -47,6 +56,10 @@ void ensureAbsenceTypeUpdateIsIgnoredWhenCategoryCannotBeMapped() { sut.on(eventDto); verifyNoInteractions(absenceTypeService); + + final InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(TENANT_ID); + inOrder.verify(tenantContextHolder).clear(); } @Test @@ -54,7 +67,7 @@ void ensureAbsenceTypeUpdateIsIgnoredWhenColorCannotBeMapped() { final VacationTypeUpdatedEventDTO eventDto = VacationTypeUpdatedEventDTO.builder() .id(UUID.randomUUID()) - .tenantId("tenant") + .tenantId(TENANT_ID.tenantId()) .sourceId(42L) .category("OTHER") .color("unknown") @@ -63,6 +76,10 @@ void ensureAbsenceTypeUpdateIsIgnoredWhenColorCannotBeMapped() { sut.on(eventDto); verifyNoInteractions(absenceTypeService); + + final InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(TENANT_ID); + inOrder.verify(tenantContextHolder).clear(); } static Stream categoryColorPermutation() { @@ -80,7 +97,7 @@ void ensureAbsenceTypeUpdateImpl(AbsenceTypeCategory category, AbsenceColor colo final VacationTypeUpdatedEventDTO eventDto = VacationTypeUpdatedEventDTO.builder() .id(UUID.randomUUID()) - .tenantId("tenant") + .tenantId(TENANT_ID.tenantId()) .sourceId(42L) .category(category.name()) .color(color.name()) @@ -90,11 +107,14 @@ void ensureAbsenceTypeUpdateImpl(AbsenceTypeCategory category, AbsenceColor colo sut.on(eventDto); verify(absenceTypeService).updateAbsenceType(new AbsenceTypeUpdate( - new TenantId("tenant"), 42L, category, color, labels )); + + final InOrder inOrder = Mockito.inOrder(tenantContextHolder); + inOrder.verify(tenantContextHolder).setTenantId(TENANT_ID); + inOrder.verify(tenantContextHolder).clear(); } } diff --git a/src/test/java/de/focusshift/zeiterfassung/tenancy/user/TenantUserCreatorAndUpdaterTest.java b/src/test/java/de/focusshift/zeiterfassung/tenancy/user/TenantUserCreatorAndUpdaterTest.java index 4a264edcc..af8498670 100644 --- a/src/test/java/de/focusshift/zeiterfassung/tenancy/user/TenantUserCreatorAndUpdaterTest.java +++ b/src/test/java/de/focusshift/zeiterfassung/tenancy/user/TenantUserCreatorAndUpdaterTest.java @@ -5,6 +5,7 @@ import de.focusshift.zeiterfassung.user.UserId; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; import org.mockito.InOrder; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -38,7 +39,7 @@ class TenantUserCreatorAndUpdaterTest { @InjectMocks private TenantUserCreatorAndUpdater sut; - @Mock + @Mock(answer = Answers.CALLS_REAL_METHODS) private TenantContextHolder tenantContextHolder; @Mock private TenantUserService tenantUserService; @@ -121,7 +122,7 @@ void ensureNoTenantUserServiceInteractionForInvalidTenantId() { verifyNoInteractions(tenantUserService); verify(tenantContextHolder, never()).setTenantId(any()); - verify(tenantContextHolder).clear(); + verify(tenantContextHolder, never()).clear(); } private static class OAuth2AuthenticationTokenWithoutClientRegistrationId extends OAuth2AuthenticationToken {