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



Author: marinaz
Date: 2007-11-27 19:19:33 -0600 (Tue, 27 Nov 2007)
New Revision: 6938

Modified:
   dumbhippo/trunk/server/src/com/dumbhippo/persistence/FacebookAccount.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/FacebookSystem.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/impl/FacebookSystemBean.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/impl/FacebookTrackerBean.java
   dumbhippo/trunk/server/src/com/dumbhippo/services/FacebookWebServices.java
Log:
Make Facebook user ids uniquely associated with Mugshot users. 
Create both FacebookResource and FacebookAccount, when a user registers their Facebook account.

Modified: dumbhippo/trunk/server/src/com/dumbhippo/persistence/FacebookAccount.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/persistence/FacebookAccount.java	2007-11-27 21:04:13 UTC (rev 6937)
+++ dumbhippo/trunk/server/src/com/dumbhippo/persistence/FacebookAccount.java	2007-11-28 01:19:33 UTC (rev 6938)
@@ -40,9 +40,10 @@
 	
 	protected FacebookAccount() {}
 	
-	public FacebookAccount(ExternalAccount externalAccount) {
+	public FacebookAccount(ExternalAccount externalAccount, String facebookApiUserId) {
 		assert(externalAccount.getAccountType().equals(ExternalAccountType.FACEBOOK));
-		this.externalAccount = externalAccount;
+		setFacebookUserId(facebookApiUserId);
+		this.externalAccount = externalAccount;		
 		this.sessionKeyValid = false;
 		this.unreadMessageCount = -1;
 		this.mostRecentMessageId = -1;
@@ -61,12 +62,12 @@
 		this.applicationEnabled = false;
 	}
 	
-	@Column(nullable=true)
+	@Column(nullable=false, unique=true)
 	public String getFacebookUserId() {
 		return facebookApiUserId;
 	}
 	
-	public void setFacebookUserId(String facebookApiUserId) {
+	protected void setFacebookUserId(String facebookApiUserId) {
 		this.facebookApiUserId = facebookApiUserId;
 	}
 	

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/FacebookSystem.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/FacebookSystem.java	2007-11-27 21:04:13 UTC (rev 6937)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/FacebookSystem.java	2007-11-28 01:19:33 UTC (rev 6938)
@@ -49,10 +49,12 @@
 	public String getApiKey();	
 	
 	// this is a migration function needed for moving from using Facebook beta to using Facebook 1.0 API
-	public void decodeUserIds();
+	// It is no longer useful and is commented out since the facebook user id should not be changed once
+	// a given FacebookAccount is created.
+	// public void decodeUserIds();
+		
+	// public void updateUserIds(List<FacebookAccount> detachedFacebookAccounts);
 	
-	public void updateUserIds(List<FacebookAccount> detachedFacebookAccounts);
-	
 	// this is a migration function needed for creating FacebookResource objects that can be claimed
 	// with AccountClaim; only run this once we make the facebookUserId in FacebookAccount unique and not null
 	public void createFacebookResources();

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/impl/FacebookSystemBean.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/impl/FacebookSystemBean.java	2007-11-27 21:04:13 UTC (rev 6937)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/impl/FacebookSystemBean.java	2007-11-28 01:19:33 UTC (rev 6938)
@@ -8,8 +8,6 @@
 
 import javax.ejb.EJB;
 import javax.ejb.Stateless;
-import javax.ejb.TransactionAttribute;
-import javax.ejb.TransactionAttributeType;
 import javax.persistence.EntityManager;
 import javax.persistence.NoResultException;
 import javax.persistence.PersistenceContext;
@@ -37,7 +35,6 @@
 import com.dumbhippo.server.Configuration.PropertyNotFoundException;
 import com.dumbhippo.server.util.EJBUtil;
 import com.dumbhippo.server.views.Viewpoint;
-import com.dumbhippo.services.FacebookWebServices;
 
 @Stateless
 public class FacebookSystemBean implements FacebookSystem {
@@ -206,6 +203,7 @@
 		return apiKey;
 	}
 	
+	/*
 	@TransactionAttribute(TransactionAttributeType.NEVER)
 	public void decodeUserIds() {
 		FacebookSystem facebookSystem = EJBUtil.defaultLookup(FacebookSystem.class);
@@ -231,6 +229,7 @@
 		    }
 		} 
 	}
+	*/
 
 	public void createFacebookResources() {
 		List<FacebookAccount> facebookAccounts = getAllAccounts();

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/impl/FacebookTrackerBean.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/impl/FacebookTrackerBean.java	2007-11-27 21:04:13 UTC (rev 6937)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/impl/FacebookTrackerBean.java	2007-11-28 01:19:33 UTC (rev 6938)
@@ -13,7 +13,9 @@
 import javax.ejb.TransactionAttribute;
 import javax.ejb.TransactionAttributeType;
 import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
 import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
 
 import org.jboss.annotation.IgnoreDependency;
 import org.slf4j.Logger;
@@ -21,6 +23,7 @@
 import com.dumbhippo.GlobalSetup;
 import com.dumbhippo.Pair;
 import com.dumbhippo.Site;
+import com.dumbhippo.persistence.AccountClaim;
 import com.dumbhippo.persistence.ExternalAccount;
 import com.dumbhippo.persistence.ExternalAccountType;
 import com.dumbhippo.persistence.FacebookAccount;
@@ -28,6 +31,7 @@
 import com.dumbhippo.persistence.FacebookEvent;
 import com.dumbhippo.persistence.FacebookEventType;
 import com.dumbhippo.persistence.FacebookPhotoDataStatus;
+import com.dumbhippo.persistence.FacebookResource;
 import com.dumbhippo.persistence.Sentiment;
 import com.dumbhippo.persistence.User;
 import com.dumbhippo.server.Configuration;
@@ -35,6 +39,7 @@
 import com.dumbhippo.server.FacebookSystem;
 import com.dumbhippo.server.FacebookSystemException;
 import com.dumbhippo.server.FacebookTracker;
+import com.dumbhippo.server.IdentitySpider;
 import com.dumbhippo.server.NotFoundException;
 import com.dumbhippo.server.Notifier;
 import com.dumbhippo.server.Pageable;
@@ -88,35 +93,24 @@
 	@EJB
 	private FacebookSystem facebookSystem;
 	
+	@EJB
+	private IdentitySpider identitySpider;
+	
 	@PostConstruct
 	public void init() {
 		cacheFactory.injectCaches(this);
 	}
 	
 	public void updateOrCreateFacebookAccount(UserViewpoint viewpoint, String facebookAuthToken) throws FacebookSystemException {
-		ExternalAccount externalAccount = externalAccounts.getOrCreateExternalAccount(viewpoint, ExternalAccountType.FACEBOOK);
+		FacebookWebServices ws = new FacebookWebServices(REQUEST_TIMEOUT, config);
+		Pair<String, String> facebookInfo = ws.getSession(facebookAuthToken);
+		String sessionKey = facebookInfo.getFirst();
+		String facebookUserId = facebookInfo.getSecond();
 		
-		FacebookAccount facebookAccount;
-		if (externalAccount.getExtra() == null) {
-		    facebookAccount = new FacebookAccount(externalAccount);
-		    em.persist(facebookAccount);
-		    externalAccount.setExtra(Long.toString(facebookAccount.getId()));
-		    externalAccounts.setSentiment(externalAccount, Sentiment.LOVE);
-		} else {
-			facebookAccount = em.find(FacebookAccount.class, Long.parseLong(externalAccount.getExtra()));
-			if (facebookAccount == null)
-				throw new RuntimeException("Invalid FacebookAccount id " + externalAccount.getExtra() + " is stored in externalAccount " + externalAccount);
-			// make sure the sentiment is LOVE; there is currently no way to unset it from the user interface,
-			// but we should allow changing the sentiment to HATE or at least INDIFFERENT in the future
-			externalAccounts.setSentiment(externalAccount, Sentiment.LOVE);
-		}
+		if (sessionKey == null || facebookUserId == null)
+			return;
 		
-		FacebookWebServices ws = new FacebookWebServices(REQUEST_TIMEOUT, config);
-		ws.updateSession(facebookAccount, facebookAuthToken);
-		
-		FacebookEvent loginStatusEvent = getLoginStatusEvent(facebookAccount, true);
-		if (loginStatusEvent != null)  
-		    notifier.onFacebookEvent(facebookAccount.getExternalAccount().getAccount().getOwner(), loginStatusEvent);
+		updateOrCreateFacebookAccount(viewpoint, sessionKey, facebookUserId, false);
 	}
 
 	public void updateOrCreateFacebookAccount(UserViewpoint viewpoint, String sessionKey, String facebookUserId, boolean applicationEnabled) throws FacebookSystemException {
@@ -124,28 +118,58 @@
 		
 		FacebookAccount facebookAccount;
 		if (externalAccount.getExtra() == null) {
-		    facebookAccount = new FacebookAccount(externalAccount);
-		    em.persist(facebookAccount);
-		    externalAccount.setExtra(Long.toString(facebookAccount.getId()));
-		    externalAccounts.setSentiment(externalAccount, Sentiment.LOVE);
+			FacebookResource res = getFacebookResource(facebookUserId);
+			facebookAccount = getFacebookAccount(facebookUserId);
+			if (res == null && facebookAccount == null) {
+				res = new FacebookResource(facebookUserId);
+				em.persist(res);
+				identitySpider.addVerifiedOwnershipClaim(viewpoint.getViewer(), res);
+			    facebookAccount = new FacebookAccount(externalAccount, facebookUserId);
+			    em.persist(facebookAccount);
+			    externalAccount.setExtra(Long.toString(facebookAccount.getId()));		
+			} else if (res != null && facebookAccount != null) {
+				AccountClaim ac = res.getAccountClaim();
+				if (ac != null) {
+					if (!ac.getOwner().equals(viewpoint.getViewer())) {
+						throw new FacebookSystemException("Facebook account " + facebookUserId + " is claimed by someone else: " + ac.getOwner());
+					} else {
+						throw new RuntimeException("Facebook account " + facebookUserId + " is claimed by the user " + viewpoint.getViewer() + " whose ExternalAccount for Facebook doesn't reflect the claim");
+					}
+				} else {
+					// we could also check here that there is no ExternalAccount of type Facebook with extra referencing 
+					// this FacebookAccount
+					assert(facebookAccount.getExternalAccount()== null);
+					identitySpider.addVerifiedOwnershipClaim(viewpoint.getViewer(), res);					
+				    externalAccount.setExtra(Long.toString(facebookAccount.getId()));	
+				}
+			} else {
+				throw new RuntimeException("Facebook resource was " + res + ", while Facebook account was " + facebookAccount + ". If one of them exists, the other one should not be null.");				
+			}
 		} else {
 			facebookAccount = em.find(FacebookAccount.class, Long.parseLong(externalAccount.getExtra()));
 			if (facebookAccount == null)
 				throw new RuntimeException("Invalid FacebookAccount id " + externalAccount.getExtra() + " is stored in externalAccount " + externalAccount);
-			externalAccounts.setSentiment(externalAccount, Sentiment.LOVE);
+			if (!facebookAccount.getFacebookUserId().equals(facebookUserId)) {
+				throw new FacebookSystemException("We do not support changing your Facebook account yet.");
+			}
+		    Query resourceQuery = em.createQuery("from FacebookResource f where f.facebookUserId = :facebookUserId");
+			resourceQuery.setParameter("facebookUserId", facebookUserId);
+			FacebookResource res = getFacebookResource(facebookUserId);
+			if (res != null) {
+				assert(res.getAccountClaim().equals(viewpoint.getViewer()));
+			} else {
+				throw new RuntimeException("No FacebookResource found for " + facebookUserId + ", while there exists a corresponding FacebookAccount");
+			}			
 		}
 		
-		if (facebookAccount.getFacebookUserId() != null 
-			&& !facebookAccount.getFacebookUserId().equals(facebookUserId)) {
-				throw new FacebookSystemException("We do not support changing your Facebook account yet.");
-	    }
-			
 	    facebookAccount.setSessionKey(sessionKey);
-		facebookAccount.setFacebookUserId(facebookUserId);
 	    if (sessionKey != null)
 		    facebookAccount.setSessionKeyValid(true);	
 	    facebookAccount.setApplicationEnabled(applicationEnabled);
-
+		// make sure the sentiment is LOVE; there is currently no way to unset it from the user interface,
+		// but we should allow changing the sentiment to HATE or at least INDIFFERENT in the future
+		externalAccounts.setSentiment(externalAccount, Sentiment.LOVE);
+	    
 		FacebookEvent loginStatusEvent = getLoginStatusEvent(facebookAccount, true);
 		if (loginStatusEvent != null)  
 		    notifier.onFacebookEvent(facebookAccount.getExternalAccount().getAccount().getOwner(), loginStatusEvent);
@@ -157,9 +181,29 @@
 			    	updateFbmlForUser(user);
 			    }
 		    });
-		}	 
+		}
 	}
 	
+	private FacebookResource getFacebookResource(String facebookUserId) {
+	    Query resourceQuery = em.createQuery("from FacebookResource f where f.facebookUserId = :facebookUserId");
+		resourceQuery.setParameter("facebookUserId", facebookUserId);
+		try {
+			return (FacebookResource)resourceQuery.getSingleResult();
+		} catch (NoResultException e) {
+			return null;
+		}
+	}
+	
+	private FacebookAccount getFacebookAccount(String facebookUserId) {
+		Query accountQuery = em.createQuery("from FacebookAccount f where f.facebookUserId = :facebookUserId");
+		accountQuery.setParameter("facebookUserId", facebookUserId);
+		try {
+			return (FacebookAccount)accountQuery.getSingleResult();
+		} catch (NoResultException e) {
+			return null;
+		}		
+	}
+	
 	@TransactionAttribute(TransactionAttributeType.NEVER)
 	public void updateFbmlForUser(final User user) {
 		TxUtils.assertNoTransaction();

Modified: dumbhippo/trunk/server/src/com/dumbhippo/services/FacebookWebServices.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/services/FacebookWebServices.java	2007-11-27 21:04:13 UTC (rev 6937)
+++ dumbhippo/trunk/server/src/com/dumbhippo/services/FacebookWebServices.java	2007-11-28 01:19:33 UTC (rev 6938)
@@ -6,10 +6,8 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 import org.slf4j.Logger;
@@ -80,11 +78,27 @@
 		}
 		
 		facebookAccount.setSessionKey(handler.getSessionKey());
-		facebookAccount.setFacebookUserId(handler.getFacebookUserId());
 		if (handler.getSessionKey() != null)
 	        facebookAccount.setSessionKeyValid(true);			
 	}
 	
+	public Pair<String, String> getSession(String facebookAuthToken) {
+		List<String> params = new ArrayList<String>();
+		String methodName = "facebook.auth.getSession";
+        params.add("method=" + methodName);
+		params.add("auth_token=" + facebookAuthToken);
+		
+		String wsUrl = generateFacebookRequest(params);
+			
+		FacebookSaxHandler handler = parseUrl(new FacebookSaxHandler(), wsUrl);
+		
+		if (handleErrorCode(null, handler, methodName)) {
+			return new Pair<String, String>(null, null);
+		}
+		
+		return new Pair<String, String>(handler.getSessionKey(), handler.getFacebookUserId());
+	}
+	
 	/**
 	 * Return a pair of update times for messages and pokes notifications. 
 	 * First element is an update time if the number of unread messages changed or the most 
@@ -387,7 +401,8 @@
         	return true;
         
 		if (handler.getErrorCode() > 0) {
-		    if (handler.getErrorCode() == FacebookSaxHandler.FacebookErrorCode.API_EC_PARAM_SESSION_KEY.getCode()) {
+		    if (handler.getErrorCode() == FacebookSaxHandler.FacebookErrorCode.API_EC_PARAM_SESSION_KEY.getCode() &&
+		    	facebookAccount != null) {
 			    // setSessionKeyValid to false if we received the response that the session key is no longer valid
 		    	// FIXME this is somewhat conceptually weird, because we shouldn't do web services with a transaction 
 		    	// open, which means modifying a persistence bean won't do anything persistent.
@@ -403,6 +418,7 @@
 		return false;
 	}
 	
+	/*
 	public void decodeUserIds(List<FacebookAccount> facebookAccounts) {
 		logger.debug("will decode user ids for {} Facebook accounts", facebookAccounts.size());
 		StringBuffer ids = new StringBuffer();
@@ -446,5 +462,5 @@
 		// if some ids were already decoded
 		logger.debug("decoded user ids for {} Facebook accounts", count);
 	}
-	
+	*/
  }



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