You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by aj...@apache.org on 2009/04/20 00:29:12 UTC
svn commit: r766538 - in /incubator/jspwiki/trunk:
src/WebContent/templates/default/ src/WebContent/templates/default/editors/
src/java/org/apache/wiki/action/ tests/java/org/apache/wiki/action/
Author: ajaquith
Date: Sun Apr 19 22:29:12 2009
New Revision: 766538
URL: http://svn.apache.org/viewvc?rev=766538&view=rev
Log:
Massive refactoring to EditActionBean, and related spam-protection classes. Bug-fix to ContentManager's page-save task. Editing actually works again! More fixes coming later.
Added:
incubator/jspwiki/trunk/tests/java/org/apache/wiki/action/EditActionBeanTest.java
Modified:
incubator/jspwiki/trunk/src/WebContent/templates/default/EditContent.jsp
incubator/jspwiki/trunk/src/WebContent/templates/default/PreviewContent.jsp
incubator/jspwiki/trunk/src/WebContent/templates/default/editors/plain.jsp
incubator/jspwiki/trunk/src/java/org/apache/wiki/action/EditActionBean.java
incubator/jspwiki/trunk/tests/java/org/apache/wiki/action/AllTests.java
Modified: incubator/jspwiki/trunk/src/WebContent/templates/default/EditContent.jsp
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/templates/default/EditContent.jsp?rev=766538&r1=766537&r2=766538&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/templates/default/EditContent.jsp (original)
+++ incubator/jspwiki/trunk/src/WebContent/templates/default/EditContent.jsp Sun Apr 19 22:29:12 2009
@@ -15,8 +15,6 @@
<wiki:TabbedSection defaultTab="editcontent">
<wiki:Tab id="editcontent" titleKey="edit.tab.edit" accesskey="e">
- <s:errors />
- <s:messages />
<wiki:Editor/>
</wiki:Tab>
Modified: incubator/jspwiki/trunk/src/WebContent/templates/default/PreviewContent.jsp
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/templates/default/PreviewContent.jsp?rev=766538&r1=766537&r2=766538&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/templates/default/PreviewContent.jsp (original)
+++ incubator/jspwiki/trunk/src/WebContent/templates/default/PreviewContent.jsp Sun Apr 19 22:29:12 2009
@@ -25,8 +25,10 @@
<s:hidden name="link" />
<s:hidden name="page" value="${wikiActionBean.page.name}" />
<s:hidden name="remember" />
+ <s:hidden name="startTime" />
<s:hidden name="text" />
- <s:hidden name="<%=SpamFilter.getHashFieldName(request)%>"><c:out value="${lastchange}" /></s:hidden>
+ <%-- Spam detection fields --%>
+ <wiki:SpamProtect />
</p>
<div id="submitbuttons">
<c:set var="editTitle"><fmt:message key="editor.preview.edit.title"/></c:set>
Modified: incubator/jspwiki/trunk/src/WebContent/templates/default/editors/plain.jsp
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/templates/default/editors/plain.jsp?rev=766538&r1=766537&r2=766538&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/templates/default/editors/plain.jsp (original)
+++ incubator/jspwiki/trunk/src/WebContent/templates/default/editors/plain.jsp Sun Apr 19 22:29:12 2009
@@ -22,9 +22,10 @@
</p>
</c:if>
- <%-- Edit.jsp relies on these being found. So be careful, if you make changes. --%>
+ <%-- EditActionBean relies on these being found. So be careful, if you make changes. --%>
<p id="submitbuttons">
<s:hidden name="page"><wiki:Variable var='pagename' /></s:hidden>
+ <s:hidden name="startTime" />
<c:set var="saveTitle" scope="page"><fmt:message key="editor.plain.save.title" /></c:set>
<wiki:CheckRequestContext context='edit'>
<s:submit name="save" accesskey="s" title="${saveTitle}" />
Modified: incubator/jspwiki/trunk/src/java/org/apache/wiki/action/EditActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/java/org/apache/wiki/action/EditActionBean.java?rev=766538&r1=766537&r2=766538&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/java/org/apache/wiki/action/EditActionBean.java (original)
+++ incubator/jspwiki/trunk/src/java/org/apache/wiki/action/EditActionBean.java Sun Apr 19 22:29:12 2009
@@ -22,8 +22,8 @@
package org.apache.wiki.action;
import java.io.IOException;
+import java.net.URI;
import java.security.Principal;
-import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
@@ -34,7 +34,9 @@
import net.sourceforge.stripes.validation.*;
import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.wiki.*;
+import org.apache.wiki.WikiContext;
+import org.apache.wiki.WikiEngine;
+import org.apache.wiki.WikiSession;
import org.apache.wiki.api.WikiException;
import org.apache.wiki.api.WikiPage;
import org.apache.wiki.auth.permissions.PagePermission;
@@ -42,12 +44,12 @@
import org.apache.wiki.content.PageNotFoundException;
import org.apache.wiki.content.lock.PageLock;
import org.apache.wiki.filters.RedirectException;
-import org.apache.wiki.filters.SpamProtect;
import org.apache.wiki.htmltowiki.HtmlStringToWikiTranslator;
import org.apache.wiki.log.Logger;
import org.apache.wiki.log.LoggerFactory;
import org.apache.wiki.providers.ProviderException;
import org.apache.wiki.ui.stripes.HandlerPermission;
+import org.apache.wiki.ui.stripes.SpamProtect;
import org.apache.wiki.ui.stripes.WikiActionBeanContext;
import org.apache.wiki.ui.stripes.WikiRequestContext;
import org.apache.wiki.util.TextUtil;
@@ -84,7 +86,7 @@
private String m_link = null;
- private Date m_startTime = null;
+ private long m_startTime = -1;
/**
* Event handler method that cancels any locks the user possesses for the
@@ -95,11 +97,12 @@
*/
@DontValidate
@HandlesEvent( "cancel" )
- @HandlerPermission( permissionClass = PagePermission.class, target = "${page.qualifiedName}", actions = PagePermission.EDIT_ACTION )
+ @HandlerPermission( permissionClass = PagePermission.class, target = "${page.path}", actions = PagePermission.EDIT_ACTION )
@WikiRequestContext( "cancel" )
public Resolution cancel()
{
- String pagereq = m_page.getName();
+ WikiPage page = getPage();
+ String pagereq = page.getName();
log.debug( "Cancelled editing " + pagereq );
// Cancel page lock
@@ -115,12 +118,12 @@
}
@HandlesEvent( "comment" )
- @HandlerPermission( permissionClass = PagePermission.class, target = "${page.qualifiedName}", actions = PagePermission.COMMENT_ACTION )
+ @HandlerPermission( permissionClass = PagePermission.class, target = "${page.path}", actions = PagePermission.COMMENT_ACTION )
@WikiRequestContext( "comment" )
public Resolution comment()
{
- // Set the editing start time
- m_startTime = new Date();
+ // Set the editing start time (will be written to the JSPs as encrypted parameter)
+ setStartTime( System.currentTimeMillis() );
return null;
}
@@ -132,7 +135,7 @@
* @return a forward resolution back to the preview page.
*/
@HandlesEvent( "diff" )
- @HandlerPermission( permissionClass = PagePermission.class, target = "${page.qualifiedName}", actions = PagePermission.VIEW_ACTION )
+ @HandlerPermission( permissionClass = PagePermission.class, target = "${page.path}", actions = PagePermission.VIEW_ACTION )
@WikiRequestContext( "diff" )
public Resolution diff()
{
@@ -142,7 +145,7 @@
@DefaultHandler
@DontValidate
@HandlesEvent( "edit" )
- @HandlerPermission( permissionClass = PagePermission.class, target = "${page.qualifiedName}", actions = PagePermission.EDIT_ACTION )
+ @HandlerPermission( permissionClass = PagePermission.class, target = "${page.path}", actions = PagePermission.EDIT_ACTION )
@WikiRequestContext( "edit" )
public Resolution edit() throws ProviderException
{
@@ -150,15 +153,19 @@
HttpServletRequest request = wikiContext.getRequest();
HttpSession session = request.getSession();
Principal user = wikiContext.getCurrentUser();
- String pageName = m_page.getName();
+ WikiPage page = getPage();
+ String pageName = page.getName();
log.info( "Editing page " + pageName + ". User=" + user.getName() + ", host=" + request.getRemoteAddr() );
+ // Set the editing start time (will be written to the JSPs as encrypted parameter)
+ setStartTime( System.currentTimeMillis() );
+
// If page is locked, make sure we tell the user
List<Message> messages = wikiContext.getMessages();
WikiEngine engine = wikiContext.getEngine();
ContentManager mgr = engine.getContentManager();
- PageLock lock = mgr.getCurrentLock( m_page );
+ PageLock lock = mgr.getCurrentLock( page );
if( lock != null )
{
messages.add( new LocalizableMessage( "edit.locked", lock.getLocker(), lock.getTimeLeft() ) );
@@ -169,29 +176,26 @@
WikiPage latest;
try
{
- latest = engine.getPage( m_page.getName() );
+ latest = engine.getPage( page.getName() );
}
catch( PageNotFoundException e )
{
- latest = m_page;
+ latest = page;
}
- if( latest.getVersion() != m_page.getVersion() )
+ if( latest.getVersion() != page.getVersion() )
{
- errors.addGlobalError( new LocalizableError( "edit.restoring", m_page.getVersion() ) );
+ errors.addGlobalError( new LocalizableError( "edit.restoring", page.getVersion() ) );
}
// Attempt to lock the page.
- lock = mgr.lockPage( m_page, user.getName() );
+ lock = mgr.lockPage( page, user.getName() );
if( lock != null )
{
session.setAttribute( LOCK_PREFIX + pageName, lock );
}
// Load the page text
- m_text = engine.getPureText( m_page );
-
- // Set the editing start time
- m_startTime = new Date();
+ m_text = engine.getPureText( page );
return new ForwardResolution( "/Edit.jsp" );
}
@@ -292,7 +296,7 @@
*
* @return the start time
*/
- public Date getStartTime()
+ public long getStartTime()
{
return m_startTime;
}
@@ -322,9 +326,9 @@
{
// Set author: prefer authenticated/asserted principals first
WikiSession wikiSession = getContext().getWikiSession();
- if( m_author == null || !wikiSession.isAnonymous() )
+ if( getAuthor() == null || !wikiSession.isAnonymous() )
{
- m_author = wikiSession.getUserPrincipal().getName();
+ setAuthor( wikiSession.getUserPrincipal().getName() );
}
}
@@ -334,11 +338,11 @@
* @return a forward resolution back to the preview page.
*/
@HandlesEvent( "preview" )
- @HandlerPermission( permissionClass = PagePermission.class, target = "${page.qualifiedName}", actions = PagePermission.VIEW_ACTION )
+ @HandlerPermission( permissionClass = PagePermission.class, target = "${page.path}", actions = PagePermission.VIEW_ACTION )
@WikiRequestContext( "preview" )
public Resolution preview()
{
- log.debug( "Previewing " + m_page.getName() );
+ log.debug( "Previewing " + getPage().getName() );
return new ForwardResolution( "/Preview.jsp" );
}
@@ -355,34 +359,45 @@
@ValidationMethod( on = "save", when = ValidationState.NO_ERRORS )
public void validateNoConflicts() throws ProviderException
{
- if( m_startTime.before( m_page.getLastModified() ) )
+ ValidationErrors errors = getContext().getValidationErrors();
+ WikiPage page = getPage();
+ boolean exists = getContext().getEngine().pageExists( page );
+ long lastModified = exists ? page.getLastModified().getTime() : -1;
+ if( exists && m_startTime < lastModified )
{
// Retrieve and escape the conflicting text
- String conflictText = m_page.getContentAsString();
+ String conflictText = page.getContentAsString();
conflictText = StringEscapeUtils.escapeXml( conflictText );
conflictText = TextUtil.replaceString( conflictText, "\n", "<br />" );
m_conflictText = conflictText;
// Create a validation error
- ValidationErrors errors = getContext().getValidationErrors();
errors.add( "text", new LocalizableError( "edit.conflict" ) );
}
+
+ // Is the user trying to edit a special page? Tsk, tsk.
+ URI uri = getContext().getEngine().getSpecialPageReference( page.getName() );
+ if( uri != null )
+ {
+ errors.add( "page", new LocalizableError( "edit.specialpage" ) );
+ }
}
@HandlesEvent( "save" )
- @HandlerPermission( permissionClass = PagePermission.class, target = "${page.qualifiedName}", actions = PagePermission.EDIT_ACTION )
+ @HandlerPermission( permissionClass = PagePermission.class, target = "${page.path}", actions = PagePermission.EDIT_ACTION )
@WikiRequestContext( "save" )
- @SpamProtect
+ @SpamProtect( content = "text" )
public Resolution save() throws WikiException
{
WikiSession wikiSession = getContext().getWikiSession();
HttpServletRequest request = getContext().getHttpRequest();
HttpSession session = request.getSession();
WikiContext wikiContext = getContext();
+ WikiPage page = getPage();
WikiEngine engine = getContext().getEngine();
- String pagereq = m_page.getName();
+ String pagereq = page.getName();
- log.info( "Saving page " + m_page.getName() + ". UserPrincipal=" + wikiSession.getUserPrincipal().getName() + ", Author="
+ log.info( "Saving page " + page.getName() + ". UserPrincipal=" + wikiSession.getUserPrincipal().getName() + ", Author="
+ m_author + ", Host=" + getContext().getRequest().getRemoteAddr() );
// Set author information and other metadata
@@ -411,11 +426,11 @@
{
engine.saveText( wikiContext, m_text );
}
- session.removeAttribute( LOCK_PREFIX +m_page.getName() );
+ session.removeAttribute( LOCK_PREFIX +page.getName() );
}
catch( DecisionRequiredException ex )
{
- session.removeAttribute( LOCK_PREFIX +m_page.getName() );
+ session.removeAttribute( LOCK_PREFIX +page.getName() );
return new RedirectResolution( ViewActionBean.class, "view" ).addParameter( "page", "ApprovalRequiredForPageChanges" );
}
catch( RedirectException ex )
@@ -546,14 +561,14 @@
* tampered with by the user. When the <code>save</code> event is
* executed, it will be decrypted and used to detect edit conflicts. This
* value is initialized to the current time when the
- * {@link #initDefaultValues()} method fires.
+ * {@link #edit()} or {@link #comment()} methods fire.
*
* @param date the start time
*/
@Validate( required = true, encrypted = true )
- public void setStartTime( Date date )
+ public void setStartTime( long time )
{
- m_startTime = date;
+ m_startTime = time;
}
/**
Modified: incubator/jspwiki/trunk/tests/java/org/apache/wiki/action/AllTests.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/tests/java/org/apache/wiki/action/AllTests.java?rev=766538&r1=766537&r2=766538&view=diff
==============================================================================
--- incubator/jspwiki/trunk/tests/java/org/apache/wiki/action/AllTests.java (original)
+++ incubator/jspwiki/trunk/tests/java/org/apache/wiki/action/AllTests.java Sun Apr 19 22:29:12 2009
@@ -37,6 +37,7 @@
TestSuite suite = new TestSuite("ActionBean tests");
suite.addTest( DeleteActionBeanTest.suite() );
+ suite.addTest( EditActionBeanTest.suite() );
suite.addTest( GroupActionBeanTest.suite() );
suite.addTest( LoginActionBeanTest.suite() );
suite.addTest( RenameActionBeanTest.suite() );
Added: incubator/jspwiki/trunk/tests/java/org/apache/wiki/action/EditActionBeanTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/tests/java/org/apache/wiki/action/EditActionBeanTest.java?rev=766538&view=auto
==============================================================================
--- incubator/jspwiki/trunk/tests/java/org/apache/wiki/action/EditActionBeanTest.java (added)
+++ incubator/jspwiki/trunk/tests/java/org/apache/wiki/action/EditActionBeanTest.java Sun Apr 19 22:29:12 2009
@@ -0,0 +1,177 @@
+/*
+ JSPWiki - a JSP-based WikiWiki clone.
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.apache.wiki.action;
+
+import java.util.Properties;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import net.sourceforge.stripes.mock.MockRoundtrip;
+import net.sourceforge.stripes.util.CryptoUtil;
+import net.sourceforge.stripes.validation.ValidationErrors;
+
+import org.apache.wiki.TestEngine;
+import org.apache.wiki.api.WikiPage;
+
+public class EditActionBeanTest extends TestCase
+{
+ TestEngine m_engine;
+
+ public void setUp()
+ {
+ // Start the WikiEngine, and stash reference
+ Properties props = new Properties();
+ try
+ {
+ props.load( TestEngine.findTestProperties() );
+ m_engine = new TestEngine( props );
+ }
+ catch( Exception e )
+ {
+ throw new RuntimeException( "Could not set up TestEngine: " + e.getMessage() );
+ }
+ }
+
+ public void tearDown()
+ {
+ m_engine.shutdown();
+ }
+
+ public void testEditNoParameter() throws Exception
+ {
+ // Try editing without specifying a page
+ MockRoundtrip trip = m_engine.guestTrip( "/Edit.action" );
+ String startTime = String.valueOf( System.currentTimeMillis() );
+ trip.addParameter( "startTime", CryptoUtil.encrypt( startTime ) );
+ trip.addParameter( "text", "This is the edited text" );
+ TestEngine.addSpamProtectParams( trip );
+ trip.execute( "save" );
+
+ // ...we should NOT see any page bound to the ActionBean
+ EditActionBean bean = trip.getActionBean( EditActionBean.class );
+ assertNull( bean.getPage() );
+
+ // ...and the "page" param should be flagged as invalid
+ ValidationErrors errors = trip.getValidationErrors();
+ assertEquals( 1, errors.size() );
+ assertTrue( errors.hasFieldErrors() );
+ assertTrue( errors.containsKey( "page" ) );
+
+ // ...and the destination should be the original display JSP (for
+ // displaying errors)
+ assertEquals( MockRoundtrip.DEFAULT_SOURCE_PAGE, trip.getDestination() );
+ }
+
+ public void testEditSpecialPage() throws Exception
+ {
+ // Make sure no special page FindPage actually exists
+ m_engine.deletePage( "FindPage" );
+
+ // Try editing the 'special page'
+ MockRoundtrip trip = m_engine.guestTrip( "/Edit.action" );
+ String startTime = String.valueOf( System.currentTimeMillis() );
+ trip.addParameter( "page", "FindPage" );
+ trip.addParameter( "startTime", CryptoUtil.encrypt( startTime ) );
+ trip.addParameter( "text", "This is the edited text" );
+ TestEngine.addSpamProtectParams( trip );
+ trip.execute( "save" );
+
+ // ...we should NOT see any page bound to the ActionBean
+ EditActionBean bean = trip.getActionBean( EditActionBean.class );
+ assertNull( bean.getPage() );
+
+ // ...and the "page" param should be flagged as invalid
+ ValidationErrors errors = trip.getValidationErrors();
+ assertEquals( 1, errors.size() );
+ assertTrue( errors.hasFieldErrors() );
+ assertTrue( errors.containsKey( "page" ) );
+
+ // ...and the destination should be the original display JSP (for
+ // displaying errors)
+ assertEquals( MockRoundtrip.DEFAULT_SOURCE_PAGE, trip.getDestination() );
+ }
+
+ public void testEditExistingPage() throws Exception
+ {
+
+ String pageName = "EditActionBeanTest" + System.currentTimeMillis();
+
+ m_engine.saveText( pageName, "This is a test." );
+ WikiPage page = m_engine.getPage( pageName );
+ assertNotNull( "Did not save page " + pageName + "!", page );
+
+ // Set up the marked-up page
+ MockRoundtrip trip = m_engine.guestTrip( "/Edit.action" );
+ trip.setParameter( "page", pageName );
+ String startTime = String.valueOf( System.currentTimeMillis() );
+ trip.addParameter( "startTime", CryptoUtil.encrypt( startTime ) );
+ trip.addParameter( "text", "This is the edited text" );
+ TestEngine.addSpamProtectParams( trip );
+ trip.execute( "save" );
+
+ // ...we should automatically see the test page bound to the ActionBean
+ EditActionBean bean = trip.getActionBean( EditActionBean.class );
+ ValidationErrors errors = trip.getValidationErrors();
+ assertEquals( 0, errors.size() );
+ assertEquals( page, bean.getPage() );
+
+ // ...and the destination should be Wiki.action (aka display JSP)
+ assertEquals( "/Wiki.action?view=&page=" + pageName, trip.getDestination() );
+
+ // Delete the test page
+ m_engine.deletePage( pageName );
+ }
+
+ public void testEditNewPage() throws Exception
+ {
+
+ String pageName = "EditActionBeanTest" + System.currentTimeMillis();
+ assertFalse( m_engine.pageExists( pageName ) );
+
+ // Set up the marked-up page
+ MockRoundtrip trip = m_engine.guestTrip( "/Edit.action" );
+ trip.setParameter( "page", pageName );
+ String startTime = String.valueOf( System.currentTimeMillis() );
+ trip.addParameter( "startTime", CryptoUtil.encrypt( startTime ) );
+ trip.addParameter( "text", "This is the edited text" );
+ TestEngine.addSpamProtectParams( trip );
+ trip.execute( "save" );
+
+ // ...we should automatically see the test page bound to the ActionBean
+ EditActionBean bean = trip.getActionBean( EditActionBean.class );
+ ValidationErrors errors = trip.getValidationErrors();
+ assertEquals( 0, errors.size() );
+ assertNotNull( bean.getPage() );
+ assertEquals( pageName, bean.getPage().getName() );
+
+ // ...and the destination should be Wiki.action (aka display JSP)
+ assertEquals( "/Wiki.action?view=&page=" + pageName, trip.getDestination() );
+
+ // Delete the test page
+ m_engine.deletePage( pageName );
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite( EditActionBeanTest.class );
+ }
+}