added the possibility to search for articles by topic
[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.misc.StringUtil;
38 import mir.servlet.AdminServletModule;
39 import mir.servlet.ServletModuleExc;
40 import mir.servlet.ServletModuleFailure;
41 import mir.util.HTTPRequestParser;
42 import mir.util.JDBCStringRoutines;
43 import mir.util.SQLQueryBuilder;
44 import mir.util.StringRoutines;
45 import mir.util.URLBuilder;
46 import mircoders.entity.EntityContent;
47 import mircoders.entity.EntityUsers;
48 import mircoders.global.MirGlobal;
49 import mircoders.module.ModuleContent;
50 import mircoders.storage.DatabaseContent;
51 import mircoders.storage.DatabaseContentToTopics;
52
53 import javax.servlet.http.HttpServletRequest;
54 import javax.servlet.http.HttpServletResponse;
55 import java.util.ArrayList;
56 import java.util.Collections;
57 import java.util.GregorianCalendar;
58 import java.util.HashMap;
59 import java.util.Iterator;
60 import java.util.List;
61 import java.util.Locale;
62 import java.util.Map;
63
64 /**
65  * Article admin interface code
66  */
67
68 public class ServletModuleContent extends AdminServletModule {
69   private ModuleContent contentModule = new ModuleContent();
70
71   public ServletModuleContent() {
72     addPropagatedParameter("selectarticleurl");
73     addPropagatedParameter("searchtopic");
74
75     definition = "content";
76     mainModule = contentModule;
77   }
78
79   public void search(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc, ServletModuleFailure {
80     try {
81       String extraTables = "";
82       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
83       SQLQueryBuilder queryBuilder = new SQLQueryBuilder();
84       String searchField = requestParser.getParameterWithDefault("searchfield", "");
85       String searchValue = requestParser.getParameterWithDefault("searchvalue", "").trim();
86       String searchOrder = requestParser.getParameterWithDefault("searchorder", "");
87       String searchispublished = requestParser.getParameterWithDefault("searchispublished", "");
88       String searchArticleType = requestParser.getParameterWithDefault("searcharticletype", "");
89       String searchTopic = requestParser.getParameterWithDefault("searchtopic", "");
90
91       if (searchValue.length()>0) {
92         if ("id".equals(searchField)) {
93           queryBuilder.appendAndCondition(
94             "id='"+JDBCStringRoutines.escapeStringLiteral(searchValue)+"'");
95         }
96         else if ("contents".equals(searchField)) {
97           queryBuilder.appendAndCondition(
98             "(lower(content_data) like " + "'%" + JDBCStringRoutines.escapeStringLiteral(searchValue.toLowerCase()) + "%')"+
99             " or (lower(description) like " + "'%" + JDBCStringRoutines.escapeStringLiteral(searchValue.toLowerCase()) + "%')");
100         }
101         else {
102           queryBuilder.appendAndCondition(
103             "lower("+ searchField + ") like " +
104             "'%" + JDBCStringRoutines.escapeStringLiteral(searchValue.toLowerCase()) + "%'");
105         }
106       }
107
108       if (searchispublished.length()>0) {
109         if ("0".equals(searchispublished)) {
110           queryBuilder.appendAndCondition("is_published='f'");
111         }
112         else {
113           queryBuilder.appendAndCondition("is_published='t'");
114         }
115       }
116
117       if (searchArticleType.length()>0) {
118         queryBuilder.appendAndCondition("to_article_type="+Integer.parseInt(searchArticleType));
119       }
120
121       if (searchOrder.length()>0) {
122         if ("datedesc".equals(searchOrder)) {
123           queryBuilder.appendDescendingOrder("webdb_create");
124         }
125         else if ("dateasc".equals(searchOrder)) {
126           queryBuilder.appendAscendingOrder("webdb_create");
127         }
128         else if ("title".equals(searchOrder)) {
129           queryBuilder.appendAscendingOrder("title");
130         }
131         else if ("creator".equals(searchOrder)) {
132           queryBuilder.appendAscendingOrder("creator");
133         }
134       }
135
136       if (searchTopic.length() > 0) {
137         queryBuilder.appendAndCondition("cxt.content_id = id");
138         queryBuilder.appendAndCondition("cxt.topic_id = " + JDBCStringRoutines.escapeStringLiteral(searchTopic));
139
140         extraTables = "content_x_topic cxt";
141       }
142
143       returnList(aRequest, aResponse, queryBuilder.getWhereClause(), queryBuilder.getOrderByClause(), 0,
144           Collections.EMPTY_MAP, null, extraTables);
145     }
146     catch (Throwable e) {
147       throw new ServletModuleFailure(e);
148     }
149   }
150
151   public void add(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
152     editObject(aRequest, aResponse, null);
153   }
154
155   public void insert(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
156     try {
157       Map withValues = getIntersectingValues(aRequest, DatabaseContent.getInstance());
158
159       String now = StringUtil.date2webdbDate(new GregorianCalendar());
160       withValues.put("date", now);
161       withValues.put("publish_path", StringUtil.webdbDate2path(now));
162       withValues.put("to_publisher", ServletHelper.getUser(aRequest).getId());
163       withValues.put("is_produced", "0");
164       if (!withValues.containsKey("is_published")) {
165         withValues.put("is_published","0");
166       }
167       if (!withValues.containsKey("is_html")) {
168         withValues.put("is_html","0");
169       }
170
171       String webdbCreate = (String) withValues.get("webdb_create");
172       if (webdbCreate==null || webdbCreate.trim().length()==0) {
173         withValues.remove("webdb_create");
174       }
175
176       String id = mainModule.add(withValues);
177       logAdminUsage(aRequest, id, "object added");
178
179       DatabaseContentToTopics.getInstance().setTopics(id, aRequest.getParameterValues("to_topic"));
180
181       editObject(aRequest, aResponse, id);
182     }
183     catch (Throwable e) {
184       throw new ServletModuleFailure(e);
185     }
186   }
187
188   public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
189     String idParam = aRequest.getParameter("id");
190     if (idParam == null)
191       throw new ServletModuleExc("Invalid call: id not supplied ");
192     editObject(aRequest, aResponse, idParam);
193   }
194
195   /**
196    * Attaches media to an article
197    */
198   public void attach(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
199     String  mediaIdParam = aRequest.getParameter("mid");
200     String  articleId = aRequest.getParameter("articleid");
201     if (articleId == null || mediaIdParam==null) {
202       throw new ServletModuleExc("smod content :: attach :: articleid/mid missing");
203     }
204
205     // check if mediaIdParam and articleid are correct integers
206     try {
207       Integer.parseInt(mediaIdParam);
208       Integer.parseInt(articleId);
209     }
210     catch (NumberFormatException e) {
211       throw new ServletModuleExc("smod content :: attach :: invalid articleid/mid", e);
212     }
213     
214     if (!MirGlobal.accessControl().article().mayEditArticle(ServletHelper.getUser(aRequest), articleId)) {
215       throw new ServletModuleExc("Article has been locked");
216     }
217
218     try {
219       EntityContent entContent = (EntityContent) mainModule.getById(articleId);
220       entContent.attach(mediaIdParam);
221     }
222     catch(Throwable e) {
223       throw new ServletModuleFailure(e);
224     }
225
226     logAdminUsage(aRequest, articleId, "media " + mediaIdParam + " attached");
227
228     editObject(aRequest, aResponse, articleId);
229   }
230
231   /**
232    * Deattaches media from an article
233    */
234   public void dettach(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
235     String  articleId = aRequest.getParameter("articleid");
236     String  midParam = aRequest.getParameter("mid");
237     if (articleId == null)
238       throw new ServletModuleExc("smod content :: dettach :: articleid missing");
239     if (midParam == null)
240       throw new ServletModuleExc("smod content :: dettach :: mid missing");
241
242     if (!MirGlobal.accessControl().article().mayEditArticle(ServletHelper.getUser(aRequest), articleId))
243       throw new ServletModuleExc("Article has been locked");
244
245     try {
246       EntityContent entContent = (EntityContent)mainModule.getById(articleId);
247       entContent.dettach(articleId, midParam);
248     }
249     catch(Throwable e) {
250       throw new ServletModuleFailure(e);
251     }
252
253     logAdminUsage(aRequest, articleId, "media " + midParam + " deattached");
254
255     editObject(aRequest, aResponse, articleId);
256   }
257
258   /**
259    * Locks an article
260    */
261   public void lock(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
262   {
263     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
264
265     String idParam = requestParser.getParameter("id");
266     if (idParam == null) {
267       throw new ServletModuleExc("Wrong call: (id) is missing");
268     }
269
270     EntityUsers user = ServletHelper.getUser(aRequest);
271
272     if (!MirGlobal.accessControl().article().mayLockArticle(user, idParam)) {
273       throw new ServletModuleExc("Unable to lock");
274     }
275
276     contentModule.lockArticle(idParam, user.getId(), false);
277
278     editObject(aRequest, aResponse, idParam);
279   }
280
281   /**
282    * Unlocks an article
283    */
284   public void unlock(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
285   {
286     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
287
288     String idParam = requestParser.getParameter("id");
289     if (idParam == null) {
290       throw new ServletModuleExc("Wrong call: (id) is missing");
291     }
292
293     EntityUsers user = ServletHelper.getUser(aRequest);
294
295     if (!MirGlobal.accessControl().article().mayUnlockArticle(user, idParam)) {
296       throw new ServletModuleExc("Unable to unlock");
297     }
298
299     contentModule.unlockArticle(idParam, user.getId(), false);
300
301     editObject(aRequest, aResponse, idParam);
302   }
303
304   /**
305    * Forcelocks an article
306    */
307   public void forcelock(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
308     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
309
310     String idParam = requestParser.getParameter("id");
311     if (idParam == null)
312       throw new ServletModuleExc("Wrong call: (id) is missing");
313
314     EntityUsers user = ServletHelper.getUser(aRequest);
315
316     if (!MirGlobal.accessControl().article().mayForceLockArticle(user, idParam))
317       throw new ServletModuleExc("Unable to force lock");
318
319     contentModule.lockArticle(idParam, user.getId(), true);
320
321     editObject(aRequest, aResponse, idParam);
322   }
323
324   /**
325    * Stores an article
326    */
327   public void update(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
328     try {
329       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
330
331       String idParam = requestParser.getParameter("id");
332       if (idParam == null) {
333         throw new ServletModuleExc("Wrong call: (id) is missing");
334       }
335
336       if (!MirGlobal.accessControl().article().mayEditArticle(ServletHelper.getUser(aRequest), idParam)) {
337         throw new ServletModuleExc("Article has been locked");
338       }
339
340       Map withValues = getIntersectingValues(aRequest, DatabaseContent.getInstance());
341
342       withValues.put("is_produced", "0");
343       if (!withValues.containsKey("is_published")) {
344         withValues.put("is_published","0");
345       }
346       if (!withValues.containsKey("is_html")) {
347         withValues.put("is_html","0");
348       }
349
350       String webdbCreate = (String) withValues.get("webdb_create");
351       if (webdbCreate==null || webdbCreate.trim().length()==0) {
352         withValues.remove("webdb_create");
353       }
354
355       String id = mainModule.set(withValues);
356
357       logAdminUsage(aRequest, id, "object modified");
358
359       DatabaseContentToTopics.getInstance().setTopics(aRequest.getParameter("id"), aRequest.getParameterValues("to_topic"));
360
361       if (MirGlobal.accessControl().article().mayUnlockArticle(ServletHelper.getUser(aRequest), idParam) &&
362           requestParser.getParameterWithDefault("unlock", "0").equals("1")) {
363         contentModule.unlockArticle(id, ServletHelper.getUser(aRequest).getId(), false);
364       }
365
366       editObject(aRequest, aResponse, idParam);
367     }
368     catch (Throwable e) {
369       throw new ServletModuleFailure(e);
370     }
371   }
372
373
374   /**
375    * Returns the basic article editing form.
376    *
377    * @param anId identifier of the article. <code>null</code>, means show an
378    *     empty form to add a new article.
379    */
380   public void editObject(HttpServletRequest aRequest, HttpServletResponse aResponse,
381                          String anId) throws ServletModuleExc {
382     try {
383       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
384       Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] { getLocale(aRequest), getFallbackLocale(aRequest)});
385       EntityAdapterModel model = MirGlobal.localizer().dataModel().adapterModel();
386       Object article;
387       URLBuilder urlBuilder = new URLBuilder();
388
389       urlBuilder.setValue("module", "Content");
390       urlBuilder.setValue("do", "edit");
391       urlBuilder.setValue("id", anId);
392       urlBuilder.setValue("returnurl", requestParser.getParameter("returnurl"));
393
394       if (anId !=null) {
395         responseData.put("new", Boolean.FALSE);
396         article = model.makeEntityAdapter("content", mainModule.getById(anId));
397
398         EntityUsers user = ServletHelper.getUser(aRequest);
399
400         responseData.put("mayEdit",
401             new Boolean(MirGlobal.accessControl().article().mayEditArticle(user, anId)));
402         responseData.put("mayLock", new Boolean(MirGlobal.accessControl().article().mayLockArticle(user, anId)));
403         responseData.put("mayForceLock", new Boolean(MirGlobal.accessControl().article().mayForceLockArticle(user, anId)));
404         responseData.put("mayUnlock", new Boolean(MirGlobal.accessControl().article().mayUnlockArticle(user, anId)));
405       }
406       else {
407         List fields = DatabaseContent.getInstance().getFieldNames();
408         responseData.put("new", Boolean.TRUE);
409         Map emptyArticle = new HashMap();
410         Iterator i = fields.iterator();
411         while (i.hasNext()) {
412           emptyArticle.put(i.next(), null);
413         }
414
415         emptyArticle.put("to_topics", null);
416
417         MirGlobal.localizer().adminInterface().initializeArticle(emptyArticle);
418         article = emptyArticle;
419
420         responseData.put("mayEdit", Boolean.TRUE);
421         responseData.put("mayLock", Boolean.FALSE);
422         responseData.put("mayForceLock", Boolean.FALSE);
423         responseData.put("mayUnlock", Boolean.FALSE);
424
425       }
426       responseData.put("article", article);
427
428       List topicsList = new ArrayList();
429
430       String[] topicCategories = getConfiguration().getStringArray("Mir.Localizer.Admin.TopicLists");
431
432       if (topicCategories.length==0 ) {
433         Map categoryMap = new HashMap();
434         categoryMap.put("key", "topic");
435         categoryMap.put("listtype", "0");
436         categoryMap.put("listparameter", "3");
437         categoryMap.put("items", EntityAdapterEngine.retrieveAdapterList(model, "topic", "", "title", -1, 0));
438         topicsList.add(categoryMap);
439       }
440       else {
441         for (int i = 0; i < topicCategories.length; i++) {
442           Map categoryMap = new HashMap();
443           List parts = StringRoutines.splitString(topicCategories[i], ":");
444
445           String key = null;
446
447           if (parts.size() > 0) {
448             key = (String) parts.get(0);
449           }
450           String listtype = "0";
451           if (parts.size() > 1) {
452             listtype = (String) parts.get(1);
453           }
454           String listparameter = "5";
455           if (parts.size() > 2) {
456             listparameter = (String) parts.get(2);
457           }
458           String where = "";
459           if (parts.size() > 3) {
460             where = (String) parts.get(3);
461           }
462           String order = "";
463           if (parts.size() > 4) {
464             order = (String) parts.get(4);
465           }
466
467           if (key != null) {
468             categoryMap.put("key", key);
469             categoryMap.put("listtype", listtype);
470             categoryMap.put("listparameter", listparameter);
471             categoryMap.put("items", EntityAdapterEngine.retrieveAdapterList(model, "topic", where, order, -1, 0));
472             topicsList.add(categoryMap);
473           }
474         }
475       }
476
477       responseData.put("topics", topicsList);
478
479       responseData.put("returnurl", requestParser.getParameter("returnurl"));
480       responseData.put("thisurl", urlBuilder.getQuery());
481
482       ServletHelper.generateResponse(aResponse.getWriter(), responseData, editGenerator);
483     }
484     catch (Throwable e) {
485       throw new ServletModuleFailure(e);
486     }
487   }
488
489   public void selectparent(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
490     try {
491       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
492       URLBuilder urlBuilder = new URLBuilder();
493
494       urlBuilder.setValue("module", "Content");
495       urlBuilder.setValue("do", "setparent");
496       urlBuilder.setValue("childid", requestParser.getParameter("id"));
497       urlBuilder.setValue("returnurl", requestParser.getParameter("returnurl"));
498
499       returnList(aRequest, aResponse, "", "", 0,
500           Collections.singletonMap("selectarticleurl", urlBuilder.getQuery()));
501     }
502     catch (Throwable e) {
503       throw new ServletModuleFailure(e);
504     }
505   }
506
507   public void listchildren(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
508     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
509     String articleId = requestParser.getParameter("article_id");
510
511     if (articleId == null) {
512       throw new ServletModuleExc("ServletModuleContent.listchildren: article_id not set!");
513     }
514
515     try {
516       returnList(aRequest, aResponse, "to_content = " + articleId, "webdb_create desc", 0);
517     }
518     catch (Throwable e) {
519       throw new ServletModuleFailure(e);
520     }
521   }
522
523   public void setparent(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
524     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
525     String articleId = requestParser.getParameter("childid");
526     String parentId  = requestParser.getParameter("id");
527     String returnUrl = requestParser.getParameter("returnurl");
528
529     if (!MirGlobal.accessControl().article().mayEditArticle(ServletHelper.getUser(aRequest), articleId))
530       throw new ServletModuleExc("Article has been locked");
531
532     try {
533       EntityContent article = (EntityContent) mainModule.getById(articleId);
534       article.setFieldValue("to_content", parentId);
535       article.setProduced(false);
536       article.update();
537       logAdminUsage(aRequest, articleId, "parent set to " + parentId);
538     }
539     catch(Throwable e) {
540       getLogger().error("ServletModuleContent.setparent: " + e.getMessage());
541
542       throw new ServletModuleFailure(e);
543     }
544
545     ServletHelper.redirect(aResponse, returnUrl);
546   }
547
548   public void clearparent(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
549     HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
550     String articleId = requestParser.getParameter("id");
551     String returnUrl = requestParser.getParameter("returnurl");
552
553     try {
554       EntityContent article = (EntityContent) mainModule.getById(articleId);
555       article.setFieldValue("to_content", null);
556       article.setProduced(false);
557       article.update();
558       logAdminUsage(aRequest, articleId, "parent cleared");
559     }
560     catch(Throwable e) {
561       getLogger().error("ServletModuleContent.clearparent: " + e.getMessage(), e);
562
563       throw new ServletModuleFailure("ServletModuleContent.clearparent: " + e.getMessage(), e);
564     }
565
566     ServletHelper.redirect(aResponse, returnUrl);
567   }
568
569   public void showPreview(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
570     try {
571       HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
572       String articleId = requestParser.getParameter("id");
573       EntityAdapter article = getModel().makeEntityAdapter("content", mainModule.getById(articleId));
574       String preview = requestParser.getParameterWithDefault("preview", "default");
575
576       Map generationValues = new HashMap();
577       Generator generator =
578           MirGlobal.localizer().adminInterface().prepareArticlePreview(preview, article, generationValues);
579
580       generator.generate(aResponse.getWriter(), generationValues, getLogger());
581     }
582     catch (Exception e) {
583       throw new ServletModuleFailure(e);
584     }
585   }
586 }