001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.plugin; 020 021import org.apache.wiki.api.core.Context; 022import org.apache.wiki.api.core.ContextEnum; 023import org.apache.wiki.api.core.Engine; 024import org.apache.wiki.api.core.Page; 025import org.apache.wiki.api.exceptions.PluginException; 026import org.apache.wiki.api.exceptions.ProviderException; 027import org.apache.wiki.api.plugin.Plugin; 028import org.apache.wiki.auth.AuthorizationManager; 029import org.apache.wiki.auth.permissions.PermissionFactory; 030import org.apache.wiki.pages.PageManager; 031import org.apache.wiki.preferences.Preferences; 032import org.apache.wiki.render.RenderingManager; 033import org.apache.wiki.util.HttpUtil; 034import org.apache.wiki.util.TextUtil; 035 036import java.util.ArrayList; 037import java.util.List; 038import java.util.Map; 039import java.util.ResourceBundle; 040 041 042/** 043 * Inserts page contents. Muchos thanks to Scott Hurlbert for the initial code. 044 * 045 * <p>Parameters : </p> 046 * <ul> 047 * <li><b>page</b> - the name of the page to be inserted</li> 048 * <li><b>style</b> - the style to use</li> 049 * <li><b>maxlength</b> - the maximum length of the page to be inserted (page contents)</li> 050 * <li><b>class</b> - the class to use</li> 051 * <li><b>section</b> - the section of the page that has to be inserted (separated by "----"</li> 052 * <li><b>default</b> - the text to insert if the requested page does not exist</li> 053 * </ul> 054 * 055 * @since 2.1.37 056 */ 057public class InsertPage implements Plugin { 058 059 /** Parameter name for setting the page. Value is <tt>{@value}</tt>. */ 060 public static final String PARAM_PAGENAME = "page"; 061 /** Parameter name for setting the style. Value is <tt>{@value}</tt>. */ 062 public static final String PARAM_STYLE = "style"; 063 /** Parameter name for setting the maxlength. Value is <tt>{@value}</tt>. */ 064 public static final String PARAM_MAXLENGTH = "maxlength"; 065 /** Parameter name for setting the class. Value is <tt>{@value}</tt>. */ 066 public static final String PARAM_CLASS = "class"; 067 /** Parameter name for setting the show option. Value is <tt>{@value}</tt>. */ 068 public static final String PARAM_SHOW = "show"; 069 /** Parameter name for setting the section. Value is <tt>{@value}</tt>. */ 070 public static final String PARAM_SECTION = "section"; 071 /** Parameter name for setting the default. Value is <tt>{@value}</tt>. */ 072 public static final String PARAM_DEFAULT = "default"; 073 074 private static final String DEFAULT_STYLE = ""; 075 076 private static final String ONCE_COOKIE = "JSPWiki.Once."; 077 078 /** This attribute is stashed in the WikiContext to make sure that we don't have circular references. */ 079 public static final String ATTR_RECURSE = "org.apache.wiki.plugin.InsertPage.recurseCheck"; 080 081 /** 082 * {@inheritDoc} 083 */ 084 @Override @SuppressWarnings("unchecked") 085 public String execute( final Context context, final Map<String, String> params ) throws PluginException { 086 final Engine engine = context.getEngine(); 087 088 final StringBuilder res = new StringBuilder(); 089 090 final String clazz = params.get( PARAM_CLASS ); 091 final String includedPage = params.get( PARAM_PAGENAME ); 092 String style = params.get( PARAM_STYLE ); 093 final boolean showOnce = "once".equals( params.get( PARAM_SHOW ) ); 094 final String defaultstr = params.get( PARAM_DEFAULT ); 095 final int section = TextUtil.parseIntParameter(params.get( PARAM_SECTION ), -1 ); 096 int maxlen = TextUtil.parseIntParameter(params.get( PARAM_MAXLENGTH ), -1 ); 097 098 final ResourceBundle rb = Preferences.getBundle( context, Plugin.CORE_PLUGINS_RESOURCEBUNDLE ); 099 100 if( style == null ) { 101 style = DEFAULT_STYLE; 102 } 103 104 if( maxlen == -1 ) { 105 maxlen = Integer.MAX_VALUE; 106 } 107 108 if( includedPage != null ) { 109 final Page page; 110 try { 111 final String pageName = engine.getFinalPageName( includedPage ); 112 if( pageName != null ) { 113 page = engine.getManager( PageManager.class ).getPage( pageName ); 114 } else { 115 page = engine.getManager( PageManager.class ).getPage( includedPage ); 116 } 117 } catch( final ProviderException e ) { 118 res.append( "<span class=\"error\">Page could not be found by the page provider.</span>" ); 119 return res.toString(); 120 } 121 122 if( page != null ) { 123 // Check for recursivity 124 List<String> previousIncludes = context.getVariable( ATTR_RECURSE ); 125 126 if( previousIncludes != null ) { 127 if( previousIncludes.contains( page.getName() ) ) { 128 return "<span class=\"error\">Error: Circular reference - you can't include a page in itself!</span>"; 129 } 130 } else { 131 previousIncludes = new ArrayList<>(); 132 } 133 134 // Check for permissions 135 final AuthorizationManager mgr = engine.getManager( AuthorizationManager.class ); 136 137 if( !mgr.checkPermission( context.getWikiSession(), PermissionFactory.getPagePermission( page, "view") ) ) { 138 res.append("<span class=\"error\">You do not have permission to view this included page.</span>"); 139 return res.toString(); 140 } 141 142 // Show Once 143 // Check for page-cookie, only include page if cookie is not yet set 144 String cookieName = ""; 145 146 if( showOnce ) { 147 cookieName = ONCE_COOKIE + TextUtil.urlEncodeUTF8( page.getName() ).replaceAll( "\\+", "%20" ); 148 149 if( HttpUtil.retrieveCookieValue( context.getHttpRequest(), cookieName ) != null ) { 150 return ""; //silent exit 151 } 152 153 } 154 155 // move here, after premature exit points (permissions, page-cookie) 156 previousIncludes.add( page.getName() ); 157 context.setVariable( ATTR_RECURSE, previousIncludes ); 158 159 /** 160 * We want inclusion to occur within the context of 161 * its own page, because we need the links to be correct. 162 */ 163 164 final Context includedContext = context.clone(); 165 includedContext.setPage( page ); 166 167 String pageData = engine.getManager( PageManager.class ).getPureText( page ); 168 String moreLink = ""; 169 170 if( section != -1 ) { 171 try { 172 pageData = TextUtil.getSection( pageData, section ); 173 } catch( final IllegalArgumentException e ) { 174 throw new PluginException( e.getMessage() ); 175 } 176 } 177 178 if( pageData.length() > maxlen ) { 179 pageData = pageData.substring( 0, maxlen )+" ..."; 180 moreLink = "<p><a href=\""+context.getURL( ContextEnum.PAGE_VIEW.getRequestContext(),includedPage)+"\">"+rb.getString("insertpage.more")+"</a></p>"; 181 } 182 183 res.append("<div class=\"inserted-page "); 184 if( clazz != null ) res.append( clazz ); 185 if( !style.equals(DEFAULT_STYLE) ) res.append( "\" style=\"" ).append( style ); 186 if( showOnce ) res.append( "\" data-once=\"" ).append( cookieName ); 187 res.append("\" >"); 188 189 res.append( engine.getManager( RenderingManager.class ).textToHTML( includedContext, pageData ) ); 190 res.append( moreLink ); 191 192 res.append("</div>"); 193 194 // 195 // Remove the name from the stack; we're now done with this. 196 // 197 previousIncludes.remove( page.getName() ); 198 context.setVariable( ATTR_RECURSE, previousIncludes ); 199 } else { 200 if( defaultstr != null ) { 201 res.append( defaultstr ); 202 } else { 203 res.append( "There is no page called '" ).append( includedPage ).append( "'. Would you like to " ); 204 res.append( "<a href=\"" ).append( context.getURL( ContextEnum.PAGE_EDIT.getRequestContext(), includedPage ) ).append( "\">create it?</a>" ); 205 } 206 } 207 } else { 208 res.append( "<span class=\"error\">" ); 209 res.append( "You have to define a page!" ); 210 res.append( "</span>" ); 211 } 212 return res.toString(); 213 } 214 215}