001: /**
002: * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, version 2.1, dated February 1999.
003: *
004: * This program is free software; you can redistribute it and/or modify
005: * it under the terms of the latest version of the GNU Lesser General
006: * Public License as published by the Free Software Foundation;
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public License
014: * along with this program (LICENSE.txt); if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
016: */package org.jamwiki.servlets;
017:
018: import java.util.Vector;
019: import javax.servlet.http.HttpServletRequest;
020: import javax.servlet.http.HttpServletResponse;
021: import org.apache.commons.lang.StringUtils;
022: import org.jamwiki.WikiBase;
023: import org.jamwiki.WikiException;
024: import org.jamwiki.WikiMessage;
025: import org.jamwiki.authentication.WikiUserAuth;
026: import org.jamwiki.model.Role;
027: import org.jamwiki.model.Topic;
028: import org.jamwiki.model.TopicVersion;
029: import org.jamwiki.model.Watchlist;
030: import org.jamwiki.parser.ParserInput;
031: import org.jamwiki.parser.ParserOutput;
032: import org.jamwiki.parser.ParserUtil;
033: import org.jamwiki.utils.DiffUtil;
034: import org.jamwiki.utils.LinkUtil;
035: import org.jamwiki.utils.NamespaceHandler;
036: import org.jamwiki.utils.WikiLink;
037: import org.jamwiki.utils.WikiLogger;
038: import org.jamwiki.utils.WikiUtil;
039: import org.springframework.web.servlet.ModelAndView;
040:
041: /**
042: * Used to process topic edits including saving an edit, preview, resolving
043: * conflicts and dealing with spam.
044: */
045: public class EditServlet extends JAMWikiServlet {
046:
047: private static final WikiLogger logger = WikiLogger
048: .getLogger(EditServlet.class.getName());
049: protected static final String JSP_EDIT = "edit.jsp";
050:
051: /**
052: *
053: */
054: protected ModelAndView handleJAMWikiRequest(
055: HttpServletRequest request, HttpServletResponse response,
056: ModelAndView next, WikiPageInfo pageInfo) throws Exception {
057: ModelAndView loginRequired = loginRequired(request, pageInfo);
058: if (loginRequired != null) {
059: return loginRequired;
060: }
061: if (isSave(request)) {
062: save(request, next, pageInfo);
063: } else {
064: edit(request, next, pageInfo);
065: }
066: return next;
067: }
068:
069: /**
070: *
071: */
072: private void edit(HttpServletRequest request, ModelAndView next,
073: WikiPageInfo pageInfo) throws Exception {
074: String topicName = WikiUtil.getTopicFromRequest(request);
075: String virtualWiki = WikiUtil.getVirtualWikiFromURI(request);
076: Topic topic = loadTopic(virtualWiki, topicName);
077: // topic name might be updated by loadTopic
078: topicName = topic.getName();
079: Integer lastTopicVersionId = retrieveLastTopicVersionId(
080: request, topic);
081: next.addObject("lastTopicVersionId", lastTopicVersionId);
082: loadEdit(request, next, pageInfo, virtualWiki, topicName, true);
083: String contents = null;
084: if (isPreview(request)) {
085: preview(request, next, pageInfo);
086: return;
087: }
088: pageInfo.setContentJsp(JSP_EDIT);
089: if (!StringUtils
090: .isBlank(request.getParameter("topicVersionId"))) {
091: // editing an older version
092: Integer topicVersionId = new Integer(request
093: .getParameter("topicVersionId"));
094: TopicVersion topicVersion = WikiBase
095: .getDataHandler()
096: .lookupTopicVersion(topicVersionId.intValue(), null);
097: if (topicVersion == null) {
098: throw new WikiException(new WikiMessage(
099: "common.exception.notopic"));
100: }
101: contents = topicVersion.getVersionContent();
102: if (!lastTopicVersionId.equals(topicVersionId)) {
103: next.addObject("topicVersionId", topicVersionId);
104: }
105: } else if (!StringUtils
106: .isBlank(request.getParameter("section"))) {
107: // editing a section of a topic
108: int section = (new Integer(request.getParameter("section")))
109: .intValue();
110: contents = ParserUtil.parseSlice(request.getContextPath(),
111: request.getLocale(), virtualWiki, topicName,
112: section);
113: } else {
114: // editing a full new or existing topic
115: contents = (topic == null) ? "" : topic.getTopicContent();
116: }
117: next.addObject("contents", contents);
118: }
119:
120: /**
121: *
122: */
123: private boolean handleSpam(HttpServletRequest request,
124: ModelAndView next, WikiPageInfo pageInfo, String topicName,
125: String contents) throws Exception {
126: String result = ServletUtil.checkForSpam(request, topicName,
127: contents);
128: if (result == null) {
129: return false;
130: }
131: WikiMessage spam = new WikiMessage("edit.exception.spam",
132: result);
133: next.addObject("spam", spam);
134: String virtualWiki = WikiUtil.getVirtualWikiFromURI(request);
135: next.addObject("contents", contents);
136: loadEdit(request, next, pageInfo, virtualWiki, topicName, false);
137: next.addObject("editSpam", "true");
138: pageInfo.setContentJsp(JSP_EDIT);
139: return true;
140: }
141:
142: /**
143: *
144: */
145: private boolean isPreview(HttpServletRequest request) {
146: return !StringUtils.isBlank(request.getParameter("preview"));
147: }
148:
149: /**
150: *
151: */
152: private boolean isSave(HttpServletRequest request) {
153: return !StringUtils.isBlank(request.getParameter("save"));
154: }
155:
156: /**
157: *
158: */
159: private void loadEdit(HttpServletRequest request,
160: ModelAndView next, WikiPageInfo pageInfo,
161: String virtualWiki, String topicName, boolean useSection)
162: throws Exception {
163: pageInfo.setPageTitle(new WikiMessage("edit.title", topicName));
164: pageInfo.setTopicName(topicName);
165: WikiLink wikiLink = LinkUtil.parseWikiLink(topicName);
166: String namespace = wikiLink.getNamespace();
167: if (namespace != null
168: && namespace
169: .equals(NamespaceHandler.NAMESPACE_CATEGORY)) {
170: ServletUtil.loadCategoryContent(next, virtualWiki,
171: topicName);
172: }
173: if (request.getParameter("editComment") != null) {
174: next.addObject("editComment", request
175: .getParameter("editComment"));
176: }
177: if (useSection && request.getParameter("section") != null) {
178: next.addObject("section", request.getParameter("section"));
179: }
180: next.addObject("minorEdit", new Boolean(request
181: .getParameter("minorEdit") != null));
182: Watchlist watchlist = ServletUtil.currentWatchlist(request,
183: virtualWiki);
184: if (request.getParameter("watchTopic") != null
185: || (watchlist.containsTopic(topicName) && !isPreview(request))) {
186: next.addObject("watchTopic", new Boolean(true));
187: }
188: }
189:
190: /**
191: * Initialize topic values for the topic being edited. If a topic with
192: * the specified name already exists then it will be initialized,
193: * otherwise a new topic is created.
194: */
195: private Topic loadTopic(String virtualWiki, String topicName)
196: throws Exception {
197: Topic topic = ServletUtil.initializeTopic(virtualWiki,
198: topicName);
199: if (topic.getReadOnly()) {
200: throw new WikiException(new WikiMessage("error.readonly"));
201: }
202: return topic;
203: }
204:
205: /**
206: *
207: */
208: private ModelAndView loginRequired(HttpServletRequest request,
209: WikiPageInfo pageInfo) throws Exception {
210: String topicName = WikiUtil.getTopicFromRequest(request);
211: String virtualWiki = WikiUtil.getVirtualWikiFromURI(request);
212: WikiUserAuth user = ServletUtil.currentUser();
213: if (ServletUtil.isEditable(virtualWiki, topicName, user)) {
214: return null;
215: }
216: if (!user.hasRole(Role.ROLE_EDIT_EXISTING)) {
217: WikiMessage messageObject = new WikiMessage(
218: "login.message.edit");
219: return ServletUtil.viewLogin(request, pageInfo, WikiUtil
220: .getTopicFromURI(request), messageObject);
221: }
222: if (!user.hasRole(Role.ROLE_EDIT_NEW)
223: && WikiBase.getDataHandler().lookupTopic(virtualWiki,
224: topicName, false, null) == null) {
225: WikiMessage messageObject = new WikiMessage(
226: "login.message.editnew");
227: return ServletUtil.viewLogin(request, pageInfo, WikiUtil
228: .getTopicFromURI(request), messageObject);
229: }
230: Topic topic = WikiBase.getDataHandler().lookupTopic(
231: virtualWiki, topicName, false, null);
232: if (topic == null) {
233: // this should never trigger, but better safe than sorry...
234: return null;
235: }
236: if (topic.getAdminOnly()) {
237: WikiMessage messageObject = new WikiMessage(
238: "login.message.editadmin", topicName);
239: return ServletUtil.viewLogin(request, pageInfo, WikiUtil
240: .getTopicFromURI(request), messageObject);
241: }
242: if (topic.getReadOnly()) {
243: throw new WikiException(new WikiMessage("error.readonly"));
244: }
245: // it should be impossible to get here...
246: throw new WikiException(new WikiMessage("error.unknown",
247: "Unable to determine topic editing permissions"));
248: }
249:
250: /**
251: *
252: */
253: private void preview(HttpServletRequest request, ModelAndView next,
254: WikiPageInfo pageInfo) throws Exception {
255: String topicName = WikiUtil.getTopicFromRequest(request);
256: String virtualWiki = WikiUtil.getVirtualWikiFromURI(request);
257: String contents = (String) request.getParameter("contents");
258: Topic previewTopic = new Topic();
259: previewTopic.setName(topicName);
260: previewTopic.setTopicContent(contents);
261: previewTopic.setVirtualWiki(virtualWiki);
262: next.addObject("editPreview", "true");
263: pageInfo.setContentJsp(JSP_EDIT);
264: next.addObject("contents", contents);
265: ServletUtil.viewTopic(request, next, pageInfo, null,
266: previewTopic, false);
267: }
268:
269: /**
270: *
271: */
272: private void resolve(HttpServletRequest request, ModelAndView next,
273: WikiPageInfo pageInfo) throws Exception {
274: String topicName = WikiUtil.getTopicFromRequest(request);
275: String virtualWiki = WikiUtil.getVirtualWikiFromURI(request);
276: Topic lastTopic = WikiBase.getDataHandler().lookupTopic(
277: virtualWiki, topicName, false, null);
278: String contents1 = lastTopic.getTopicContent();
279: String contents2 = request.getParameter("contents");
280: next.addObject("lastTopicVersionId", lastTopic
281: .getCurrentVersionId());
282: next.addObject("contents", contents1);
283: next.addObject("contentsResolve", contents2);
284: Vector diffs = DiffUtil.diff(contents1, contents2);
285: next.addObject("diffs", diffs);
286: loadEdit(request, next, pageInfo, virtualWiki, topicName, false);
287: next.addObject("editResolve", "true");
288: pageInfo.setContentJsp(JSP_EDIT);
289: }
290:
291: /**
292: *
293: */
294: private Integer retrieveLastTopicVersionId(
295: HttpServletRequest request, Topic topic) throws Exception {
296: return (!StringUtils.isBlank(request
297: .getParameter("lastTopicVersionId"))) ? new Integer(
298: request.getParameter("lastTopicVersionId")) : topic
299: .getCurrentVersionId();
300: }
301:
302: /**
303: *
304: */
305: private void save(HttpServletRequest request, ModelAndView next,
306: WikiPageInfo pageInfo) throws Exception {
307: String topicName = WikiUtil.getTopicFromRequest(request);
308: String virtualWiki = WikiUtil.getVirtualWikiFromURI(request);
309: Topic topic = loadTopic(virtualWiki, topicName);
310: Topic lastTopic = WikiBase.getDataHandler().lookupTopic(
311: virtualWiki, topicName, false, null);
312: if (lastTopic != null
313: && !lastTopic.getCurrentVersionId().equals(
314: retrieveLastTopicVersionId(request, topic))) {
315: // someone else has edited the topic more recently
316: resolve(request, next, pageInfo);
317: return;
318: }
319: String contents = request.getParameter("contents");
320: String sectionName = "";
321: if (!StringUtils.isBlank(request.getParameter("section"))) {
322: // load section of topic
323: int section = (new Integer(request.getParameter("section")))
324: .intValue();
325: ParserOutput parserOutput = new ParserOutput();
326: contents = ParserUtil.parseSplice(parserOutput, request
327: .getContextPath(), request.getLocale(),
328: virtualWiki, topicName, section, contents);
329: sectionName = parserOutput.getSectionName();
330: }
331: if (contents == null) {
332: logger
333: .warning("The topic " + topicName
334: + " has no content");
335: throw new WikiException(new WikiMessage(
336: "edit.exception.nocontent", topicName));
337: }
338: if (lastTopic != null
339: && lastTopic.getTopicContent().equals(contents)) {
340: // topic hasn't changed. redirect to prevent user from refreshing and re-submitting
341: ServletUtil.redirect(next, virtualWiki, topic.getName());
342: return;
343: }
344: if (handleSpam(request, next, pageInfo, topicName, contents)) {
345: return;
346: }
347: // parse for signatures and other syntax that should not be saved in raw form
348: WikiUserAuth user = ServletUtil.currentUser();
349: ParserInput parserInput = new ParserInput();
350: parserInput.setContext(request.getContextPath());
351: parserInput.setLocale(request.getLocale());
352: parserInput.setWikiUser(user);
353: parserInput.setTopicName(topicName);
354: parserInput.setUserIpAddress(ServletUtil.getIpAddress(request));
355: parserInput.setVirtualWiki(virtualWiki);
356: ParserOutput parserOutput = ParserUtil.parseMetadata(
357: parserInput, contents);
358: // parse signatures and other values that need to be updated prior to saving
359: contents = ParserUtil.parseMinimal(parserInput, contents);
360: topic.setTopicContent(contents);
361: if (!StringUtils.isBlank(parserOutput.getRedirect())) {
362: // set up a redirect
363: topic.setRedirectTo(parserOutput.getRedirect());
364: topic.setTopicType(Topic.TYPE_REDIRECT);
365: } else if (topic.getTopicType() == Topic.TYPE_REDIRECT) {
366: // no longer a redirect
367: topic.setRedirectTo(null);
368: topic.setTopicType(Topic.TYPE_ARTICLE);
369: }
370: TopicVersion topicVersion = new TopicVersion(user, ServletUtil
371: .getIpAddress(request), request
372: .getParameter("editComment"), contents);
373: if (request.getParameter("minorEdit") != null) {
374: topicVersion.setEditType(TopicVersion.EDIT_MINOR);
375: }
376: WikiBase.getDataHandler().writeTopic(topic, topicVersion,
377: parserOutput.getCategories(), parserOutput.getLinks(),
378: true, null);
379: // update watchlist
380: if (user.hasRole(Role.ROLE_USER)) {
381: Watchlist watchlist = ServletUtil.currentWatchlist(request,
382: virtualWiki);
383: boolean watchTopic = (request.getParameter("watchTopic") != null);
384: if (watchlist.containsTopic(topicName) != watchTopic) {
385: WikiBase.getDataHandler().writeWatchlistEntry(
386: watchlist, virtualWiki, topicName,
387: user.getUserId(), null);
388: }
389: }
390: // redirect to prevent user from refreshing and re-submitting
391: String target = topic.getName();
392: if (!StringUtils.isBlank(sectionName)) {
393: target += "#" + sectionName;
394: }
395: ServletUtil.redirect(next, virtualWiki, target);
396: }
397: }
|