r7146 - in dumbhippo/trunk/server/src/com/dumbhippo: persistence server server/blocks server/impl services



Author: marinaz
Date: 2008-01-07 20:12:04 -0600 (Mon, 07 Jan 2008)
New Revision: 7146

Modified:
   dumbhippo/trunk/server/src/com/dumbhippo/persistence/BlockType.java
   dumbhippo/trunk/server/src/com/dumbhippo/persistence/ExternalAccountType.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/FacebookTracker.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/blocks/FlickrPersonBlockView.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/blocks/PicasaPersonBlockView.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/blocks/YouTubePersonBlockView.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/impl/FacebookTrackerBean.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/impl/StackerBean.java
   dumbhippo/trunk/server/src/com/dumbhippo/services/FacebookWebServices.java
Log:
Publish updates about user actions to the Facebook news feeds.

Modified: dumbhippo/trunk/server/src/com/dumbhippo/persistence/BlockType.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/persistence/BlockType.java	2008-01-07 22:25:39 UTC (rev 7145)
+++ dumbhippo/trunk/server/src/com/dumbhippo/persistence/BlockType.java	2008-01-08 02:12:04 UTC (rev 7146)
@@ -161,6 +161,11 @@
 		public boolean isDirectlyChattable() {
 			return false;
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.FACEBOOK;
+		}
 	},
 	FACEBOOK_EVENT { // 8
 		@Override
@@ -182,6 +187,11 @@
 		public boolean isDirectlyChattable() {
 			return false; // not completely clear ... it would make sense for some subtypes and not others
 		}
+
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.FACEBOOK;
+		}
 	},
 	FLICKR_PERSON { // 9
 		// Right now we only get completely public Flickr photos
@@ -199,6 +209,11 @@
 		public boolean isDirectlyChattable() {
 			return true; // per-photo chats might make more sense long-term
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.FACEBOOK;
+		}
 	},
 	FLICKR_PHOTOSET { // 10
 		// Right now we only get completely public Flickr photosets
@@ -216,6 +231,11 @@
 		public boolean isDirectlyChattable() {
 			return true;
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.FLICKR;
+		}
 	},
 	YOUTUBE_PERSON { // 11
 		@Override
@@ -232,6 +252,11 @@
 		public boolean isDirectlyChattable() {
 			return true;  // per-video chats might make more sense long-term
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.YOUTUBE;
+		}
 	},
 	MYSPACE_PERSON { // 12
 		@Override
@@ -248,6 +273,11 @@
 		public boolean isDirectlyChattable() {
 			return false; // wait until we have block-per-entry
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.MYSPACE;
+		}
 	},
 	MUSIC_CHAT { // 13
 		@Override
@@ -280,6 +310,11 @@
 		public boolean isDirectlyChattable() {
 			return true;
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.BLOG;
+		}
 	},
 	DELICIOUS_PUBLIC_BOOKMARK { // 15
 		@Override
@@ -296,6 +331,11 @@
 		public boolean isDirectlyChattable() {
 			return true;
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.DELICIOUS;
+		}
 	},
 	TWITTER_PERSON { // 16
 		@Override
@@ -312,6 +352,11 @@
 		public boolean isDirectlyChattable() {
 			return false;
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.TWITTER;
+		}
 	},
 	// an item from the Digg "stuff you Dugg" feed
 	DIGG_DUGG_ENTRY { // 17
@@ -329,6 +374,11 @@
 		public boolean isDirectlyChattable() {
 			return true;
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.DIGG;
+		}
 	},
 	// an item from the Reddit Overview feed, which is your comments and submissions both
 	REDDIT_ACTIVITY_ENTRY { // 18
@@ -346,6 +396,11 @@
 		public boolean isDirectlyChattable() {
 			return true;
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.REDDIT;
+		}
 	},
 	// a revision to a group's attributes
 	GROUP_REVISION { // 19		
@@ -378,6 +433,11 @@
 		public boolean isDirectlyChattable() {
 			return true;
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.NETFLIX;
+		}
 	},
 	// a question to the user about account options
 	ACCOUNT_QUESTION { // 21
@@ -416,6 +476,11 @@
 		public boolean isDirectlyChattable() {
 			return true;
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.GOOGLE_READER;
+		}
 	},
 	PICASA_PERSON { // 23
 		@Override
@@ -432,6 +497,11 @@
 		public boolean isDirectlyChattable() {
 			return true; // might want per-album chats eventually
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.PICASA;
+		}
 	},
 	AMAZON_REVIEW { // 24
 		@Override
@@ -448,6 +518,11 @@
 		public boolean isDirectlyChattable() {
 			return true;
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.AMAZON;
+		}
 	}, 
 	AMAZON_WISH_LIST_ITEM { // 25
 		@Override
@@ -464,6 +539,11 @@
 		public boolean isDirectlyChattable() {
 			return true;
 		}
+		
+		@Override
+		public ExternalAccountType getExternalAccountSource() {
+			return ExternalAccountType.AMAZON;
+		}
 	};
 	
 	// This enumeration specifies a number of qualities.  First, whether
@@ -523,4 +603,8 @@
     public boolean getClickedCountUseful() {
     	return false;
     }
+    
+    public ExternalAccountType getExternalAccountSource() {
+    	return null;
+    }
 }

Modified: dumbhippo/trunk/server/src/com/dumbhippo/persistence/ExternalAccountType.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/persistence/ExternalAccountType.java	2008-01-07 22:25:39 UTC (rev 7145)
+++ dumbhippo/trunk/server/src/com/dumbhippo/persistence/ExternalAccountType.java	2008-01-08 02:12:04 UTC (rev 7146)
@@ -352,7 +352,7 @@
 		
 		@Override
 		public String getLinkText(String handle, String extra) {
-			return handle;
+			return "Videos by " + handle;
 		}
 		
 		@Override

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/FacebookTracker.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/FacebookTracker.java	2008-01-07 22:25:39 UTC (rev 7145)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/FacebookTracker.java	2008-01-08 02:12:04 UTC (rev 7146)
@@ -4,6 +4,7 @@
 
 import javax.ejb.Local;
 
+import com.dumbhippo.persistence.Block;
 import com.dumbhippo.persistence.FacebookAccount;
 import com.dumbhippo.persistence.User;
 import com.dumbhippo.server.views.UserViewpoint;
@@ -22,6 +23,8 @@
 	
 	public void updateFbmlForUser(User user);
 	
+	public void publishUserAction(Block block, User user);
+	
 	public void updateMessageCount(long facebookAccountId);
 	
 	public void updateTaggedPhotos(long facebookAccountId);

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/blocks/FlickrPersonBlockView.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/blocks/FlickrPersonBlockView.java	2008-01-07 22:25:39 UTC (rev 7145)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/blocks/FlickrPersonBlockView.java	2008-01-08 02:12:04 UTC (rev 7146)
@@ -37,7 +37,7 @@
 	}
 
 	public @Override String getBlockSummaryHeading() {
-		return "Posted photos";
+		return "Posted new photos";
 	}
 
 	public @Override String getBlockSummaryLink() {

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/blocks/PicasaPersonBlockView.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/blocks/PicasaPersonBlockView.java	2008-01-07 22:25:39 UTC (rev 7145)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/blocks/PicasaPersonBlockView.java	2008-01-08 02:12:04 UTC (rev 7146)
@@ -37,7 +37,7 @@
 	}
 
 	public @Override String getBlockSummaryHeading() {
-		return "Posted albums";
+		return "Posted new albums";
 	}
 
 	public @Override String getBlockSummaryLink() {

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/blocks/YouTubePersonBlockView.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/blocks/YouTubePersonBlockView.java	2008-01-07 22:25:39 UTC (rev 7145)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/blocks/YouTubePersonBlockView.java	2008-01-08 02:12:04 UTC (rev 7146)
@@ -37,7 +37,7 @@
 	}
 
 	public @Override String getBlockSummaryHeading() {
-		return "Posted videos";
+		return "Posted new videos";
 	}
 
 	public @Override String getBlockSummaryLink() {

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/impl/FacebookTrackerBean.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/impl/FacebookTrackerBean.java	2008-01-07 22:25:39 UTC (rev 7145)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/impl/FacebookTrackerBean.java	2008-01-08 02:12:04 UTC (rev 7146)
@@ -4,8 +4,11 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.Callable;
 
@@ -27,6 +30,8 @@
 import com.dumbhippo.Site;
 import com.dumbhippo.persistence.Account;
 import com.dumbhippo.persistence.AccountClaim;
+import com.dumbhippo.persistence.Block;
+import com.dumbhippo.persistence.BlockType;
 import com.dumbhippo.persistence.ExternalAccount;
 import com.dumbhippo.persistence.ExternalAccountType;
 import com.dumbhippo.persistence.FacebookAccount;
@@ -280,16 +285,16 @@
 					}
 				}	
 			});
-			Pair<Account, Set<ExternalAccountView>> accountsPair = TxUtils.runInTransaction(new Callable<Pair<Account, Set<ExternalAccountView>>>() {
-				public Pair<Account, Set<ExternalAccountView>> call() {
-					    Account account = accounts.lookupAccountByUser(user);
-					    UserViewpoint viewpoint = new UserViewpoint(account.getOwner(), Site.MUGSHOT);
-						Set<ExternalAccountView> allAccounts = externalAccounts.getExternalAccountViews(viewpoint, account.getOwner());
-				        externalAccounts.loadThumbnails(viewpoint, allAccounts);
-				        return new Pair<Account, Set<ExternalAccountView>>(account, allAccounts);
-				}	
-			});
 		    if (facebookAccount != null && facebookAccount.isApplicationEnabled()) {
+				Pair<Account, Set<ExternalAccountView>> accountsPair = TxUtils.runInTransaction(new Callable<Pair<Account, Set<ExternalAccountView>>>() {
+					public Pair<Account, Set<ExternalAccountView>> call() {
+						    Account account = accounts.lookupAccountByUser(user);
+						    UserViewpoint viewpoint = new UserViewpoint(account.getOwner(), Site.MUGSHOT);
+							Set<ExternalAccountView> allAccounts = externalAccounts.getExternalAccountViews(viewpoint, account.getOwner());
+					        externalAccounts.loadThumbnails(viewpoint, allAccounts);
+					        return new Pair<Account, Set<ExternalAccountView>>(account, allAccounts);
+					}	
+				});
 		        FacebookWebServices ws = new FacebookWebServices(REQUEST_TIMEOUT, config);
 			    ws.setProfileFbml(facebookAccount, createFbmlForUser(accountsPair.getFirst(), accountsPair.getSecond()));
             }		    
@@ -299,6 +304,74 @@
 		}
 	}
 	
+	@TransactionAttribute(TransactionAttributeType.NEVER)
+	public void publishUserAction(final Block block, final User user) {		
+		TxUtils.assertNoTransaction();
+		
+    	// let's publish Facebook news items about roughly one of 20 tracks the user plays
+    	if (block.getBlockType() == BlockType.MUSIC_PERSON && (new Random()).nextInt(20) != 19)
+    		return;
+    	
+		try {
+			FacebookAccount facebookAccount = TxUtils.runInTransaction(new Callable<FacebookAccount>() {
+				public FacebookAccount call() {
+					try {
+					    return facebookSystem.lookupFacebookAccount(SystemViewpoint.getInstance(), user);
+					} catch (NotFoundException e) {
+						return null;
+					}
+				}	
+			});
+			if (facebookAccount != null && facebookAccount.isApplicationEnabled()) {
+				BlockView blockView = TxUtils.runInTransaction(new Callable<BlockView>() {
+					public BlockView call() {
+						try {
+			                return stacker.loadBlock(new UserViewpoint(user, Site.MUGSHOT), block);
+						} catch (NotFoundException e) {
+							logger.error("The block {} was not found for user {} when creating user action for Facebook about it", block, user);
+							return null;
+						}
+					}	
+				});
+				
+				if (blockView != null) {
+					String titleTemplate = "{actor} {action} {link}{where}";
+					Map<String, CharSequence> titleData = new HashMap<String, CharSequence>();
+					
+					String action = blockView.getSummaryHeading().toLowerCase();
+					String link = "<a target{{=}}'_blank' href{{=}}'" + getAbsoluteUrl(blockView.getSummaryLink()) + "'>" + blockView.getSummaryLinkText() + "</a>";
+                    String where = "";
+					if (blockView.getBlockType().getExternalAccountSource() != null) {
+                        if (blockView.getSummaryHeading().contains("Chatted about")) {
+                        	where = " from " + blockView.getBlockType().getExternalAccountSource().getSiteName();
+                        } else {
+                        	where = " on " + blockView.getBlockType().getExternalAccountSource().getSiteName();                        	
+                        }
+                    } else if (!blockView.getBlockType().equals(BlockType.MUSIC_PERSON)) {
+                        // There are multiple options for how we know about someone's music (Rhapsody, Last.fm, 
+                    	// iTunes, Yahoo Music Player, Rhythmbox). It'd be nice to be able to identify this here,
+                    	// but for now, let's just not say anything. All other actions, like sharing a link,
+                    	// joining a group, or chatting happen on Mugshot.
+                    	where = " on Mugshot";                        	                    	
+                    }
+					
+					logger.debug("action: {}", action);
+					logger.debug("link: {}", link);
+					logger.debug("where: {}", where);
+					
+					titleData.put("action", action);
+					titleData.put("link", link);
+					titleData.put("where", where);
+			        FacebookWebServices ws = new FacebookWebServices(REQUEST_TIMEOUT, config);
+				    ws.publishUserAction(facebookAccount, titleTemplate, titleData);
+				}
+            }		    
+		} catch (Exception e) {
+			logger.error("Caught an exception when getting a FacebookAccount for {}: {}", user, e.getMessage());
+			throw new RuntimeException(e);            			
+		}
+	}
+	
 	// FIXME this is calling web services with a transaction open, which holds 
 	// a db connection open so other threads can't use it, and could also 
 	// time out the transaction

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/impl/StackerBean.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/impl/StackerBean.java	2008-01-07 22:25:39 UTC (rev 7145)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/impl/StackerBean.java	2008-01-08 02:12:04 UTC (rev 7146)
@@ -724,10 +724,14 @@
 			    }				
 				updateGroupBlockDatas(attached, isGroupParticipation, reason);
 
-				if (participant != null && block.getBlockType() != BlockType.FACEBOOK_EVENT) {
+				// FACEBOOK_EVENT blocks are never public, but we might as well check explicitly.
+				// We'll need to change this logic if we want to display some private blocks to
+				// a subset of person's friends who can also see those private blocks on Mugshot.
+				if (participant != null && block.isPublicBlock() && block.getBlockType() != BlockType.FACEBOOK_EVENT) {
 				    TxUtils.runOnCommit(new Runnable() {
 					    public void run() {
 					    	facebookTracker.updateFbmlForUser(participant);
+					        facebookTracker.publishUserAction(block, participant);
 					    }
 				    });
 				}	 

Modified: dumbhippo/trunk/server/src/com/dumbhippo/services/FacebookWebServices.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/services/FacebookWebServices.java	2008-01-07 22:25:39 UTC (rev 7145)
+++ dumbhippo/trunk/server/src/com/dumbhippo/services/FacebookWebServices.java	2008-01-08 02:12:04 UTC (rev 7146)
@@ -8,6 +8,7 @@
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.slf4j.Logger;
@@ -363,6 +364,20 @@
 		}
 	}
 	
+	public void publishUserAction(FacebookAccount facebookAccount, CharSequence titleTemplate,
+                                  Map<String, CharSequence> titleData) {
+		try {
+	        FacebookXmlRestClient facebookClient = new FacebookXmlRestClient(apiKey, secret, facebookAccount.getSessionKey());	
+	        facebookClient.feed_publishTemplatizedAction(Integer.valueOf(facebookAccount.getFacebookUserId()), titleTemplate, 
+	        		                                     titleData, null, null, null, null, null);
+		} catch (FacebookException e) {
+			logger.error("FacebookException when publishing user action for {}: {}",
+					     facebookAccount.getFacebookUserId(), e.toString());
+		} catch (IOException e) {
+			logger.error("IOException when converting {} to an integer", facebookAccount.getFacebookUserId());
+		}
+	}
+	
 	private String generateFacebookRequest(List<String> params) {
 		params.add("api_key=" + apiKey);
 		params.add("call_id=" + System.currentTimeMillis());



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