partial implementation (reads)
This commit is contained in:
parent
ea37bcb93c
commit
2c2a68b580
|
@ -1,8 +1,12 @@
|
|||
# Changelog
|
||||
|
||||
## [v2.7.1-SNAPSHOT] - 2022-09-14
|
||||
|
||||
- - Feature #23847 Social service: temporarily block of notifications for given username(s)
|
||||
|
||||
## [v2.7.0] - 2022-09-12
|
||||
|
||||
- Sphinx documentation added
|
||||
- Sphinx documentation added
|
||||
|
||||
## [v2.6.2] - 2022-07-27
|
||||
|
||||
|
|
42
pom.xml
42
pom.xml
|
@ -12,7 +12,7 @@
|
|||
<groupId>org.gcube.portal</groupId>
|
||||
<artifactId>social-networking-library-ws</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>2.7.0</version>
|
||||
<version>2.7.1-SNAPSHOT]</version>
|
||||
<name>social-networking-library-ws</name>
|
||||
<description>Rest interface for the social networking library.</description>
|
||||
<properties>
|
||||
|
@ -39,6 +39,11 @@
|
|||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>1.8.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
@ -73,6 +78,16 @@
|
|||
<artifactId>ehcache</artifactId>
|
||||
<version>2.10.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.spy</groupId>
|
||||
<artifactId>spymemcached</artifactId>
|
||||
<version>2.12.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.gcube.common</groupId>
|
||||
<artifactId>authorization-control-library</artifactId>
|
||||
<version>[1.0.1,2.0.0-SNAPSHOT)</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.gcube.common.portal</groupId>
|
||||
<artifactId>portal-manager</artifactId>
|
||||
|
@ -301,7 +316,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- SPHINX PLUGIN triggered at 'compile' -->
|
||||
<plugin>
|
||||
<groupId>kr.motd.maven</groupId>
|
||||
<artifactId>sphinx-maven-plugin</artifactId>
|
||||
|
@ -348,7 +362,29 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>aspectj-maven-plugin</artifactId>
|
||||
<version>1.7</version>
|
||||
<configuration>
|
||||
<complianceLevel>1.8</complianceLevel>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<aspectLibraries>
|
||||
<aspectLibrary>
|
||||
<groupId>org.gcube.common</groupId>
|
||||
<artifactId>authorization-control-library</artifactId>
|
||||
</aspectLibrary>
|
||||
</aspectLibraries>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- Copy Enunciate Documentation from your-application/docs to your-application.war -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package org.gcube.portal.social.networking.ws.ex;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
public class AuthException extends WebApplicationException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public AuthException(Throwable cause) {
|
||||
super(cause, Status.FORBIDDEN);
|
||||
}
|
||||
|
||||
}
|
|
@ -26,6 +26,7 @@ import org.gcube.applicationsupportlayer.social.NotificationsManager;
|
|||
import org.gcube.applicationsupportlayer.social.ScopeBeanExt;
|
||||
import org.gcube.applicationsupportlayer.social.shared.SocialNetworkingSite;
|
||||
import org.gcube.applicationsupportlayer.social.shared.SocialNetworkingUser;
|
||||
import org.gcube.common.authorization.control.annotations.AuthorizationControl;
|
||||
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
|
||||
import org.gcube.common.authorization.library.utils.Caller;
|
||||
import org.gcube.common.scope.api.ScopeProvider;
|
||||
|
@ -40,11 +41,13 @@ import org.gcube.portal.social.networking.caches.UsersCache;
|
|||
import org.gcube.portal.social.networking.liferay.ws.GroupManagerWSBuilder;
|
||||
import org.gcube.portal.social.networking.liferay.ws.LiferayJSONWsCredentials;
|
||||
import org.gcube.portal.social.networking.liferay.ws.UserManagerWSBuilder;
|
||||
import org.gcube.portal.social.networking.ws.ex.AuthException;
|
||||
import org.gcube.portal.social.networking.ws.mappers.CatalogueEventTypeMapper;
|
||||
import org.gcube.portal.social.networking.ws.mappers.JobMapper;
|
||||
import org.gcube.portal.social.networking.ws.mappers.WorkspaceItemMapper;
|
||||
import org.gcube.portal.social.networking.ws.outputs.ResponseBean;
|
||||
import org.gcube.portal.social.networking.ws.utils.CassandraConnection;
|
||||
import org.gcube.portal.social.networking.ws.utils.DistributedCacheClient;
|
||||
import org.gcube.portal.social.networking.ws.utils.ErrorMessages;
|
||||
import org.gcube.social_networking.socialnetworking.model.beans.JobNotificationBean;
|
||||
|
||||
|
@ -72,6 +75,8 @@ import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
|
|||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
|
||||
import net.spy.memcached.MemcachedClient;
|
||||
|
||||
/**
|
||||
* REST interface for the social networking library (notifications).
|
||||
*/
|
||||
|
@ -84,6 +89,7 @@ public class Notifications {
|
|||
|
||||
// Logger
|
||||
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Notifications.class);
|
||||
private static final String INFRASTRUCTURE_MANAGER_ROLE = "Infrastructure-Manager";
|
||||
|
||||
@GET
|
||||
@Path("get-range-notifications/")
|
||||
|
@ -130,6 +136,47 @@ public class Notifications {
|
|||
return Response.status(status).entity(responseBean).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("is-user-disabled/")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
/**
|
||||
* Return whether the notifications for this user are enabled or not
|
||||
* @param from must be greater or equal to 1, range[0, infinity]
|
||||
* @param quantity quantity must be greater or equal to 0
|
||||
* @return notifications up to quantity
|
||||
* @throws ValidationException
|
||||
*/
|
||||
@StatusCodes ({
|
||||
@ResponseCode ( code = 200, condition = "Users with silenced notifications are reported in the 'result' field of the returned object"),
|
||||
@ResponseCode ( code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
|
||||
})
|
||||
@AuthorizationControl(allowedRoles={INFRASTRUCTURE_MANAGER_ROLE}, exception=AuthException.class)
|
||||
public Response isUserDisabled(String usernameToCheck) throws ValidationException{
|
||||
ResponseBean responseBean = new ResponseBean();
|
||||
Status status = Status.OK;
|
||||
try{
|
||||
Boolean userDisabled= !isNotificationEnabled(usernameToCheck);
|
||||
responseBean.setResult(userDisabled);
|
||||
responseBean.setSuccess(true);
|
||||
logger.debug("are User " + usernameToCheck + " Notifications Disabled?"+userDisabled);
|
||||
}catch(Exception e){
|
||||
logger.error("Unable to read whether the notifications for this user are enabled or not.", e);
|
||||
responseBean.setMessage(e.getMessage());
|
||||
responseBean.setSuccess(false);
|
||||
status = Status.INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return Response.status(status).entity(responseBean).build();
|
||||
}
|
||||
|
||||
private boolean isNotificationEnabled(String usernameToCheck) {
|
||||
MemcachedClient entries = new DistributedCacheClient().getMemcachedClient();
|
||||
Boolean userEnabled = false;
|
||||
if(entries.get(usernameToCheck) == null)
|
||||
userEnabled = true;
|
||||
return userEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a JOB notification to a given recipient
|
||||
* @param job The job bean
|
||||
|
@ -225,26 +272,28 @@ public class Notifications {
|
|||
if (! event.idsAsGroup()) {
|
||||
for (int i = 0; i < idsToNotify.length; i++) {
|
||||
String userIdToNotify = idsToNotify[i];
|
||||
String username2Notify = null;
|
||||
try {
|
||||
username2Notify = um.getUserByUsername(userIdToNotify).getUsername();
|
||||
}
|
||||
catch (Exception e) {
|
||||
status = Status.BAD_REQUEST;
|
||||
logger.error("Username not found", e);
|
||||
responseBean.setSuccess(false);
|
||||
responseBean.setMessage("Username not found, got: " + userIdToNotify);
|
||||
return Response.status(status).entity(responseBean).build();
|
||||
}
|
||||
|
||||
deliveryResult =
|
||||
if (isNotificationEnabled(userIdToNotify)) {
|
||||
String username2Notify = null;
|
||||
try {
|
||||
username2Notify = um.getUserByUsername(userIdToNotify).getUsername();
|
||||
}
|
||||
catch (Exception e) {
|
||||
status = Status.BAD_REQUEST;
|
||||
logger.error("Username not found", e);
|
||||
responseBean.setSuccess(false);
|
||||
responseBean.setMessage("Username not found, got: " + userIdToNotify);
|
||||
return Response.status(status).entity(responseBean).build();
|
||||
}
|
||||
|
||||
deliveryResult =
|
||||
nm.notifyCatalogueEvent(
|
||||
CatalogueEventTypeMapper.getType(event.getType()),
|
||||
username2Notify,
|
||||
event.getItemId(),
|
||||
event.getNotifyText(),
|
||||
event.getItemURL());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} else { //the ids are contexts
|
||||
for (int i = 0; i < idsToNotify.length; i++) {
|
||||
|
@ -261,13 +310,15 @@ public class Notifications {
|
|||
String[] userIdsToNotify = getUsernamesByContext(scope).toArray(new String[0]); //resolve the members
|
||||
for (int j = 0; j < userIdsToNotify.length; j++) {
|
||||
String userIdToNotify = userIdsToNotify[j];
|
||||
deliveryResult =
|
||||
nm.notifyCatalogueEvent(
|
||||
CatalogueEventTypeMapper.getType(event.getType()),
|
||||
userIdToNotify,
|
||||
event.getItemId(),
|
||||
event.getNotifyText(),
|
||||
event.getItemURL());
|
||||
if (isNotificationEnabled(userIdToNotify)) {
|
||||
deliveryResult =
|
||||
nm.notifyCatalogueEvent(
|
||||
CatalogueEventTypeMapper.getType(event.getType()),
|
||||
userIdToNotify,
|
||||
event.getItemId(),
|
||||
event.getNotifyText(),
|
||||
event.getItemURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -338,18 +389,20 @@ public class Notifications {
|
|||
if (! event.idsAsGroup()) {
|
||||
for (int i = 0; i < idsToNotify.length; i++) {
|
||||
String userIdToNotify = idsToNotify[i];
|
||||
String username2Notify = "";
|
||||
try {
|
||||
username2Notify = um.getUserByUsername(userIdToNotify).getUsername();
|
||||
if (isNotificationEnabled(userIdToNotify)) {
|
||||
String username2Notify = "";
|
||||
try {
|
||||
username2Notify = um.getUserByUsername(userIdToNotify).getUsername();
|
||||
}
|
||||
catch (Exception e) {
|
||||
status = Status.NOT_ACCEPTABLE;
|
||||
logger.error("Username not found", e);
|
||||
responseBean.setSuccess(false);
|
||||
responseBean.setMessage("Username not found, received: " + userIdToNotify);
|
||||
return Response.status(status).entity(responseBean).build();
|
||||
}
|
||||
deliveryResult = notifyWorkspaceEvent(event, nm, username2Notify);
|
||||
}
|
||||
catch (Exception e) {
|
||||
status = Status.NOT_ACCEPTABLE;
|
||||
logger.error("Username not found", e);
|
||||
responseBean.setSuccess(false);
|
||||
responseBean.setMessage("Username not found, received: " + userIdToNotify);
|
||||
return Response.status(status).entity(responseBean).build();
|
||||
}
|
||||
deliveryResult = notifyWorkspaceEvent(event, nm, username2Notify);
|
||||
}
|
||||
} else { //the ids are contexts
|
||||
for (int i = 0; i < idsToNotify.length; i++) {
|
||||
|
@ -366,7 +419,8 @@ public class Notifications {
|
|||
String[] userIdsToNotify = getUsernamesByContext(scope).toArray(new String[0]); //resolve the members
|
||||
for (int j = 0; j < userIdsToNotify.length; j++) {
|
||||
String userIdToNotify = userIdsToNotify[j];
|
||||
deliveryResult = notifyWorkspaceEvent(event, nm, userIdToNotify);
|
||||
if (isNotificationEnabled(userIdToNotify))
|
||||
deliveryResult = notifyWorkspaceEvent(event, nm, userIdToNotify);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
package org.gcube.portal.social.networking.ws.utils;
|
||||
|
||||
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
|
||||
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.gcube.common.resources.gcore.ServiceEndpoint;
|
||||
import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint;
|
||||
import org.gcube.common.resources.gcore.utils.Group;
|
||||
import org.gcube.common.scope.api.ScopeProvider;
|
||||
import org.gcube.resources.discovery.client.api.DiscoveryClient;
|
||||
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
|
||||
import org.gcube.smartgears.ContextProvider;
|
||||
import org.gcube.smartgears.context.application.ApplicationContext;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.spy.memcached.KetamaConnectionFactory;
|
||||
import net.spy.memcached.MemcachedClient;
|
||||
|
||||
/**
|
||||
* @author Massimiliano Assante at ISTI-CNR
|
||||
*/
|
||||
public class DistributedCacheClient {
|
||||
|
||||
// Logger
|
||||
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(DistributedCacheClient.class);
|
||||
|
||||
private static final String MEMCACHED_RESOURCE_NAME = "Memcached";
|
||||
private static final String CATEGORY = "Database";
|
||||
|
||||
private MemcachedClient mClient;
|
||||
|
||||
/**
|
||||
* Build the singleton instance
|
||||
*/
|
||||
public DistributedCacheClient(){
|
||||
List<InetSocketAddress> addrs = discoverHostOfServiceEndpoint();
|
||||
try {
|
||||
mClient = new MemcachedClient(new KetamaConnectionFactory(), addrs);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public MemcachedClient getMemcachedClient() {
|
||||
return mClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve endpoint resoruce from IS
|
||||
* @return List of InetSocketAddresses
|
||||
* @throws Exception
|
||||
*/
|
||||
private static List<InetSocketAddress> discoverHostOfServiceEndpoint(){
|
||||
|
||||
String currentScope = ScopeProvider.instance.get();
|
||||
ApplicationContext ctx = ContextProvider.get(); // get this info from SmartGears
|
||||
String infrastructure = "/"+ctx.container().configuration().infrastructure();
|
||||
ScopeProvider.instance.set(infrastructure);
|
||||
List<InetSocketAddress> toReturn = new ArrayList<InetSocketAddress>();
|
||||
try{
|
||||
SimpleQuery query = queryFor(ServiceEndpoint.class);
|
||||
query.addCondition("$resource/Profile/Name/text() eq '"+ MEMCACHED_RESOURCE_NAME +"'");
|
||||
query.addCondition("$resource/Profile/Category/text() eq '"+ CATEGORY +"'");
|
||||
DiscoveryClient<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
|
||||
List<ServiceEndpoint> ses = client.submit(query);
|
||||
if (ses.isEmpty()) {
|
||||
logger.error("There is no Memcached cluster having name: " + MEMCACHED_RESOURCE_NAME + " and Category " + CATEGORY + " on root context in this infrastructure: ");
|
||||
return null;
|
||||
}
|
||||
for (ServiceEndpoint se : ses) {
|
||||
Group<AccessPoint> aps = se.profile().accessPoints();
|
||||
for (AccessPoint ap : aps.asCollection()) {
|
||||
String address = ap.address(); //e.g. socialnetworking-d-d4s.d4science.org:11211
|
||||
String[] splits = address.split(":");
|
||||
String hostname = splits[0];
|
||||
int port = Integer.parseInt(splits[1]);
|
||||
toReturn.add(new InetSocketAddress(hostname, port));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch(Exception e){
|
||||
logger.error("Error while retrieving hosts for the Memcached cluster having name: " + MEMCACHED_RESOURCE_NAME + " and Category " + CATEGORY + " on root context");
|
||||
}finally{
|
||||
ScopeProvider.instance.set(currentScope);
|
||||
}
|
||||
ScopeProvider.instance.set(currentScope);
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue