    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.logging.log4j.LogManager;
    022import org.apache.logging.log4j.Logger;
    023import org.apache.wiki.api.core.Context;
    024import org.apache.wiki.api.core.Engine;
    025import org.apache.wiki.api.core.Page;
    026import org.apache.wiki.api.exceptions.PluginException;
    027import org.apache.wiki.api.exceptions.RedirectException;
    028import org.apache.wiki.api.exceptions.WikiException;
    029import org.apache.wiki.api.plugin.Plugin;
    030import org.apache.wiki.api.spi.Wiki;
    031import org.apache.wiki.pages.PageManager;
    032import org.apache.wiki.parser.MarkupParser;
    033import org.apache.wiki.preferences.Preferences;
    034import org.apache.wiki.util.TextUtil;
    035
    036import java.io.PrintWriter;
    037import java.io.StringWriter;
    038import java.security.Principal;
    039import java.text.MessageFormat;
    040import java.text.SimpleDateFormat;
    041import java.util.Date;
    042import java.util.Map;
    043import java.util.Properties;
    044import java.util.ResourceBundle;
    045import java.util.StringTokenizer;
    046
    047/**
    048 *  Provides a handler for bug reports.  Still under construction.
    049 *
    050 *  <p>Parameters : </p>
    051 *  <ul>
    052 *  <li><b>title</b> -  title of the bug, this is required.  If it is empty (as in "")  it is a signal to the handler to return quietly.</li>
    053 *  <li><b>description</b> - description of the bug.</li>
    054 *  <li><b>version</b> - version</li>
    055 *  <li><b>map</b> - I have no idea </li>
    056 *  <li><b>page</b> - The name of the page to be created for this bug report </li>
    057 *  </ul>
    058 *
    059 */
    060public class BugReportHandler implements Plugin {
    061
    062    private static final Logger LOG = LogManager.getLogger( BugReportHandler.class );
    063    private static final String DEFAULT_DATEFORMAT = "dd-MMM-yyyy HH:mm:ss zzz";
    064
    065    /** Parameter name for setting the title.  Value is <tt>{@value}</tt>. */
    066    public static final String PARAM_TITLE          = "title";
    067    /** Parameter name for setting the description.  Value is <tt>{@value}</tt>. */
    068    public static final String PARAM_DESCRIPTION    = "description";
    069    /** Parameter name for setting the version.  Value is <tt>{@value}</tt>. */
    070    public static final String PARAM_VERSION        = "version";
    071    /** Parameter name for setting the map.  Value is <tt>{@value}</tt>. */
    072    public static final String PARAM_MAPPINGS       = "map";
    073    /** Parameter name for setting the page.  Value is <tt>{@value}</tt>. */
    074    public static final String PARAM_PAGE           = "page";
    075
    076    /**
    077     *  {@inheritDoc}
    078     */
    079    @Override
    080    public String execute( final Context context, final Map< String, String > params ) throws PluginException {
    081        final String title = params.get( PARAM_TITLE );
    082        String description = params.get( PARAM_DESCRIPTION );
    083        String version = params.get( PARAM_VERSION );
    084        String submitter = null;
    085        final SimpleDateFormat format = new SimpleDateFormat( DEFAULT_DATEFORMAT );
    086        final ResourceBundle rb = Preferences.getBundle( context, Plugin.CORE_PLUGINS_RESOURCEBUNDLE );
    087        final Principal wup = context.getCurrentUser();
    088
    089        if( wup != null ) {
    090            submitter = wup.getName();
    091        }
    092
    093        if( title == null ) {
    094            throw new PluginException(rb.getString("bugreporthandler.titlerequired"));
    095        }
    096        if( title.isEmpty() ) {
    097            return "";
    098        }
    099
    100        if( description == null ) {
    101            description = "";
    102        }
    103        if( version == null ) {
    104            version = "unknown";
    105        }
    106
    107        final Properties mappings = parseMappings( params.get( PARAM_MAPPINGS ) );
    108
    109        //  Start things
    110        try {
    111            final StringWriter str = new StringWriter();
    112            final PrintWriter out = new PrintWriter( str );
    113            final Date d = new Date();
    114
    115            //  Outputting of basic data
    116            out.println( "|" + mappings.getProperty(PARAM_TITLE,"Title" ) + "|" + title );
    117            out.println( "|" + mappings.getProperty("date","Date" ) + "|" + format.format( d ) );
    118            out.println( "|" + mappings.getProperty(PARAM_VERSION,"Version" ) + "|" + version );
    119            if( submitter != null ) {
    120                out.println("|"+mappings.getProperty("submitter","Submitter") + "|" + submitter );
    121            }
    122
    123            //  Outputting the other parameters added to this.
    124            for( final Map.Entry< String, String > entry : params.entrySet() ) {
    125                if( !( entry.getKey().equals( PARAM_TITLE ) ||
    126                       entry.getKey().equals( PARAM_DESCRIPTION ) ||
    127                       entry.getKey().equals( PARAM_VERSION ) ||
    128                       entry.getKey().equals( PARAM_MAPPINGS ) ||
    129                       entry.getKey().equals( PARAM_PAGE ) ||
    130                       entry.getKey().startsWith( "_" )
    131                     ) ) {
    132                    //  If no mapping has been defined, just ignore it.
    133                    final String head = mappings.getProperty( entry.getKey(), entry.getKey() );
    134                    if( !head.isEmpty() ) {
    135                        out.println( "|" + head + "|" + entry.getValue() );
    136                    }
    137                }
    138            }
    139
    140            out.println();
    141            out.println( description );
    142            out.close();
    143
    144            //  Now create a new page for this bug report
    145            final String pageName = findNextPage( context, title, TextUtil.replaceEntities(params.get( PARAM_PAGE )) );
    146            final Page newPage = Wiki.contents().page( context.getEngine(), pageName );
    147            final Context newContext = context.clone();
    148            newContext.setPage( newPage );
    149            context.getEngine().getManager( PageManager.class ).saveText( newContext, str.toString() );
    150
    151            final MessageFormat formatter = new MessageFormat("");
    152            formatter.applyPattern( rb.getString("bugreporthandler.new") );
    153            final String[] args = { "<a href=\""+context.getViewURL(pageName)+"\">"+pageName+"</a>" };
    154
    155            return formatter.format( args );
    156        } catch( final RedirectException e ) {
    157            LOG.info("Saving not allowed, reason: '"+e.getMessage()+"', can't redirect to "+e.getRedirect());
    158            throw new PluginException("Saving not allowed, reason: "+e.getMessage());
    159        } catch( final WikiException e ) {
    160            LOG.error( "Unable to save page!", e );
    161            return rb.getString("bugreporthandler.unable" );
    162        }
    163    }
    164
    165    /**
    166     *  Finds a free page name for adding the bug report.  Tries to construct a page, and if it's found, adds a number to it
    167     *  and tries again.
    168     */
    169    private synchronized String findNextPage( final Context context, final String title, final String baseName ) {
    170        final String basicPageName = ( ( baseName != null ) ? baseName : "Bug" ) + MarkupParser.cleanLink( title );
    171        final Engine engine = context.getEngine();
    172
    173        String pageName = basicPageName;
    174        long   lastbug  = 2;
    175        while( engine.getManager( PageManager.class ).wikiPageExists( pageName ) ) {
    176            pageName = basicPageName + lastbug++;
    177        }
    178
    179        return pageName;
    180    }
    181
    182    /**
    183     *  Just parses a mappings list in the form of "a=b;b=c;c=d".
    184     *  <p>
    185     *  FIXME: Should probably be in TextUtil or somewhere.
    186     */
    187    private Properties parseMappings( final String mappings ) {
    188        final Properties props = new Properties();
    189        if( mappings == null ) {
    190            return props;
    191        }
    192
    193        final StringTokenizer tok = new StringTokenizer( mappings, ";" );
    194        while( tok.hasMoreTokens() ) {
    195            final String t = tok.nextToken();
    196            final int colon = t.indexOf("=");
    197            final String key;
    198            final String value;
    199
    200            if( colon > 0 ) {
    201                key = t.substring(0,colon);
    202                value = t.substring(colon+1);
    203            } else {
    204                key = t;
    205                value = "";
    206            }
    207
    208            props.setProperty( key, value );
    209        }
    210        return props;
    211    }
    212
    213}