/** * This file Copyright (c) 2005-2007 Aptana, Inc. This program is * dual-licensed under both the Aptana Public License and the GNU General * Public license. You may elect to use one or the other of these licenses. * * This program is distributed in the hope that it will be useful, but * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or * NONINFRINGEMENT. Redistribution, except as permitted by whichever of * the GPL or APL you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or modify this * program under the terms of the GNU General Public License, * Version 3, as published by the Free Software Foundation. You should * have received a copy of the GNU General Public License, Version 3 along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Aptana provides a special exception to allow redistribution of this file * with certain Eclipse Public Licensed code and certain additional terms * pursuant to Section 7 of the GPL. You may view the exception and these * terms on the web at http://www.aptana.com/legal/gpl/. * * 2. For the Aptana Public License (APL), this program and the * accompanying materials are made available under the terms of the APL * v1.0 which accompanies this distribution, and is available at * http://www.aptana.com/legal/apl/. * * You may view the GPL, Aptana's exception and additional terms, and the * APL in the file titled license.html at the root of the corresponding * plugin containing this source file. * * Any modifications to this file must keep this entire header intact. */ package com.aptana.ide.server.jetty.comet; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.text.DateFormat; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.swt.widgets.Display; import sun.misc.BASE64Decoder; import com.aptana.ide.core.model.IModelListener; import com.aptana.ide.core.model.IModifiableObject; import com.aptana.ide.core.model.RESTServiceProvider; import com.aptana.ide.core.model.ServiceError; import com.aptana.ide.core.model.ServiceErrors; import com.aptana.ide.core.model.channel.ChannelType; import com.aptana.ide.core.model.user.AptanaUser; import com.aptana.ide.core.model.user.User; import com.aptana.ide.core.model.user.UserRequestBuilder; import com.aptana.ide.core.model.user.UsernameAvailable; import com.aptana.ide.core.model.user.UsernameResolver; import dojox.cometd.Bayeux; import dojox.cometd.Channel; /** * @author Kevin Sawicki (ksawicki@aptana.com) */ public class UserClient extends CometClient { /** * SUCCESS */ public static final String SUCCESS = "success"; //$NON-NLS-1$ /** * USER_VALID */ public static final String USER_VALID = "userValid"; //$NON-NLS-1$ /** * USERNAME_VALID */ public static final String USERNAME_VALID = "usernameValid"; //$NON-NLS-1$ /** * PASSWORD_VALID */ public static final String PASSWORD_VALID = "passwordValid"; //$NON-NLS-1$ /** * RESOLVE_USER_ACTION */ public static final String RESOLVE_USER_ACTION = "resolveUser"; //$NON-NLS-1$ /** * CREATE_USER_ACTION */ public static final String CREATE_USER_ACTION = "createUser"; //$NON-NLS-1$ /** * LOGIN_USER_ACTION */ public static final String LOGIN_USER_ACTION = "loginUser"; //$NON-NLS-1$ /** * LOGOUT_USER */ public static final String LOGOUT_USER_ACTION = "logoutUser"; //$NON-NLS-1$ /** * CURRENT_USER_ACTION */ public static final String CURRENT_USER_ACTION = "currentUser"; //$NON-NLS-1$ /** * UPDATE_USER_ACTION */ public static final String UPDATE_USER_ACTION = "updateUser"; //$NON-NLS-1$ /** * CURRENT_USER */ public static final String CURRENT_USER = "/portal/user"; //$NON-NLS-1$ /** * LOGIN_USER */ public static final String LOGIN_USER = "/portal/user/login"; //$NON-NLS-1$ /** * LOGOUT_USER */ public static final String LOGOUT_USER = "/portal/user/logout"; //$NON-NLS-1$ /** * CREATE_USER */ public static final String CREATE_USER = "/portal/user/create"; //$NON-NLS-1$ /** * RESOLVE_USER */ public static final String RESOLVE_USER = "/portal/user/resolve"; //$NON-NLS-1$ /** * RESOLVE_USER */ public static final String UPDATE_USER = "/portal/user/update"; //$NON-NLS-1$ /** * EMAIL_CHANNEL */ public static final String EMAIL_CHANNEL = "1"; //$NON-NLS-1$ private IModelListener listener = new IModelListener() { public void modelChanged(IModifiableObject object) { if (object instanceof User) { Map<Object, Object> responseData = new HashMap<Object, Object>(); responseData.put(CometConstants.RESPONSE, CURRENT_USER_ACTION); User user = (User) object; if(user.hasCredentials()) { fillResponse(responseData, user); Bayeux localBayeux = bayeux; if (localBayeux != null) { Channel userChannel = localBayeux.getChannel(CURRENT_USER, true); userChannel.publish(client, responseData, getID(null)); } } else { responseData.put(CometConstants.RESPONSE, LOGOUT_USER_ACTION); responseData.put(SUCCESS, Boolean.TRUE); Bayeux localBayeux = bayeux; if (localBayeux != null) { Channel userChannel = localBayeux.getChannel(LOGOUT_USER, true); userChannel.publish(client, responseData, getID(null)); } } } } }; /** * Creates a new user client */ public UserClient() { AptanaUser.getSignedInUser().addListener(listener); } /** * @see com.aptana.ide.server.jetty.comet.CometClient#destroy() */ public void destroy() { AptanaUser.getSignedInUser().removeListener(listener); super.destroy(); } private void fillResponse(Map<Object, Object> responseData, User user) { if (user.hasCredentials()) { try { BASE64Decoder decoder = new BASE64Decoder(); String encryptedPassword = user.getField(User.ENCRYPTED_PASSWORD); String password = null; if (encryptedPassword != null) { password = new String(decoder.decodeBuffer(encryptedPassword)); } else { password = user.getField(User.PASSWORD); } responseData.put(User.PASSWORD, password); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } responseData.put(User.ID_ELEMENT, user.getField(User.ID_ELEMENT)); responseData.put(User.USERNAME, user.getField(User.USERNAME)); responseData.put(User.FIRST_NAME, user.getField(User.FIRST_NAME)); responseData.put(User.LAST_NAME, user.getField(User.LAST_NAME)); responseData.put(User.PHONE, user.getField(User.PHONE)); responseData.put(User.IP_ADDRESS, user.getField(User.IP_ADDRESS)); responseData.put(User.ADDRESS1, user.getField(User.ADDRESS1)); responseData.put(User.ADDRESS2, user.getField(User.ADDRESS2)); responseData.put(User.CITY, user.getField(User.CITY)); responseData.put(User.STATE, user.getField(User.STATE)); responseData.put(User.ZIP, user.getField(User.ZIP)); responseData.put(User.COUNTRY, user.getField(User.COUNTRY)); responseData.put(User.ROLE, user.getField(User.ROLE)); responseData.put(User.COMPANY, user.getField(User.COMPANY)); responseData.put(User.ORG_TYPE, user.getField(User.ORG_TYPE)); responseData.put(User.ORG_SIZE, user.getField(User.ORG_SIZE)); responseData.put(User.SITES_PER_YEAR, user.getField(User.SITES_PER_YEAR)); responseData.put(User.AJAX, Boolean.parseBoolean(user.getField(User.AJAX))); responseData.put(User.JAVASCRIPT, Boolean.parseBoolean(user.getField(User.JAVASCRIPT))); responseData.put(User.PHP, Boolean.parseBoolean(user.getField(User.PHP))); responseData.put(User.RUBY, Boolean.parseBoolean(user.getField(User.RUBY))); responseData.put(User.JAVA, Boolean.parseBoolean(user.getField(User.JAVA))); responseData.put(User.PYTHON, Boolean.parseBoolean(user.getField(User.PYTHON))); responseData.put(User.NET, Boolean.parseBoolean(user.getField(User.NET))); responseData.put(User.SITE_DEVELOPMENT, Boolean.parseBoolean(user.getField(User.SITE_DEVELOPMENT))); responseData.put(User.APPLICATION_DEVELOPMENT, Boolean.parseBoolean(user.getField(User.APPLICATION_DEVELOPMENT))); responseData.put(User.NEWSLETTER, Boolean.parseBoolean(user.getField(User.NEWSLETTER))); responseData.put(User.CREATED_AT, user.getField(User.CREATED_AT)); for (com.aptana.ide.core.model.channel.Channel channel : user.getChannels().getItems()) { ChannelType type = channel.getChannelType(); if (type != null && EMAIL_CHANNEL.equals(type.getId()) && channel.isPrimary()) { responseData.put(User.EMAIL, channel.getValue()); break; } } } else { responseData.put(User.ID_ELEMENT, Boolean.FALSE); responseData.put(User.USERNAME, Boolean.FALSE); responseData.put(User.PASSWORD, Boolean.FALSE); responseData.put(User.EMAIL, Boolean.FALSE); } } /** * @see com.aptana.ide.server.jetty.comet.CometClient#getResponse(java.lang.String, java.lang.Object) */ protected Object getResponse(String toChannel, Object request) { if (CURRENT_USER.equals(toChannel)) { Map<Object, Object> responseData = new HashMap<Object, Object>(); responseData.put(CometConstants.RESPONSE, CURRENT_USER_ACTION); fillResponse(responseData, AptanaUser.getSignedInUser()); return responseData; } else if (LOGIN_USER.equals(toChannel)) { if (request instanceof Map) { Map values = (Map) request; if (values.containsKey(User.USERNAME) && values.containsKey(User.PASSWORD)) { final String name = values.get(User.USERNAME).toString(); final String password = values.get(User.PASSWORD).toString(); Map<Object, Object> responseData = new HashMap<Object, Object>(); final User user = new User(name, password, null, null, null, null, null); user.setRequestBuilder(new UserRequestBuilder()); user.setServiceProvider(new RESTServiceProvider()); responseData.put(CometConstants.RESPONSE, LOGIN_USER_ACTION); try { user.setDefaultLocation(new URL(AptanaUser.LOGINS)); // Get the user location user.update(); if (user.hasLocation()) { // Get the user model user.update(); // Call the sign-in method in the UI thread to avoid issue // http://support.aptana.com/asap/browse/STU-4438 Display.getDefault().syncExec(new Runnable() { public void run() { AptanaUser.signIn(name, password, user.getLocation(), user.getId()); } }); responseData.put(USER_VALID, Boolean.TRUE); responseData.put(USERNAME_VALID, Boolean.TRUE); responseData.put(PASSWORD_VALID, Boolean.TRUE); responseData.put(User.ID_ELEMENT, user.getId()); responseData.put(User.USERNAME, user.getUsername()); responseData.put(User.PASSWORD, user.getPassword()); } else { responseData.put(USER_VALID, Boolean.FALSE); responseData.put(USERNAME_VALID, Boolean.FALSE); responseData.put(PASSWORD_VALID, Boolean.FALSE); } } catch (MalformedURLException e) { } return responseData; } } } else if (LOGOUT_USER.equals(toChannel)) { Map<Object, Object> responseData = new HashMap<Object, Object>(); responseData.put(CometConstants.RESPONSE, LOGOUT_USER_ACTION); try { AptanaUser.signOut(); responseData.put(SUCCESS, Boolean.TRUE); } catch (Exception e) { responseData.put(SUCCESS, Boolean.FALSE); } return responseData; } else if (CREATE_USER.equals(toChannel)) { if (request instanceof Map) { Map values = (Map) request; if (values.containsKey(User.USERNAME) && values.containsKey(User.PASSWORD) && values.containsKey(User.EMAIL)) { String name = values.get(User.USERNAME).toString(); String firstName = values.get(User.FIRST_NAME).toString(); String lastName = values.get(User.LAST_NAME).toString(); String password = values.get(User.PASSWORD).toString(); String email = values.get(User.EMAIL).toString(); String challenge = values.get(User.CAPTCHA_CHALLENGE).toString(); String response = values.get(User.CAPTCHA_RESPONSE).toString(); Map<Object, Object> responseData = new HashMap<Object, Object>(); responseData.put(CometConstants.RESPONSE, CREATE_USER_ACTION); // TODO service for password validity? responseData.put(PASSWORD_VALID, Boolean.TRUE); final User user = new User(name, password, email, firstName, lastName, challenge, response); user.setRequestBuilder(new UserRequestBuilder()); user.setServiceProvider(new RESTServiceProvider()); try { user.setDefaultLocation(new URL(AptanaUser.USERS)); user.commit(); if (user.hasLocation()) { user.update(); responseData.put(USERNAME_VALID, Boolean.TRUE); responseData.put(SUCCESS, Boolean.TRUE); // Call the sign-in method in the UI thread to avoid issue // http://support.aptana.com/asap/browse/STU-4438 Display.getDefault().syncExec(new Runnable() { public void run() { AptanaUser.signIn(user.getUsername(), user .getPassword(), user.getLocation(), user.getId()); } }); } else { responseData.put(USERNAME_VALID, Boolean.valueOf(UsernameAvailable .isUsernameAvailable(name))); responseData.put(SUCCESS, Boolean.FALSE); List<String> errors = new ArrayList<String>(); ServiceErrors serviceErrors = user.getLastServiceErrors(); if (serviceErrors != null && serviceErrors.getItems() != null) { for (ServiceError se : serviceErrors.getItems()) { errors.add(se.getMessage()); } } responseData.put(ServiceErrors.ERRORS_ELEMENT, errors); } } catch (MalformedURLException e) { responseData.put(USERNAME_VALID, Boolean.valueOf(UsernameAvailable.isUsernameAvailable(name))); responseData.put(ServiceErrors.ERRORS_ELEMENT, Arrays.asList(new String[] { e.getMessage() })); } responseData.put(CometConstants.RESPONSE, CREATE_USER_ACTION); return responseData; } } } else if (RESOLVE_USER.equals(toChannel)) { if (request instanceof Map) { Map values = (Map) request; if (values.containsKey(User.EMAIL)) { String email = values.get(User.EMAIL).toString(); User possibleUser = UsernameResolver.doesUsernameResolve(email); if (possibleUser != null) { Map<Object, Object> responseData = new HashMap<Object, Object>(); responseData.put(User.USERNAME, possibleUser.getUsername()); responseData.put(CometConstants.RESPONSE, RESOLVE_USER_ACTION); ServiceErrors errors = possibleUser.getLastServiceErrors(); if (errors != null) { responseData.put(ServiceErrors.ERRORS_ELEMENT, errors.getErrorStrings()); } return responseData; } } } } else if (UPDATE_USER.equals(toChannel)) { if (request instanceof Map) { Map values = (Map) request; String firstName = values.get(User.FIRST_NAME).toString(); String lastName = values.get(User.LAST_NAME).toString(); String phone = values.get(User.PHONE).toString(); String email = values.get(User.EMAIL).toString(); String address1 = values.get(User.ADDRESS1).toString(); String address2 = values.get(User.ADDRESS2).toString(); String city = values.get(User.CITY).toString(); String state = values.get(User.STATE).toString(); String zip = values.get(User.ZIP).toString(); String country = values.get(User.COUNTRY).toString(); String role = values.get(User.ROLE).toString(); String company = values.get(User.COMPANY).toString(); String organizationType = values.get(User.ORG_TYPE).toString(); String organizationSize = values.get(User.ORG_SIZE).toString(); String sitesPerYear = values.get(User.SITES_PER_YEAR).toString(); String ajax = getBooleanString(values, User.AJAX); String javascript = getBooleanString(values, User.JAVASCRIPT); String php = getBooleanString(values, User.PHP); String ruby = getBooleanString(values, User.RUBY); String python = getBooleanString(values, User.PYTHON); String java = getBooleanString(values, User.JAVA); String net = getBooleanString(values, User.NET); String siteDevelopment = getBooleanString(values, User.SITE_DEVELOPMENT); String applicationDevelopment = getBooleanString(values, User.APPLICATION_DEVELOPMENT); String newsletter = getBooleanString(values, User.NEWSLETTER); String createdAt = values.get(User.CREATED_AT).toString(); // Format the response date to something that the Javascript Part on the portal can parse back to a date instance try { createdAt = DateFormat.getDateInstance(DateFormat.SHORT).parse(createdAt).toString(); } catch (ParseException e) { } User user = AptanaUser.getSignedInUser(); Map<Object, Object> responseData = new HashMap<Object, Object>(); responseData.put(CometConstants.RESPONSE, UPDATE_USER_ACTION); if (user != null) { user.setField(User.FIRST_NAME, firstName); user.setField(User.LAST_NAME, lastName); user.setField(User.EMAIL, email); user.setField(User.PHONE, phone); user.setField(User.ADDRESS1, address1); user.setField(User.ADDRESS2, address2); user.setField(User.CITY, city); user.setField(User.STATE, state); user.setField(User.ZIP, zip); user.setField(User.COUNTRY, country); user.setField(User.ROLE, role); user.setField(User.COMPANY, company); user.setField(User.ORG_TYPE, organizationType); user.setField(User.ORG_SIZE, organizationSize); user.setField(User.SITES_PER_YEAR, sitesPerYear); user.setField(User.AJAX, ajax); user.setField(User.JAVASCRIPT, javascript); user.setField(User.PHP, php); user.setField(User.RUBY, ruby); user.setField(User.PYTHON, python); user.setField(User.JAVA, java); user.setField(User.NET, net); user.setField(User.SITE_DEVELOPMENT, siteDevelopment); user.setField(User.APPLICATION_DEVELOPMENT, applicationDevelopment); user.setField(User.NEWSLETTER, newsletter); user.setField(User.CREATED_AT, createdAt); // Also set the email in EMAIL_CHANNEL for (com.aptana.ide.core.model.channel.Channel channel : user.getChannels().getItems()) { ChannelType type = channel.getChannelType(); if (type != null && EMAIL_CHANNEL.equals(type.getId()) && channel.isPrimary()) { channel.setField(com.aptana.ide.core.model.channel.Channel.VALUE, user.getField(User.EMAIL)); break; } } user.commit(); List<String> errors = new ArrayList<String>(); ServiceErrors serviceErrors = user.getLastServiceErrors(); if (serviceErrors != null && serviceErrors.getItems() != null) { for (ServiceError se : serviceErrors.getItems()) { errors.add(se.getMessage()); } responseData.put(SUCCESS, (errors.size() > 0 ? Boolean.FALSE : Boolean.TRUE)); } else { responseData.put(SUCCESS, Boolean.TRUE); } responseData.put(ServiceErrors.ERRORS_ELEMENT, errors); } else { responseData.put(SUCCESS, Boolean.FALSE); } return responseData; } } return null; } private String getBooleanString(Map values, String key) { Object value = values.get(key); if (value == null) return Boolean.FALSE.toString(); if (value instanceof String) return Boolean.toString(Boolean.parseBoolean((String) value)); if (value instanceof Boolean) return Boolean.toString((Boolean) value); return Boolean.FALSE.toString(); } /** * @see com.aptana.ide.server.jetty.comet.CometClient#getSubscriptionIDs() */ protected String[] getSubscriptionIDs() { return new String[] { RESOLVE_USER, CURRENT_USER, LOGIN_USER, LOGOUT_USER, CREATE_USER, UPDATE_USER }; } /** * @see com.aptana.ide.server.jetty.comet.CometClient#getID(java.lang.String) */ protected String getID(String msgId) { return Long.toString(System.currentTimeMillis()); } }