diff --git a/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.desc.xml new file mode 100644 index 0000000000..6cbac029b6 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.desc.xml @@ -0,0 +1,8 @@ + + Presence Custom View Configuration + Add webscript aspect to space node + /ui/presence/config?n={nodeRef}&w={webscriptUrl} + + user + required + diff --git a/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.html.ftl new file mode 100644 index 0000000000..1fd65886eb --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.html.ftl @@ -0,0 +1,54 @@ + + + + Online Presence Space Configurator + + + +

Online Presence Space Configurator

+
+ +
+ Space nodeRef: +
e.g. "workspace://SpacesStore/e3741425-35cf-11dc-9762-4b73d0280543"
+
+ +
+ Webscript URL: + +
+ +
+ +
+ +
+ +<#if args.n?exists> +
Aspect added to space.
+ + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.js b/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.js new file mode 100644 index 0000000000..5fc65fea3f --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.js @@ -0,0 +1,7 @@ +if (args["n"] != null) +{ + var dest = search.findNode(args["n"]); + dest.addAspect("cm:webscriptable"); + dest.properties["cm:webscript"] = args["w"]; + dest.save(); +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.desc.xml new file mode 100644 index 0000000000..234a25b79c --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.desc.xml @@ -0,0 +1,8 @@ + + Presence Custom View + Show online presence status of space users + /ui/presence/status?nodeRef={noderef} + + user + required + diff --git a/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.html.ftl new file mode 100644 index 0000000000..dda7864173 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.html.ftl @@ -0,0 +1,70 @@ + + +
Invited Users Presence Status
+
+ online=online
+ offline=offline
+ unknown=unknown +
+
+<#list presenceResults as pr> +
+
+
${pr[0]}
+
+ +
+ + diff --git a/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.js b/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.js new file mode 100644 index 0000000000..91c94205ed --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.js @@ -0,0 +1,53 @@ +main(); + +function main() +{ + var nodeRef = args["nodeRef"]; + var space = search.findNode(nodeRef); + var tokens, user, group; + var results = new Array(); + + for each(perm in space.permissions) + { + tokens = perm.split(";"); + if (tokens[0] == "ALLOWED") + { + if (("CollaboratorContributorCoordinatorEditor").indexOf(tokens[2]) != -1) + { + user = people.getPerson(tokens[1]); + if (user != null) + { + pushUnique(results, user, presence.getDetails(user)); + } + else + { + group = people.getGroup(tokens[1]); + if (group != null) + { + for each(user in people.getMembers(group)) + { + pushUnique(results, user, presence.getDetails(user)); + } + } + } + } + } + } + + model.space = space; + model.presenceResults = results; +} + +function pushUnique(results, user, details) +{ + var fullName = user.properties["firstName"] + " " + user.properties["lastName"]; + + for (i=0; i < results.length; i++) + { + if (results[i][0] == fullName) + { + return; + } + } + results.push(new Array(fullName, details)); +} diff --git a/source/java/org/alfresco/web/bean/ajax/PresenceProxyBean.java b/source/java/org/alfresco/web/bean/ajax/PresenceProxyBean.java new file mode 100644 index 0000000000..6dd48fc37b --- /dev/null +++ b/source/java/org/alfresco/web/bean/ajax/PresenceProxyBean.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.bean.ajax; + +import java.io.IOException; +import java.util.Map; + +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; + +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.web.app.servlet.ajax.InvokeCommand; +import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpMethod; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Bean which proxies requests to online presence servers. + * + * @author Mike Hatfield + */ +public class PresenceProxyBean +{ + private static Log logger = LogFactory.getLog(PresenceProxyBean.class); + + @InvokeCommand.ResponseMimetype(value=MimetypeMap.MIMETYPE_HTML) + public void proxyRequest() throws Exception + { + FacesContext fc = FacesContext.getCurrentInstance(); + ResponseWriter out = fc.getResponseWriter(); + + Map requestMap = fc.getExternalContext().getRequestParameterMap(); + String url = (String)requestMap.get("url"); + + if (logger.isDebugEnabled()) + logger.debug("PresenceProxyBean.proxyRequest() url=" + url); + + if (url != null) + { + String response = getUrlResponse(url); + out.write(response); + } + } + + /** + * Perform request + * + * @throws IOException + */ + public String getUrlResponse(String requestUrl) + { + String response = ""; + HttpClient client = new HttpClient(); + HttpMethod method = new GetMethod(requestUrl); + method.setRequestHeader("Accept", "*/*"); + client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler()); + try + { + int statusCode = client.executeMethod(method); + if (statusCode == HttpStatus.SC_OK) + { + response = method.getResponseBodyAsString(); + } + else + { + response = method.getStatusText(); + } + } + catch (HttpException e) + { + response = e.getMessage(); + } + catch (IOException e) + { + response = e.getMessage(); + } + finally + { + // Release the connection. + method.releaseConnection(); + } + + return response; + } +} diff --git a/source/java/org/alfresco/web/bean/users/CreateUserWizard.java b/source/java/org/alfresco/web/bean/users/CreateUserWizard.java index 915e7e2ed7..cfcc36aee8 100644 --- a/source/java/org/alfresco/web/bean/users/CreateUserWizard.java +++ b/source/java/org/alfresco/web/bean/users/CreateUserWizard.java @@ -75,6 +75,8 @@ public class CreateUserWizard extends BaseWizardBean protected String companyId = null; protected String homeSpaceName = ""; protected NodeRef homeSpaceLocation = null; + protected String presenceProvider = null; + protected String presenceUsername = null; /** AuthenticationService bean reference */ private AuthenticationService authenticationService; @@ -144,6 +146,8 @@ public class CreateUserWizard extends BaseWizardBean this.companyId = ""; this.homeSpaceName = ""; this.homeSpaceLocation = getDefaultHomeSpace(); + this.presenceProvider = ""; + this.presenceUsername = ""; } /** @@ -187,6 +191,40 @@ public class CreateUserWizard extends BaseWizardBean this.companyId = companyId; } + /** + * @return Returns the presenceProvider. + */ + public String getPresenceProvider() + { + return this.presenceProvider; + } + + /** + * @param presenceProvider + * The presenceProvider to set. + */ + public void setPresenceProvider(String presenceProvider) + { + this.presenceProvider = presenceProvider; + } + + /** + * @return Returns the presenceUsername. + */ + public String getPresenceUsername() + { + return this.presenceUsername; + } + + /** + * @param presenceUsername + * The presenceUsername to set. + */ + public void setPresenceUsername(String presenceUsername) + { + this.presenceUsername = presenceUsername; + } + /** * @return Returns the email. */ diff --git a/source/java/org/alfresco/web/bean/users/EditUserWizard.java b/source/java/org/alfresco/web/bean/users/EditUserWizard.java index dc9892b77a..525f319245 100644 --- a/source/java/org/alfresco/web/bean/users/EditUserWizard.java +++ b/source/java/org/alfresco/web/bean/users/EditUserWizard.java @@ -70,6 +70,8 @@ public class EditUserWizard extends CreateUserWizard this.userName = (String) props.get("userName"); this.email = (String) props.get("email"); this.companyId = (String) props.get("organizationId"); + this.presenceProvider = (String) props.get("presenceProvider"); + this.presenceUsername = (String) props.get("presenceUsername"); // calculate home space name and parent space Id from homeFolderId this.homeSpaceLocation = null; // default to Company root space @@ -177,6 +179,8 @@ public class EditUserWizard extends CreateUserWizard props.put(ContentModel.PROP_HOMEFOLDER, newHomeFolderRef); props.put(ContentModel.PROP_EMAIL, this.email); props.put(ContentModel.PROP_ORGID, this.companyId); + props.put(ContentModel.PROP_PRESENCEPROVIDER, this.presenceProvider); + props.put(ContentModel.PROP_PRESENCEUSERNAME, this.presenceUsername); this.nodeService.setProperties(nodeRef, props); // TODO: RESET HomeSpace Ref found in top-level navigation bar! diff --git a/source/web/WEB-INF/faces-config-beans.xml b/source/web/WEB-INF/faces-config-beans.xml index efdb6126e6..aa35d045a2 100644 --- a/source/web/WEB-INF/faces-config-beans.xml +++ b/source/web/WEB-INF/faces-config-beans.xml @@ -4044,6 +4044,15 @@ request + + + Bean proxying ajax calls for the online Presence webscript + + PresenceProxyBean + org.alfresco.web.bean.ajax.PresenceProxyBean + request + + Bean that returns manages the tree data for the navigator component diff --git a/source/web/images/icons/presence_offline.gif b/source/web/images/icons/presence_offline.gif new file mode 100644 index 0000000000..7c6d45be67 Binary files /dev/null and b/source/web/images/icons/presence_offline.gif differ diff --git a/source/web/images/icons/presence_online.gif b/source/web/images/icons/presence_online.gif new file mode 100644 index 0000000000..6c621aaf32 Binary files /dev/null and b/source/web/images/icons/presence_online.gif differ diff --git a/source/web/images/icons/presence_unknown.gif b/source/web/images/icons/presence_unknown.gif new file mode 100644 index 0000000000..d244428495 Binary files /dev/null and b/source/web/images/icons/presence_unknown.gif differ diff --git a/source/web/jsp/users/person-properties.jsp b/source/web/jsp/users/person-properties.jsp index ecd5c31868..2ac16d260a 100644 --- a/source/web/jsp/users/person-properties.jsp +++ b/source/web/jsp/users/person-properties.jsp @@ -86,4 +86,22 @@ + + + : + + + + + + + + + + : + + + + + \ No newline at end of file diff --git a/source/web/scripts/ajax/presence.js b/source/web/scripts/ajax/presence.js new file mode 100644 index 0000000000..7ae2e29346 --- /dev/null +++ b/source/web/scripts/ajax/presence.js @@ -0,0 +1,93 @@ +/* +* Prerequisites: mootools.v1.11.js +*/ +var Presence = +{ + init: function() + { + window.contextPath = Presence.getContextPath(); + + var users = $$("#presenceContainer .presenceStatus"); + users.each(function(user, i) + { + // ajax call to load online status + var userDetails = user.attributes["rel"].value.split("|"); + var proxyURL = window.contextPath + "/ajax/invoke/PresenceProxyBean.proxyRequest"; + var statusURL = Presence.getStatusURL(userDetails); + + if (statusURL != "") + { + var myAjax = new Ajax(proxyURL, { + method: 'get', + headers: {'If-Modified-Since': 'Sat, 1 Jan 2000 00:00:00 GMT'}, + onComplete: function(textResponse, xmlResponse) + { + var statusType = Presence.getStatusType(userDetails[0], textResponse); + user.addClass(statusType); + } + }); + myAjax.request("url=" + escape(statusURL)); + } + else + { + user.addClass("unknown"); + } + }); + }, + + /* Calculates and returns the context path for the current page */ + getContextPath: function() + { + var path = window.location.pathname; + var idx = path.indexOf("/", 1); + var contextPath = ""; + if (idx != -1) + { + contextPath = path.substring(0, idx); + } + else + { + contextPath = ""; + } + + return contextPath; + }, + + getStatusURL: function(userDetails) + { + var provider = userDetails[0]; + var username = userDetails[1]; + var statusURL = ""; + + switch(provider) + { + case "skype": + statusURL = "http://mystatus.skype.com/" + username + ".txt"; + break; + case "yahoo": + statusURL = "http://opi.yahoo.com/online?u=" + username + "&m=t&t=1"; + break; + } + + return statusURL; + }, + + getStatusType: function(provider, response) + { + var statusType = "unknown"; + + switch(provider) + { + case "skype": + statusType = (response == "Online") ? "online" : "offline"; + break; + case "yahoo": + statusType = (response == "01") ? "online" : "offline"; + break; + } + + return statusType; + } +} + +window.addEvent('domready', Presence.init);