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