Compare commits

...

7 Commits

7 changed files with 176 additions and 72 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target/
/deploy.sh

View File

@ -1,10 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="social-mail-servlet">
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<property name="context-root" value="social-mail-servlet"/>
<property name="java-output-path" value="/social-mail-servlet/target/classes"/>
</wb-module>
</project-modules>

View File

@ -4,6 +4,10 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v3.0.0] - 2024-04-18
- Removed social networking lib dep
## [v2.5.0] - 2021-06-22
- Feature #21689 Social Mail Servlet to StorageHub migration

View File

@ -32,18 +32,11 @@ See [Releases](https://code-repo.d4science.org/gCubeSystem/oauth-service/release
This project is licensed under the EUPL V.1.1 License - see the [LICENSE.md](LICENSE.md) file for details.
## About the gCube Framework
This software is part of the [gCubeFramework](https://www.gcube-system.org/ "gCubeFramework"): an
open-source software toolkit used for building and operating Hybrid Data
open-source software toolkit used for building and operating Data
Infrastructures enabling the dynamic deployment of Virtual Research Environments
by favouring the realisation of reuse oriented policies.
The projects leading to this software have received funding from a series of European Union programmes including:
- the Sixth Framework Programme for Research and Technological Development
- DILIGENT (grant no. 004260);
- the Seventh Framework Programme for research, technological development and demonstration
- D4Science (grant no. 212488), D4Science-II (grant no.239019), ENVRI (grant no. 283465), EUBrazilOpenBio (grant no. 288754), iMarine(grant no. 283644);
- the H2020 research and innovation programme
- BlueBRIDGE (grant no. 675680), EGIEngage (grant no. 654142), ENVRIplus (grant no. 654182), Parthenos (grant no. 654119), SoBigData (grant no. 654024),DESIRA (grant no. 818194), ARIADNEplus (grant no. 823914), RISIS2 (grant no. 824091), PerformFish (grant no. 727610), AGINFRAplus (grant no. 731001);
The projects leading to this software have received funding from a series of European Union programmes see [FUNDING.md](FUNDING.md)

37
pom.xml
View File

@ -4,7 +4,7 @@
<parent>
<groupId>org.gcube.tools</groupId>
<artifactId>maven-parent</artifactId>
<version>1.1.0</version>
<version>1.2.0</version>
<relativePath />
</parent>
@ -12,7 +12,7 @@
<groupId>org.gcube.portal</groupId>
<artifactId>social-mail-servlet</artifactId>
<packaging>war</packaging>
<version>2.5.0</version>
<version>3.0.0</version>
<scm>
<connection>scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId}.git</connection>
<developerConnection>scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId}.git</developerConnection>
@ -37,7 +37,7 @@
<dependency>
<groupId>org.gcube.distribution</groupId>
<artifactId>maven-portal-bom</artifactId>
<version>3.6.3</version>
<version>3.7.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -71,15 +71,22 @@
<artifactId>aslsocial</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>storagehub-client-library</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.portal</groupId>
<artifactId>social-networking-library</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.social-networking</groupId>
<artifactId>social-service-client</artifactId>
<version>[2.0.0-SNAPSHOT, 3.0.0)</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
@ -109,7 +116,13 @@
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<scope>provided</scope>
</dependency>
<dependency>
@ -164,14 +177,6 @@
<webappDirectory>${webappDirectory}</webappDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>

View File

@ -17,6 +17,7 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.gcube.application.framework.core.session.SessionManager;
import org.gcube.common.encryption.StringEncrypter;
import org.gcube.common.portal.PortalContext;
import org.gcube.common.resources.gcore.ServiceEndpoint;
@ -54,6 +55,9 @@ public class PortalSchedulerService extends HttpServlet {
private static DatabookStore store;
public void init() {
PortalContext context = PortalContext.getConfiguration();
String scope = "/" + context.getInfrastructureName();
ScopeProvider.instance.set(scope);
store = new DBCassandraAstyanaxImpl();
}
@ -77,7 +81,7 @@ public class PortalSchedulerService extends HttpServlet {
pop3Scheduler.scheduleAtFixedRate(new PeriodicTask(store, popAccount, request), 0, pollingInterval, TimeUnit.MINUTES);
String portalName = "unknown";
try {
popAccount.getPortalName() ;
portalName = popAccount.getPortalName() ;
}
catch (NullPointerException e){
_log.warn("Could not read popAccount data portal name", e);

View File

@ -2,26 +2,18 @@ package org.gcube.portal.socialmail;
import static org.gcube.common.authorization.client.Constants.authorizationService;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage.RecipientType;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringEscapeUtils;
@ -34,14 +26,11 @@ import org.gcube.applicationsupportlayer.social.mailing.AppType;
import org.gcube.applicationsupportlayer.social.mailing.SocialMailingUtil;
import org.gcube.applicationsupportlayer.social.shared.SocialNetworkingSite;
import org.gcube.applicationsupportlayer.social.shared.SocialNetworkingUser;
import org.gcube.common.authorization.library.provider.AccessTokenProvider;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.authorization.library.provider.UserInfo;
import org.gcube.common.portal.PortalContext;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.storagehub.client.plugins.AbstractPlugin;
import org.gcube.common.storagehub.client.proxies.MessageManagerClient;
import org.gcube.common.storagehub.model.exceptions.IdNotFoundException;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.portal.databook.server.DatabookStore;
import org.gcube.portal.databook.shared.Comment;
import org.gcube.portal.databook.shared.Feed;
@ -54,14 +43,35 @@ import org.gcube.portal.notifications.bean.GenericItemBean;
import org.gcube.portal.notifications.thread.CommentNotificationsThread;
import org.gcube.portal.notifications.thread.LikeNotificationsThread;
import org.gcube.portal.notifications.thread.MessageNotificationsThread;
import org.gcube.social_networking.social_networking_client_library.MessageClient;
import org.gcube.social_networking.socialnetworking.model.beans.MessageInbox;
import org.gcube.social_networking.socialnetworking.model.beans.MessageInputBean;
import org.gcube.social_networking.socialnetworking.model.beans.Recipient;
import org.gcube.vomanagement.usermanagement.UserManager;
import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager;
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.sun.mail.util.MailSSLSocketFactory;
import jakarta.mail.Address;
import jakarta.mail.BodyPart;
import jakarta.mail.Flags;
import jakarta.mail.Folder;
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
import jakarta.mail.Multipart;
import jakarta.mail.NoSuchProviderException;
import jakarta.mail.Session;
import jakarta.mail.Store;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage.RecipientType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.ResponseBody;
/**
*
* @author Massimiliano Assante, CNR-ISTI
@ -70,6 +80,7 @@ import com.sun.mail.util.MailSSLSocketFactory;
public class PeriodicTask implements Runnable {
private static final Log _log = LogFactoryUtil.getLog(PeriodicTask.class);
private static final String APP_ID_NEWSFEED = "org.gcube.portlets.user.newsfeed.server.NewsServiceImpl";
private static final String SHUB_MESSAGES_ENDPOINT = "workspace/messages/";
private DatabookStore socialStore;
private EmailPopAccount popAccount;
@ -136,6 +147,20 @@ public class PeriodicTask implements Runnable {
}
return toReturn;
}
private static String generateAuthorizationToken(String username, String scope) {
List<String> userRoles = new ArrayList<>();
userRoles.add(DEFAULT_ROLE);
String token;
try {
token = authorizationService().generateUserToken(new UserInfo(username, userRoles), scope);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return token;
}
private final static String DEFAULT_ROLE = "OrganizationMember";
private static void setAuthorizationToken(ASLSession session) throws Exception {
@ -250,6 +275,16 @@ public class PeriodicTask implements Runnable {
* @throws Exception
*/
private void handleMessageReply(String portalName, String messageId, Message message, ASLSession fakeSession) {
String legacyToken = SecurityTokenProvider.instance.get();
_log.info("*****username=" + fakeSession.getUsername());
_log.info("*****context=" + fakeSession.getScope());
legacyToken = generateAuthorizationToken(fakeSession.getUsername(), fakeSession.getScope());
SecurityTokenProvider.instance.set(legacyToken);
String subject = "";
String messageText = "";
try {
@ -261,34 +296,23 @@ public class PeriodicTask implements Runnable {
_log.debug("Found message reply, subject: " + subject + " body: " + messageText);
String newMessageId = null;
List<String> recipientIds = new ArrayList<>();
ArrayList<String> recipientIds = new ArrayList<String>();
try {
String username = fakeSession.getUsername();
String scope = fakeSession.getScope();
ScopeProvider.instance.set(scope);
_log.debug("calling service token on scope " + scope);
String context = fakeSession.getScope();
ScopeProvider.instance.set(context);
_log.debug("calling service token on context " + context);
List<String> userRoles = new ArrayList<>();
userRoles.add(DEFAULT_ROLE);
fakeSession.setSecurityToken(null);
String token = authorizationService().generateUserToken(new UserInfo(username, userRoles), scope);
String token = authorizationService().generateUserToken(new UserInfo(username, userRoles), context);
SecurityTokenProvider.instance.set(token);
MessageManagerClient mmClient = AbstractPlugin.messages().build();
org.gcube.common.storagehub.model.messages.Message theMessage = null;
try {
theMessage = mmClient.get(messageId);
}
catch (IdNotFoundException e) {
_log.warn("Message with id "+ messageId + " could not be found, trying by name ...");
List<org.gcube.common.storagehub.model.messages.Message> messages = mmClient.getReceivedMessages();
Collections.reverse(messages); //the messages are returned in chronological order, but the messages we look for is one of the newests
_log.warn("Messages size="+messages.size());
for(org.gcube.common.storagehub.model.messages.Message msg: messages) {
if (msg.getName().equals(messageId)) {
theMessage = msg;
break;
}
}
}
MessageInbox theMessage = null;
_log.info("Looking for Message with id "+ messageId);
String messagesEndpoint = getStorageHubURLFromContext(context)+SHUB_MESSAGES_ENDPOINT;
theMessage = getMessageWSById(messagesEndpoint, messageId, token);
_log.info("Got Message = " + theMessage.toString());
if (theMessage != null) {
String[] addresses = theMessage.getAddresses();
for (int i = 0; i < addresses.length; i++) {
@ -302,17 +326,20 @@ public class PeriodicTask implements Runnable {
recipientIds.remove(fakeSession.getUsername());
_log.debug("Message Recipients:");
ArrayList<Recipient> recipients = new ArrayList<Recipient>();
for (String rec : recipientIds) {
recipients.add(new Recipient(rec));
_log.debug(rec);
}
_log.debug("Constructing reply message");
messageText += getReplyHeaderMessage(sender, originalSentTime, originalText);
_log.debug("Trying to send message with subject: " + subject + " to: " + recipientIds.toString());
newMessageId = mmClient.sendMessage(recipientIds, subject, messageText, new ArrayList<String>());
} else {
_log.error("Message with id "+ messageId + " could not be found even iterating by name, exiting.");
}
MessageInputBean message2Send = new MessageInputBean(messageText, subject, recipients);
MessageClient messagesClient = new MessageClient();
newMessageId = messagesClient.writeMessage(message2Send);
}
} catch (Exception e) {
e.printStackTrace();
@ -336,6 +363,48 @@ public class PeriodicTask implements Runnable {
}
}
/**
* temporary method that get the URL of the Shub based on the context
* @param context
* @return the url
*/
private String getStorageHubURLFromContext(String context) {
String toReturn = "";
if (context.startsWith("/d4science")) {
toReturn = "https://api.d4science.org/";
} else if (context.startsWith("/gcube")) {
toReturn = "https://api.dev.d4science.org/";
} else {
toReturn = "https://api.pre.d4science.org/";
}
return toReturn;
}
/**
* read a message from shub given the id
* @param urlString
* @param token
* @return
* @throws IOException
*/
private static MessageInbox getMessageWSById(String uri, String messageId, String token) throws IOException {
String urlString = uri+messageId;
_log.info("***** getMessageWSById urlString = " + urlString);
OkHttpClient client = new OkHttpClient().newBuilder().build();
Request request = new Request.Builder()
.url(urlString)
.addHeader("gcube-token", token)
.build();
ResponseBody responseBody = client.newCall(request).execute().body();
String json = responseBody.string();
_log.info("***** getMessageWSById Response = " + json);
ObjectMapper objectMapper = new ObjectMapper();
MessageInbox theMessage = objectMapper.readValue(json, MessageInbox.class);
return theMessage;
}
private String getReplyHeaderMessage(String senderId, Date date, String message) {
List<String> toPass = new ArrayList<String>();
toPass.add(senderId);
@ -376,6 +445,15 @@ public class PeriodicTask implements Runnable {
* @throws Exception
*/
private void handlePostReply(String portalName, String postId, Message message, ASLSession fakeSession) throws Exception {
String token = AccessTokenProvider.instance.get();
String legacyToken = SecurityTokenProvider.instance.get();
_log.info("*****username=" + fakeSession.getUsername());
_log.info("*****context=" + fakeSession.getScope());
legacyToken = generateAuthorizationToken(fakeSession.getUsername(), fakeSession.getScope());
SecurityTokenProvider.instance.set(legacyToken);
String commentText = extractText(portalName, postId, message);
_log.info("Extracted id: " + postId + " text=" + commentText);
String escapedCommentText = org.gcube.portal.socialmail.Utils.escapeHtmlAndTransformUrl(commentText);
@ -386,6 +464,7 @@ public class PeriodicTask implements Runnable {
likePost(postId, fakeSession);
}
else {
Comment comment = new Comment(UUID.randomUUID().toString(), fakeSession.getUsername(),
new Date(), postId, escapedCommentText, fakeSession.getUserFullName(), fakeSession.getUserAvatarId());
@ -411,12 +490,21 @@ public class PeriodicTask implements Runnable {
* @param fakeSession
*/
private void likePost(String postId, ASLSession fakeSession) {
String token = AccessTokenProvider.instance.get();
String legacyToken = SecurityTokenProvider.instance.get();
_log.info("*****username=" + fakeSession.getUsername());
_log.info("*****context=" + fakeSession.getScope());
legacyToken = generateAuthorizationToken(fakeSession.getUsername(), fakeSession.getScope());
SecurityTokenProvider.instance.set(legacyToken);
if (postId == null || postId.compareTo("") == 0) {
_log.warn("Found email with no feedId from " + fakeSession.getUserEmailAddress() + ". Going to trash it");
return;
}
Like like = new Like(UUID.randomUUID().toString(), fakeSession.getUsername(),
new Date(), postId, fakeSession.getUserFullName(), fakeSession.getUserAvatarId());
@ -436,7 +524,7 @@ public class PeriodicTask implements Runnable {
NotificationsManager nm = new ApplicationNotificationsManager(
site,
fakeSession.getScope(),
post.getVreid(),
new SocialNetworkingUser(fakeSession.getUsername(), fakeSession.getUserEmailAddress(), fakeSession.getUserFullName(), fakeSession.getUserAvatarId()),
APP_ID_NEWSFEED
);