adding a form on the edit article pages that allows you to add an image attachment...
[mir.git] / source / mircoders / servlet / ServletModuleContent.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30
31 package mircoders.servlet;
32
33 import mir.entity.adapter.EntityAdapter;
34 import mir.entity.adapter.EntityAdapterEngine;
35 import mir.entity.adapter.EntityAdapterModel;
36 import mir.generator.Generator;
37 import mir.log.LoggerWrapper;
38 import mir.misc.StringUtil;
39 import mir.servlet.ServletModule;
40 import mir.servlet.ServletModuleExc;
41 import mir.servlet.ServletModuleFailure;
42 import mir.util.*;
43 import mircoders.entity.EntityContent;
44 import mircoders.entity.EntityUsers;
45 import mircoders.global.MirGlobal;
46 import mircoders.module.ModuleContent;
47 import mircoders.storage.DatabaseContent;
48 import mircoders.storage.DatabaseContentToTopics;
49
50 import javax.servlet.http.HttpServletRequest;
51 import javax.servlet.http.HttpServletResponse;
52 import java.util.*;
53
54 /**
55  * Article admin interface code
56  */
57
58 public class ServletModuleContent extends ServletModule {
59   private static ServletModuleContent instance = new ServletModuleContent();
60   public static ServletModule getInstance() { return instance; }
61   private static ModuleContent contentModule;
62
63   private ServletModuleContent() {
64     super();
65     propagatedParameters.add("selectarticleurl");
66
67     logger = new LoggerWrapper("ServletModule.Content");
68
69     try {
70       definition = "content";
71       contentModule = new ModuleContent();
72       mainModule = contentModule;
73     }
74     catch (Throwable e) {
75       logger.fatal("ServletModuleContent could not be initialized: " + e.toString());
76     }
77   }
78
79   public void search(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc, ServletModuleFailure {
80     try {
81       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
82       SQLQueryBuilder queryBuilder = new SQLQueryBuilder();
83       String searchField = requestParser.getParameterWithDefault("searchfield", "");
84       String searchValue = requestParser.getParameterWithDefault("searchvalue", "").trim();
85       String searchOrder = requestParser.getParameterWithDefault("searchorder", "");
86       String searchispublished = requestParser.getParameterWithDefault("searchispublished", "");
87       String searchArticleType = requestParser.getParameterWithDefault("searcharticletype", "");
88
89       if (searchValue.length()>0) {
90         if (searchField.equals("id"))
91           queryBuilder.appendAndCondition(
92             "id='"+JDBCStringRoutines.escapeStringLiteral(searchValue)+"'");
93         else if (searchField.equals("contents"))
94           queryBuilder.appendAndCondition(
95             "(lower(content_data) like " + "'%" + JDBCStringRoutines.escapeStringLiteral(searchValue.toLowerCase()) + "%')"+
96             " or (lower(description) like " + "'%" + JDBCStringRoutines.escapeStringLiteral(searchValue.toLowerCase()) + "%')");
97         else
98           queryBuilder.appendAndCondition(
99             "lower("+ searchField + ") like " +
100             "'%" + JDBCStringRoutines.escapeStringLiteral(searchValue.toLowerCase()) + "%'");
101       }
102
103       if (searchispublished.length()>0) {
104         if (searchispublished.equals("0"))
105           queryBuilder.appendAndCondition("is_published='f'");
106         else
107           queryBuilder.appendAndCondition("is_published='t'");
108       }
109
110       if (searchArticleType.length()>0) {
111         queryBuilder.appendAndCondition("to_article_type="+Integer.parseInt(searchArticleType));
112       }
113
114       if (searchOrder.length()>0) {
115         if (searchOrder.equals("datedesc"))
116           queryBuilder.appendDescendingOrder("webdb_create");
117         else if (searchOrder.equals("dateasc"))
118           queryBuilder.appendAscendingOrder("webdb_create");
119         else if (searchOrder.equals("title"))
120           queryBuilder.appendAscendingOrder("title");
121         else if (searchOrder.equals("creator"))
122           queryBuilder.appendAscendingOrder("creator");
123       }
124
125       returnList(aRequest, aResponse, queryBuilder.getWhereClause(), queryBuilder.getOrderByClause(), 0);
126     }
127     catch (Throwable e) {
128       throw new ServletModuleFailure(e);
129     }
130   }
131
132   public void add(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
133     editObject(aRequest, aResponse, null);
134   }
135
136   public void insert(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
137     try {
138       Map withValues = getIntersectingValues(aRequest, DatabaseContent.getInstance());
139
140       String now = StringUtil.date2webdbDate(new GregorianCalendar());
141       withValues.put("date", now);
142       withValues.put("publish_path", StringUtil.webdbDate2path(now));
143       withValues.put("to_publisher", ServletHelper.getUser(aRequest).getId());
144       withValues.put("is_produced", "0");
145       if (!withValues.containsKey("is_published"))
146         withValues.put("is_published","0");
147       if (!withValues.containsKey("is_html"))
148         withValues.put("is_html","0");
149
150       String webdbCreate = (String) withValues.get("webdb_create");
151       if (webdbCreate==null || webdbCreate.trim().length()==0)
152         withValues.remove("webdb_create");
153
154       String id = mainModule.add(withValues);
155       logAdminUsage(aRequest, id, "object added");
156
157       DatabaseContentToTopics.getInstance().setTopics(id, aRequest.getParameterValues("to_topic"));
158
159       editObject(aRequest, aResponse, id);
160     }
161     catch (Throwable e) {
162       throw new ServletModuleFailure(e);
163     }
164   }
165
166   public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
167     String idParam = aRequest.getParameter("id");
168     if (idParam == null)
169       throw new ServletModuleExc("Invalid call: id not supplied ");
170     editObject(aRequest, aResponse, idParam);
171   }
172
173   /**
174    * Attaches media to an article
175    */
176   public void attach(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
177     String  mediaIdParam = aRequest.getParameter("mid");
178     String  articleId = aRequest.getParameter("articleid");
179     if (articleId == null || mediaIdParam==null)
180       throw new ServletModuleExc("smod content :: attach :: articleid/mid missing");
181     // check if mediaIdParam and articleid are correct integers
182     try
183     {
184       Integer.parseInt(mediaIdParam);
185       Integer.parseInt(articleId);
186     }
187     catch(NumberFormatException e)
188     {
189       throw new ServletModuleExc("smod content :: attach :: invalid articleid/mid");
190     }
191     
192     if (!MirGlobal.accessControl().article().mayEditArticle(ServletHelper.getUser(aRequest), articleId))
193       throw new ServletModuleExc("Article has been locked");
194
195     try {
196       EntityContent entContent = (EntityContent) mainModule.getById(articleId);
197       entContent.attach(mediaIdParam);
198     }
199     catch(Throwable e) {
200       throw new ServletModuleFailure(e);
201     }
202
203     logAdminUsage(aRequest, articleId, "media " + mediaIdParam + " attached");
204
205     editObject(aRequest, aResponse, articleId);
206   }
207
208   /**
209    * Deattaches media from an article
210    */
211   public void dettach(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
212   {
213     String  articleId = aRequest.getParameter("articleid");
214     String  midParam = aRequest.getParameter("mid");
215     if (articleId == null)
216       throw new ServletModuleExc("smod content :: dettach :: articleid missing");
217     if (midParam == null)
218       throw new ServletModuleExc("smod content :: dettach :: mid missing");
219
220     if (!MirGlobal.accessControl().article().mayEditArticle(ServletHelper.getUser(aRequest), articleId))
221       throw new ServletModuleExc("Article has been locked");
222
223     try {
224       EntityContent entContent = (EntityContent)mainModule.getById(articleId);
225       entContent.dettach(articleId, midParam);
226     }
227     catch(Throwable e) {
228       throw new ServletModuleFailure(e);
229     }
230
231     logAdminUsage(aRequest, articleId, "media " + midParam + " deattached");
232
233     editObject(aRequest, aResponse, articleId);
234   }
235
236   /**
237    * Locks an article
238    */
239   public void lock(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
240   {
241     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
242
243     String idParam = requestParser.getParameter("id");
244     if (idParam == null)
245       throw new ServletModuleExc("Wrong call: (id) is missing");
246
247     EntityUsers user = ServletHelper.getUser(aRequest);
248
249     if (!MirGlobal.accessControl().article().mayLockArticle(user, idParam))
250       throw new ServletModuleExc("Unable to lock");
251
252     contentModule.lockArticle(idParam, user.getId(), false);
253
254     editObject(aRequest, aResponse, idParam);
255   }
256
257   /**
258    * Unlocks an article
259    */
260   public void unlock(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
261   {
262     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
263
264     String idParam = requestParser.getParameter("id");
265     if (idParam == null)
266       throw new ServletModuleExc("Wrong call: (id) is missing");
267
268     EntityUsers user = ServletHelper.getUser(aRequest);
269
270     if (!MirGlobal.accessControl().article().mayUnlockArticle(user, idParam))
271       throw new ServletModuleExc("Unable to unlock");
272
273     contentModule.unlockArticle(idParam, user.getId(), false);
274
275     editObject(aRequest, aResponse, idParam);
276   }
277
278   /**
279    * Forcelocks an article
280    */
281   public void forcelock(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
282   {
283     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
284
285     String idParam = requestParser.getParameter("id");
286     if (idParam == null)
287       throw new ServletModuleExc("Wrong call: (id) is missing");
288
289     EntityUsers user = ServletHelper.getUser(aRequest);
290
291     if (!MirGlobal.accessControl().article().mayForceLockArticle(user, idParam))
292       throw new ServletModuleExc("Unable to force lock");
293
294     contentModule.lockArticle(idParam, user.getId(), true);
295
296     editObject(aRequest, aResponse, idParam);
297   }
298
299   /**
300    * Stores an article
301    */
302   public void update(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
303   {
304     try {
305       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
306
307       String idParam = requestParser.getParameter("id");
308       if (idParam == null)
309         throw new ServletModuleExc("Wrong call: (id) is missing");
310
311       if (!MirGlobal.accessControl().article().mayEditArticle(ServletHelper.getUser(aRequest), idParam))
312         throw new ServletModuleExc("Article has been locked");
313
314       Map withValues = getIntersectingValues(aRequest, DatabaseContent.getInstance());
315
316       withValues.put("is_produced", "0");
317       if (!withValues.containsKey("is_published"))
318         withValues.put("is_published","0");
319       if (!withValues.containsKey("is_html"))
320         withValues.put("is_html","0");
321
322       String webdbCreate = (String) withValues.get("webdb_create");
323       if (webdbCreate==null || webdbCreate.trim().length()==0)
324         withValues.remove("webdb_create");
325
326       String id = mainModule.set(withValues);
327
328       logAdminUsage(aRequest, id, "object modified");
329
330       DatabaseContentToTopics.getInstance().setTopics(aRequest.getParameter("id"), aRequest.getParameterValues("to_topic"));
331
332       if (MirGlobal.accessControl().article().mayUnlockArticle(ServletHelper.getUser(aRequest), idParam) &&
333          (requestParser.getParameterWithDefault("unlock", "0").equals("1"))) {
334         contentModule.unlockArticle(id, ServletHelper.getUser(aRequest).getId(), false);
335       }
336
337       editObject(aRequest, aResponse, idParam);
338     }
339     catch (Throwable e) {
340       throw new ServletModuleFailure(e);
341     }
342   }
343
344
345   /**
346    * Returns the basic article editing form.
347    *
348    * @param id identifier of the article. <code>null</code>, means show an
349    *     empty form to add a new article.
350    */
351   public void editObject(HttpServletRequest aRequest, HttpServletResponse aResponse, String id)
352       throws ServletModuleExc {
353     try {
354       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
355       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] { getLocale(aRequest), getFallbackLocale(aRequest)});
356       EntityAdapterModel model = MirGlobal.localizer().dataModel().adapterModel();
357       Map article;
358       URLBuilder urlBuilder = new URLBuilder();
359
360       urlBuilder.setValue("module", "Content");
361       urlBuilder.setValue("do", "edit");
362       urlBuilder.setValue("id", id);
363       urlBuilder.setValue("returnurl", requestParser.getParameter("returnurl"));
364
365       if (id!=null) {
366         responseData.put("new", Boolean.FALSE);
367         article = model.makeEntityAdapter("content", mainModule.getById(id));
368
369         EntityUsers user = ServletHelper.getUser(aRequest);
370
371         responseData.put("mayEdit", new Boolean(MirGlobal.accessControl().article().mayEditArticle(user, id)));
372         responseData.put("mayLock", new Boolean(MirGlobal.accessControl().article().mayLockArticle(user, id)));
373         responseData.put("mayForceLock", new Boolean(MirGlobal.accessControl().article().mayForceLockArticle(user, id)));
374         responseData.put("mayUnlock", new Boolean(MirGlobal.accessControl().article().mayUnlockArticle(user, id)));
375       }
376       else {
377         List fields = DatabaseContent.getInstance().getFieldNames();
378         responseData.put("new", Boolean.TRUE);
379         article = new HashMap();
380         Iterator i = fields.iterator();
381         while (i.hasNext()) {
382           article.put(i.next(), null);
383         }
384
385         article.put("to_topics", null);
386
387         MirGlobal.localizer().adminInterface().initializeArticle(article);
388
389         responseData.put("mayEdit", Boolean.TRUE);
390         responseData.put("mayLock", Boolean.FALSE);
391         responseData.put("mayForceLock", Boolean.FALSE);
392         responseData.put("mayUnlock", Boolean.FALSE);
393       }
394       responseData.put("article", article);
395
396       List topicsList = new ArrayList();
397
398       String[] topicCategories = configuration.getStringArray("Mir.Localizer.Admin.TopicLists");
399
400       if (topicCategories.length==0 ) {
401         Map categoryMap = new HashMap();
402         categoryMap.put("key", "topic");
403         categoryMap.put("listtype", "0");
404         categoryMap.put("listparameter", "3");
405         categoryMap.put("items", EntityAdapterEngine.retrieveAdapterList(model, "topic", "", "title", -1, 0));
406         topicsList.add(categoryMap);
407       }
408       else {
409         for (int i = 0; i < topicCategories.length; i++) {
410           try {
411             Map categoryMap = new HashMap();
412             List parts = StringRoutines.splitString(topicCategories[i], ":");
413
414             String key = null;
415             String listtype = "0";
416             String listparameter = "5";
417             String where = "";
418             String order = "";
419
420             if (parts.size() > 0)
421               key = (String) parts.get(0);
422             if (parts.size() > 1)
423               listtype = (String) parts.get(1);
424             if (parts.size() > 2)
425               listparameter = (String) parts.get(2);
426             if (parts.size() > 3)
427               where = (String) parts.get(3);
428             if (parts.size() > 4)
429               order = (String) parts.get(4);
430
431             if (key != null) {
432               categoryMap.put("key", key);
433               categoryMap.put("listtype", listtype);
434               categoryMap.put("listparameter", listparameter);
435               categoryMap.put("items", EntityAdapterEngine.retrieveAdapterList(model, "topic", where, order, -1, 0));
436               topicsList.add(categoryMap);
437             }
438           }
439           catch (Throwable t) {
440             logger.error("error while preparing topics: " + t.toString());
441           }
442         }
443       }
444
445       responseData.put("topics", topicsList);
446
447       responseData.put("returnurl", requestParser.getParameter("returnurl"));
448       responseData.put("thisurl", urlBuilder.getQuery());
449
450       ServletHelper.generateResponse(aResponse.getWriter(), responseData, editGenerator);
451     }
452     catch (Throwable e) {
453       throw new ServletModuleFailure(e);
454     }
455   }
456
457   public void selectparent(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
458     try {
459       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
460       URLBuilder urlBuilder = new URLBuilder();
461
462       urlBuilder.setValue("module", "Content");
463       urlBuilder.setValue("do", "setparent");
464       urlBuilder.setValue("childid", requestParser.getParameter("id"));
465       urlBuilder.setValue("returnurl", requestParser.getParameter("returnurl"));
466
467       returnList(aRequest, aResponse, "", "", 0,
468           Collections.singletonMap("selectarticleurl", urlBuilder.getQuery()));
469     }
470     catch (Throwable e) {
471       throw new ServletModuleFailure(e);
472     }
473   }
474
475   public void listchildren(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
476     try {
477       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
478       String articleId = requestParser.getParameter("article_id");
479
480       if (articleId == null)
481         throw new ServletModuleExc("ServletModuleContent.listchildren: article_id not set!");
482
483       returnList(aRequest, aResponse, "to_content = " + articleId, "webdb_create desc", 0);
484     }
485     catch (Throwable e) {
486       throw new ServletModuleFailure(e);
487     }
488   }
489
490   public void setparent(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
491   {
492     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
493     String articleId = requestParser.getParameter("childid");
494     String parentId  = requestParser.getParameter("id");
495     String returnUrl = requestParser.getParameter("returnurl");
496
497     if (!MirGlobal.accessControl().article().mayEditArticle(ServletHelper.getUser(aRequest), articleId))
498       throw new ServletModuleExc("Article has been locked");
499
500     try {
501       EntityContent article = (EntityContent) mainModule.getById(articleId);
502       article.setFieldValue("to_content", parentId);
503       article.setProduced(false);
504       article.update();
505       logAdminUsage(aRequest, articleId, "parent set to " + parentId);
506     }
507     catch(Throwable e) {
508       logger.error("ServletModuleContent.setparent: " + e.getMessage());
509       throw new ServletModuleFailure(e);
510     }
511
512     ServletHelper.redirect(aResponse, returnUrl);
513   }
514
515   public void clearparent(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
516   {
517     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
518     String articleId = requestParser.getParameter("id");
519     String returnUrl = requestParser.getParameter("returnurl");
520
521     try {
522       EntityContent article = (EntityContent) mainModule.getById(articleId);
523       article.setFieldValue("to_content", "");
524       article.setProduced(false);
525       article.update();
526       logAdminUsage(aRequest, articleId, "parent cleared");
527     }
528     catch(Throwable e) {
529       e.printStackTrace(logger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));
530       logger.error("ServletModuleContent.clearparent: " + e.getMessage());
531
532       throw new ServletModuleFailure("ServletModuleContent.clearparent: " + e.getMessage(), e);
533     }
534
535     ServletHelper.redirect(aResponse, returnUrl);
536   }
537
538   public void showPreview(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
539     try {
540       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
541       String articleId = requestParser.getParameter("id");
542       EntityAdapter article = model.makeEntityAdapter("content", mainModule.getById(articleId));
543       String preview = requestParser.getParameterWithDefault("preview", "default");
544
545       Map generationValues = new HashMap();
546       Generator generator =
547           MirGlobal.localizer().adminInterface().prepareArticlePreview(preview, article, generationValues);
548
549       generator.generate(aResponse.getWriter(), generationValues, logger);
550     }
551     catch (Exception e) {
552       throw new ServletModuleFailure(e);
553     }
554   }
555 }