r7170 - in dumbhippo/trunk: openfire/src/plugins/hippo/src/java/com/dumbhippo/jive server/src/com/dumbhippo/server server/src/com/dumbhippo/server/dm server/src/com/dumbhippo/server/impl



Author: otaylor
Date: 2008-01-09 21:53:49 -0600 (Wed, 09 Jan 2008)
New Revision: 7170

Added:
   dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/OldBlocksIQHandler.java
Modified:
   dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/BlocksIQHandler.java
   dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/HippoPlugin.java
   dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/QueryIQMethod.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/Stacker.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/dm/GroupChatBlockDMO.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/dm/UserDMO.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/impl/StackerBean.java
Log:
BlockIQHandler Stacker StackerBean: Add new IQ's getOldBlocks (to get blocks possibly not
  at the top of the stack) and setStackFilter
OldBlockIQHandler: Move the legacy IQ's into a renamed class
UserDMO StackerBean: Add .stackFilter property
GroupChatBLockDMO: Fix returning "" for the .titleLink property


Modified: dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/BlocksIQHandler.java
===================================================================
--- dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/BlocksIQHandler.java	2008-01-10 03:26:26 UTC (rev 7169)
+++ dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/BlocksIQHandler.java	2008-01-10 03:53:49 UTC (rev 7170)
@@ -1,150 +1,59 @@
 package com.dumbhippo.jive;
 
-import java.util.Collections;
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.ejb.EJB;
 
-import org.dom4j.Element;
 import org.jivesoftware.util.Log;
 import org.xmpp.packet.IQ;
 
-import com.dumbhippo.TypeUtils;
-import com.dumbhippo.XmlBuilder;
-import com.dumbhippo.identity20.Guid;
-import com.dumbhippo.identity20.Guid.ParseException;
+import com.dumbhippo.dm.DMSession;
 import com.dumbhippo.jive.annotations.IQHandler;
 import com.dumbhippo.jive.annotations.IQMethod;
-import com.dumbhippo.persistence.UserBlockData;
+import com.dumbhippo.persistence.Block;
 import com.dumbhippo.server.NotFoundException;
-import com.dumbhippo.server.Pageable;
 import com.dumbhippo.server.Stacker;
-import com.dumbhippo.server.ViewStreamBuilder;
-import com.dumbhippo.server.blocks.BlockView;
-import com.dumbhippo.server.views.ObjectView;
+import com.dumbhippo.server.dm.BlockDMO;
+import com.dumbhippo.server.dm.BlockDMOKey;
+import com.dumbhippo.server.dm.DataService;
 import com.dumbhippo.server.views.UserViewpoint;
-import com.dumbhippo.server.views.ViewStream;
 
 @IQHandler(namespace=BlocksIQHandler.BLOCKS_NAMESPACE)
 public class BlocksIQHandler extends AnnotatedIQHandler {
-	static final String BLOCKS_NAMESPACE = "http://dumbhippo.com/protocol/blocks";; 
+	static final String BLOCKS_NAMESPACE = "http://mugshot.org/p/blocks";; 
 	
 	@EJB
 	private Stacker stacker;
 	
-	@EJB
-	private ViewStreamBuilder viewStreamBuilder;
-
 	public BlocksIQHandler() {
-		super("Hippo blocks IQ Handler");
+		super("Hippo Blocks IQ Handler");
 		Log.debug("creating BlocksIQHandler");
 	}
 	
-	private String getBlocksXml(UserViewpoint viewpoint, String filter, String elementName, List<BlockView> views) {
-		List<ObjectView> objectList = TypeUtils.castList(ObjectView.class, views);
-		
-		XmlBuilder xml = new XmlBuilder();
-		
-		xml.openElement(elementName,
-					    "xmlns", BLOCKS_NAMESPACE,
-					    "filter", filter,
-				        "serverTime", Long.toString(System.currentTimeMillis()));
-		
-		ViewStream stream = viewStreamBuilder.buildStream(viewpoint, objectList);
-		stream.writeToXmlBuilder(xml);
-		
-		xml.closeElement();
-		
-		return xml.toString();
-	}
-
-	private boolean parseBoolean(String value) throws IQException {
-        if (value.equals("true"))
-        	return true;
-        else if (value.equals("false"))
-        	return false;
-        else
-        	throw IQException.createBadRequest("Unrecognized boolean value '" + value + "'");
-	}
 	
-	@IQMethod(name="blocks", type=IQ.Type.get)
-	public void getBlocks(UserViewpoint viewpoint, IQ request, IQ reply) throws IQException {
-		Element child = request.getChildElement();
+	// See docs for Stacker.getOldBlocks() for details
+	
+	@IQMethod(name="getOldBlocks", type=IQ.Type.get)
+	@IQParams({ "filter=null", "stackedBefore=-1", "desiredCount=20" })
+	public List<BlockDMO> getOldBlocks(UserViewpoint viewpoint, String filter, long stackedBefore, int desiredCount) throws IQException {
+		List<BlockDMO> results = new ArrayList<BlockDMO>();
 		
-        String lastTimestampStr = child.attributeValue("lastTimestamp");
-        if (lastTimestampStr == null)
-        	throw IQException.createBadRequest("get/blocks IQ missing lastTimestamp attribute");
-        
-        String filter = child.attributeValue("filter");
-        boolean filterProvided = (filter != null);
-        if (!filterProvided) {
-        	filter = stacker.getUserStackFilterPrefs(viewpoint.getViewer());
-        } else {
-        	stacker.setUserStackFilterPrefs(viewpoint.getViewer(), filter);
-        }
-        
-        long lastTimestamp;
-        try {
-        	lastTimestamp = Long.parseLong(lastTimestampStr);
-        } catch (NumberFormatException e) {
-        	throw IQException.createBadRequest("get/blocks IQ lastTimestamp attribute not valid");
-        }      
-        
-		Pageable<BlockView> pageable = new Pageable<BlockView>("stack");
-		pageable.setPosition(0);
-		pageable.setInitialPerPage(25);
-		stacker.pageStack(viewpoint, viewpoint.getViewer(), pageable, lastTimestamp, filter, false);
-		List<BlockView> views = pageable.getResults();
+		DMSession session = DataService.currentSessionRO();
 		
-		// If views.size() == 0, there can be no missing unanswered questions; skip to avoid having
-		// to deal with the 'views.size() - 1 == -1' case
-		if (lastTimestamp <= 0 && views.size() > 0) {
-			long earliestTimestamp = views.get(views.size() - 1).getUserBlockData().getStackTimestampAsLong();
-			views.addAll(stacker.getUnansweredQuestions(viewpoint, earliestTimestamp));
+		for (Block block : stacker.getOldBlocks(viewpoint, filter, stackedBefore, desiredCount)) {
+			try {
+				results.add(session.find(BlockDMO.class, new BlockDMOKey(block)));
+			} catch (NotFoundException e) {
+			}
 		}
 		
-		String xml = getBlocksXml(viewpoint, filterProvided ? null : filter, "blocks", views);
-        
-		reply.setChildElement(XmlParser.elementFromXml(xml));
+		return results;
 	}
-
-	@IQMethod(name="blockHushed", type=IQ.Type.set)
-	public void setBlockHushed(UserViewpoint viewpoint, IQ request, IQ reply) throws IQException {
-		Element child = request.getChildElement();
-		
-        String blockId = child.attributeValue("blockId");
-        if (blockId == null)
-        	throw IQException.createBadRequest("missing blockId attribute");
-        Guid blockGuid;
-        try {
-        	blockGuid = new Guid(blockId);
-        } catch (ParseException e) {
-        	throw IQException.createBadRequest("invalid blockId attribute");
-        }
-        
-        UserBlockData userBlockData;
-        try {
-			userBlockData = stacker.lookupUserBlockData(viewpoint, blockGuid);
-		} catch (NotFoundException e) {
-        	throw IQException.createBadRequest("blockId attribute doesn't refer to a recognized block for this user");
-		}
-        
-        String value = child.attributeValue("hushed");
-        if (value == null)
-        	throw IQException.createBadRequest("missing hushed attribute");
-        
-        boolean hushed = parseBoolean(value);
-        
-        stacker.setBlockHushed(userBlockData, hushed);
-        
-        BlockView blockView;
-		try {
-			blockView = stacker.loadBlock(viewpoint, userBlockData);
-		} catch (NotFoundException e) {
-			throw new RuntimeException("Can't load block view for the user's own block", e);
-		}
-        
-		String xml = getBlocksXml(viewpoint, null, "blockHushed", Collections.singletonList(blockView));
-		reply.setChildElement(XmlParser.elementFromXml(xml));
+	
+	@IQMethod(name="setStackFilter", type=IQ.Type.set)
+	@IQParams({ "filter=null" })
+	public void setStackFilter(UserViewpoint viewpoint, String filter) throws IQException {
+		stacker.setUserStackFilterPrefs(viewpoint.getViewer(), filter);
 	}
 }

Modified: dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/HippoPlugin.java
===================================================================
--- dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/HippoPlugin.java	2008-01-10 03:26:26 UTC (rev 7169)
+++ dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/HippoPlugin.java	2008-01-10 03:53:49 UTC (rev 7170)
@@ -90,7 +90,8 @@
 			addIQHandler(new HotnessIQHandler());	
 			addIQHandler(new RecentPostsIQHandler());
 			addIQHandler(new PostControlsIQHandler());
-			addIQHandler(new GroupIQHandler());			
+			addIQHandler(new GroupIQHandler());	
+			addIQHandler(new OldBlocksIQHandler());
 			addIQHandler(new BlocksIQHandler());
 			addIQHandler(new AccountQuestionIQHandler());
 			addIQHandler(new SettingsIQHandler());			

Added: dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/OldBlocksIQHandler.java
===================================================================
--- dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/OldBlocksIQHandler.java	2008-01-10 03:26:26 UTC (rev 7169)
+++ dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/OldBlocksIQHandler.java	2008-01-10 03:53:49 UTC (rev 7170)
@@ -0,0 +1,150 @@
+package com.dumbhippo.jive;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.ejb.EJB;
+
+import org.dom4j.Element;
+import org.jivesoftware.util.Log;
+import org.xmpp.packet.IQ;
+
+import com.dumbhippo.TypeUtils;
+import com.dumbhippo.XmlBuilder;
+import com.dumbhippo.identity20.Guid;
+import com.dumbhippo.identity20.Guid.ParseException;
+import com.dumbhippo.jive.annotations.IQHandler;
+import com.dumbhippo.jive.annotations.IQMethod;
+import com.dumbhippo.persistence.UserBlockData;
+import com.dumbhippo.server.NotFoundException;
+import com.dumbhippo.server.Pageable;
+import com.dumbhippo.server.Stacker;
+import com.dumbhippo.server.ViewStreamBuilder;
+import com.dumbhippo.server.blocks.BlockView;
+import com.dumbhippo.server.views.ObjectView;
+import com.dumbhippo.server.views.UserViewpoint;
+import com.dumbhippo.server.views.ViewStream;
+
+ IQHandler(namespace=OldBlocksIQHandler.BLOCKS_NAMESPACE)
+public class OldBlocksIQHandler extends AnnotatedIQHandler {
+	static final String BLOCKS_NAMESPACE = "http://dumbhippo.com/protocol/blocks";; 
+	
+	@EJB
+	private Stacker stacker;
+	
+	@EJB
+	private ViewStreamBuilder viewStreamBuilder;
+
+	public OldBlocksIQHandler() {
+		super("Old Hippo Blocks IQ Handler");
+		Log.debug("creating OldBlocksIQHandler");
+	}
+	
+	private String getBlocksXml(UserViewpoint viewpoint, String filter, String elementName, List<BlockView> views) {
+		List<ObjectView> objectList = TypeUtils.castList(ObjectView.class, views);
+		
+		XmlBuilder xml = new XmlBuilder();
+		
+		xml.openElement(elementName,
+					    "xmlns", BLOCKS_NAMESPACE,
+					    "filter", filter,
+				        "serverTime", Long.toString(System.currentTimeMillis()));
+		
+		ViewStream stream = viewStreamBuilder.buildStream(viewpoint, objectList);
+		stream.writeToXmlBuilder(xml);
+		
+		xml.closeElement();
+		
+		return xml.toString();
+	}
+
+	private boolean parseBoolean(String value) throws IQException {
+        if (value.equals("true"))
+        	return true;
+        else if (value.equals("false"))
+        	return false;
+        else
+        	throw IQException.createBadRequest("Unrecognized boolean value '" + value + "'");
+	}
+	
+	@IQMethod(name="blocks", type=IQ.Type.get)
+	public void getBlocks(UserViewpoint viewpoint, IQ request, IQ reply) throws IQException {
+		Element child = request.getChildElement();
+		
+        String lastTimestampStr = child.attributeValue("lastTimestamp");
+        if (lastTimestampStr == null)
+        	throw IQException.createBadRequest("get/blocks IQ missing lastTimestamp attribute");
+        
+        String filter = child.attributeValue("filter");
+        boolean filterProvided = (filter != null);
+        if (!filterProvided) {
+        	filter = stacker.getUserStackFilterPrefs(viewpoint.getViewer());
+        } else {
+        	stacker.setUserStackFilterPrefs(viewpoint.getViewer(), filter);
+        }
+        
+        long lastTimestamp;
+        try {
+        	lastTimestamp = Long.parseLong(lastTimestampStr);
+        } catch (NumberFormatException e) {
+        	throw IQException.createBadRequest("get/blocks IQ lastTimestamp attribute not valid");
+        }      
+        
+		Pageable<BlockView> pageable = new Pageable<BlockView>("stack");
+		pageable.setPosition(0);
+		pageable.setInitialPerPage(25);
+		stacker.pageStack(viewpoint, viewpoint.getViewer(), pageable, lastTimestamp, filter, false);
+		List<BlockView> views = pageable.getResults();
+		
+		// If views.size() == 0, there can be no missing unanswered questions; skip to avoid having
+		// to deal with the 'views.size() - 1 == -1' case
+		if (lastTimestamp <= 0 && views.size() > 0) {
+			long earliestTimestamp = views.get(views.size() - 1).getUserBlockData().getStackTimestampAsLong();
+			views.addAll(stacker.getUnansweredQuestions(viewpoint, earliestTimestamp));
+		}
+		
+		String xml = getBlocksXml(viewpoint, filterProvided ? null : filter, "blocks", views);
+        
+		reply.setChildElement(XmlParser.elementFromXml(xml));
+	}
+
+	@IQMethod(name="blockHushed", type=IQ.Type.set)
+	public void setBlockHushed(UserViewpoint viewpoint, IQ request, IQ reply) throws IQException {
+		Element child = request.getChildElement();
+		
+        String blockId = child.attributeValue("blockId");
+        if (blockId == null)
+        	throw IQException.createBadRequest("missing blockId attribute");
+        Guid blockGuid;
+        try {
+        	blockGuid = new Guid(blockId);
+        } catch (ParseException e) {
+        	throw IQException.createBadRequest("invalid blockId attribute");
+        }
+        
+        UserBlockData userBlockData;
+        try {
+			userBlockData = stacker.lookupUserBlockData(viewpoint, blockGuid);
+		} catch (NotFoundException e) {
+        	throw IQException.createBadRequest("blockId attribute doesn't refer to a recognized block for this user");
+		}
+        
+        String value = child.attributeValue("hushed");
+        if (value == null)
+        	throw IQException.createBadRequest("missing hushed attribute");
+        
+        boolean hushed = parseBoolean(value);
+        
+        stacker.setBlockHushed(userBlockData, hushed);
+        
+        BlockView blockView;
+		try {
+			blockView = stacker.loadBlock(viewpoint, userBlockData);
+		} catch (NotFoundException e) {
+			throw new RuntimeException("Can't load block view for the user's own block", e);
+		}
+        
+		String xml = getBlocksXml(viewpoint, null, "blockHushed", Collections.singletonList(blockView));
+		reply.setChildElement(XmlParser.elementFromXml(xml));
+	}
+}

Modified: dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/QueryIQMethod.java
===================================================================
--- dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/QueryIQMethod.java	2008-01-10 03:26:26 UTC (rev 7169)
+++ dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/QueryIQMethod.java	2008-01-10 03:53:49 UTC (rev 7170)
@@ -73,6 +73,8 @@
 				paramInfo[i] = new BooleanParamInfo(name, defaultValue);
 			} else if (paramType == Integer.TYPE) {
 				paramInfo[i] = new IntegerParamInfo(name, defaultValue);
+			} else if (paramType == Long.TYPE) {
+				paramInfo[i] = new LongParamInfo(name, defaultValue);
 			} else if (paramType.isAssignableFrom(UserViewpoint.class)) {
 				paramInfo[i] = new ViewpointParamInfo();
 			} else if (DMObject.class.isAssignableFrom(paramType)) {
@@ -212,6 +214,23 @@
 		}
 	}
 	
+	private static class LongParamInfo extends ParamInfo {
+		protected LongParamInfo(String name, String defaultValue) {
+			super(name, defaultValue);
+			if (optional && defaultValue == null)
+				throw new RuntimeException("null is not a valid default for an long parameter");
+		}
+
+		@Override
+		public Object parse(String value) throws IQException {
+			try {
+				return Long.parseLong(value);
+			} catch (NumberFormatException e) {
+				throw IQException.createBadRequest("Bad long value for parameter '" + value + "': " + e.getMessage());
+			}
+		}
+	}
+	
 	private static class DMOParamInfo extends ParamInfo {
 		private Class<?> clazz;
 		

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/Stacker.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/Stacker.java	2008-01-10 03:26:26 UTC (rev 7169)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/Stacker.java	2008-01-10 03:53:49 UTC (rev 7170)
@@ -173,6 +173,23 @@
 	 * @return list of blockviews, sorted in reverse-chronological order
 	 */
 	public List<BlockView> getUnansweredQuestions(UserViewpoint viewpoint, long stackedBefore);
+	
+	/**
+	 * Gets a set of blocks of interest to a user. The intent here is to be used to round out 
+	 * the top of the user's stack with other interesting blocks, hence the name "old blocks".
+	 * The two types of "blocks of interest" that might not be at the top of the stack
+	 * are old unanswered account question blocks, and blocks that are more specifically
+	 * filtered than in the stack.
+	 * 
+	 * @param viewpoint the user
+	 * @param filter string specifying filter on the blocks to return
+	 * @param stackedBefore only return blocks stacked before this timestamp
+	 * @param desiredCount target number of blocks to return (more may be returned under some circumstances,
+	 *    such as having outstanding unanswered account question blocks)
+	 * 
+	 * @return list of blockviews, sorted in reverse-chronological order
+	 */
+	public List<Block> getOldBlocks(UserViewpoint viewpoint, String filter, long stackedBefore, int desiredCount);
 
 	public UserBlockData lookupUserBlockData(UserViewpoint viewpoint, Guid guid) throws NotFoundException;
 	public UserBlockData lookupUserBlockData(UserViewpoint viewpoint, BlockKey key) throws NotFoundException;

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/dm/GroupChatBlockDMO.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/dm/GroupChatBlockDMO.java	2008-01-10 03:26:26 UTC (rev 7169)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/dm/GroupChatBlockDMO.java	2008-01-10 03:53:49 UTC (rev 7170)
@@ -20,4 +20,12 @@
 	public StoreKey<?,?> getVisibilityDelegate() {
 		return getGroup().getStoreKey();
 	}
+	
+	// GroupMemberBlockView returns "" for the title link, and I'm hestitant to change
+	// that for fear something is depending on it in the JSP's, so we just override
+	// it here to a more sensible null.
+	@Override
+	public String getTitleLink() {
+		return null;
+	}
 }

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/dm/UserDMO.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/dm/UserDMO.java	2008-01-10 03:26:26 UTC (rev 7169)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/dm/UserDMO.java	2008-01-10 03:53:49 UTC (rev 7170)
@@ -433,6 +433,12 @@
 		return result;
 	}
 	
+	@DMProperty
+	@DMFilter("viewer.canSeePrivate(this)")
+	public String getStackFilter() {
+		return user.getAccount().getStackFilter();
+	}
+	
 	@DMInit(group=CURRENT_TRACK_GROUP)
 	public void initCurrentTrack() {
 		try {

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/impl/StackerBean.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/impl/StackerBean.java	2008-01-10 03:26:26 UTC (rev 7169)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/impl/StackerBean.java	2008-01-10 03:53:49 UTC (rev 7170)
@@ -986,7 +986,8 @@
 	 * 
 	 * @param viewpoint
 	 * @param user
-	 * @param lastTimestamp -1 to ignore this param, otherwise the timestamp to get changes since
+	 * @param lastTimestamp -1 to ignore this param, otherwise only return blocks newer than this
+	 * @param stackedBefore -1 to ignore this param, otherwise only return blocks older than this
 	 * @param start
 	 * @param count
 	 * @param participantOnly if true, only include blocks where someone participated, and sort by participation time 
@@ -995,7 +996,9 @@
 	 * @param noSelfSource 
 	 * @return 
 	 */
-	private List<UserBlockData> getBlocks(Viewpoint viewpoint, User user, long lastTimestamp, int start, int count, 
+	private List<UserBlockData> getBlocks(Viewpoint viewpoint, User user, 
+									      long lastTimestamp, long stackedBefore,
+										  int start, int count, 
 			                              String filter, boolean participantOnly) {
 		StackFilterExpression parsedExpression = new StackFilterExpression(filter);
 		
@@ -1017,6 +1020,14 @@
 		if (lastTimestamp > 0)
 			sb.append(" AND ubd.stackTimestamp > :timestamp ");
 		
+		// if lastTimestamp == 0 then all blocks are included so just skip the test in the sql
+		// The timestamp here is the timestamp of the block last seen by the client. 
+		// Using > here rather than >= means that if two blocks are stacked within the
+		// same millisecond and notified on separately, then the second block will get
+		// lost, but that's better than always sending two blocks.
+		if (stackedBefore > 0)
+			sb.append(" AND ubd.stackTimestamp < :stackedBefore ");
+
 		if (parsedExpression.isNoFeed())
 			sb.append(" AND block.filterFlags != " + StackFilterFlags.FEED.getValue());
 		
@@ -1078,6 +1089,8 @@
 		q.setMaxResults(count);
 		if (lastTimestamp > 0)
 			q.setParameter("timestamp", new Date(lastTimestamp));
+		if (stackedBefore > 0)
+			q.setParameter("stackedBefore", new Date(stackedBefore));
 		q.setParameter("user", user);
 		if (viewpoint instanceof UserViewpoint)
 			q.setParameter("viewpointGuid", ((UserViewpoint) viewpoint).getViewer().getGuid().toString());
@@ -1087,7 +1100,7 @@
 
 	// Note the off-by-one difference betweeb minTimestamp and lastTimestamp
 	public List<UserBlockData> getStackBlocks(User user, int start, int count, long minTimestamp) {
-		return getBlocks(SystemViewpoint.getInstance(), user, minTimestamp - 1, start, count, null, false);
+		return getBlocks(SystemViewpoint.getInstance(), user, minTimestamp - 1, -1, start, count, null, false);
 	}
 	
 	private interface BlockSource<T> {
@@ -1176,7 +1189,7 @@
 		pageStack(viewpoint, new BlockSource<UserBlockData>() {
 			public List<Pair<Block, UserBlockData>> get(int start, int count) {
 				List<Pair<Block, UserBlockData>> results = new ArrayList<Pair<Block, UserBlockData>>();
-				for (UserBlockData ubd : getBlocks(viewpoint, user, lastTimestamp, start, count, filter, participantOnly)) {
+				for (UserBlockData ubd : getBlocks(viewpoint, user, lastTimestamp, -1, start, count, filter, participantOnly)) {
 					results.add(new Pair<Block, UserBlockData>(ubd.getBlock(), ubd));
 				}
 				return results;
@@ -1614,20 +1627,23 @@
 		pageable.setTotalCount(groupSystem.getPublicGroupCount());
 	}
 	
-
-	public List<BlockView> getUnansweredQuestions(UserViewpoint viewpoint, long stackedBefore) {
+	private List<UserBlockData> getUnansweredQuestionsBlockData(UserViewpoint viewpoint, long stackedBefore) {
 		Query q = em.createQuery("   SELECT ubd FROM UserBlockData ubd " +
-				                 "    WHERE ubd.user = :user " +
-				                 "      AND ubd.block.blockType = " + BlockType.ACCOUNT_QUESTION.ordinal() + " " +
-				                 "      AND ubd.clickedTimestamp IS NULL " +
-				                 "      AND ubd.stackTimestamp < :stackedBefore " +
-				                 " ORDER BY ubd.stackTimestamp DESC")
-		    .setParameter("user", viewpoint.getViewer())
-		    .setParameter("stackedBefore", new Date(stackedBefore));
+                "    WHERE ubd.user = :user " +
+                "      AND ubd.block.blockType = " + BlockType.ACCOUNT_QUESTION.ordinal() + " " +
+                "      AND ubd.clickedTimestamp IS NULL " +
+                "      AND ubd.stackTimestamp < :stackedBefore " +
+                " ORDER BY ubd.stackTimestamp DESC")
+           .setParameter("user", viewpoint.getViewer())
+           .setParameter("stackedBefore", new Date(stackedBefore));
 		
+		return TypeUtils.castList(UserBlockData.class, q.getResultList());
+	}
+	
+	public List<BlockView> getUnansweredQuestions(UserViewpoint viewpoint, long stackedBefore) {
 		List<BlockView> results = new ArrayList<BlockView>();
 		
-		for (UserBlockData ubd : TypeUtils.castList(UserBlockData.class, q.getResultList())) {
+		for (UserBlockData ubd : getUnansweredQuestionsBlockData(viewpoint, stackedBefore)) {
 			try {
 				results.add(loadBlock(viewpoint, ubd));
 			} catch (NotFoundException e) {
@@ -1639,6 +1655,21 @@
 		return results;
 	}	
 	
+	public List<Block> getOldBlocks(UserViewpoint viewpoint, String filter, long stackedBefore, int desiredCount) {
+		List<Block> results = new ArrayList<Block>();
+		
+		for (UserBlockData ubd : getUnansweredQuestionsBlockData(viewpoint, stackedBefore)) {
+			results.add(ubd.getBlock());
+		}
+		
+		for (UserBlockData ubd : getBlocks(viewpoint, viewpoint.getViewer(), -1, stackedBefore, 0, desiredCount - results.size(), filter, false)) {
+			results.add(ubd.getBlock());
+		}
+
+		
+		return results;
+	}	
+
 	public UserBlockData lookupUserBlockData(UserViewpoint viewpoint, Guid guid) throws NotFoundException {
 		Query q = em.createQuery("SELECT ubd FROM UserBlockData ubd, Block block WHERE ubd.user = :user AND ubd.block = block AND block.id = :blockId");
 		q.setParameter("user", viewpoint.getViewer());
@@ -2234,5 +2265,6 @@
 	
 	public void setUserStackFilterPrefs(User user, String filter) {
 		user.getAccount().setStackFilter(filter);
+		DataService.currentSessionRW().changed(UserDMO.class, user.getGuid(), "stackFilter");
 	}
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]