implemented first version of the notification plugin

This commit is contained in:
Francesco Mangiacrapa 2024-04-10 15:20:53 +02:00
parent 70ec76748e
commit 75a964ad09
12 changed files with 260 additions and 97 deletions

View File

@ -1,6 +1,9 @@
# Changelog for org.gcube.application.cms.notifications-plugins
## [v1.0.4-SNAPSHOT] - 2023-09-06
## [v1.0.5-SNAPSHOT] - 2023-09-06
- Implemented the notification-plugin [#26453]
## [v1.0.4] - 2023-09-06
- Using parent version range [#25572]
## [v1.0.3] - 2023-03-06

View File

@ -38,6 +38,7 @@ This plugin requires a configuration of type:
{
"type": "NOTIFICATION_TYPE",
"send": "true/false",
"placeholder_title": "PLACEHOLDER_TITLE_1",
"placeholder_msg": "PLACEHOLDER_MESSAGE_1",
"export_as_pdf": {
"placeholder_msg": "Export as PDF placeholder",
@ -55,6 +56,7 @@ This plugin requires a configuration of type:
{
"type": "NOTIFICATION_TYPE",
"send": "true/false",
"placeholder_title": "PLACEHOLDER_TITLE_2",
"placeholder_msg": "PLACEHOLDER_MESSAGE_2",
"export_as_pdf": {
"placeholder_msg": "Export as PDF placeholder",
@ -80,11 +82,11 @@ Where:
and
* `EVENT_NAME` (mandatory) can be: `PROJECT_CREATED`, `PROJECT_UPDATED`, `PROJECT_DELETED`, `LIFECYCLE_STEP_PERFORMED`.
* `USER_ROLE` (mandatory) can be: `Data-Manager`, `Data-Editor`, `Member"`, `Item_Creator`, `Any`;
* `EVENT_NAME` (mandatory) can be: `PROJECT_CREATED`, `PROJECT_UPDATED`, `PROJECT_DELETED`, `LIFECYCLE_STEP_PERFORMED`;
* `USER_ROLE` (mandatory) can be: `Data-Manager`, `Data-Editor`, `Member`, `Item_Creator`, `Any`;
* `TARGET_PHASE` (mandatory) can be: `DRAFT`, `Pending Approval`, `Published`, `Any`;
* `LAST_INVOKED_STEP` (optional) can be: `SUBMIT-FOR-REVIEW`, `APPROVE-SUBMITTED`, `REJECT-DRAFT`, `UNPUBLISH`;
* `NOTIFICATION_TYPE` (mandatory) can be: `USER_POST`, `VRE_POST`, `EMAIL`;
* `NOTIFICATION_TYPE` (mandatory) can be: `USER_NOTIFICATION`, `VRE_POST`, `EMAIL`;
## Change log

View File

@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>notifications-plugins</artifactId>
<version>1.0.4-SNAPSHOT</version>
<version>1.0.5-SNAPSHOT</version>
<name>gCube CMS - Notifications Plugins</name>
<parent>

View File

@ -11,7 +11,7 @@ public class NotificationGenericConstants {
};
public static enum NOTIFICATION_TYPE {
USER_POST, EMAIL, VRE_POST
USER_NOTIFICATION, EMAIL, VRE_POST
};
}

View File

@ -163,6 +163,7 @@ public class NotificationsPlugin extends AbstractPlugin implements EventListener
@Override
@Synchronized
public InitializationReport initInContext() throws InitializationException {
log.debug("Called initInContext");
InitializationReport report = new InitializationReport();
try {
String context = UserUtils.getCurrent().getContext();

View File

@ -26,7 +26,7 @@ import lombok.extern.slf4j.Slf4j;
public class IAMClientCredentialsReader {
private static final String SE_PROFILE_NAME = "geoportal";
private static final String SE_CATEGORY_NAME = "SystemClient";
private static final String SE_CATEGORY_NAME = "SystemWorkspaceClient";
/**
* Gets the credentials.

View File

@ -58,7 +58,14 @@ public class ManageDoActionNotification {
String projectName = docAsMap.size() > 0 ? docAsMap.values().stream().findFirst().get() + ""
: itemObserved.getProjectId();
placeholderMapValues.putProjectName(projectName);
placeholderMapValues.putUser(itemObserved.getUserCaller().getUsername());
placeholderMapValues.putUserCaller(itemObserved.getUserCaller().getUsername());
try {
//Setting the user creator of the project
placeholderMapValues.putItemCreator(itemObserved.getProject().getInfo().getCreationInfo().getUser().getUsername());
}catch (Exception e) {
// TODO: handle exception
}
nMPlaceholdersS.setPlaceholderMapValues(placeholderMapValues);
@ -106,7 +113,7 @@ public class ManageDoActionNotification {
}
try {
NotifyUsers mnu = new NotifyUsers(itemObserved, notificationsCompliantToPhase,
NotifyToSocial mnu = new NotifyToSocial(itemObserved, notificationsCompliantToPhase,
nMPlaceholdersS, notifyUsers, catalogueEventType);
mnu.sendNotification();
} catch (Exception e) {

View File

@ -25,7 +25,7 @@ import org.gcube.social_networking.socialnetworking.model.beans.catalogue.Catalo
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class NotifyUsers {
public class NotifyToSocial {
private List<User> recipientUsers;
private NMessagesPlaceholdersSubstitutorUtil nMPlaceholdersSUtil;
@ -34,7 +34,7 @@ public class NotifyUsers {
private CatalogueEventType catalogueEventType;
private ItemObserved<Project> itemObserved;
public NotifyUsers(ItemObserved<Project> itemObserved, List<NotificationWhen> listWhen,
public NotifyToSocial(ItemObserved<Project> itemObserved, List<NotificationWhen> listWhen,
NMessagesPlaceholdersSubstitutorUtil nMPlaceholdersSUtil, List<User> recipientUsers,
CatalogueEventType catalogueEventType) {
this.socialClients = new SocialClients();
@ -48,32 +48,44 @@ public class NotifyUsers {
public void sendNotification() throws Exception {
log.info("send notification...");
List<Notify> listNotifies = toNotify();
log.info("listNotifies are {} ", listNotifies);
for (Notify notify : listNotifies) {
switch (notify.getType()) {
case USER_POST:
case USER_NOTIFICATION:
log.info("Notification type {}, send: {}", notify.getType(), notify.getSend());
if (notify.getSend()) {
log.debug("Building message...");
String subject = "Message";
log.debug("Building Notification...");
String subject = "Notification";
String body = null;
subject = nMPlaceholdersSUtil.replacePlaceholder(itemObserved, notify.getPlaceholder_title());
body = nMPlaceholdersSUtil.replacePlaceholder(itemObserved, notify.getPlaceholder_msg());
log.debug("subject: {}", subject);
log.debug("body: {}", body);
log.info("Sending message to users: {}", recipientUsers);
if (itemObserved.getOptionalMessage() != null) {
body += "\n" + itemObserved.getOptionalMessage();
}
postMessage(subject, body, catalogueEventType);
log.info("Going to sent notification to users: {}", recipientUsers);
log.info("subject: {}", subject);
log.info("body: {}", body);
userNotify(subject, body, catalogueEventType);
}
break;
case VRE_POST:
log.info("Notification type {}, send: {}", notify.getType(), notify.getSend());
if (notify.getSend()) {
log.info("Notification type {}, send: {}", notify.getType(), notify.getSend());
PostInputBean toWrite = null;
Post thePost = socialClients.writeUserPost(toWrite);
log.info("{} post created: {} ", notify.getType(), thePost);
PostInputBean toWrite = new PostInputBean();
String title = nMPlaceholdersSUtil.replacePlaceholder(itemObserved, notify.getPlaceholder_title());
String body = nMPlaceholdersSUtil.replacePlaceholder(itemObserved, notify.getPlaceholder_msg());
if (itemObserved.getOptionalMessage() != null) {
body += "\n" + itemObserved.getOptionalMessage();
}
toWrite.setText(body);
if (title != null)
toWrite.setPreviewtitle(title);
vrePost(toWrite, notify);
}
break;
case EMAIL:
@ -86,6 +98,63 @@ public class NotifyUsers {
}
private void vrePost(PostInputBean toWrite, Notify notify) {
final SecretManager secretManager = SecretManagerProvider.instance.get();
try {
final Secret geoportalSecret = GeoportalServiceAccount.getGeoportalSecret();
secretManager.startSession(geoportalSecret);
// secretManager.startSession(geoportalSecret);
log.debug("{} is going to send vrePost {}", SecretManagerProvider.instance.get().getUser().getUsername(),
toWrite);
// String bodyWithTag = toWrite.getText() + "\n #" + geoportalSecret.getUser().getUsername();
// log.debug("body with tag: {}", bodyWithTag);
// toWrite.setText(bodyWithTag);
toWrite.setEnablenotification(true);
log.info("Going to write user post: {}", toWrite);
Post thePost = socialClients.writeUserPost(toWrite);
log.info("{} post created: {} ", notify.getType(), thePost);
} catch (Exception e) {
log.error("Error while sending vrePost", e);
} finally {
if (secretManager != null) {
try {
secretManager.endSession();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
protected void userNotify(String subject, String bodyMessage, CatalogueEventType catalogueEventType)
throws Exception {
CatalogueEvent catalogueEvent = getCatalogueEvent(subject, bodyMessage);
SecretManager secretManager = SecretManagerProvider.instance.get();
try {
Secret secret = GeoportalServiceAccount.getGeoportalSecret();
secretManager.startSession(secret);
log.debug("{} is going to send the following notification {}",
SecretManagerProvider.instance.get().getUser().getUsername(), catalogueEvent);
NotificationClient nc = socialClients.getNotificationClient();
nc.sendCatalogueEvent(catalogueEvent);
} catch (Exception e) {
log.error("Error while sending notification", e);
} finally {
if (secretManager != null) {
try {
secretManager.endSession();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private List<Notify> toNotify() {
List<Notify> listNotifies = new ArrayList<Notify>();
for (NotificationWhen notificationWhen : listNotificationWhen) {
@ -95,57 +164,12 @@ public class NotifyUsers {
return listNotifies;
}
protected void postMessage(String subject, String bodyMessage, CatalogueEventType catalogueEventType)
throws Exception {
CatalogueEvent catalogueEvent = getCatalogueEvent(subject, bodyMessage);
SecretManager secretManager = SecretManagerProvider.instance.get();
try {
Secret geoportalSecret = GeoportalServiceAccount.getGeoportalSecret();
secretManager.startSession(geoportalSecret);
sendNotification(catalogueEvent);
} catch (Exception e) {
log.error("Error while sending notification", e);
} finally {
if (secretManager != null) {
secretManager.endSession();
}
}
}
protected void sendNotification(CatalogueEvent catalogueEvent) throws Exception {
try {
Thread thread = new Thread() {
public void run() {
try {
log.debug("{} is going to send the following notification {}",
SecretManagerProvider.instance.get().getUser().getUsername(), catalogueEvent);
NotificationClient nc = socialClients.getNotificationClient();
nc.sendCatalogueEvent(catalogueEvent);
} catch (Exception e) {
log.error("Error while sending notification from thread", e);
} finally {
}
}
};
// thread.run();
thread.start();
} catch (Exception e) {
log.error("Error while sending notification", e);
}
// log.debug("{} is going to send the following notification {}", SecretManagerProvider.instance.get().getUser().getUsername(), catalogueEvent);
// NotificationClient nc = socialClients.getNotificationClient();
// nc.sendCatalogueEvent(catalogueEvent);
}
protected CatalogueEvent getCatalogueEvent(String subject, String bodyMessage) throws Exception {
CatalogueEvent catalogueEvent = new CatalogueEvent();
catalogueEvent.setType(catalogueEventType);
catalogueEvent.setNotifyText(bodyMessage);
catalogueEvent.setItemId(subject);
String itemURL = nMPlaceholdersSUtil.getPlaceholderMapValues().getFirstApplicationLink();
if (itemURL != null) {
catalogueEvent.setItemURL(new URL(itemURL));

View File

@ -52,14 +52,15 @@ public class NMessagesPlaceholdersSubstitutorUtil {
if (notificationPlaceholder == null || notificationPlaceholder.isEmpty())
return notificationPlaceholder;
this.placeholderMapValues = ResolveProjectLinkFromPlaceholder.resolveLink(itemObserved, placeholderMapValues, notificationPlaceholder);
log.trace("stringSub is {}",stringSub);
if (stringSub != null) {
log.debug("notificationPlaceholder: {}", notificationPlaceholder);
String templateString = notificationMessagesProperties.getProperty(notificationPlaceholder);
this.placeholderMapValues = ResolveProjectLinkFromPlaceholder.resolveLink(itemObserved, placeholderMapValues, templateString);
log.debug("templateString: {}", templateString);
// Replace
String resolvedString = stringSub.replace(templateString);

View File

@ -11,24 +11,25 @@ public class SubstitutorPlaceholdersMap extends HashMap<String, String> {
public static final String PROJECT_ID = "project_id";
public static final String PROJECT_NAME = "project_name";
public static final String USER = "user";
public static final String USER_CALLER = "user_caller";
private static final String ITEM_CREATOR = "item_creator";
public static final String PRIVATE_DATA_ENTRY_LINK = "private_data_entry_link";
public static final String PUBLIC_DATA_ENTRY_LINK = "public_data_entry_link";
public static final String PRIVATE_DATA_VIEWER_LINK = "private_data_viewer_link";
public static final String PUBLIC_DATA_VIEWER_LINK = "public_data_viewer_link";
public SubstitutorPlaceholdersMap() {
super();
}
@Override
public String put(String key, String value) {
return put(key, value);
public String putUserCaller(String username) {
return put(USER_CALLER, username);
}
public String putUser(String username) {
return put(USER, username);
public String putItemCreator(String username) {
return put(ITEM_CREATOR, username);
}
public String putProjectName(String projectName) {

View File

@ -25,6 +25,7 @@ import org.gcube.application.cms.tests.plugins.BasicPluginTest;
import org.gcube.application.geoportal.common.model.document.Project;
import org.gcube.application.geoportal.common.model.document.accounting.AccountingInfo;
import org.gcube.application.geoportal.common.model.document.accounting.PublicationInfo;
import org.gcube.application.geoportal.common.model.document.accounting.User;
import org.gcube.application.geoportal.common.model.document.lifecycle.LifecycleInformation;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor;
import org.gcube.application.geoportal.common.utils.tests.GCubeTest;
@ -33,30 +34,44 @@ import org.junit.Test;
import com.fasterxml.jackson.core.JsonProcessingException;
/**
* The Class CatalogueBindingPluginTest.
*
* @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
*
* Apr 10, 2024
*/
public class CatalogueBindingPluginTest extends BasicPluginTest {
NotificationsPlugin plugin;
/**
* Check plugin.
*/
@Before
public void checkPlugin() {
org.junit.Assume.assumeTrue(GCubeTest.isTestInfrastructureEnabled());
plugin = (NotificationsPlugin) plugins.get(NotificationsPlugin.DESCRIPTOR.getId());
try {
plugin.init();
} catch (InitializationException e1) {
e1.printStackTrace();
}
try {
plugin.initInContext();
} catch (InitializationException e1) {
e1.printStackTrace();
}
// try {
// plugin.init();
// } catch (InitializationException e1) {
// e1.printStackTrace();
// }
//
// try {
// plugin.initInContext();
// } catch (InitializationException e1) {
// e1.printStackTrace();
// }
System.out.println("Plugin check: " + plugin);
}
/**
* Check plugin config.
*/
//@Test
public void checkPluginConfig() {
org.junit.Assume.assumeTrue(GCubeTest.isTestInfrastructureEnabled());
@ -75,8 +90,11 @@ public class CatalogueBindingPluginTest extends BasicPluginTest {
}
/**
* Check notifications SUBMIT_FOR_REVIEW to USERS
*/
//@Test
public void checkNotifications_LIFECYCLE_STEP_PERFORMED() {
public void checkNotifications_LIFECYCLE_STEP_PERFORMED_TO_SUBMIT_FOR_REVIEW() {
org.junit.Assume.assumeTrue(GCubeTest.isTestInfrastructureEnabled());
UseCaseDescriptor descriptor = TestProfiles.profiles.get("profiledConcessioni");
@ -94,22 +112,109 @@ public class CatalogueBindingPluginTest extends BasicPluginTest {
ItemObserved<Project> item = mockItemObserverd();
//Setting creator
User creator = new User();
creator.setUsername("gianluca.vannini");
item.getProject().getInfo().getCreationInfo().setUser(creator);
EventManager.Event event = Event.LIFECYCLE_STEP_PERFORMED;
item.setEvent(event);
LifecycleInformation lifecycleInfo = item.getProject().getLifecycleInformation();
//(Pending Approval, "SUBMIT-FOR-REVIEW")
// lifecycleInfo.setPhase("Pending Approval");
// lifecycleInfo.setLastInvokedStep("SUBMIT-FOR-REVIEW");
//(DRAFT, REJECT-DRAFT)
lifecycleInfo.setPhase("DRAFT");
lifecycleInfo.setLastInvokedStep("REJECT-DRAFT");
//Test Stage (Pending Approval, "SUBMIT-FOR-REVIEW")
lifecycleInfo.setPhase("Pending Approval");
lifecycleInfo.setLastInvokedStep("SUBMIT-FOR-REVIEW");
System.out.println("By notifying event " + event + " project " + item.getProjectId());
EventManager.getInstance().notify(event, item);
}
/**
* Check notifications REJECT_DRAFT to USERS
*/
//@Test
public void checkNotifications_LIFECYCLE_STEP_PERFORMED_TO_REJECT_DRAFT() {
//org.junit.Assume.assumeTrue(GCubeTest.isTestInfrastructureEnabled());
UseCaseDescriptor descriptor = TestProfiles.profiles.get("profiledConcessioni");
private void sysOut(SubscribeNotificationEvent subscribeNotificationEvent) {
NotificationEventsSubscribedConfig notificationEventsSubs;
try {
System.out.println(NotificationEventsSubscribedConfig.class.getSimpleName() + ": ");
notificationEventsSubs = plugin.readNotificationsSubscribedFromConfigurationInTheUCD(descriptor);
List<SubscribeNotificationEvent> events = notificationEventsSubs.getListNotificationEventSubscribed();
for (SubscribeNotificationEvent subscribeNotificationEvent : events) {
sysOut(subscribeNotificationEvent);
}
} catch (Exception e) {
e.printStackTrace();
}
ItemObserved<Project> item = mockItemObserverd();
//Setting creator
User creator = new User();
creator.setUsername("gianluca.vannini");
item.getProject().getInfo().getCreationInfo().setUser(creator);
EventManager.Event event = Event.LIFECYCLE_STEP_PERFORMED;
item.setEvent(event);
LifecycleInformation lifecycleInfo = item.getProject().getLifecycleInformation();
//Test Stage (DRAFT, REJECT-DRAFT)
lifecycleInfo.setPhase("DRAFT");
lifecycleInfo.setLastInvokedStep("REJECT-DRAFT");
System.out.println("By notifying event " + event + " project " + item.getProjectId());
EventManager.getInstance().notify(event, item);
}
/**
* Check the VRE POST
*/
//@Test
public void checkNotifications_LIFECYCLE_STEP_PERFORMED_TO_APPROVE_SUBMITTED() {
org.junit.Assume.assumeTrue(GCubeTest.isTestInfrastructureEnabled());
UseCaseDescriptor descriptor = TestProfiles.profiles.get("profiledConcessioni");
NotificationEventsSubscribedConfig notificationEventsSubs;
try {
System.out.println(NotificationEventsSubscribedConfig.class.getSimpleName() + ": ");
notificationEventsSubs = plugin.readNotificationsSubscribedFromConfigurationInTheUCD(descriptor);
List<SubscribeNotificationEvent> events = notificationEventsSubs.getListNotificationEventSubscribed();
for (SubscribeNotificationEvent subscribeNotificationEvent : events) {
sysOut(subscribeNotificationEvent);
}
} catch (Exception e) {
e.printStackTrace();
}
ItemObserved<Project> item = mockItemObserverd();
//Setting creator
User creator = new User();
creator.setUsername("gianluca.vannini");
item.getProject().getInfo().getCreationInfo().setUser(creator);
EventManager.Event event = Event.LIFECYCLE_STEP_PERFORMED;
item.setEvent(event);
LifecycleInformation lifecycleInfo = item.getProject().getLifecycleInformation();
//Test Stage (Published, null)
lifecycleInfo.setPhase("Published");
lifecycleInfo.setLastInvokedStep("APPROVE-SUBMITTED");
System.out.println("By notifying event " + event + " project " + item.getProjectId());
EventManager.getInstance().notify(event, item);
}
/**
* Sys out.
*
* @param subscribeNotificationEvent the subscribe notification event
*/
private static void sysOut(SubscribeNotificationEvent subscribeNotificationEvent) {
System.out.println("\n#SubscribeNotificationEvent - Event: " + subscribeNotificationEvent.getEvent());
List<NotificationFor> listNotificationFor = subscribeNotificationEvent.getNotificationFor();
for (NotificationFor notificationFor : listNotificationFor) {
@ -129,6 +234,11 @@ public class CatalogueBindingPluginTest extends BasicPluginTest {
}
}
/**
* Mock item observerd.
*
* @return the item observed
*/
private static ItemObserved<Project> mockItemObserverd() {
UseCaseDescriptor descriptor = TestProfiles.profiles.get("profiledConcessioni");
@ -148,7 +258,7 @@ public class CatalogueBindingPluginTest extends BasicPluginTest {
// MOCK PROJECT
Project testProject = new Project();
testProject.setId("63bda06581b811167f6a0769");
testProject.setId("655489965bdd5478cca320ea");
testProject.setProfileID(descriptor.getId());
PublicationInfo info = new PublicationInfo(descriptor.getCreationInfo(), null, null);
testProject.setInfo(info);
@ -168,9 +278,15 @@ public class CatalogueBindingPluginTest extends BasicPluginTest {
testProject.setLifecycleInformation(lifecycleInfo);
item.setProject(testProject);
item.setOptionalMessage("My great message");
return item;
}
/**
* Matching notification test.
*/
//@Test
public void matchingNotificationTest() {
org.junit.Assume.assumeTrue(GCubeTest.isTestInfrastructureEnabled());
@ -205,6 +321,9 @@ public class CatalogueBindingPluginTest extends BasicPluginTest {
System.out.println("Filtered notifications: "+listWhen);
}
/**
* Check serialize deserialize.
*/
// @Test
public void checkSerializeDeserialize() {
org.junit.Assume.assumeTrue(GCubeTest.isTestInfrastructureEnabled());
@ -230,6 +349,11 @@ public class CatalogueBindingPluginTest extends BasicPluginTest {
}
/**
* Mock subscribe notification event.
*
* @return the subscribe notification event
*/
public static SubscribeNotificationEvent mockSubscribeNotificationEvent() {
SubscribeNotificationEvent sne = new SubscribeNotificationEvent();
sne.setEvent(Event.LIFECYCLE_STEP_PERFORMED);

View File

@ -40,7 +40,7 @@ public class StringReplacerTest {
// valuesMap.put(SubstitutorPlaceholdersMap.PROJECT_ID, PROJECT_ID);
SubstitutorPlaceholdersMap smp = new SubstitutorPlaceholdersMap();
smp.putUser(USERNAME);
smp.putUserCaller(USERNAME);
smp.putPublicDataEntryLink(APPLICATION_LINK);
smp.putProjectId(PROJECT_ID);
smp.putProjectName(PROJECT_NAME);