getSupportedEvents()
+ {
+ return EVENTS;
+ }
+}
diff --git a/application-licensing-licensor/application-licensing-licensor-api/src/main/resources/META-INF/components.txt b/application-licensing-licensor/application-licensing-licensor-api/src/main/resources/META-INF/components.txt
index 8c0e376e..d19ece8d 100644
--- a/application-licensing-licensor/application-licensing-licensor-api/src/main/resources/META-INF/components.txt
+++ b/application-licensing-licensor/application-licensing-licensor-api/src/main/resources/META-INF/components.txt
@@ -19,8 +19,12 @@ com.xwiki.licensing.internal.helpers.LicensingOwnerConfigurationSource
com.xwiki.licensing.internal.upgrades.UpgradeExtensionHandler
com.xwiki.licensing.internal.upgrades.AutomaticUpgradesConfigurationSource
com.xwiki.licensing.internal.upgrades.LicensedExtensionUpgradeManager
+com.xwiki.licensing.internal.upgrades.NewExtensionVersionAvailableManager
+com.xwiki.licensing.internal.upgrades.NewVersionNotificationManager
com.xwiki.licensing.internal.upgrades.LicensingSchedulerListener
com.xwiki.licensing.internal.upgrades.notifications.ExtensionAutoUpgradedEventDescriptor
-com.xwiki.licensing.internal.upgrades.notifications.ExtensionAutoUpgradedEventConverter
+com.xwiki.licensing.internal.upgrades.notifications.ExtensionEventConverter
com.xwiki.licensing.internal.upgrades.notifications.ExtensionAutoUpgradedEventDisplayer
-com.xwiki.licensing.internal.upgrades.notifications.ExtensionAutoUpgradedFailedEventDescriptor
\ No newline at end of file
+com.xwiki.licensing.internal.upgrades.notifications.ExtensionAutoUpgradedFailedEventDescriptor
+com.xwiki.licensing.internal.upgrades.notifications.newVersion.NewExtensionVersionAvailableEventDescriptor
+com.xwiki.licensing.internal.upgrades.notifications.newVersion.NewExtensionVersionAvailableEventDisplayer
\ No newline at end of file
diff --git a/application-licensing-licensor/application-licensing-licensor-api/src/main/resources/templates/newVersionAvailable.vm b/application-licensing-licensor/application-licensing-licensor-api/src/main/resources/templates/newVersionAvailable.vm
new file mode 100644
index 00000000..2035e40b
--- /dev/null
+++ b/application-licensing-licensor/application-licensing-licensor-api/src/main/resources/templates/newVersionAvailable.vm
@@ -0,0 +1,66 @@
+#template('notification/macros.vm')
+
+#set ($mainIcon = "bell")
+#set ($smallIcon = "arrow_up")
+#set ($compositeEventDate = $escapetool.xml($datetool.whenIs($event.dates.get(0))))
+
+#macro (getExtensionUpgradeURL $extensionInfo)
+ #set ($extensionNamespace =
+ "#if ($extensionInfo.namespace == 'root')$xcontext.mainWikiName#{else}$extensionInfo.namespace#end")
+ #set ($queryParams = $escapetool.url({
+ 'section': 'XWiki.Extensions',
+ 'extensionId': $event.getApplication(),
+ 'extensionVersion': $extensionInfo.version,
+ 'extensionNamespace': $extensionNamespace
+ }))
+ $xwiki.getURL($services.model.createDocumentReference($xcontext.mainWikiName, 'XWiki', 'XWikiPreferences'),
+ 'admin', $queryParams)##
+#end
+
+#macro (displayEventDetails $event)
+
+
+ $escapetool.xml($event.user.name)
+
+ ## The event body contains information about the extension name, version and targeted namespace.
+ #set ($extensionInfo = $jsontool.fromString($event.getBody()))
+
+
+ $extensionInfo.extensionName - $extensionInfo.namespace - $extensionInfo.version
+
+
+ $escapetool.xml($datetool.whenIs($event.date))
+
+#end
+
+#define ($content)
+ #set ($document = $xwiki.getDocument($event.document))
+
+ ## Notifications are rendered in the context of their wiki, so we need to use the XWikiContext#originalWikiId
+ ## to actually know where the request comes from.
+ #if ($xcontext.getContext().getOriginalWikiId() != $event.document.wikiReference.name)
+ ($services.wiki.getById($event.document.wikiReference.name).prettyName)
+ #end
+
+
+
+ #if ($event.events.size() == 1)
+ $services.localization.render("licensor.notification.newVersion.singular")
+ #else
+ $services.localization.render("licensor.notification.newVersion.plural")
+ #end
+
+
$compositeEventDate
+
+#end
+
+#define ($details)
+ #define($rows)
+ #foreach($thisEvent in $event.events)
+ #displayEventDetails($thisEvent)
+ #end
+ #end
+ #displayNotificationEventDetailsSkeletons($events.size(), $rows)
+#end
+
+#displayNotificationEventSkeleton($mainIcon $smallIcon $content $details)
\ No newline at end of file
diff --git a/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/DefaultLicensingConfigurationTest.java b/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/DefaultLicensingConfigurationTest.java
index ef736628..76d0ed38 100644
--- a/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/DefaultLicensingConfigurationTest.java
+++ b/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/DefaultLicensingConfigurationTest.java
@@ -40,6 +40,8 @@
import org.xwiki.test.junit5.mockito.InjectMockComponents;
import org.xwiki.test.junit5.mockito.MockComponent;
+import com.xpn.xwiki.objects.BaseObject;
+
@ComponentTest
class DefaultLicensingConfigurationTest
{
diff --git a/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/upgrades/NewExtensionVersionAvailableManagerTest.java b/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/upgrades/NewExtensionVersionAvailableManagerTest.java
new file mode 100644
index 00000000..26d09a6e
--- /dev/null
+++ b/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/upgrades/NewExtensionVersionAvailableManagerTest.java
@@ -0,0 +1,198 @@
+/*
+ * See the NOTICE file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package com.xwiki.licensing.internal.upgrades;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.xwiki.extension.ExtensionId;
+import org.xwiki.extension.InstalledExtension;
+import org.xwiki.extension.repository.InstalledExtensionRepository;
+import org.xwiki.extension.version.Version;
+import org.xwiki.extension.version.internal.DefaultVersion;
+import org.xwiki.observation.ObservationManager;
+import org.xwiki.test.junit5.mockito.ComponentTest;
+import org.xwiki.test.junit5.mockito.InjectMockComponents;
+import org.xwiki.test.junit5.mockito.MockComponent;
+
+import com.xwiki.licensing.LicensedExtensionManager;
+import com.xwiki.licensing.LicensingConfiguration;
+import com.xwiki.licensing.internal.upgrades.notifications.newVersion.NewExtensionVersionAvailableEvent;
+
+/**
+ * Unit tests for {@link NewExtensionVersionAvailableManager}.
+ *
+ * @version $Id$
+ * @since 1.23
+ */
+@ComponentTest
+public class NewExtensionVersionAvailableManagerTest
+{
+ @InjectMockComponents
+ private NewExtensionVersionAvailableManager newVersionAvailableManager;
+
+ @MockComponent
+ private InstalledExtensionRepository installedRepository;
+
+ @MockComponent
+ private UpgradeExtensionHandler upgradeExtensionHandler;
+
+ @MockComponent
+ private LicensedExtensionManager licensedExtensionManager;
+
+ @MockComponent
+ private LicensingConfiguration licensingConfig;
+
+ @MockComponent
+ private ObservationManager observationManager;
+
+ @MockComponent
+ private NewVersionNotificationManager newVersionNotificationManager;
+
+ @Mock
+ private InstalledExtension installedExtension1;
+
+ @Mock
+ private InstalledExtension installedExtension2;
+
+ private ExtensionId extensionId1;
+
+ private ExtensionId extensionId2;
+
+ @BeforeEach
+ public void configure() throws Exception
+ {
+ this.extensionId1 = new ExtensionId("extensionId1", new DefaultVersion("1.0"));
+ this.extensionId2 = new ExtensionId("extensionId2", new DefaultVersion("2.0"));
+
+ when(this.installedExtension1.getName()).thenReturn("Application 1");
+ when(this.installedExtension1.getId()).thenReturn(extensionId1);
+ when(this.installedRepository.getInstalledExtension(this.extensionId1)).thenReturn(this.installedExtension1);
+
+ when(this.installedExtension2.getName()).thenReturn("Application 2");
+ when(this.installedExtension2.getId()).thenReturn(extensionId2);
+ when(this.installedRepository.getInstalledExtension(this.extensionId2)).thenReturn(this.installedExtension2);
+ }
+
+ @Test
+ void checkLicensedExtensionsAvailableVersionsWithMultipleExtensionsAndVersionsNotVerified() throws Exception
+ {
+ when(this.licensingConfig.getAutoUpgradeAllowList()).thenReturn(Collections.emptyList());
+ when(this.licensedExtensionManager.getLicensedExtensions())
+ .thenReturn(Arrays.asList(this.extensionId1, this.extensionId2));
+
+ String namespace = "wiki:test";
+ when(this.installedExtension1.getNamespaces()).thenReturn(Collections.singletonList(namespace));
+ when(this.installedRepository.getInstalledExtension(this.extensionId1.getId(), namespace))
+ .thenReturn(this.installedExtension1);
+
+ when(this.installedExtension2.getNamespaces()).thenReturn(null);
+ when(this.installedRepository.getInstalledExtension(this.extensionId2.getId(), null))
+ .thenReturn(this.installedExtension2);
+
+ when(this.upgradeExtensionHandler.getInstallableVersions(extensionId1))
+ .thenReturn(Collections.singletonList((Version) new DefaultVersion("2.1")));
+ when(this.upgradeExtensionHandler.getInstallableVersions(extensionId2))
+ .thenReturn(Arrays.asList((Version) new DefaultVersion("3.1"), (Version) new DefaultVersion("2.1")));
+ when(this.newVersionNotificationManager.isNotificationAlreadySent(this.extensionId1.getId(), namespace,
+ "2.1")).thenReturn(false);
+ when(this.newVersionNotificationManager.isNotificationAlreadySent(this.extensionId2.getId(), "root",
+ "3.1")).thenReturn(false);
+
+ this.newVersionAvailableManager.checkLicensedExtensionsAvailableVersions();
+
+ verify(this.observationManager, times(1)).notify(any(NewExtensionVersionAvailableEvent.class),
+ eq(this.extensionId1.getId()),
+ eq("{\"extensionName\":\"Application 1\",\"namespace\":\"wiki:test\",\"version\":\"2.1\"}"));
+ verify(this.observationManager, times(1)).notify(any(NewExtensionVersionAvailableEvent.class),
+ eq(this.extensionId2.getId()),
+ eq("{\"extensionName\":\"Application 2\",\"namespace\":\"root\",\"version\":\"3.1\"}"));
+ }
+
+ @Test
+ void checkLicensedExtensionsAvailableVersionsWithVerifiedVersions() throws Exception
+ {
+ when(this.licensingConfig.getAutoUpgradeAllowList()).thenReturn(Collections.emptyList());
+ when(this.licensedExtensionManager.getLicensedExtensions())
+ .thenReturn(Arrays.asList(this.extensionId1, this.extensionId2));
+
+ String namespace = "wiki:test";
+ when(this.installedExtension1.getNamespaces()).thenReturn(Collections.singletonList(namespace));
+ when(this.installedRepository.getInstalledExtension(this.extensionId1.getId(), namespace))
+ .thenReturn(this.installedExtension1);
+
+ when(this.installedExtension2.getNamespaces()).thenReturn(null);
+ when(this.installedRepository.getInstalledExtension(this.extensionId2.getId(), null))
+ .thenReturn(this.installedExtension2);
+
+ when(this.upgradeExtensionHandler.getInstallableVersions(extensionId1))
+ .thenReturn(Arrays.asList((Version) new DefaultVersion("2.2"), (Version) new DefaultVersion("2.1")));
+ when(this.upgradeExtensionHandler.getInstallableVersions(extensionId2))
+ .thenReturn(Arrays.asList((Version) new DefaultVersion("3.1"), (Version) new DefaultVersion("3.0")));
+
+ when(this.newVersionNotificationManager.isNotificationAlreadySent(this.extensionId1.getId(), namespace,
+ "2.2")).thenReturn(true);
+ when(this.newVersionNotificationManager.isNotificationAlreadySent(this.extensionId2.getId(), null,
+ "3.0")).thenReturn(true);
+
+ this.newVersionAvailableManager.checkLicensedExtensionsAvailableVersions();
+
+ verify(this.observationManager, never()).notify(any(NewExtensionVersionAvailableEvent.class),
+ eq(this.extensionId1.getId()), any(String.class));
+ verify(this.observationManager, times(1)).notify(any(NewExtensionVersionAvailableEvent.class),
+ eq(this.extensionId2.getId()),
+ eq("{\"extensionName\":\"Application 2\",\"namespace\":\"root\",\"version\":\"3.1\"}"));
+ verify(this.observationManager, never()).notify(any(NewExtensionVersionAvailableEvent.class),
+ eq(this.extensionId2.getId()),
+ eq("{\"extensionName\":\"Application 2\",\"namespace\":\"root\",\"version\":\"3.0\"}"));
+ }
+
+ @Test
+ void checkLicensedExtensionsAvailableVersionsWithoutNewVersions() throws Exception
+ {
+ when(this.licensingConfig.getAutoUpgradeAllowList()).thenReturn(
+ Collections.singletonList(this.extensionId2.getId()));
+ when(this.licensedExtensionManager.getLicensedExtensions())
+ .thenReturn(Arrays.asList(this.extensionId1, this.extensionId2));
+
+ String namespace = "wiki:test";
+ when(this.installedExtension1.getNamespaces()).thenReturn(Collections.singletonList(namespace));
+ when(this.installedRepository.getInstalledExtension(this.extensionId1.getId(), namespace))
+ .thenReturn(this.installedExtension1);
+
+ when(this.upgradeExtensionHandler.getInstallableVersions(extensionId1)).thenReturn(Collections.emptyList());
+
+ this.newVersionAvailableManager.checkLicensedExtensionsAvailableVersions();
+
+ verify(this.observationManager, never()).notify(any(NewExtensionVersionAvailableEvent.class),
+ eq(this.extensionId1), any(String.class));
+ verify(this.installedRepository, never()).getInstalledExtension(this.extensionId2);
+ }
+}
diff --git a/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/upgrades/NewVersionNotificationManagerTest.java b/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/upgrades/NewVersionNotificationManagerTest.java
new file mode 100644
index 00000000..8f1b57c8
--- /dev/null
+++ b/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/upgrades/NewVersionNotificationManagerTest.java
@@ -0,0 +1,188 @@
+/*
+ * See the NOTICE file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package com.xwiki.licensing.internal.upgrades;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import javax.inject.Provider;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.slf4j.Logger;
+import org.xwiki.test.junit5.mockito.ComponentTest;
+import org.xwiki.test.junit5.mockito.InjectMockComponents;
+import org.xwiki.test.junit5.mockito.MockComponent;
+
+import com.xpn.xwiki.XWiki;
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.doc.XWikiDocument;
+import com.xpn.xwiki.objects.BaseObject;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Unit tests for {@link NewVersionNotificationManager}.
+ *
+ * @version $Id$
+ * @since 1.23
+ */
+@ComponentTest
+class NewVersionNotificationManagerTest
+{
+ @InjectMockComponents
+ private NewVersionNotificationManager newVersionNotificationManager;
+
+ @MockComponent
+ private Provider xcontextProvider;
+
+ @MockComponent
+ private Logger logger;
+
+ @Mock
+ private XWikiContext xcontext;
+
+ @Mock
+ private XWiki xwiki;
+
+ @Mock
+ private XWikiDocument licensingDoc;
+
+ @Mock
+ private BaseObject newVersionObject1;
+
+ @Mock
+ private BaseObject newVersionObject2;
+
+ @BeforeEach
+ void configure() throws Exception
+ {
+ when(this.xcontextProvider.get()).thenReturn(xcontext);
+ when(this.xcontext.getWiki()).thenReturn(xwiki);
+ when(this.xwiki.getDocument(NewVersionNotificationManager.LICENSING_CONFIG_DOC, xcontext)).thenReturn(
+ licensingDoc);
+ }
+
+ @Test
+ void isNotificationAlreadySent() throws Exception
+ {
+ when(this.licensingDoc.getXObjects(NewVersionNotificationManager.NEW_VERSION_NOTIFICATION_CLASS)).thenReturn(
+ Arrays.asList(newVersionObject1, newVersionObject2));
+
+ when(newVersionObject1.getStringValue(NewVersionNotificationManager.EXTENSION_ID)).thenReturn("extension1");
+ when(newVersionObject1.getStringValue(NewVersionNotificationManager.NAMESPACE)).thenReturn("root");
+ when(newVersionObject1.getStringValue(NewVersionNotificationManager.VERSION)).thenReturn("1.1");
+
+ when(newVersionObject2.getStringValue(NewVersionNotificationManager.EXTENSION_ID)).thenReturn("extension1");
+ when(newVersionObject2.getStringValue(NewVersionNotificationManager.NAMESPACE)).thenReturn("xwiki:test");
+ when(newVersionObject2.getStringValue(NewVersionNotificationManager.VERSION)).thenReturn("1.1");
+
+ assertTrue(this.newVersionNotificationManager.isNotificationAlreadySent("extension1", "root", "1.1"));
+ }
+
+ @Test
+ void isNotificationAlreadySentWithDifferentInfo() throws Exception
+ {
+ when(this.licensingDoc.getXObjects(NewVersionNotificationManager.NEW_VERSION_NOTIFICATION_CLASS)).thenReturn(
+ Arrays.asList(newVersionObject1, null, newVersionObject2));
+
+ when(newVersionObject1.getStringValue(NewVersionNotificationManager.EXTENSION_ID)).thenReturn("extension1");
+ when(newVersionObject1.getStringValue(NewVersionNotificationManager.NAMESPACE)).thenReturn("root");
+ when(newVersionObject1.getStringValue(NewVersionNotificationManager.VERSION)).thenReturn("1.0");
+
+ when(newVersionObject2.getStringValue(NewVersionNotificationManager.EXTENSION_ID)).thenReturn("extension1");
+ when(newVersionObject2.getStringValue(NewVersionNotificationManager.NAMESPACE)).thenReturn("xwiki:test");
+ when(newVersionObject2.getStringValue(NewVersionNotificationManager.VERSION)).thenReturn("1.1");
+
+ assertFalse(this.newVersionNotificationManager.isNotificationAlreadySent("extension1", "root", "1.1"));
+ }
+
+ @Test
+ void markNotificationAsSent() throws Exception
+ {
+ when(this.licensingDoc.getXObjects(NewVersionNotificationManager.NEW_VERSION_NOTIFICATION_CLASS)).thenReturn(
+ null);
+
+ when(this.licensingDoc.createXObject(NewVersionNotificationManager.NEW_VERSION_NOTIFICATION_CLASS,
+ xcontext)).thenReturn(0);
+ when(this.licensingDoc.getXObject(NewVersionNotificationManager.NEW_VERSION_NOTIFICATION_CLASS, 0)).thenReturn(
+ this.newVersionObject1);
+
+ this.newVersionNotificationManager.markNotificationAsSent("extension1", "root", "2.1");
+
+ verify(this.newVersionObject1, times(1)).setStringValue(NewVersionNotificationManager.EXTENSION_ID,
+ "extension1");
+ verify(this.newVersionObject1, times(1)).setStringValue(NewVersionNotificationManager.NAMESPACE, "root");
+ verify(this.newVersionObject1, times(1)).setStringValue(NewVersionNotificationManager.VERSION, "2.1");
+ verify(this.xwiki, times(1)).saveDocument(any(XWikiDocument.class),
+ eq("Added NewVersionNotificationClass object for extension1."), any(XWikiContext.class));
+ }
+
+ @Test
+ void markNotificationAsSentOnSameNamespace() throws Exception
+ {
+ when(this.licensingDoc.getXObjects(NewVersionNotificationManager.NEW_VERSION_NOTIFICATION_CLASS)).thenReturn(
+ Collections.singletonList(newVersionObject1));
+
+ when(newVersionObject1.getStringValue(NewVersionNotificationManager.EXTENSION_ID)).thenReturn("extension1");
+ when(newVersionObject1.getStringValue(NewVersionNotificationManager.NAMESPACE)).thenReturn("root");
+ when(newVersionObject1.getStringValue(NewVersionNotificationManager.VERSION)).thenReturn("1.0");
+
+ this.newVersionNotificationManager.markNotificationAsSent("extension1", "root", "1.1");
+
+ verify(this.newVersionObject1, times(1)).setStringValue(NewVersionNotificationManager.VERSION, "1.1");
+ verify(this.xwiki, times(1)).saveDocument(any(XWikiDocument.class),
+ eq("Added NewVersionNotificationClass object for extension1."), any(XWikiContext.class));
+ }
+
+ @Test
+ void markNotificationAsSentOnDifferentNamespace() throws Exception
+ {
+ when(this.licensingDoc.getXObjects(NewVersionNotificationManager.NEW_VERSION_NOTIFICATION_CLASS)).thenReturn(
+ Arrays.asList(newVersionObject1, null));
+
+ when(newVersionObject1.getStringValue(NewVersionNotificationManager.EXTENSION_ID)).thenReturn("extension1");
+ when(newVersionObject1.getStringValue(NewVersionNotificationManager.NAMESPACE)).thenReturn("root");
+ when(newVersionObject1.getStringValue(NewVersionNotificationManager.VERSION)).thenReturn("1.0");
+
+ when(this.licensingDoc.createXObject(NewVersionNotificationManager.NEW_VERSION_NOTIFICATION_CLASS,
+ xcontext)).thenReturn(1);
+ when(this.licensingDoc.getXObject(NewVersionNotificationManager.NEW_VERSION_NOTIFICATION_CLASS, 1)).thenReturn(
+ this.newVersionObject2);
+
+ this.newVersionNotificationManager.markNotificationAsSent("extension1", "xwiki:test", "1.1");
+
+ verify(this.newVersionObject1, never()).setStringValue(NewVersionNotificationManager.VERSION, "1.1");
+ verify(this.newVersionObject2, times(1)).setStringValue(NewVersionNotificationManager.EXTENSION_ID,
+ "extension1");
+ verify(this.newVersionObject2, times(1)).setStringValue(NewVersionNotificationManager.NAMESPACE, "xwiki:test");
+ verify(this.newVersionObject2, times(1)).setStringValue(NewVersionNotificationManager.VERSION, "1.1");
+ verify(this.xwiki, times(1)).saveDocument(any(XWikiDocument.class),
+ eq("Added NewVersionNotificationClass object for extension1."), any(XWikiContext.class));
+ }
+}
diff --git a/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/upgrades/notifications/ExtensionAutoUpgradedEventConverterTest.java b/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/upgrades/notifications/ExtensionEventConverterTest.java
similarity index 69%
rename from application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/upgrades/notifications/ExtensionAutoUpgradedEventConverterTest.java
rename to application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/upgrades/notifications/ExtensionEventConverterTest.java
index 38528c49..cf391465 100644
--- a/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/upgrades/notifications/ExtensionAutoUpgradedEventConverterTest.java
+++ b/application-licensing-licensor/application-licensing-licensor-api/src/test/java/com/xwiki/licensing/internal/upgrades/notifications/ExtensionEventConverterTest.java
@@ -19,40 +19,34 @@
*/
package com.xwiki.licensing.internal.upgrades.notifications;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.xwiki.eventstream.Event;
import org.xwiki.eventstream.RecordableEvent;
import org.xwiki.eventstream.RecordableEventConverter;
-import org.xwiki.test.mockito.MockitoComponentMockingRule;
+import org.xwiki.test.junit5.mockito.ComponentTest;
+import org.xwiki.test.junit5.mockito.InjectMockComponents;
+import org.xwiki.test.junit5.mockito.MockComponent;
/**
- * Unit tests for {@link ExtensionAutoUpgradedEventConverter}.
+ * Unit tests for {@link ExtensionEventConverter}.
*
* @version $Id$
* @since 1.17
*/
-public class ExtensionAutoUpgradedEventConverterTest
+@ComponentTest
+class ExtensionEventConverterTest
{
- @Rule
- public MockitoComponentMockingRule mocker =
- new MockitoComponentMockingRule<>(ExtensionAutoUpgradedEventConverter.class);
+ @InjectMockComponents
+ ExtensionEventConverter extensionEventConverter;
+ @MockComponent
private RecordableEventConverter defaultConverter;
-
- @Before
- public void configure() throws Exception
- {
- this.defaultConverter = this.mocker.getInstance(RecordableEventConverter.class);
- }
-
@Test
public void convert() throws Exception
{
@@ -62,7 +56,7 @@ public void convert() throws Exception
when(this.defaultConverter.convert(event, null, message)).thenReturn(convertedEvent);
- assertEquals(convertedEvent, this.mocker.getComponentUnderTest().convert(event, null, message));
+ assertEquals(convertedEvent, this.extensionEventConverter.convert(event, null, message));
verify(convertedEvent).setBody(message);
}
diff --git a/application-licensing-licensor/application-licensing-licensor-ui/src/main/resources/Licenses/Code/NewExtensionVersionAvailableJob.xml b/application-licensing-licensor/application-licensing-licensor-ui/src/main/resources/Licenses/Code/NewExtensionVersionAvailableJob.xml
new file mode 100644
index 00000000..878367c1
--- /dev/null
+++ b/application-licensing-licensor/application-licensing-licensor-ui/src/main/resources/Licenses/Code/NewExtensionVersionAvailableJob.xml
@@ -0,0 +1,168 @@
+
+
+
+
+
+ Licenses.Code
+ NewExtensionVersionAvailableJob
+
+
+ 0
+ xwiki:XWiki.Admin
+ Licenses.Code.WebHome
+ xwiki:XWiki.Admin
+ xwiki:XWiki.Admin
+ 1.1
+ NewExtensionVersionAvailableJob
+
+ false
+ xwiki/2.1
+ false
+
+
+ Licenses.Code.NewExtensionVersionAvailableJob
+ 0
+ XWiki.SchedulerJobClass
+ 5bdc26a3-8be2-421d-9a2f-e3baaa6ff4b1
+
+ XWiki.SchedulerJobClass
+
+
+
+
+
+
+
+
+ 0
+ contextDatabase
+ 9
+ Job execution context database
+ 30
+ 0
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+ 0
+ contextLang
+ 8
+ Job execution context lang
+ 30
+ 0
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+ 0
+ contextUser
+ 7
+ Job execution context user
+ 30
+ 0
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+ 0
+ cron
+ 5
+ Cron Expression
+ 30
+ 0
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+ 0
+ jobClass
+ 3
+ Job Class
+ 60
+ 0
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+ 0
+ jobDescription
+ 2
+ Job Description
+ 10
+ 45
+ 0
+ com.xpn.xwiki.objects.classes.TextAreaClass
+
+
+ 0
+ jobName
+ 1
+ Job Name
+ 60
+ 0
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+
+ 0
+ status
+ 4
+ Status
+ 30
+ 0
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+
+ xwiki
+
+
+ en
+
+
+ XWiki.superadmin
+
+
+ 0 0 0 ? * SUN
+
+
+ com.xwiki.licensing.internal.upgrades.NewExtensionVersionAvailableJob
+
+
+
+
+
+ New version available
+
+
+
+
+
+ Normal
+
+
+
diff --git a/application-licensing-licensor/application-licensing-licensor-ui/src/main/resources/Licenses/Code/NewVersionNotificationClass.xml b/application-licensing-licensor/application-licensing-licensor-ui/src/main/resources/Licenses/Code/NewVersionNotificationClass.xml
new file mode 100644
index 00000000..49bbc15d
--- /dev/null
+++ b/application-licensing-licensor/application-licensing-licensor-ui/src/main/resources/Licenses/Code/NewVersionNotificationClass.xml
@@ -0,0 +1,136 @@
+
+
+
+
+
+ Licenses.Code
+ NewVersionNotificationClass
+
+
+ 0
+ xwiki:XWiki.Admin
+ WebHome
+ xwiki:XWiki.Admin
+ xwiki:XWiki.Admin
+ 1.1
+ NewVersionNotificationClass
+
+ false
+ xwiki/2.1
+ true
+
+
+ Licenses.Code.NewVersionNotificationClass
+
+
+
+
+
+
+
+
+
+ 0
+
+ extensionId
+ 1
+ 1
+ extensionId
+ 30
+ 0
+
+
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+
+ 0
+
+ namespace
+ 2
+ 1
+ namespace
+ 30
+ 0
+
+
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+
+ 0
+
+ version
+ 3
+ 1
+ version
+ 30
+ 0
+
+
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+
+ Licenses.Code.NewVersionNotificationClass
+ 0
+ XWiki.DocumentSheetBinding
+ ebba70d3-6049-4a58-a8e2-d8ffd899d7fa
+
+ XWiki.DocumentSheetBinding
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+ input
+
+
+ 0
+ sheet
+ 1
+ 1
+ Sheet
+ 0
+
+
+ 30
+ none
+
+ 0
+
+
+
+ com.xpn.xwiki.objects.classes.PageClass
+
+
+
+ XWiki.ClassSheet
+
+
+
diff --git a/application-licensing-licensor/application-licensing-licensor-ui/src/main/resources/Licenses/Code/Translations.xml b/application-licensing-licensor/application-licensing-licensor-ui/src/main/resources/Licenses/Code/Translations.xml
index 4f1475fd..6c855a2f 100644
--- a/application-licensing-licensor/application-licensing-licensor-ui/src/main/resources/Licenses/Code/Translations.xml
+++ b/application-licensing-licensor/application-licensing-licensor-ui/src/main/resources/Licenses/Code/Translations.xml
@@ -93,6 +93,10 @@ licensor.notification.autoUpgrade.failed.description=An extension failed to be u
licensor.notification.autoUpgrade.plural=Upgrade to the last compatible version has been attempted for multiple extensions
licensor.notification.autoUpgrade.singular=Upgrade to the last compatible version has been attempted for an extension
licensor.notification.autoUpgrade.type=Automatic upgrades
+licensor.notification.newVersion.description=A new version is available for a licensed extension. This can be disabled also by enabling automatic upgrades for a certain extension
+licensor.notification.newVersion.name=New extension version available
+licensor.notification.newVersion.plural=New versions available for multiple extensions
+licensor.notification.newVersion.singular=New version available for an extension
licensor.accessDenied=Only the administrators with programming rights are allowed to manage the licenses.
licensor.unavailableOnSubWiki=The licenses are managed from {0}the main wiki{1}.
licensor.updateLicenses.label=Check for License Updates