package org.fluxtream.connectors.flickr;
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.servlet.http.HttpServletRequest;
import org.fluxtream.core.Configuration;
import org.fluxtream.core.auth.AuthHelper;
import org.fluxtream.core.connectors.Connector;
import org.fluxtream.connectors.controllers.ControllerSupport;
import org.fluxtream.core.domain.ApiKey;
import org.fluxtream.core.domain.Guest;
import org.fluxtream.core.domain.Notification;
import org.fluxtream.core.services.GuestService;
import org.fluxtream.core.services.NotificationsService;
import org.apache.commons.io.IOUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import static org.fluxtream.core.utils.HttpUtils.fetch;
import static org.fluxtream.core.utils.Utils.hash;
@Controller
@RequestMapping(value="/flickr")
public class FlickrController {
private static final String FLICKR_RENEWTOKEN_APIKEYID = "flickr.renewtoken.apiKeyId";
@Autowired
GuestService guestService;
@Autowired
Configuration env;
@Autowired
NotificationsService notificationsService;
@RequestMapping(value = "/token")
public String getToken(HttpServletRequest request)
throws NoSuchAlgorithmException
{
String api_key = env.get("flickrConsumerKey");
String api_sig = env.get("flickrConsumerSecret") + "api_key" + api_key + "permsread";
api_sig = hash(api_sig);
final String validRedirectUrl = env.get("flickr.validRedirectURL");
if (!validRedirectUrl.startsWith(ControllerSupport.getLocationBase(request, env))) {
final long guestId = AuthHelper.getGuestId();
final String validRedirectBase = getBaseURL(validRedirectUrl);
notificationsService.addNamedNotification(guestId, Notification.Type.WARNING, Connector.getConnector("flickr").statusNotificationName(),
"Adding a Flickr connector only works when logged in through " + validRedirectBase +
". You are logged in through " + ControllerSupport.getLocationBase(request, env) +
".<br>Please re-login via the supported URL or inform your Fluxtream administrator " +
"that the flickr.validRedirectURL setting does not match your needs.");
return "redirect:/app";
}
if (request.getParameter("apiKeyId") != null)
request.getSession().setAttribute(FLICKR_RENEWTOKEN_APIKEYID,
request.getParameter("apiKeyId"));
String loginUrl = "https://flickr.com/services/auth/" +
"?api_key=" + api_key + "&perms=read&api_sig=" + api_sig;
return "redirect:" + loginUrl;
}
public static String getBaseURL(String url) {
try {
URI uri = new URI(url);
StringBuilder rootURI = new StringBuilder(uri.getScheme()).append("://").append(uri.getHost());
if (uri.getPort() != -1) {
rootURI.append(":" + uri.getPort());
}
return (rootURI.toString());
}
catch (URISyntaxException e) {
return null;
}
}
@RequestMapping(value = "/upgradeToken")
public String upgradeToken(HttpServletRequest request) throws NoSuchAlgorithmException, DocumentException, IOException {
String api_key = env.get("flickrConsumerKey");
String frob = request.getParameter("frob");
Map<String,String> params = new HashMap<String,String>();
params.put("method", "flickr.auth.getToken");
params.put("api_key", api_key);
params.put("frob", frob);
String api_sig = sign(params);
String getTokenUrl = "https://api.flickr.com/services/rest/" +
"?method=flickr.auth.getToken&api_key=" + api_key + "&frob=" + frob + "&api_sig=" + api_sig;
Guest guest = AuthHelper.getGuest();
String authToken = null;
try {
authToken = fetch(getTokenUrl);
}
catch (Exception e) {
e.printStackTrace();
notificationsService.addNamedNotification(AuthHelper.getGuestId(),
Notification.Type.ERROR, Connector.getConnector("flickr").statusNotificationName(),
"Oops, we could not link your Flickr account<br>" +
"Please contact your administrator.");
return "redirect:/app";
}
StringReader stringReader = new StringReader(authToken);
StringBuilder sb = new StringBuilder();
final List<String> responseLines = IOUtils.readLines(stringReader);
sb.append("<root>");
for (int i=1; i<responseLines.size(); i++)
sb.append(responseLines.get(i));
sb.append("</root>");
SAXReader reader = new SAXReader();
Document document = reader.read(new StringReader(authToken));
Element user = (Element) document.selectSingleNode("rsp/auth/user");
String username = user.attributeValue("username");
String nsid = user.attributeValue("nsid");
String fullname = user.attributeValue("fullname");
String token = document.selectSingleNode("rsp/auth/token/text()").getStringValue();
Connector flickrConnector = Connector.getConnector("flickr");
ApiKey apiKey;
if (request.getSession().getAttribute(FLICKR_RENEWTOKEN_APIKEYID)!=null) {
final String apiKeyIdString = (String)request.getSession().getAttribute(FLICKR_RENEWTOKEN_APIKEYID);
long apiKeyId = Long.valueOf(apiKeyIdString);
apiKey = guestService.getApiKey(apiKeyId);
} else
apiKey = guestService.createApiKey(guest.getId(), flickrConnector);
guestService.populateApiKey(apiKey.getId());
guestService.setApiKeyAttribute(apiKey, "username", username);
guestService.setApiKeyAttribute(apiKey, "token", token);
guestService.setApiKeyAttribute(apiKey, "nsid", nsid);
guestService.setApiKeyAttribute(apiKey, "fullname", fullname);
if (request.getSession().getAttribute(FLICKR_RENEWTOKEN_APIKEYID)!=null) {
request.getSession().removeAttribute(FLICKR_RENEWTOKEN_APIKEYID);
return "redirect:/app/tokenRenewed/flickr";
}
return "redirect:/app/from/"+flickrConnector.getName();
}
String sign(Map<String,String> parameters) throws NoSuchAlgorithmException {
String toSign = env.get("flickrConsumerSecret");
SortedSet<String> eachKey= new TreeSet<String>(parameters.keySet());
for (String key : eachKey)
toSign += key + parameters.get(key);
String sig = hash(toSign);
return sig;
}
String getConsumerKey() {
return env.get("flickrConsumerKey");
}
String getConsumerSecret() {
return env.get("flickrConsumerSecret");
}
}