Commit 564077e2 authored by Guus der Kinderen's avatar Guus der Kinderen Committed by daryl herzmann

OF-35 - PubSub Admin console + PEP (#875)

* Updates to eclipse classpath file

* PubSub Admin Console Node Summary

* Started to add PubSub Admin functionality modelled after the Group Chat
  Admin screens.
* Node summary page shows summary table of current leaf nodes.
* Deletion of Nodes supported.
* Sub page with summary of current subscribers and ability to cancel
  subscriptions.

* Added Admin page for items on PubSub Node

* Modelled after the subscribers page.
* Also some small improvements to previous PubSub admin code.

* Update PubSub JSP pages to use JSTL

* OF-35: Instead of Tab, use Sub-Tab.

* OF-35: PubSubManager does use Module interface

* OF-35: Potentially, can manage _all_ services. Renaming to PubSubServiceManager

* OF-35: Doesn't keep state, need not be a singleton.

* OF-35: PubSubServiceManager should be reusable for other PubSubServices.

* OF-35: Renamed to -Info to avoid name clash with pre-existing PEPServiceManager.

* OF-35: Add PEP support

* OF-35: Expose PEP in User details.
parent 5442e0f8
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
<classpathentry kind="src" output="work/plugins-dev/userCreation/target/classes" path="src/plugins/userCreation/src/java"/> <classpathentry kind="src" output="work/plugins-dev/userCreation/target/classes" path="src/plugins/userCreation/src/java"/>
<classpathentry kind="src" output="work/plugins-dev/userImportExport/target/classes" path="src/plugins/userImportExport/src/java"/> <classpathentry kind="src" output="work/plugins-dev/userImportExport/target/classes" path="src/plugins/userImportExport/src/java"/>
<classpathentry kind="src" output="work/plugins-dev/userservice/target/classes" path="src/plugins/userservice/src/java"/> <classpathentry kind="src" output="work/plugins-dev/userservice/target/classes" path="src/plugins/userservice/src/java"/>
<classpathentry kind="src" output="work/plugins-dev/websocket/target/classes" path="src/plugins/websocket/src/java"/>
<classpathentry kind="src" output="work/plugins-dev/xmldebugger/target/classes" path="src/plugins/xmldebugger/src/java"/> <classpathentry kind="src" output="work/plugins-dev/xmldebugger/target/classes" path="src/plugins/xmldebugger/src/java"/>
<classpathentry kind="src" path="src/test/java"/> <classpathentry kind="src" path="src/test/java"/>
<classpathentry kind="src" path="src/test/throttletest/src"/> <classpathentry kind="src" path="src/test/throttletest/src"/>
...@@ -125,12 +124,13 @@ ...@@ -125,12 +124,13 @@
<classpathentry kind="lib" path="src/web/WEB-INF/lib/commons-fileupload.jar"/> <classpathentry kind="lib" path="src/web/WEB-INF/lib/commons-fileupload.jar"/>
<classpathentry kind="lib" path="src/web/WEB-INF/lib/commons-io.jar"/> <classpathentry kind="lib" path="src/web/WEB-INF/lib/commons-io.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="lib" path="src/plugins/stunserver/lib/jstun-0.6.1.jar"/> <classpathentry kind="lib" path="src/plugins/stunserver/lib/jstun-0.7.4.jar"/>
<classpathentry kind="lib" path="build/lib/merge/jetty-jmx.jar"/> <classpathentry kind="lib" path="build/lib/merge/jetty-jmx.jar"/>
<classpathentry kind="lib" path="build/lib/merge/mina-integration-jmx.jar"/> <classpathentry kind="lib" path="build/lib/merge/mina-integration-jmx.jar"/>
<classpathentry kind="lib" path="build/lib/dist/bcpg-jdk15on.jar"/> <classpathentry kind="lib" path="build/lib/dist/bcpg-jdk15on.jar"/>
<classpathentry kind="lib" path="build/lib/dist/bcpkix-jdk15on.jar"/> <classpathentry kind="lib" path="build/lib/dist/bcpkix-jdk15on.jar"/>
<classpathentry kind="lib" path="build/lib/dist/bcprov-jdk15on.jar"/> <classpathentry kind="lib" path="build/lib/dist/bcprov-jdk15on.jar"/>
<classpathentry kind="lib" path="build/lib/merge/commons-pool2.jar"/>
<classpathentry kind="lib" path="build/lib/merge/jetty-servlets.jar"/> <classpathentry kind="lib" path="build/lib/merge/jetty-servlets.jar"/>
<classpathentry kind="lib" path="build/lib/merge/spdy-client.jar"/> <classpathentry kind="lib" path="build/lib/merge/spdy-client.jar"/>
<classpathentry kind="lib" path="build/lib/merge/spdy-core.jar"/> <classpathentry kind="lib" path="build/lib/merge/spdy-core.jar"/>
...@@ -161,7 +161,6 @@ ...@@ -161,7 +161,6 @@
<classpathentry kind="lib" path="src/plugins/rayo/lib/rayo-core-2.0-SNAPSHOT.jar"/> <classpathentry kind="lib" path="src/plugins/rayo/lib/rayo-core-2.0-SNAPSHOT.jar"/>
<classpathentry kind="lib" path="src/plugins/rayo/lib/netty-3.5.1.Final.jar"/> <classpathentry kind="lib" path="src/plugins/rayo/lib/netty-3.5.1.Final.jar"/>
<classpathentry kind="lib" path="src/plugins/rayo/lib/freetts.jar"/> <classpathentry kind="lib" path="src/plugins/rayo/lib/freetts.jar"/>
<classpathentry kind="lib" path="src/plugins/websocket/lib/commons-pool2-2.3.jar"/>
<classpathentry kind="lib" path="src/plugins/hazelcast/lib/hazelcast-3.5.1.jar"/> <classpathentry kind="lib" path="src/plugins/hazelcast/lib/hazelcast-3.5.1.jar"/>
<classpathentry kind="lib" path="src/plugins/rayo/lib/codecLib_dtmf.jar"/> <classpathentry kind="lib" path="src/plugins/rayo/lib/codecLib_dtmf.jar"/>
<classpathentry kind="lib" path="src/plugins/rayo/lib/jspeex.jar"/> <classpathentry kind="lib" path="src/plugins/rayo/lib/jspeex.jar"/>
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<install4j version="6.1.5" transformSequenceNumber="5"> <install4j version="6.1.4" transformSequenceNumber="5">
<directoryPresets config="${compiler:RELEASE_FULL_PATH}/resources/security/truststore" /> <directoryPresets config="${compiler:RELEASE_FULL_PATH}/resources/security/truststore" />
<application name="${compiler:APP_NAME}" distributionSourceDir="" applicationId="${compiler:APPLICATION_ID}" mediaDir="../../target/release" mediaFilePattern="${compiler:FILE_PREFIX}_${compiler:VERSION_MAJOR}_${compiler:VERSION_MINOR}_${compiler:VERSION_REVISION}" compression="9" lzmaCompression="true" pack200Compression="false" excludeSignedFromPacking="true" commonExternalFiles="false" createMd5Sums="true" shrinkRuntime="true" shortName="${compiler:APP_SHORT_NAME}" publisher="${compiler:PUBLISHER}" publisherWeb="${compiler:PUBLISHER_URL}" version="${compiler:VERSION_MAJOR}.${compiler:VERSION_MINOR}.${compiler:VERSION_REVISION}" allPathsRelative="true" backupOnSave="false" autoSave="true" convertDotsToUnderscores="true" macSignature="????" macVolumeId="419a18ebe125f2bf" javaMinVersion="1.5" javaMaxVersion="" allowBetaVM="true" jdkMode="runtimeJre" jdkName=""> <application name="${compiler:APP_NAME}" distributionSourceDir="" applicationId="${compiler:APPLICATION_ID}" mediaDir="../../target/release" mediaFilePattern="${compiler:FILE_PREFIX}_${compiler:VERSION_MAJOR}_${compiler:VERSION_MINOR}_${compiler:VERSION_REVISION}" compression="9" lzmaCompression="true" pack200Compression="false" excludeSignedFromPacking="true" commonExternalFiles="false" createMd5Sums="true" shrinkRuntime="true" shortName="${compiler:APP_SHORT_NAME}" publisher="${compiler:PUBLISHER}" publisherWeb="${compiler:PUBLISHER_URL}" version="${compiler:VERSION_MAJOR}.${compiler:VERSION_MINOR}.${compiler:VERSION_REVISION}" allPathsRelative="true" backupOnSave="false" autoSave="true" convertDotsToUnderscores="true" macSignature="????" macVolumeId="419a18ebe125f2bf" javaMinVersion="1.5" javaMaxVersion="" allowBetaVM="true" jdkMode="runtimeJre" jdkName="">
<languages skipLanguageSelection="false" languageSelectionInPrincipalLanguage="false"> <languages skipLanguageSelection="false" languageSelectionInPrincipalLanguage="false">
...@@ -867,8 +867,6 @@ ...@@ -867,8 +867,6 @@
</autoUpdate> </autoUpdate>
</windows> </windows>
</mediaSets> </mediaSets>
<buildIds buildAll="false"> <buildIds buildAll="false" />
<mediaSet refId="3" />
</buildIds>
<buildOptions verbose="false" faster="false" disableSigning="false" disableJreBundling="false" debug="false" /> <buildOptions verbose="false" faster="false" disableSigning="false" disableJreBundling="false" debug="false" />
</install4j> </install4j>
...@@ -552,6 +552,16 @@ tab.server.descr=Click to manage server settings ...@@ -552,6 +552,16 @@ tab.server.descr=Click to manage server settings
sidebar.sidebar-media-services=Media Services sidebar.sidebar-media-services=Media Services
sidebar.media-proxy=Media Proxy sidebar.media-proxy=Media Proxy
sidebar.media-proxy.descr=Click to view media proxy settings. sidebar.media-proxy.descr=Click to view media proxy settings.
sidebar.sidebar-pubsub=PubSub
sidebar.pubsub-node-summary=Node Summary
sidebar.pubsub-node-summary.descr=Click to manage PubSub nodes
sidebar.sidebar-node-options=Node Options
sidebar.pubsub-node-items=Published Items
sidebar.pubsub-node-items.descr=Click to view items published to the node
sidebar.pubsub-node-subscribers=Node Subscribers
sidebar.pubsub-node-subscribers.descr=Click to view the node&#39;s subscribers
sidebar.pubsub-node-delete=Delete Node
sidebar.pubsub-node-delete.descr=Click to delete the node
tab.tab-users=Users/Groups tab.tab-users=Users/Groups
tab.tab-users.descr=Click to manage users and groups tab.tab-users.descr=Click to manage users and groups
sidebar.sidebar-users=Users sidebar.sidebar-users=Users
...@@ -564,6 +574,8 @@ tab.tab-users.descr=Click to manage users and groups ...@@ -564,6 +574,8 @@ tab.tab-users.descr=Click to manage users and groups
sidebar.user-roster.descr=Click to view the user&#39;s roster sidebar.user-roster.descr=Click to view the user&#39;s roster
sidebar.user-password=Password sidebar.user-password=Password
sidebar.user-password.descr=Click to change the user&#39;s password sidebar.user-password.descr=Click to change the user&#39;s password
sidebar.user-pep-node-summary=Personal Eventing
sidebar.user-pep-node-summary.descr=Click to manage Personal Eventing Protocol nodes
sidebar.user-groups=User Groups sidebar.user-groups=User Groups
sidebar.user-groups.descr=Click to change user groups sidebar.user-groups.descr=Click to change user groups
sidebar.user-lockout=Lock Out sidebar.user-lockout=Lock Out
...@@ -2626,6 +2638,62 @@ user.groups.member.info=Below is a list of groups for user ...@@ -2626,6 +2638,62 @@ user.groups.member.info=Below is a list of groups for user
user.groups.name=Group Name user.groups.name=Group Name
user.groups.form.update=User groups edited successfully. user.groups.form.update=User groups edited successfully.
# PubSub Admin page
pubsub.node.summary.title=PubSub Nodes
pubsub.node.summary.info=Below is an overview of the Leaf Nodes in the PubSub service.
pubsub.node.summary.total_nodes=Total Nodes
pubsub.node.summary.sorted_id=Sorted by Node ID
pubsub.node.summary.id=Node ID
pubsub.node.summary.name=Name
pubsub.node.summary.description=Description
pubsub.node.summary.items=Items
pubsub.node.summary.subscribers=Subscribers
pubsub.node.summary.no_nodes=No leaf nodes in the PubSub service.
pubsub.node.summary.table.info=Node summary is show in the following table:
pubsub.node.summary.created=Created On
pubsub.node.summary.modified=Last Modified
pubsub.node.summary.deleted=Node deleted successfully
# PubSub Delete Node
pubsub.node.delete.title=Delete Node
pubsub.node.delete.info=Are you sure you want to delete the node
pubsub.node.delete.detail=from the system?
pubsub.node.delete.details_title=Details
pubsub.node.delete.node_id=Node ID:
pubsub.node.delete.reason=Reason:
pubsub.node.delete.delete_node=Delete Node
# PubSub Node Published Items
pubsub.node.items.title=Published Items
pubsub.node.items.id=Item ID
pubsub.node.items.publisher=Publisher
pubsub.node.items.created=Created On
pubsub.node.items.payload=Payload
pubsub.node.items.table.info=Current published items are listed in the following table:
pubsub.node.items.deleted=Deleted item published by {0} from the node.
# PubSub Node Subscribers
pubsub.node.subscribers.title=Subscribers
pubsub.node.subscribers.owner=Owner
pubsub.node.subscribers.resource=Resource
pubsub.node.subscribers.status=Status
pubsub.node.subscribers.expires=Expires
pubsub.node.subscribers.table.info=Current node subscribers are listed in the following table:
pubsub.node.subscribers.deleted=Deleted subscription owned by {0} from the node.
# Plugins Admin Page # Plugins Admin Page
plugin.admin.title=Plugins plugin.admin.title=Plugins
......
/*
* Copyright (C) 2017 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.jivesoftware.openfire.pep;
import org.jivesoftware.openfire.pubsub.PubSubServiceInfo;
import org.xmpp.packet.JID;
/**
* A PubSubService manager that is specific to the implemenation of XEP-163: Personal Eventing Protocol.
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
*/
public class PEPServiceInfo extends PubSubServiceInfo
{
public PEPServiceInfo( JID owner )
{
super( new PEPServiceManager().getPEPService( owner.toBareJID() ) );
}
}
...@@ -1811,7 +1811,7 @@ public abstract class Node { ...@@ -1811,7 +1811,7 @@ public abstract class Node {
* @return the subscription whose subscription ID matches the specified ID or <tt>null</tt> * @return the subscription whose subscription ID matches the specified ID or <tt>null</tt>
* if none was found. * if none was found.
*/ */
NodeSubscription getSubscription(String subscriptionID) { public NodeSubscription getSubscription(String subscriptionID) {
return subscriptionsByID.get(subscriptionID); return subscriptionsByID.get(subscriptionID);
} }
......
/*
* Copyright (C) 2017 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.jivesoftware.openfire.pubsub;
import org.jivesoftware.openfire.XMPPServer;
/**
* A PubSubService manager that is specific to the implemenation of XEP-60: Publish-Subscribe.
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
*/
public class PubSubInfo extends PubSubServiceInfo
{
public PubSubInfo()
{
super( XMPPServer.getInstance().getPubSubModule() );
}
}
...@@ -35,7 +35,7 @@ import java.util.Map; ...@@ -35,7 +35,7 @@ import java.util.Map;
* The separation between <code>PubSubService</code> and <code>PubSubEngine</code> allows to * The separation between <code>PubSubService</code> and <code>PubSubEngine</code> allows to
* reuse the handling of packets and at the same time be able to create different pubsub * reuse the handling of packets and at the same time be able to create different pubsub
* services with different configurations. Examples of different pubsub services are: * services with different configurations. Examples of different pubsub services are:
* JEP-60: Publish-Subscribe and JEP-163: Personal Eventing Protocol. * XEP-60: Publish-Subscribe and XEP-163: Personal Eventing Protocol.
* *
* @author Matt Tucker * @author Matt Tucker
*/ */
......
package org.jivesoftware.openfire.pubsub;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class PubSubServiceInfo
{
private PubSubService pubSubService;
public PubSubServiceInfo( PubSubService pubSubService ) {
if ( pubSubService == null )
{
throw new IllegalArgumentException( "Argument 'pubSubService' cannot be null." );
}
this.pubSubService = pubSubService;
}
public Collection<Node> getNodes() {
return pubSubService.getNodes();
}
public Node getNode(String nodeID) {
return pubSubService.getNode(nodeID);
}
public List<Node> getLeafNodes() {
List<Node> leafNodes = new ArrayList<Node>();
for(Node node : pubSubService.getNodes()) {
if ( ! node.isCollectionNode() ) {
leafNodes.add(node);
}
}
return leafNodes;
}
public CollectionNode getRootCollectionNode() {
return pubSubService.getRootCollectionNode();
}
public String getServiceID() {
return pubSubService.getServiceID();
}
}
...@@ -35,6 +35,8 @@ import org.jivesoftware.openfire.auth.AuthToken; ...@@ -35,6 +35,8 @@ import org.jivesoftware.openfire.auth.AuthToken;
import org.jivesoftware.openfire.group.GroupManager; import org.jivesoftware.openfire.group.GroupManager;
import org.jivesoftware.openfire.lockout.LockOutManager; import org.jivesoftware.openfire.lockout.LockOutManager;
import org.jivesoftware.openfire.muc.MultiUserChatManager; import org.jivesoftware.openfire.muc.MultiUserChatManager;
import org.jivesoftware.openfire.pubsub.PubSubInfo;
import org.jivesoftware.openfire.pubsub.PubSubServiceInfo;
import org.jivesoftware.openfire.roster.RosterManager; import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.security.SecurityAuditManager; import org.jivesoftware.openfire.security.SecurityAuditManager;
import org.jivesoftware.openfire.user.User; import org.jivesoftware.openfire.user.User;
...@@ -124,6 +126,10 @@ public class WebManager extends WebBean { ...@@ -124,6 +126,10 @@ public class WebManager extends WebBean {
return getXMPPServer().getServerInfo(); return getXMPPServer().getServerInfo();
} }
public PubSubServiceInfo getPubSubInfo() {
return new PubSubInfo();
}
/** /**
* Logs a security event as the currently logged in user. (convenience routine for SecurityAuditManager) * Logs a security event as the currently logged in user. (convenience routine for SecurityAuditManager)
* *
......
...@@ -283,6 +283,34 @@ ...@@ -283,6 +283,34 @@
description="${sidebar.media-proxy.descr}"/> description="${sidebar.media-proxy.descr}"/>
</sidebar> </sidebar>
<!-- PubSub Node Administration -->
<sidebar id="sidebar-pubsub" name="${sidebar.sidebar-pubsub}">
<!-- PubSub Node Summary -->
<item id="pubsub-node-summary" name="${sidebar.pubsub-node-summary}"
url="pubsub-node-summary.jsp"
description="${sidebar.pubsub-node-summary.descr}">
<!-- Node Options -->
<sidebar id="sidebar-node-options" name="${sidebar.sidebar-node-options}">
<!-- Published Items -->
<item id="pubsub-node-items" name="${sidebar.pubsub-node-items}"
url="pubsub-node-items.jsp"
description="${sidebar.pubsub-node-items.descr}"/>
<!-- Node Subscribers -->
<item id="pubsub-node-subscribers" name="${sidebar.pubsub-node-subscribers}"
url="pubsub-node-subscribers.jsp"
description="${sidebar.pubsub-node-subscribers.descr}"/>
<!-- Delete Node -->
<item id="pubsub-node-delete" name="${sidebar.pubsub-node-delete}"
url="pubsub-node-delete.jsp"
description="${sidebar.pubsub-node-delete.descr}"/>
</sidebar>
</item>
</sidebar>
</tab> </tab>
<!-- Users/Groups --> <!-- Users/Groups -->
...@@ -314,6 +342,11 @@ ...@@ -314,6 +342,11 @@
url="user-groups.jsp" url="user-groups.jsp"
description="${sidebar.user-groups.descr}"/> description="${sidebar.user-groups.descr}"/>
<!-- PEP Node Administration -->
<item id="user-pep-node-summary" name="${sidebar.user-pep-node-summary}"
url="pubsub-node-summary.jsp"
description="${sidebar.user-pep-node-summary.descr}"/>
<!-- Password --> <!-- Password -->
<item id="user-password" name="${sidebar.user-password}" <item id="user-password" name="${sidebar.user-password}"
url="user-password.jsp" url="user-password.jsp"
...@@ -500,8 +533,8 @@ ...@@ -500,8 +533,8 @@
<!-- Plugins --> <!-- Plugins -->
<tab id="tab-plugins" name="${tab.tab-plugins}" url="plugin-admin.jsp" description="${tab.tab-plugins.descr}"> <tab id="tab-plugins" name="${tab.tab-plugins}" url="plugin-admin.jsp" description="${tab.tab-plugins.descr}">
<!-- Group Chat Settings --> <!-- Plugin Admin -->
<sidebar id="sidebar-plugin-adamin" name="${sidebar.sidebar-plugin-admin}"> <sidebar id="sidebar-plugin-admin" name="${sidebar.sidebar-plugin-admin}">
<!-- Plugins --> <!-- Plugins -->
<item id="plugin-settings" name="${sidebar.plugin-settings}" <item id="plugin-settings" name="${sidebar.plugin-settings}"
......
<%@ page import="org.jivesoftware.openfire.pubsub.Node,
org.jivesoftware.util.CookieUtils,
org.jivesoftware.util.ParamUtils"
errorPage="error.jsp"
%>
<%@ page import="org.jivesoftware.util.StringUtils" %>
<%@ page import="java.net.URLDecoder" %>
<%@ page import="org.xmpp.packet.JID" %>
<%@ page import="org.jivesoftware.openfire.pep.PEPServiceInfo" %>
<%@ page import="org.jivesoftware.openfire.pubsub.PubSubServiceInfo" %>
<%@ page import="java.net.URLEncoder" %>
<%@ page import="org.jivesoftware.openfire.XMPPServer" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="admin" prefix="admin" %>
<jsp:useBean id="webManager" class="org.jivesoftware.util.WebManager" />
<% webManager.init(request, response, session, application, out ); %>
<% // Get parameters //
boolean cancel = ParamUtils.getParameter(request,"cancel") != null;
boolean delete = ParamUtils.getParameter(request,"delete") != null;
String ownerString = ParamUtils.getParameter( request, "owner" );
if ( ownerString == null )
{
ownerString = ParamUtils.getParameter( request, "username" );
}
JID owner = null;
if (ownerString != null)
{
final String ownerValue = URLDecoder.decode( ownerString, "UTF-8" );
if ( ownerValue.contains( "@" ) )
{
owner = new JID( ownerValue ).asBareJID();
}
else
{
owner = XMPPServer.getInstance().createJID( ownerValue, null );
}
}
Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
String csrfParam = ParamUtils.getParameter(request, "csrf");
if (delete) {
if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
delete = false;
}
}
csrfParam = StringUtils.randomString(15);
CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
pageContext.setAttribute("csrf", csrfParam);
String nodeID = ParamUtils.getParameter(request,"nodeID");
String reason = ParamUtils.getParameter(request,"reason");
// Handle a cancel
if (cancel) {
response.sendRedirect("pubsub-node-summary.jsp");
return;
}
// Load the node object
PubSubServiceInfo pubSubServiceInfo;
if ( owner == null )
{
pubSubServiceInfo = webManager.getPubSubInfo();
}
else
{
pubSubServiceInfo = new PEPServiceInfo( owner );
}
Node node = pubSubServiceInfo.getNode( nodeID );
// Handle a node delete:
if (delete) {
// Delete the node
if (node != null) {
// If the node still exists then destroy it
node.delete();
// Log the event
webManager.logEvent("destroyed PubSub Node " + nodeID, "reason = " + reason );
}
// Done, so redirect
response.sendRedirect("pubsub-node-summary.jsp?deletesuccess=true&owner=" + (owner != null ? URLEncoder.encode( owner.toBareJID(), "UTF-8") : "") );
return;
}
pageContext.setAttribute("node", node);
%>
<html>
<head>
<title><fmt:message key="pubsub.node.delete.title"/></title>
<c:choose>
<c:when test="${not empty owner and owner.domain eq webManager.serverInfo.XMPPDomain}">
<meta name="subPageID" content="user-pep-node-summary"/>
<meta name="extraParams" content="username=${admin:urlEncode(owner.node)}&nodeID=${node.nodeID}" />
</c:when>
<c:otherwise>
<meta name="subPageID" content="pubsub-node-delete"/>
<meta name="extraParams" content="nodeID=${node.nodeID}"/>
</c:otherwise>
</c:choose>
</head>
<body>
<p>
<fmt:message key="pubsub.node.delete.info" />
<b>
<c:out value="${node.nodeID}"/>
</b>
<fmt:message key="pubsub.node.delete.detail" />
</p>
<form action="pubsub-node-delete.jsp">
<input type="hidden" name="csrf" value="${csrf}">
<input type="hidden" name="nodeID" value="${node.nodeID}">
<fieldset>
<legend><fmt:message key="pubsub.node.delete.details_title" /></legend>
<div>
<table cellpadding="3" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
<td class="c1">
<fmt:message key="pubsub.node.delete.node_id" />
</td>
<td>
<c:out value="${node.nodeID}"/>
</td>
</tr>
<tr>
<td class="c1">
<fmt:message key="pubsub.node.delete.reason" />
</td>
<td>
<input type="text" size="50" maxlength="150" name="reason">
</td>
</tr>
</tbody>
</table>
</div>
</fieldset>
<br><br>
<input type="submit" name="delete" value="<fmt:message key="pubsub.node.delete.delete_node" />">
<input type="submit" name="cancel" value="<fmt:message key="global.cancel" />">
</form>
</body>
</html>
<%@ page import="org.jivesoftware.openfire.pubsub.LeafNode,
org.jivesoftware.openfire.pubsub.Node,
org.jivesoftware.openfire.pubsub.PublishedItem,
org.jivesoftware.util.CookieUtils,
org.jivesoftware.util.ParamUtils,
org.jivesoftware.util.StringUtils,
java.net.URLEncoder,
java.util.Arrays"
errorPage="error.jsp"
%>
<%@ page import="java.net.URLDecoder" %>
<%@ page import="org.xmpp.packet.JID" %>
<%@ page import="org.jivesoftware.openfire.pep.PEPServiceInfo" %>
<%@ page import="org.jivesoftware.openfire.pubsub.PubSubServiceInfo" %>
<%@ page import="org.jivesoftware.openfire.XMPPServer" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="admin" prefix="admin" %>
<jsp:useBean id="webManager" class="org.jivesoftware.util.WebManager" />
<% webManager.init(request, response, session, application, out); %>
<% // Get parameters
String nodeID = ParamUtils.getParameter(request,"nodeID");
String deleteID = ParamUtils.getParameter(request,"deleteID");
String ownerString = ParamUtils.getParameter( request, "owner" );
if ( ownerString == null )
{
ownerString = ParamUtils.getParameter( request, "username" );
}
JID owner = null;
if (ownerString != null)
{
final String ownerValue = URLDecoder.decode( ownerString, "UTF-8" );
if ( ownerValue.contains( "@" ) )
{
owner = new JID( ownerValue ).asBareJID();
}
else
{
owner = XMPPServer.getInstance().createJID( ownerValue, null );
}
}
Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
String csrfParam = ParamUtils.getParameter(request, "csrf");
if (deleteID != null) {
if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
deleteID = null;
}
}
// Load the node object
PubSubServiceInfo pubSubServiceInfo;
if ( owner == null )
{
pubSubServiceInfo = webManager.getPubSubInfo();
}
else
{
pubSubServiceInfo = new PEPServiceInfo( owner );
}
Node node = pubSubServiceInfo.getNode( nodeID );
if (node == null) {
// The requested node does not exist so return to the list of the existing node
response.sendRedirect("pubsub-node-summary.jsp");
return;
}
// Delete specified subscription ID
if (deleteID != null) {
PublishedItem pi = node.getPublishedItem(deleteID);
if (pi != null) {
LeafNode lNode = (LeafNode) node;
lNode.deleteItems(Arrays.asList(pi));
// Log the event
webManager.logEvent("Delete item ID: " + deleteID + ", from node ID: " + nodeID, "Publisher: " + pi.getPublisher().toBareJID());
// Done, so redirect
response.sendRedirect("pubsub-node-items.jsp?nodeID=" + URLEncoder.encode(nodeID, "UTF-8") + "&deleteSuccess=true&owner=" + (owner != null ? URLEncoder.encode(owner.toBareJID(), "UTF-8") : "") + "&ownerOfDeleted=" + URLEncoder.encode(pi.getPublisher().toBareJID(), "UTF-8"));
return;
}
}
csrfParam = StringUtils.randomString(15);
CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
pageContext.setAttribute("csrf", csrfParam);
pageContext.setAttribute("node", node);
%>
<html>
<head>
<title><fmt:message key="pubsub.node.items.title"/></title>
<c:choose>
<c:when test="${not empty owner and owner.domain eq webManager.serverInfo.XMPPDomain}">
<meta name="subPageID" content="user-pep-node-summary"/>
<meta name="extraParams" content="username=${admin:urlEncode(owner.node)}&nodeID=${node.nodeID}&create=false" />
</c:when>
<c:otherwise>
<meta name="subPageID" content="pubsub-node-items"/>
<meta name="extraParams" content="nodeID=${node.nodeID}&create=false"/>
</c:otherwise>
</c:choose>
</head>
<body>
<p>
<fmt:message key="pubsub.node.summary.table.info" />
</p>
<c:if test="${param.deleteSuccess}">
<div class="jive-success">
<table cellpadding="0" cellspacing="0" border="0">
<tbody>
<tr><td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16" border="0" alt=""></td>
<td class="jive-icon-label">
<fmt:message key="pubsub.node.items.deleted">
<fmt:param value="${param.ownerOfDeleted}"/>
</fmt:message>
</td></tr>
</tbody>
</table>
</div><br>
</c:if>
<div class="jive-table">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<thead>
<tr>
<th scope="col"><fmt:message key="pubsub.node.summary.id" /></th>
<th scope="col"><fmt:message key="pubsub.node.summary.name" /></th>
<th scope="col"><fmt:message key="pubsub.node.summary.description" /></th>
<th scope="col"><fmt:message key="pubsub.node.summary.items" /></th>
<th scope="col"><fmt:message key="pubsub.node.summary.subscribers" /></th>
<th scope="col"><fmt:message key="pubsub.node.summary.created" /></th>
<th scope="col"><fmt:message key="pubsub.node.summary.modified" /></th>
</tr>
</thead>
<tbody>
<tr>
<td><c:out value="${node.getNodeID()}"/></td>
<td><c:out value="${node.getName()}"/></td>
<td><c:out value="${node.getDescription()}"/></td>
<td><c:out value="${node.getPublishedItems().size()}"/></td>
<td><c:out value="${node.getAllSubscriptions().size()}"/></td>
<td><fmt:formatDate type="both" dateStyle="medium" timeStyle="short" value="${node.getCreationDate()}" /></td>
<td><fmt:formatDate type="both" dateStyle="medium" timeStyle="short" value="${node.getModificationDate()}" /></td>
</tr>
</tbody>
</table>
</div>
<br>
<p>
<fmt:message key="pubsub.node.items.table.info" />
</p>
<div class="jive-table">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<thead>
<tr>
<th scope="col"><fmt:message key="pubsub.node.items.id" /></th>
<th scope="col"><fmt:message key="pubsub.node.items.publisher" /></th>
<th scope="col"><fmt:message key="pubsub.node.items.created" /></th>
<th scope="col"><fmt:message key="pubsub.node.items.payload" /></th>
<th scope="col"><fmt:message key="global.delete" /></th>
</tr>
</thead>
<tbody>
<c:forEach var="item" items="${node.getPublishedItems()}">
<tr>
<td>
<c:out value="${item.getID()}"/>
</td>
<td>
<c:out value="${item.getPublisher().toBareJID()}"/>
</td>
<td>
<fmt:formatDate type="both" dateStyle="medium" timeStyle="short" value="${item.getCreationDate()}" />
</td>
<td>
<c:out value="${item.getPayloadXML()}"/>
</td>
<td width="1%" align="center" style="border-right:1px #ccc solid;">
<c:url value="pubsub-node-items.jsp" var="url">
<c:param name="nodeID" value="${node.getNodeID()}" />
<c:param name="deleteID" value="${item.getID()}" />
<c:param name="csrf" value="${csrf}" />
<c:if test="${not empty owner}">
<c:param name="owner">${admin:urlEncode(owner)}</c:param>
</c:if>
</c:url>
<a href="${url}" title="<fmt:message key="global.click_delete" />">
<img src="images/delete-16x16.gif" width="16" height="16" border="0" alt="">
</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</body>
</html>
<%@ page import="org.jivesoftware.openfire.pubsub.Node,
org.jivesoftware.openfire.pubsub.NodeSubscription,
org.jivesoftware.util.CookieUtils,
org.jivesoftware.util.ParamUtils,
org.jivesoftware.util.StringUtils,
java.net.URLEncoder"
errorPage="error.jsp"
%>
<%@ page import="java.net.URLDecoder" %>
<%@ page import="org.xmpp.packet.JID" %>
<%@ page import="org.jivesoftware.openfire.pep.PEPServiceInfo" %>
<%@ page import="org.jivesoftware.openfire.pubsub.PubSubServiceInfo" %>
<%@ page import="org.jivesoftware.openfire.XMPPServer" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="admin" prefix="admin" %>
<jsp:useBean id="webManager" class="org.jivesoftware.util.WebManager" />
<% webManager.init(request, response, session, application, out); %>
<% // Get parameters
String nodeID = ParamUtils.getParameter(request,"nodeID");
String deleteID = ParamUtils.getParameter(request,"deleteID");
String ownerString = ParamUtils.getParameter( request, "owner" );
if ( ownerString == null )
{
ownerString = ParamUtils.getParameter( request, "username" );
}
JID owner = null;
if (ownerString != null)
{
final String ownerValue = URLDecoder.decode( ownerString, "UTF-8" );
if ( ownerValue.contains( "@" ) )
{
owner = new JID( ownerValue ).asBareJID();
}
else
{
owner = XMPPServer.getInstance().createJID( ownerValue, null );
}
}
Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
String csrfParam = ParamUtils.getParameter(request, "csrf");
if (deleteID != null) {
if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
deleteID = null;
}
}
// Load the node object
PubSubServiceInfo pubSubServiceInfo;
if ( owner == null )
{
pubSubServiceInfo = webManager.getPubSubInfo();
}
else
{
pubSubServiceInfo = new PEPServiceInfo( owner );
}
Node node = pubSubServiceInfo.getNode( nodeID );
if (node == null) {
// The requested node does not exist so return to the list of the existing node
response.sendRedirect("pubsub-node-summary.jsp");
return;
}
// Delete specified subscription ID
if (deleteID != null) {
NodeSubscription subscription = node.getSubscription(deleteID);
if (subscription != null) {
node.cancelSubscription(subscription);
// Log the event
webManager.logEvent("Cancelled subscription ID: " + deleteID + ", from node ID: " + nodeID, "Owner: " + subscription.getOwner().toBareJID());
// Done, so redirect
response.sendRedirect("pubsub-node-subscribers.jsp?nodeID=" + URLEncoder.encode(nodeID, "UTF-8") + "&deleteSuccess=true&owner=" + (owner != null ? URLEncoder.encode(owner.toBareJID(), "UTF-8") : "") + "&ownerOfDeleted=" + URLEncoder.encode(subscription.getOwner().toBareJID(), "UTF-8"));
return;
}
}
csrfParam = StringUtils.randomString(15);
CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
pageContext.setAttribute("csrf", csrfParam);
pageContext.setAttribute("node", node);
%>
<html>
<head>
<title><fmt:message key="pubsub.node.subscribers.title"/></title>
<c:choose>
<c:when test="${not empty owner and owner.domain eq webManager.serverInfo.XMPPDomain}">
<meta name="subPageID" content="user-pep-node-summary"/>
<meta name="extraParams" content="username=${admin:urlEncode(owner.node)}&nodeID=${node.nodeID}&create=false" />
</c:when>
<c:otherwise>
<meta name="subPageID" content="pubsub-node-subscribers"/>
<meta name="extraParams" content="nodeID=${node.nodeID}&create=false"/>
</c:otherwise>
</c:choose>
</head>
<body>
<p>
<fmt:message key="pubsub.node.summary.table.info" />
</p>
<c:if test="${param.deleteSuccess}">
<div class="jive-success">
<table cellpadding="0" cellspacing="0" border="0">
<tbody>
<tr><td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16" border="0" alt=""></td>
<td class="jive-icon-label">
<fmt:message key="pubsub.node.subscribers.deleted">
<fmt:param value="${param.ownerOfDeleted}"/>
</fmt:message>
</td></tr>
</tbody>
</table>
</div><br>
</c:if>
<div class="jive-table">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<thead>
<tr>
<th scope="col"><fmt:message key="pubsub.node.summary.id" /></th>
<th scope="col"><fmt:message key="pubsub.node.summary.name" /></th>
<th scope="col"><fmt:message key="pubsub.node.summary.description" /></th>
<th scope="col"><fmt:message key="pubsub.node.summary.items" /></th>
<th scope="col"><fmt:message key="pubsub.node.summary.subscribers" /></th>
<th scope="col"><fmt:message key="pubsub.node.summary.created" /></th>
<th scope="col"><fmt:message key="pubsub.node.summary.modified" /></th>
</tr>
</thead>
<tbody>
<tr>
<td><c:out value="${node.getNodeID()}"/></td>
<td><c:out value="${node.getName()}"/></td>
<td><c:out value="${node.getDescription()}"/></td>
<td><c:out value="${node.getPublishedItems().size()}"/></td>
<td><c:out value="${node.getAllSubscriptions().size()}"/></td>
<td><fmt:formatDate type="both" dateStyle="medium" timeStyle="short" value="${node.getCreationDate()}" /></td>
<td><fmt:formatDate type="both" dateStyle="medium" timeStyle="short" value="${node.getModificationDate()}" /></td>
</tr>
</tbody>
</table>
</div>
<br>
<p>
<fmt:message key="pubsub.node.subscribers.table.info" />
</p>
<div class="jive-table">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<thead>
<tr>
<th scope="col"><fmt:message key="pubsub.node.subscribers.owner" /></th>
<th scope="col"><fmt:message key="pubsub.node.subscribers.resource" /></th>
<th scope="col"><fmt:message key="pubsub.node.subscribers.status" /></th>
<th scope="col"><fmt:message key="pubsub.node.subscribers.expires" /></th>
<th scope="col"><fmt:message key="global.delete" /></th>
</tr>
</thead>
<tbody>
<c:forEach var="subscription" items="${node.getAllSubscriptions()}">
<tr>
<td>
<c:out value="${subscription.getOwner().toBareJID()}"/>
</td>
<td>
<c:out value="${subscription.getJID().getResource()}"/>
</td>
<td>
<c:out value="${subscription.getState().name()}"/>
</td>
<td>
<fmt:formatDate type="both" dateStyle="medium" timeStyle="short" value="${subscription.getExpire()}" />
</td>
<td width="1%" align="center" style="border-right:1px #ccc solid;">
<c:url value="pubsub-node-subscribers.jsp" var="url">
<c:param name="nodeID" value="${node.getNodeID()}" />
<c:param name="deleteID" value="${subscription.getID()}" />
<c:param name="csrf" value="${csrf}" />
<c:if test="${not empty owner}">
<c:param name="owner">${admin:urlEncode(owner)}</c:param>
</c:if>
</c:url>
<a href="${url}" title="<fmt:message key="global.click_delete" />">
<img src="images/delete-16x16.gif" width="16" height="16" border="0" alt="">
</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</body>
</html>
<%@ page import="org.jivesoftware.openfire.pubsub.Node,
org.jivesoftware.openfire.pubsub.PubSubServiceInfo,
org.jivesoftware.util.ParamUtils,
java.util.Collections"
errorPage="error.jsp"
%>
<%@ page import="java.util.Comparator" %>
<%@ page import="java.util.List" %>
<%@ page import="org.xmpp.packet.JID" %>
<%@ page import="org.jivesoftware.openfire.pep.PEPServiceInfo" %>
<%@ page import="java.net.URLDecoder" %>
<%@ page import="org.jivesoftware.openfire.XMPPServer" %>
<%@ page import="org.jivesoftware.openfire.pep.PEPService" %>
<%@ page import="org.jivesoftware.openfire.pep.PEPServiceManager" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="admin" prefix="admin" %>
<jsp:useBean id="webManager" class="org.jivesoftware.util.WebManager" />
<% webManager.init(request, response, session, application, out ); %>
<% // Get parameters
int start = ParamUtils.getIntParameter(request,"start",0);
int range = ParamUtils.getIntParameter(request,"range",webManager.getRowsPerPage("pubsub-node-summary", 15));
String ownerString = ParamUtils.getParameter( request, "owner" );
if ( ownerString == null )
{
ownerString = ParamUtils.getParameter( request, "username" );
}
JID owner = null;
if (ownerString != null)
{
final String ownerValue = URLDecoder.decode( ownerString, "UTF-8" );
if ( ownerValue.contains( "@" ) )
{
owner = new JID( ownerValue ).asBareJID();
}
else
{
owner = XMPPServer.getInstance().createJID( ownerValue, null );
}
}
if (request.getParameter("range") != null) {
webManager.setRowsPerPage("pubsub-node-summary", range);
}
PubSubServiceInfo pubSubServiceInfo;
if ( owner == null )
{
pubSubServiceInfo = webManager.getPubSubInfo();
}
else if ( new PEPServiceManager().getPEPService( owner.toBareJID() ) != null )
{
pubSubServiceInfo = new PEPServiceInfo( owner );
}
else
{
pubSubServiceInfo = null;
}
List<Node> nodes;
if ( pubSubServiceInfo != null )
{
nodes = pubSubServiceInfo.getLeafNodes();
}
else
{
nodes = Collections.emptyList();
}
Collections.sort(nodes, new Comparator<Node>() {
public int compare(Node node1, Node node2) {
return node1.getNodeID().toLowerCase().compareTo(node2.getNodeID().toLowerCase());
}
});
int nodeCount = nodes.size();
// paginator vars
int numPages = (int)Math.ceil((double)nodeCount/(double)range);
if(start > nodeCount) {
start=nodeCount;
}
int curPage = (start/range) + 1;
int maxNodeIndex = (start+range <= nodeCount ? start+range : nodeCount);
pageContext.setAttribute("nodeCount", nodeCount);
pageContext.setAttribute("numPages", numPages);
pageContext.setAttribute("start", start);
pageContext.setAttribute("range", range);
pageContext.setAttribute("curPage", curPage);
pageContext.setAttribute("maxNodeIndex", maxNodeIndex);
pageContext.setAttribute("nodes", nodes.subList(start, maxNodeIndex));
pageContext.setAttribute("owner", owner );
%>
<html>
<head>
<title><fmt:message key="pubsub.node.summary.title"/></title>
<c:choose>
<c:when test="${not empty owner and owner.domain eq webManager.serverInfo.XMPPDomain}">
<meta name="subPageID" content="user-pep-node-summary"/>
<meta name="extraParams" content="username=${admin:urlEncode( owner.node)}" />
</c:when>
<c:otherwise>
<meta name="pageID" content="pubsub-node-summary"/>
</c:otherwise>
</c:choose>
</head>
<body>
<p>
<fmt:message key="pubsub.node.summary.info" />
</p>
<c:if test="${param.deletesuccess}">
<div class="jive-success">
<table cellpadding="0" cellspacing="0" border="0">
<tbody>
<tr><td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16" border="0" alt=""></td>
<td class="jive-icon-label">
<fmt:message key="pubsub.node.summary.deleted" />
</td></tr>
</tbody>
</table>
</div><br>
</c:if>
<p>
<fmt:message key="pubsub.node.summary.total_nodes" />: <c:out value="${nodeCount}"/>
<c:if test="${numPages gt 1}">
<fmt:message key="global.showing" /> <c:out value="${start+1}"/>-<c:out value="${maxNodeIndex}"/>
</c:if>
<fmt:message key="pubsub.node.summary.sorted_id" />
</p>
<c:if test="${numPages gt 1}">
<p>
<fmt:message key="global.pages" />:
[
<c:forEach begin="1" end="${numPages}" varStatus="loop">
<c:url value="pubsub-node-summary.jsp" var="url">
<c:param name="start" value="${(loop.index-1)*range}" />
<c:if test="${not empty owner}">
<c:param name="owner">${admin:urlEncode(owner)}</c:param>
</c:if>
</c:url>
<a href="${url}" class="${ loop.index == curPage ? 'jive-current' : ''}">
<c:out value="${loop.index}"/>
</a>
<c:if test="${loop.index < numPages}">
&nbsp;
</c:if>
</c:forEach>
]
</p>
</c:if>
<div class="jive-table">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<thead>
<tr>
<th>&nbsp;</th>
<th nowrap><fmt:message key="pubsub.node.summary.id" /></th>
<th nowrap><fmt:message key="pubsub.node.summary.name" /></th>
<th nowrap><fmt:message key="pubsub.node.summary.description" /></th>
<th nowrap><fmt:message key="pubsub.node.summary.items" /></th>
<th nowrap><fmt:message key="pubsub.node.summary.subscribers" /></th>
<th nowrap><fmt:message key="global.delete" /></th>
</tr>
</thead>
<tbody>
<c:if test="${nodeCount lt 1}">
<tr>
<td align="center" colspan="7">
<fmt:message key="pubsub.node.summary.no_nodes" />
</td>
</tr>
</c:if>
<c:forEach var="node" items="${nodes}" varStatus="loop">
<tr class="${ (loop.index%2)==0 ? 'jive-even' : 'jive-odd'}">
<td width="1%">
<c:out value="${loop.index}"/>
</td>
<td width="1%" valign="middle">
<c:out value="${node.getNodeID()}"/>
</td>
<td width="1%" valign="middle">
<c:out value="${node.getName()}"/>
</td>
<td valign="middle">
<c:out value="${node.getDescription()}"/>
</td>
<td width="1%" align="center">
<c:url value="pubsub-node-items.jsp" var="url">
<c:param name="nodeID" value="${node.getNodeID()}" />
</c:url>
<a href="${url}">
<c:out value="${node.getPublishedItems().size()}" />
</a>
</td>
<td width="1%" align="center">
<c:url value="pubsub-node-subscribers.jsp" var="url">
<c:param name="nodeID" value="${node.getNodeID()}" />
</c:url>
<a href="${url}">
<c:out value="${node.getAllSubscriptions().size()}" />
</a>
</td>
<td width="1%" align="center" style="border-right:1px #ccc solid;">
<c:url value="pubsub-node-delete.jsp" var="url">
<c:param name="nodeID" value="${node.getNodeID()}" />
</c:url>
<a href="${url}" title="<fmt:message key="global.click_delete" />">
<img src="images/delete-16x16.gif" width="16" height="16" border="0" alt="">
</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<c:if test="${numPages gt 1}">
<br>
<p>
<fmt:message key="global.pages" />:
[
<c:forEach begin="1" end="${numPages}" varStatus="loop">
<c:url value="pubsub-node-summary.jsp" var="url">
<c:param name="start" value="${(loop.index-1)*range}" />
</c:url>
<a href="${url}" class="${ loop.index == curPage ? 'jive-current' : ''}">
<c:out value="${loop.index}"/>
</a>
<c:if test="${loop.index < numPages}">
&nbsp;
</c:if>
</c:forEach>
]
</p>
</c:if>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment