Skip to content

Commit

Permalink
SSP-256 Additions for Completed state on click
Browse files Browse the repository at this point in the history
  • Loading branch information
codepuppet committed Feb 26, 2015
1 parent 448fd31 commit 07b26c1
Show file tree
Hide file tree
Showing 21 changed files with 614 additions and 11 deletions.
Expand Up @@ -19,9 +19,11 @@

package org.jasig.portlet.notice;

import java.io.IOException;
import java.io.Serializable;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

Expand Down Expand Up @@ -76,8 +78,8 @@ public final void setLabel(String label) {
/**
* Perform this action on the notification to which it is attached.
*/
public abstract void invoke(ActionRequest req);

public abstract void invoke(ActionRequest req, ActionResponse res) throws IOException;
/**
* Implements deep-copy clone.
*
Expand Down
Expand Up @@ -19,10 +19,12 @@

package org.jasig.portlet.notice.action.favorite;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;

Expand Down Expand Up @@ -70,7 +72,7 @@ public static final FavoriteAction createUnfavoriteInstance() {
* Invoking a FavoriteAction toggles it.
*/
@Override
public void invoke(final ActionRequest req) {
public void invoke(final ActionRequest req, final ActionResponse res) throws IOException {
final NotificationEntry entry = getTarget();
final String notificationId = entry.getId();
final Set<String> favoriteNotices = this.getFavoriteNotices(req);
Expand Down
Expand Up @@ -19,10 +19,12 @@

package org.jasig.portlet.notice.action.hide;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;

Expand Down Expand Up @@ -70,7 +72,7 @@ public HideAction() {
* Invoking a HideAction toggles it.
*/
@Override
public void invoke(final ActionRequest req) {
public void invoke(final ActionRequest req, final ActionResponse res) throws IOException {
final NotificationEntry entry = getTarget();
final String notificationId = entry.getId();
final Map<String,Long> hiddenNoticesMap = this.getHiddenNoticesMap(req);
Expand Down
Expand Up @@ -19,10 +19,12 @@

package org.jasig.portlet.notice.action.read;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;

Expand Down Expand Up @@ -75,7 +77,7 @@ public static final ReadAction createUnReadInstance() {
* Invoking a ReadAction toggles it.
*/
@Override
public void invoke(final ActionRequest req) {
public void invoke(final ActionRequest req, final ActionResponse res) throws IOException {
final NotificationEntry entry = getTarget();
final String notificationId = entry.getId();
final Set<String> readNotices = this.getReadNotices(req);
Expand Down
@@ -0,0 +1,66 @@
/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.jasig.portlet.notice.action.stateChange;

import java.io.IOException;
import java.util.Date;
import java.util.Map;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletPreferences;
import org.jasig.portlet.notice.NotificationAction;
import org.jasig.portlet.notice.NotificationEntry;
import org.jasig.portlet.notice.NotificationState;
import org.jasig.portlet.notice.service.jpa.JpaNotificationService;
import org.jasig.portlet.notice.util.SpringContext;

/**
*
* @author mglazier
*/
public class StateChangeAction extends NotificationAction {

@Override
public void invoke(final ActionRequest req, final ActionResponse res) throws IOException {
JpaNotificationService jpaService = (JpaNotificationService) SpringContext.getApplicationContext().getBean("jpaNotificationService");

final PortletPreferences prefs = req.getPreferences();
final String clickedState = prefs.getValue("applyStateWhenClicked", "COMPLETED");
NotificationState notificationState = NotificationState.valueOf(clickedState);

boolean completedStateFound = false;

final NotificationEntry entry = getTarget();
Map<NotificationState,Date> stateMap = entry.getStates();
if (stateMap != null && stateMap.size() > 0) {
for ( NotificationState state: stateMap.keySet()) {
if (state == notificationState) {
completedStateFound = true;
}
}
}

if (!completedStateFound) {
jpaService.updateEntryState(req, entry.getId(), notificationState);
}

res.sendRedirect(entry.getUrl());
}
}
@@ -0,0 +1,107 @@
/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.jasig.portlet.notice.action.stateChange;

import java.util.ArrayList;
import java.util.List;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.portlet.notice.INotificationService;
import org.jasig.portlet.notice.NotificationAction;
import org.jasig.portlet.notice.NotificationCategory;
import org.jasig.portlet.notice.NotificationEntry;
import org.jasig.portlet.notice.NotificationResponse;

/**
*
* @author mglazier
*/
public class StateChangeNotificationServiceDecorator implements INotificationService {

public static final String STATE_CHANGE_ENABLED_PREFERENCE = "autoApplyStateWhenClicked";
public static final String DEFAULT_STATE_CHANGE_BEHAVIOR = "false"; // The feature is disabled by default

// Instance members
private INotificationService enclosedNotificationService;
private final Log log = LogFactory.getLog(getClass());

public void setEnclosedNotificationService(INotificationService enclosedNotificationService) {
this.enclosedNotificationService = enclosedNotificationService;
}

@Override
public String getName() {
return enclosedNotificationService.getName();
}

@Override
public void invoke(ActionRequest req, ActionResponse res, boolean refresh) {
enclosedNotificationService.invoke(req, res, refresh);
}

@Override
public void collect(EventRequest req, EventResponse res) {
enclosedNotificationService.collect(req, res);
}

@Override
public NotificationResponse fetch(PortletRequest req) {
// Just pass through the enclosed collection if this feature is disabled
if (!stateChangeEnabled(req)) {
return enclosedNotificationService.fetch(req);
}

// Build a fresh NotificationResponse based on a deep-copy of the one we enclose
final NotificationResponse sourceResponse = enclosedNotificationService.fetch(req);
NotificationResponse rslt = sourceResponse.cloneIfNotCloned();

for (NotificationCategory category : rslt.getCategories()) {
for (NotificationEntry entry : category.getEntries()) {
final List<NotificationAction> currentList = entry.getAvailableActions();

if (StringUtils.isNotBlank(entry.getId())) {
if (StringUtils.isNotBlank(entry.getId())) {
final List<NotificationAction> replacementList = new ArrayList<>(currentList);
replacementList.add( new StateChangeAction());
entry.setAvailableActions( replacementList);
}
}
}
}
return rslt;
}

@Override
public boolean isValid(PortletRequest req, NotificationResponse previousResponse) {
return enclosedNotificationService.isValid(req, previousResponse);
}

private boolean stateChangeEnabled(PortletRequest request) {
PortletPreferences prefs = request.getPreferences();
return Boolean.valueOf(prefs.getValue(STATE_CHANGE_ENABLED_PREFERENCE, DEFAULT_STATE_CHANGE_BEHAVIOR));
}
}
Expand Up @@ -182,7 +182,7 @@ public void invokeNotificationService(final ActionRequest req, final ActionRespo
@ActionMapping
public void invokeUserAction(final ActionRequest req, final ActionResponse res,
@RequestParam("notificationId") final String notificationId,
@RequestParam("actionId") final String actionId) {
@RequestParam("actionId") final String actionId) throws IOException {

// Prime the pump
notificationService.invoke(req, res, false);
Expand All @@ -204,7 +204,7 @@ public void invokeUserAction(final ActionRequest req, final ActionResponse res,

// We must have a target to proceed
if (target != null) {
target.invoke(req);
target.invoke(req, res);
} else {
String msg = "Target action not found for notificationId='"
+ notificationId + "' and actionId='" + actionId + "'";
Expand Down
Expand Up @@ -47,4 +47,5 @@ Set<JpaEntry> getEntriesByRecipientByStatus(String username,
*/
List<JpaEvent> getEvents(long entryId, String username);

JpaEvent createOrUpdateEvent(JpaEvent event);
}
Expand Up @@ -116,4 +116,12 @@ public List<JpaEvent> getEvents(long entryId, String username) {
return rslt;
}

@Override
@Transactional
public JpaEvent createOrUpdateEvent(JpaEvent event) {
Validate.notNull(event, "Argument 'event' cannot be null");

JpaEvent rslt = entityManager.merge(event);
return rslt;
}
}
Expand Up @@ -19,6 +19,7 @@

package org.jasig.portlet.notice.service.jpa;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
Expand Down Expand Up @@ -94,7 +95,26 @@ public NotificationResponse fetch(PortletRequest req) {
return rslt;

}


public void updateEntryState(PortletRequest req, String entryId, NotificationState state) {
if (usernameFinder.isAuthenticated(req)) {
final String username = usernameFinder.findUsername(req);

String idStr = entryId.replaceAll(ID_PREFIX, ""); // remove the prefix

JpaEntry jpaEntry = notificationDao.getEntry(Long.parseLong(idStr));
if (jpaEntry != null) {
JpaEvent event = new JpaEvent();
event.setEntry(jpaEntry);
event.setState(state);
event.setTimestamp(new Timestamp(new Date().getTime()));
event.setUsername(username);

notificationDao.createOrUpdateEvent(event);
}
}
}

/*
* Implementation
*/
Expand Down
@@ -0,0 +1,43 @@
/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.jasig.portlet.notice.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
*
* @author mglazier
*/
public class SpringContext implements ApplicationContextAware {

private static ApplicationContext context;

@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
SpringContext.context = context;
}

public static ApplicationContext getApplicationContext() {
return context;
}

}
Expand Up @@ -184,4 +184,6 @@
<property name="active" value="false"/> <!-- The emergency alerts demo can be activated by the EmergencyAlertAdminController. -->
</bean>

<!-- Use this to get bean refs from non-Spring managed classes -->
<bean id="springContext" class="org.jasig.portlet.notice.util.SpringContext" />
</beans>
Expand Up @@ -44,6 +44,9 @@
| defined in the parent applicationContext.
+-->
<bean id="rootNotificationService" class="org.jasig.portlet.notice.action.hide.HideNotificationServiceDecorator">
<property name="enclosedNotificationService" ref="stateChangeNotificationService"/>
</bean>
<bean id="stateChangeNotificationService" class="org.jasig.portlet.notice.action.stateChange.StateChangeNotificationServiceDecorator">
<property name="enclosedNotificationService" ref="readNotificationService"/>
</bean>
<bean id="readNotificationService" class="org.jasig.portlet.notice.action.read.ReadNotificationServiceDecorator">
Expand Down

0 comments on commit 07b26c1

Please sign in to comment.