diff --git a/src/main/java/org/olat/resource/accesscontrol/AccessControlModule.java b/src/main/java/org/olat/resource/accesscontrol/AccessControlModule.java index 2d37b1ac9d133a513ee9ba926e0102924eb77367..4a940459a2a6ee29fcf0282a32c94045e2ea9001 100644 --- a/src/main/java/org/olat/resource/accesscontrol/AccessControlModule.java +++ b/src/main/java/org/olat/resource/accesscontrol/AccessControlModule.java @@ -35,6 +35,8 @@ import org.olat.resource.accesscontrol.manager.ACMethodDAO; import org.olat.resource.accesscontrol.method.AccessMethodHandler; import org.olat.resource.accesscontrol.model.FreeAccessMethod; import org.olat.resource.accesscontrol.model.TokenAccessMethod; +import org.olat.resource.accesscontrol.provider.auto.AdvanceOrder; +import org.olat.resource.accesscontrol.provider.auto.manager.AdvanceOrderDAO; import org.olat.resource.accesscontrol.provider.paypal.model.PaypalAccessMethod; import org.olat.resource.accesscontrol.provider.paypalcheckout.model.PaypalCheckoutAccessMethod; import org.springframework.beans.factory.annotation.Autowired; @@ -67,6 +69,8 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO private static final String PAYPAL_CHECKOUT_ENABLED = "method.paypal.checkout.enabled"; private static final String AUTO_ENABLED = "method.auto.enabled"; private static final String AUTO_EXTERNAL_REF_DELIMITER = "method.auto.external.ref.delimiter"; + private static final String AUTO_MULTI_BOOKING = "method.auto.multi.booking"; + private static final String AUTO_RESET_TO_PENDING = "method.auto.reset.to.pending"; @Value("${resource.accesscontrol.enabled:true}") private boolean enabled; @@ -78,6 +82,10 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO private boolean autoEnabled; @Value("${method.auto.externalRef.delimiter}") private String autoExternalRefDelimiter; + @Value("${method.auto.multi.booking}") + private boolean autoMultiBooking; + @Value("${method.auto.reset.to.pending}") + private boolean autoResetToPending; @Value("${method.token.enabled:true}") private boolean tokenEnabled; @Value("${method.paypal.enabled:false}") @@ -95,6 +103,8 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO private DB dbInstance; private final ACMethodDAO acMethodManager; @Autowired + private AdvanceOrderDAO advanceOrderDao; + @Autowired private List<AccessMethodHandler> methodHandlers; @Autowired @@ -108,6 +118,7 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO //module enabled/disabled updateProperties(); updateAccessMethods(); + resetResetAutoStatusToPending(); log.info("Access control module is enabled: " + Boolean.toString(enabled)); } @@ -152,6 +163,16 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO autoExternalRefDelimiter = autoExternalRefDelimiterObj; } + String autoMultiBookingObj = getStringPropertyValue(AUTO_MULTI_BOOKING, true); + if(StringHelper.containsNonWhitespace(autoMultiBookingObj)) { + autoMultiBooking = "true".equals(autoMultiBookingObj); + } + + String autoResetToPendingObj = getStringPropertyValue(AUTO_RESET_TO_PENDING, true); + if(StringHelper.containsNonWhitespace(autoResetToPendingObj)) { + autoResetToPending = "true".equals(autoResetToPendingObj); + } + String homeEnabledObj = getStringPropertyValue(AC_HOME_ENABLED, true); if(StringHelper.containsNonWhitespace(homeEnabledObj)) { homeOverviewEnabled = "true".equals(homeEnabledObj); @@ -186,6 +207,13 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO dbInstance.commitAndCloseSession(); } + private void resetResetAutoStatusToPending() { + if (autoResetToPending) { + advanceOrderDao.updateAllStatus(AdvanceOrder.Status.PENDING); + dbInstance.commitAndCloseSession(); + } + } + @Override public boolean isEnabled() { return enabled; @@ -237,6 +265,15 @@ public class AccessControlModule extends AbstractSpringModule implements ConfigO setStringProperty(AUTO_EXTERNAL_REF_DELIMITER, autoExternalRefDelimiter, true); } + public boolean isAutoMultiBooking() { + return autoMultiBooking; + } + + public void setAutoMultiBooking(boolean autoMultiBooking) { + this.autoMultiBooking = autoMultiBooking; + setStringProperty(AUTO_MULTI_BOOKING, Boolean.toString(autoMultiBooking), true); + } + public boolean isPaypalEnabled() { return paypalEnabled; } diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAO.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAO.java index 749357b4be7f42b1105e481d914709d6a070c7a0..ea2fd7c875dcc5c76f3e63e78c5dc319cc295dad 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAO.java +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAO.java @@ -28,6 +28,7 @@ import java.util.stream.Collectors; import javax.persistence.TypedQuery; import org.olat.core.commons.persistence.DB; +import org.olat.core.commons.persistence.QueryBuilder; import org.olat.core.id.Identity; import org.olat.core.util.StringHelper; import org.olat.resource.accesscontrol.model.AccessMethod; @@ -45,7 +46,7 @@ import org.springframework.stereotype.Service; * */ @Service -class AdvanceOrderDAO { +public class AdvanceOrderDAO { @Autowired private DB dbInstance; @@ -151,15 +152,32 @@ class AdvanceOrderDAO { return advanceOrder; } - AdvanceOrder accomplishAndSave(AdvanceOrder advanceOrder) { + AdvanceOrder accomplishAndSave(AdvanceOrder advanceOrder, boolean multiOrder) { if (advanceOrder == null) return advanceOrder; - advanceOrder.setStatus(Status.DONE); + if (!multiOrder) { + advanceOrder.setStatus(Status.DONE); + } advanceOrder.setStatusModified(new Date()); advanceOrder = save(advanceOrder); return advanceOrder; } + + public void updateAllStatus(Status status) { + QueryBuilder sb = new QueryBuilder(); + sb.append("update advanceOrder advanceOrder"); + sb.append(" set advanceOrder.status = :status"); + sb.append(" , advanceOrder.lastModified = :lastModified"); + sb.and().append(" advanceOrder.status <> :status"); + + dbInstance.getCurrentEntityManager() + .createQuery(sb.toString()) + .setParameter("status", status) + .setParameter("lastModified", new Date()) + .executeUpdate(); + } + static final class IdentifierKeyValue { diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImpl.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImpl.java index 03a3d2bbd911a69d75fc84af3fe4e677bce638ae..192f0ddb1342bf5933a2193287af1503385d041b 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImpl.java +++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImpl.java @@ -166,7 +166,7 @@ public class AutoAccessManagerImpl implements AutoAccessManager, UserDataDeletab for (RepositoryEntry entry: entries) { grantAccessIfHasNoAccess(advanceOrder, entry); } - advanceOrderDAO.accomplishAndSave(advanceOrder); + advanceOrderDAO.accomplishAndSave(advanceOrder, acModule.isAutoMultiBooking()); } } diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties index aa3019de4ccffdf38ae00e05414831984ad3cab8..8197f15c22a31f0c1f4118440fdd7ac30fe8c385 100644 --- a/src/main/resources/serviceconfig/olat.properties +++ b/src/main/resources/serviceconfig/olat.properties @@ -1359,9 +1359,16 @@ method.auto.shib.shib= method.auto.shib.splitter.values=Semicolon method.auto.shib.splitter= -# External eeference may have many values separated by this delimiter. +# External reference may have many values separated by this delimiter. # If the value is not defined, no splitting is executed. method.auto.externalRef.delimiter= +# If multi booking is disabled (false), a auto booking is done once and never again. +# If multi booking is enabled (true), a auto booking is done multiple times per identifier +# value and user. If two courses have the same id, the user is booked to both. +method.auto.multi.booking=false +# If enabled (true), the status of all existing advance orders is reset to pending (on startup). +# That is, all advance orders are ready again to create a new booking. +method.auto.reset.to.pending=false ######################################## # Paypal Checkout diff --git a/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAOTest.java b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAOTest.java index a46364a4a54c4933e417eff4f3cb9d210b8fe5da..76a5c58fc00d074d88d513fa6131399558f206a0 100644 --- a/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAOTest.java +++ b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AdvanceOrderDAOTest.java @@ -27,6 +27,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import org.assertj.core.api.SoftAssertions; import org.junit.Before; import org.junit.Test; import org.olat.core.commons.persistence.DB; @@ -132,7 +133,7 @@ public class AdvanceOrderDAOTest extends OlatTestCase { AdvanceOrder advanceOrderWithOtherIdentity = sut.create(otherIdentity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); sut.save(advanceOrderWithOtherIdentity); AdvanceOrder doneAdvanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); - sut.accomplishAndSave(doneAdvanceOrder); + sut.accomplishAndSave(doneAdvanceOrder, false); dbInstance.commitAndCloseSession(); Collection<AdvanceOrder> pendingAdvanceOrders = sut.loadPendingAdvanceOrders(identity); @@ -204,7 +205,7 @@ public class AdvanceOrderDAOTest extends OlatTestCase { sut.save(aoPending); AdvanceOrder aoDone = sut.create(identity, IdentifierKey.externalId, IDENTIFIER_VALUE, freeMethod); sut.save(aoDone); - sut.accomplishAndSave(aoDone); + sut.accomplishAndSave(aoDone, false); Identity otherIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("otheruser"); AdvanceOrder aoOtherIdentity = sut.create(otherIdentity, IdentifierKey.internalId, "not matching", freeMethod); sut.save(aoOtherIdentity); @@ -234,21 +235,31 @@ public class AdvanceOrderDAOTest extends OlatTestCase { } @Test - public void shouldMarkAsDoneWhenAccomplished() { + public void shouldMarkAsDoneWhenAccomplishedAndSingleOrder() { AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); advanceOrder = sut.save(advanceOrder); - AdvanceOrder accomplishedAdvanceOrder = sut.accomplishAndSave(advanceOrder); + AdvanceOrder accomplishedAdvanceOrder = sut.accomplishAndSave(advanceOrder, false); assertThat(accomplishedAdvanceOrder.getStatus()).isEqualTo(Status.DONE); } + @Test + public void shouldMarkAsDoneWhenAccomplishedAndMultoOrder() { + AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + advanceOrder = sut.save(advanceOrder); + + AdvanceOrder accomplishedAdvanceOrder = sut.accomplishAndSave(advanceOrder, true); + + assertThat(accomplishedAdvanceOrder.getStatus()).isEqualTo(Status.PENDING); + } + @Test public void shouldNotMarkedAsDoneIfNoOffer() { AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); advanceOrder = sut.save(advanceOrder); - AdvanceOrder accomplishedAdvanceOrder = sut.accomplishAndSave(advanceOrder); + AdvanceOrder accomplishedAdvanceOrder = sut.accomplishAndSave(advanceOrder, false); assertThat(accomplishedAdvanceOrder.getStatus()).isEqualTo(advanceOrder.getStatus()); } @@ -309,4 +320,27 @@ public class AdvanceOrderDAOTest extends OlatTestCase { assertThat(exists).isFalse(); } + + @Test + public void shouldUpdateAllStatus() { + AdvanceOrder advanceOrder = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + advanceOrder.setStatus(AdvanceOrder.Status.DONE); + sut.save(advanceOrder); + AdvanceOrder advanceOrder2 = sut.create(identity, IDENTIFIER_KEY, IDENTIFIER_VALUE, freeMethod); + advanceOrder2.setStatus(AdvanceOrder.Status.DONE); + sut.save(advanceOrder2); + dbInstance.commitAndCloseSession(); + + Collection<AdvanceOrder> pending = sut.loadPendingAdvanceOrders(identity); + SoftAssertions softly = new SoftAssertions(); + softly.assertThat(pending).hasSize(0); + + sut.updateAllStatus(AdvanceOrder.Status.PENDING); + dbInstance.commitAndCloseSession(); + + pending = sut.loadPendingAdvanceOrders(identity); + softly.assertThat(pending).hasSize(2); + softly.assertAll(); + } + } diff --git a/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImplTest.java b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImplTest.java index 609f7ba3895d6ce424775a975f0f4830589c9a40..b051df83c02f5c140a77967f7a621f23a27fe2b2 100644 --- a/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImplTest.java +++ b/src/test/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImplTest.java @@ -270,7 +270,7 @@ public class AutoAccessManagerImplTest { sut.grantAccess(getPendingAdvanceOrders()); - verify(advanceOrderDaoMock, times(2)).accomplishAndSave(any(AdvanceOrder.class)); + verify(advanceOrderDaoMock, times(2)).accomplishAndSave(any(AdvanceOrder.class), false); } @Test