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 */ 019 package org.apache.wiki.xmlrpc; 020 021 import java.io.ByteArrayInputStream; 022 import java.util.Collections; 023 import java.util.Date; 024 import java.util.Hashtable; 025 import java.util.Iterator; 026 import java.util.List; 027 028 import org.apache.log4j.Logger; 029 import org.apache.wiki.WikiContext; 030 import org.apache.wiki.WikiEngine; 031 import org.apache.wiki.WikiPage; 032 import org.apache.wiki.api.exceptions.ProviderException; 033 import org.apache.wiki.attachment.Attachment; 034 import org.apache.wiki.attachment.AttachmentManager; 035 import org.apache.wiki.auth.AuthenticationManager; 036 import org.apache.wiki.auth.AuthorizationManager; 037 import org.apache.wiki.auth.WikiSecurityException; 038 import org.apache.wiki.auth.permissions.PermissionFactory; 039 import org.apache.wiki.plugin.WeblogEntryPlugin; 040 import org.apache.wiki.plugin.WeblogPlugin; 041 import org.apache.wiki.util.comparators.PageTimeComparator; 042 import org.apache.xmlrpc.XmlRpcException; 043 044 /** 045 * Provides handlers for all RPC routines of the MetaWeblog API. 046 * <P> 047 * JSPWiki does not support categories, and therefore we always return 048 * an empty list for getCategories(). Note also that this API is not 049 * suitable for general Wiki editing, since JSPWiki formats the entries 050 * in a wiki-compatible manner. And you cannot choose your page names 051 * either. Since 2.1.94 the entire MetaWeblog API is supported. 052 * 053 * @since 2.1.7 054 */ 055 056 public class MetaWeblogHandler 057 implements WikiRPCHandler 058 { 059 private static Logger log = Logger.getLogger( MetaWeblogHandler.class ); 060 061 private WikiContext m_context; 062 063 /** 064 * {@inheritDoc} 065 */ 066 public void initialize( WikiContext context ) 067 { 068 m_context = context; 069 } 070 071 /** 072 * Does a quick check against the current user 073 * and does he have permissions to do the stuff 074 * that he really wants to. 075 * <p> 076 * If there is no authentication enabled, returns normally. 077 * 078 * @throw XmlRpcException with the correct error message, if auth fails. 079 */ 080 private void checkPermissions( WikiPage page, 081 String username, 082 String password, 083 String permission ) 084 throws XmlRpcException 085 { 086 try 087 { 088 AuthenticationManager amm = m_context.getEngine().getAuthenticationManager(); 089 AuthorizationManager mgr = m_context.getEngine().getAuthorizationManager(); 090 091 if( amm.login( m_context.getWikiSession(), m_context.getHttpRequest(), username, password ) ) 092 { 093 if( !mgr.checkPermission( m_context.getWikiSession(), PermissionFactory.getPagePermission( page, permission ) )) 094 { 095 throw new XmlRpcException( 1, "No permission" ); 096 } 097 } 098 else 099 { 100 throw new XmlRpcException( 1, "Unknown login" ); 101 } 102 } 103 catch( WikiSecurityException e ) 104 { 105 throw new XmlRpcException( 1, e.getMessage(), e ); 106 } 107 return; 108 } 109 110 /** 111 * JSPWiki does not support categories, therefore JSPWiki 112 * always returns an empty list for categories. 113 * 114 * @param blogid The id of the blog. 115 * @param username The username to use 116 * @param password The password 117 * @throws XmlRpcException If something goes wrong 118 * @return An empty hashtable. 119 */ 120 public Hashtable getCategories( String blogid, 121 String username, 122 String password ) 123 throws XmlRpcException 124 { 125 WikiPage page = m_context.getEngine().getPage( blogid ); 126 127 checkPermissions( page, username, password, "view" ); 128 129 Hashtable ht = new Hashtable(); 130 131 return ht; 132 } 133 134 private String getURL( String page ) 135 { 136 return m_context.getEngine().getURL( WikiContext.VIEW, 137 page, 138 null, 139 true ); // Force absolute urls 140 } 141 142 /** 143 * Takes a wiki page, and creates a metaWeblog struct 144 * out of it. 145 * @param page The actual entry page 146 * @return A metaWeblog entry struct. 147 */ 148 private Hashtable<String,Object> makeEntry( WikiPage page ) 149 { 150 Hashtable<String, Object> ht = new Hashtable<String, Object>(); 151 152 WikiPage firstVersion = m_context.getEngine().getPage( page.getName(), 1 ); 153 154 ht.put("dateCreated", firstVersion.getLastModified()); 155 ht.put("link", getURL(page.getName())); 156 ht.put("permaLink", getURL(page.getName())); 157 ht.put("postid", page.getName()); 158 ht.put("userid", page.getAuthor()); 159 160 String pageText = m_context.getEngine().getText(page.getName()); 161 String title = ""; 162 int firstLine = pageText.indexOf('\n'); 163 164 if( firstLine > 0 ) 165 { 166 title = pageText.substring( 0, firstLine ); 167 } 168 169 if( title.trim().length() == 0 ) title = page.getName(); 170 171 // Remove wiki formatting 172 while( title.startsWith("!") ) title = title.substring(1); 173 174 ht.put("title", title); 175 ht.put("description", pageText); 176 177 return ht; 178 } 179 180 /** 181 * Returns a list of the recent posts to this weblog. 182 * 183 * @param blogid The id of the blog. 184 * @param username The username to use 185 * @param password The password 186 * @param numberOfPosts How many posts to find 187 * @throws XmlRpcException If something goes wrong 188 * @return As per MetaweblogAPI specification 189 */ 190 191 // FIXME: The implementation is suboptimal, as it 192 // goes through all of the blog entries. 193 194 @SuppressWarnings("unchecked") 195 public Hashtable getRecentPosts( String blogid, 196 String username, 197 String password, 198 int numberOfPosts) 199 throws XmlRpcException 200 { 201 Hashtable<String, Hashtable<String, Object>> result = new Hashtable<String, Hashtable<String, Object>>(); 202 203 log.info( "metaWeblog.getRecentPosts() called"); 204 205 WikiPage page = m_context.getEngine().getPage( blogid ); 206 207 checkPermissions( page, username, password, "view" ); 208 209 try 210 { 211 WeblogPlugin plugin = new WeblogPlugin(); 212 213 List<WikiPage> changed = plugin.findBlogEntries(m_context.getEngine().getPageManager(), 214 blogid, 215 new Date(0L), 216 new Date()); 217 218 Collections.sort( changed, new PageTimeComparator() ); 219 220 int items = 0; 221 for( Iterator i = changed.iterator(); i.hasNext() && items < numberOfPosts; items++ ) 222 { 223 WikiPage p = (WikiPage) i.next(); 224 225 result.put( "entry", makeEntry( p ) ); 226 } 227 228 } 229 catch( ProviderException e ) 230 { 231 log.error( "Failed to list recent posts", e ); 232 233 throw new XmlRpcException( 0, e.getMessage() ); 234 } 235 236 return result; 237 } 238 239 /** 240 * Adds a new post to the blog. 241 * 242 * @param blogid The id of the blog. 243 * @param username The username to use 244 * @param password The password 245 * @param content As per Metaweblogapi contract 246 * @param publish This parameter is ignored for JSPWiki. 247 * @return Returns an empty string 248 * @throws XmlRpcException If something goes wrong 249 */ 250 public String newPost( String blogid, 251 String username, 252 String password, 253 Hashtable content, 254 boolean publish ) 255 throws XmlRpcException 256 { 257 log.info("metaWeblog.newPost() called"); 258 WikiEngine engine = m_context.getEngine(); 259 260 WikiPage page = engine.getPage( blogid ); 261 checkPermissions( page, username, password, "createPages" ); 262 263 try 264 { 265 WeblogEntryPlugin plugin = new WeblogEntryPlugin(); 266 267 String pageName = plugin.getNewEntryPage( engine, blogid ); 268 269 WikiPage entryPage = new WikiPage( engine, pageName ); 270 entryPage.setAuthor( username ); 271 272 WikiContext context = new WikiContext( engine, entryPage ); 273 274 StringBuffer text = new StringBuffer(); 275 text.append( "!"+content.get("title") ); 276 text.append( "\n\n" ); 277 text.append( content.get("description") ); 278 279 log.debug("Writing entry: "+text); 280 281 engine.saveText( context, text.toString() ); 282 } 283 catch( Exception e ) 284 { 285 log.error("Failed to create weblog entry",e); 286 throw new XmlRpcException( 0, "Failed to create weblog entry: "+e.getMessage() ); 287 } 288 289 return ""; // FIXME: 290 } 291 292 /** 293 * Creates an attachment and adds it to the blog. The attachment 294 * is created into the main blog page, not the actual post page, 295 * because we do not know it at this point. 296 * 297 * @param blogid The id of the blog. 298 * @param username The username to use 299 * @param password The password 300 * @param content As per the MetaweblogAPI contract 301 * @return As per the MetaweblogAPI contract 302 * @throws XmlRpcException If something goes wrong 303 * 304 */ 305 public Hashtable newMediaObject( String blogid, 306 String username, 307 String password, 308 Hashtable content ) 309 throws XmlRpcException 310 { 311 WikiEngine engine = m_context.getEngine(); 312 String url = ""; 313 314 log.info("metaWeblog.newMediaObject() called"); 315 316 WikiPage page = engine.getPage( blogid ); 317 checkPermissions( page, username, password, "upload" ); 318 319 String name = (String) content.get( "name" ); 320 byte[] data = (byte[]) content.get( "bits" ); 321 322 AttachmentManager attmgr = engine.getAttachmentManager(); 323 324 try 325 { 326 Attachment att = new Attachment( engine, blogid, name ); 327 att.setAuthor( username ); 328 attmgr.storeAttachment( att, new ByteArrayInputStream( data ) ); 329 330 url = engine.getURL( WikiContext.ATTACH, att.getName(), null, true ); 331 } 332 catch( Exception e ) 333 { 334 log.error( "Failed to upload attachment", e ); 335 throw new XmlRpcException( 0, "Failed to upload media object: "+e.getMessage() ); 336 } 337 338 Hashtable<String, Object> result = new Hashtable<String, Object>(); 339 result.put("url", url); 340 341 return result; 342 } 343 344 345 /** 346 * Allows the user to edit a post. It does not allow general 347 * editability of wiki pages, because of the limitations of the 348 * metaWeblog API. 349 */ 350 boolean editPost( String postid, 351 String username, 352 String password, 353 Hashtable content, 354 boolean publish ) 355 throws XmlRpcException 356 { 357 WikiEngine engine = m_context.getEngine(); 358 log.info("metaWeblog.editPost("+postid+") called"); 359 360 // FIXME: Is postid correct? Should we determine it from the page name? 361 WikiPage page = engine.getPage( postid ); 362 checkPermissions( page, username, password, "edit" ); 363 364 try 365 { 366 WikiPage entryPage = (WikiPage)page.clone(); 367 entryPage.setAuthor( username ); 368 369 WikiContext context = new WikiContext( engine, entryPage ); 370 371 StringBuffer text = new StringBuffer(); 372 text.append( "!"+content.get("title") ); 373 text.append( "\n\n" ); 374 text.append( content.get("description") ); 375 376 log.debug("Updating entry: "+text); 377 378 engine.saveText( context, text.toString() ); 379 } 380 catch( Exception e ) 381 { 382 log.error("Failed to create weblog entry",e); 383 throw new XmlRpcException( 0, "Failed to update weblog entry: "+e.getMessage() ); 384 } 385 386 return true; 387 } 388 389 /** 390 * Gets the text of any page. The title of the page is parsed 391 * (if any is provided). 392 */ 393 Hashtable getPost( String postid, 394 String username, 395 String password ) 396 throws XmlRpcException 397 { 398 String wikiname = "FIXME"; 399 400 WikiPage page = m_context.getEngine().getPage( wikiname ); 401 402 checkPermissions( page, username, password, "view" ); 403 404 return makeEntry( page ); 405 } 406 }