producer XML configuration support: Producers can be set up using an XML input
[mir.git] / source / mircoders / servlet / ServletModuleOpenIndy.java
1 package mircoders.servlet;
2
3 import java.io.*;
4 import java.lang.*;
5 import java.sql.*;
6 import java.util.*;
7 import java.net.*;
8 import java.lang.reflect.*;
9 import javax.servlet.*;
10 import javax.servlet.http.*;
11
12 import freemarker.template.*;
13 import com.oreilly.servlet.multipart.*;
14 import com.oreilly.servlet.*;
15
16 import mir.servlet.*;
17 import mir.module.*;
18 import mir.misc.*;
19 import mir.entity.*;
20 import mir.storage.*;
21 import mir.media.*;
22
23 import mircoders.entity.*;
24 import mircoders.storage.*;
25 import mircoders.module.*;
26 import mircoders.producer.*;
27 import mircoders.global.*;
28 import mircoders.localizer.*;
29
30 /*
31  *  ServletModuleOpenIndy -
32  *   is the open-access-servlet, which is responsible for
33  *    adding comments to articles &
34  *    open-postings to the newswire
35  *
36  * @author RK
37  */
38
39 public class ServletModuleOpenIndy extends ServletModule
40 {
41
42   private String        commentFormTemplate, commentFormDoneTemplate,
43                         commentFormDupeTemplate;
44   private String        postingFormTemplate, postingFormDoneTemplate,
45                         postingFormDupeTemplate;
46   private ModuleContent contentModule;
47   private ModuleComment commentModule;
48   private ModuleImages  imageModule;
49   private ModuleTopics  themenModule;
50   private String        directOp ="yes";
51   private String        passwdProtection ="yes";
52   // Singelton / Kontruktor
53   private static ServletModuleOpenIndy instance = new ServletModuleOpenIndy();
54   public static ServletModule getInstance() { return instance; }
55
56   private ServletModuleOpenIndy() {
57     try {
58       theLog = Logfile.getInstance(MirConfig.getProp("Home") + MirConfig.getProp("ServletModule.OpenIndy.Logfile"));
59       commentFormTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentTemplate");
60       commentFormDoneTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentDoneTemplate");
61       commentFormDupeTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentDupeTemplate");
62       postingFormTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingTemplate");
63       postingFormDoneTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingDoneTemplate");
64       postingFormDupeTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingDupeTemplate");
65       directOp = MirConfig.getProp("DirectOpenposting").toLowerCase();
66       passwdProtection = MirConfig.getProp("PasswdProtection").toLowerCase();
67       mainModule = new ModuleComment(DatabaseComment.getInstance());
68       contentModule = new ModuleContent(DatabaseContent.getInstance());
69       themenModule = new ModuleTopics(DatabaseTopics.getInstance());
70       imageModule = new ModuleImages(DatabaseImages.getInstance());
71       defaultAction="addposting";
72
73     }
74     catch (StorageObjectException e) {
75         theLog.printError("servletmoduleopenindy could not be initialized");
76     }
77   }
78
79
80   /**
81    *  Method for making a comment
82    */
83
84   public void addcomment(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException
85   {
86     String aid = req.getParameter("aid"); // the article id the comment will belong to
87     String language = req.getParameter("language");
88
89     if (aid!=null && !aid.equals(""))
90     {
91       SimpleHash mergeData = new SimpleHash();
92
93       // onetimepasswd
94       if(passwdProtection.equals("yes")){
95         String passwd = this.createOneTimePasswd();
96         System.out.println(passwd);
97         HttpSession session = req.getSession(false);
98         session.setAttribute("passwd",passwd);
99         mergeData.put("passwd", passwd);
100       }
101
102       if (language!=null) {
103         HttpSession session = req.getSession(false);
104         session.setAttribute("Locale", new Locale(language, ""));
105         session.setAttribute("passwd",language);
106       }
107
108       mergeData.put("aid", aid);
109       deliver(req, res, mergeData, commentFormTemplate);
110     }
111     else throw new ServletModuleException("aid not set!");
112   }
113
114   /**
115    *  Method for inserting a comment into the Database and delivering
116    *  the commentDone Page
117    */
118
119   public void inscomment(HttpServletRequest req, HttpServletResponse res)
120   throws ServletModuleException,ServletModuleUserException
121   {
122     String aid = req.getParameter("to_media"); // the article id the comment will belong to
123     if (aid!=null && !aid.equals(""))
124     {
125       // ok, collecting data from form
126       try {
127         HashMap withValues = getIntersectingValues(req, DatabaseComment.getInstance());
128
129         //no html in comments(for now)
130         for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
131             String k=(String)i.next();
132             String v=(String)withValues.get(k);
133
134             withValues.put(k,StringUtil.removeHTMLTags(v));
135         }
136         withValues.put("is_published","1");
137
138         //checking the onetimepasswd
139         if(passwdProtection.equals("yes")){
140           HttpSession session = req.getSession(false);
141           String sessionPasswd = (String)session.getAttribute("passwd");
142           if ( sessionPasswd == null){
143             throw new ServletModuleUserException("Lost password");
144           }
145           String passwd = req.getParameter("passwd");
146           if ( passwd == null || (!sessionPasswd.equals(passwd))) {
147             throw new ServletModuleUserException("Missing password");
148           }
149           session.invalidate();
150         }
151
152         // inserting into database
153         String id = mainModule.add(withValues);
154         theLog.printDebugInfo("id: "+id);
155         //insert was not successfull
156         if(id==null){
157           deliver(req, res, new SimpleHash(), commentFormDupeTemplate);
158         }
159         else {
160           DatabaseContent.getInstance().setUnproduced("id="+aid);
161
162
163           try {
164             EntityComment comment = (EntityComment) DatabaseComment.getInstance().selectById(id);
165             MirGlobal.localizer().openPostings().afterCommentPosting(comment);
166           }
167           catch (Throwable t) {
168             throw new ServletModuleException(t.getMessage());
169           }
170           
171           
172           
173         }
174
175         // redirecting to url
176         // should implement back to article
177         SimpleHash mergeData = new SimpleHash();
178         deliver(req, res, mergeData, commentFormDoneTemplate);
179       }
180       catch (StorageObjectException e) { throw new ServletModuleException(e.toString());}
181       catch (ModuleException e) { throw new ServletModuleException(e.toString());}
182
183     }
184     else throw new ServletModuleException("aid not set!");
185
186   }
187
188   /**
189    *  Method for delivering the form-Page for open posting
190    */
191
192   public void addposting(HttpServletRequest req, HttpServletResponse res)
193     throws ServletModuleException {
194     SimpleHash mergeData = new SimpleHash();
195
196     // onetimepasswd
197     if(passwdProtection.equals("yes")){
198       String passwd = this.createOneTimePasswd();
199       System.out.println(passwd);
200       HttpSession session = req.getSession(false);
201       session.setAttribute("passwd",passwd);
202       mergeData.put("passwd", passwd);
203     }
204
205     String maxMedia = MirConfig.getProp("ServletModule.OpenIndy.MaxMediaUploadItems");
206     String numOfMedia = req.getParameter("medianum");
207     if(numOfMedia==null||numOfMedia.equals("")){
208       numOfMedia="1";
209     } else if(Integer.parseInt(numOfMedia) > Integer.parseInt(maxMedia)) {
210       numOfMedia = maxMedia;
211     }
212
213     int mediaNum = Integer.parseInt(numOfMedia);
214     SimpleList mediaFields = new SimpleList();
215     for(int i =0; i<mediaNum;i++){
216       Integer mNum = new Integer(i+1);
217       mediaFields.add(mNum.toString());
218     }
219     mergeData.put("medianum",numOfMedia);
220     mergeData.put("mediafields",mediaFields);
221
222
223     SimpleHash extraInfo = new SimpleHash();
224     try{
225       SimpleList popUpData = DatabaseLanguage.getInstance().getPopupData();
226       extraInfo.put("languagePopUpData", popUpData );
227       extraInfo.put("themenPopupData", themenModule.getTopicsAsSimpleList());
228
229 // ML: Bolivia specific, will move it towards localization
230       extraInfo.put("topics", themenModule.getTopicsList());
231       String defaultCity = req.getParameter("city");
232       if(defaultCity!=null && !defaultCity.equals("")){
233         extraInfo.put("city", defaultCity);
234       }
235
236     } catch (Exception e) {
237       theLog.printError("languagePopUpData or getTopicslist failed "
238                         +e.toString());
239       throw new ServletModuleException("OpenIndy -- failed getting language or topics: "+e.toString());
240     }
241
242
243
244     deliver(req, res, mergeData, extraInfo, postingFormTemplate);
245   }
246
247   /**
248    *  Method for inserting an open posting into the Database and delivering
249    *  the postingDone Page
250    */
251
252   public void insposting(HttpServletRequest req, HttpServletResponse res)
253     throws ServletModuleException, ServletModuleUserException
254   {
255     SimpleHash mergeData = new SimpleHash();
256     boolean setMedia=false;
257     boolean setTopic = false;
258
259     try {
260       WebdbMultipartRequest mp = new WebdbMultipartRequest(req);
261
262       HashMap withValues = mp.getParameters();
263
264       //checking the onetimepasswd
265       if(passwdProtection.equals("yes")){
266         HttpSession session = req.getSession(false);
267         String sessionPasswd = (String)session.getAttribute("passwd");
268         if ( sessionPasswd == null){
269           throw new ServletModuleUserException("Lost password");
270         }
271         String passwd = (String)withValues.get("passwd");
272         if ( passwd == null || (!sessionPasswd.equals(passwd))) {
273           throw new ServletModuleUserException("Missing password");
274         }
275         session.invalidate();
276       }
277
278       if ((((String)withValues.get("title")).length() == 0) ||
279           (((String)withValues.get("description")).length() == 0) ||
280           (((String)withValues.get("content_data")).length() == 0))
281             throw new ServletModuleUserException("Missing field");
282
283       // call the routines that escape html
284
285       for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
286         String k=(String)i.next();
287         String v=(String)withValues.get(k);
288
289         if (k.equals("content_data")){
290           //this doesn't quite work yet, so for now, all html goes
291           //withValues.put(k,StringUtil.approveHTMLTags(v));
292           //withValues.put(k,StringUtil.removeHTMLTags(v));
293         } else {
294           withValues.put(k,StringUtil.removeHTMLTags(v));
295         }
296
297       }
298
299       withValues.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
300       withValues.put("publish_path", StringUtil.webdbDate2path((String)withValues.get("date")));
301       withValues.put("is_produced", "0");
302       // op-articles are not immediatly published
303       // we don't know that all is good yet (media, title is present, etc..)
304       withValues.put("is_published","0");
305       // if op direct article-type == newswire
306       if (directOp.equals("yes")) withValues.put("to_article_type","1");
307
308       withValues.put("to_publisher","1");
309
310       // owner is openposting user
311 //      ML: this is not multi-language friendly and this can be done in a template
312 //      if (withValues.get("creator").toString().equals(""))
313 //        withValues.put("creator","Anonym");
314
315       // inserting  content into database
316       String cid = contentModule.add(withValues);
317       theLog.printDebugInfo("id: "+cid);
318       //insert was not successfull
319       if(cid==null){
320         //How do we know that it was not succesful cause of a
321         //dupe, what if it failed cause of "No space left on device"?
322         //Or is there something I am missing? Wouldn't it be better
323         //to have an explicit dupe check and then insert? I have no
324         //idea what I am talking about. this comment is in case
325         //I forget to explicitely ask. -mh
326         deliver(req, res, mergeData, postingFormDupeTemplate);
327       }
328
329       String[] to_topicsArr = mp.getParameterValues("to_topic");
330
331       if (to_topicsArr != null && to_topicsArr.length > 0) {
332         try{
333           DatabaseContentToTopics.getInstance().setTopics(cid,to_topicsArr);
334           setTopic = true;
335         } catch (Exception e) {
336           theLog.printError("setting content_x_topic failed");
337           contentModule.deleteById(cid);
338           throw new ServletModuleException("smod - openindy :: insposting: setting content_x_topic failed: "+e.toString());
339         } //end try
340       } //end if
341
342       // if op contains uploaddata
343       String mediaId=null;
344       int i=1;
345       for(Iterator it = mp.requestList.iterator(); it.hasNext();){
346         MpRequest mpReq = (MpRequest)it.next();
347         String fileName = mpReq.getFilename();
348
349         //get the content-type from what the client browser
350         //sends us. (the "Oreilly method")
351         String contentType = mpReq.getContentType();
352
353         theLog.printInfo("FROM BROWSER: "+contentType);
354
355         //if the client browser sent us unknown (text/plain is default)
356         //or if we got application/octet-stream, it's possible that
357         //the browser is in error, better check against the file extension
358         if (contentType.equals("text/plain") ||
359             contentType.equals("application/octet-stream")) {
360           /**
361            * Fallback to finding the mime-type through the standard ServletApi
362            * ServletContext getMimeType() method.
363            *
364            * This is a way to get the content-type via the .extension,
365            * we could maybe use a magic method as an additional method of
366            * figuring out the content-type, by looking at the header (first
367            * few bytes) of the file. (like the file(1) command). We could
368            * also call the "file" command through Runtime. This is an
369            * option that I almost prefer as it is already implemented and
370            * exists with an up-to-date map on most modern Unix like systems.
371            * I haven't found a really nice implementation of the magic method
372            * in pure java yet.
373            *
374            * The first method we try thought is the "Oreilly method". It
375            * relies on the content-type that the client browser sends and
376            * that sometimes is application-octet stream with
377            * broken/mis-configured browsers.
378            *
379            * The map file we use for the extensions is the standard web-app
380            * deployment descriptor file (web.xml). See Mir's web.xml or see
381            * your Servlet containers (most likely Tomcat) documentation.
382            * So if you support a new media type you have to make sure that
383            * it is in this file -mh
384            */
385           ServletContext ctx =
386             (ServletContext)MirConfig.getPropAsObject("ServletContext");
387           contentType = ctx.getMimeType(fileName);
388           if (contentType==null)
389             contentType = "text/plain"; // rfc1867 says this is the default
390         }
391         HashMap mediaValues = new HashMap();
392
393         theLog.printInfo("CONTENT TYPE IS: "+contentType);
394
395         if (contentType.equals("text/plain") ||
396             contentType.equals("application/octet-stream")) {
397           contentModule.deleteById(cid);
398           _throwBadContentType(fileName, contentType);
399         }
400
401         String mediaTitle=(String)withValues.get("media_title"+i);
402         i++;
403
404         if (mediaTitle==null)
405             mediaTitle = (String)withValues.get("title");
406
407         mediaValues.put("title", mediaTitle);
408         mediaValues.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
409         mediaValues.put("to_publisher", "1"); // op user
410         mediaValues.put("to_media_folder", "7"); // op media_folder
411         mediaValues.put("is_produced", "0");
412         mediaValues.put("is_published","0");
413
414         // @todo this should probably be moved to DatabaseMediaType -mh
415         String[] cTypeSplit = StringUtil.split(contentType, "/");
416         String wc = " mime_type LIKE '"+cTypeSplit[0]+"%'";
417
418         DatabaseMediaType mediaTypeStor = DatabaseMediaType.getInstance();
419         EntityList mediaTypesList = mediaTypeStor.selectByWhereClause(wc);
420
421         String mediaTypeId = null;
422         MirMedia mediaHandler;
423         Database mediaStorage;
424 //        ProducerMedia mediaProducer;
425
426         //if we didn't find an entry matching the
427         //content-type int the table.
428         if (mediaTypesList.size() == 0) {
429           contentModule.deleteById(cid);
430           _throwBadContentType(fileName, contentType);
431         }
432
433         Entity mediaType = null;
434         Entity mediaType2 = null;
435
436         // find out if we an exact content-type match if so take it.
437         // otherwise try to match majortype/*
438         // @todo this should probably be moved to DatabaseMediaType -mh
439         for(int j=0;j<mediaTypesList.size();j++) {
440           if(contentType.equals(
441                 mediaTypesList.elementAt(j).getValue("mime_type")))
442             mediaType = mediaTypesList.elementAt(j);
443           else if ((mediaTypesList.elementAt(j).getValue("mime_type")).equals(
444                     cTypeSplit[0]+"/*") )
445             mediaType2= mediaTypesList.elementAt(j);
446         }
447
448         if ( (mediaType == null) && (mediaType2 == null) ) {
449           contentModule.deleteById(cid);
450           _throwBadContentType(fileName, contentType);
451         }
452         else if( (mediaType == null) && (mediaType2 != null) )
453           mediaType = mediaType2;
454
455         //get the class names from the media_type table.
456         mediaTypeId = mediaType.getId();
457         try {
458           // ############### @todo: merge these and the getURL call into one
459           // getURL helper call that just takes the Entity as a parameter
460           // along with media_type
461           mediaHandler = MediaHelper.getHandler(mediaType);
462           mediaStorage = MediaHelper.getStorage(mediaType,
463                                               "mircoders.storage.Database");
464 //          Class prodCls = Class.forName("mircoders.producer.Producer"
465 //                                            +mediaType.getValue("tablename"));
466 //          mediaProducer = (ProducerMedia)prodCls.newInstance();
467         } catch (Exception e) {
468           theLog.printError("getting media handler failed: "+e.toString());
469           contentModule.deleteById(cid);
470           throw new ServletModuleException("getting media handler failed: "
471                                           +e.toString());
472         }
473
474         mediaValues.put("to_media_type",mediaTypeId);
475
476         //load the classes via reflection
477         String MediaId;
478         Entity mediaEnt = null;
479         try {
480           mediaEnt = (Entity)mediaStorage.getEntityClass().newInstance();
481           mediaEnt.setStorage(mediaStorage);
482           mediaEnt.setValues(mediaValues);
483           mediaId = mediaEnt.insert();
484
485           //save and store the media data/metadata
486           mediaHandler.set(mpReq.getMedia(), mediaEnt,
487                           mediaType);
488
489           //were done with mpReq at this point, dereference it.
490           //as it contains mucho mem. -mh 01.10.2001
491           mpReq=null;
492
493           //we got this far, associate the media to the article
494           mediaEnt.setValueForProperty("is_published","1");
495           mediaEnt.update();
496           //produce it
497 //          mediaProducer.handle(null, null, false, false, mediaId);
498           DatabaseContentToMedia.getInstance().addMedia(cid,mediaId);
499         } catch (Exception e) {
500           theLog.printError("setting media failed: "+e.toString());
501           contentModule.deleteById(cid);
502           throw new ServletModuleException("setting media failed: "
503                                             +e.toString());
504         }
505
506       } //end for Iterator...
507
508       //if we're here all is ok...
509       EntityContent contentEnt = (EntityContent)contentModule.getById(cid);
510       contentEnt.setValueForProperty("is_published","1");
511       contentEnt.update();
512
513
514
515       //dereference mp. -mh
516       mp=null;
517
518       try {
519         MirGlobal.localizer().openPostings().afterContentPosting(contentEnt);
520       }
521       catch (Throwable t) {
522         throw new ServletModuleException(t.getMessage());
523       }
524     }
525     catch (IOException e) { throw new ServletModuleException("IOException: "+ e.toString());}
526     catch (StorageObjectException e) { throw new ServletModuleException("StorageObjectException" + e.toString());}
527     catch (ModuleException e) { throw new ServletModuleException("ModuleException"+e.toString());}
528
529     deliver(req, res, mergeData, postingFormDoneTemplate);
530   }
531
532   private void _throwBadContentType (String fileName, String contentType)
533     throws ServletModuleUserException {
534
535     theLog.printDebugInfo("Wrong file type uploaded!: " + fileName+" "
536                           +contentType);
537     throw new ServletModuleUserException("The file you uploaded is of the "
538         +"following mime-type: "+contentType
539         +", we do not support this mime-type. "
540         +"Error One or more files of unrecognized type. Sorry");
541   }
542
543   protected String createOneTimePasswd(){
544     Random r = new Random();
545     int random = r.nextInt();
546     long l = System.currentTimeMillis();
547     l = (l*l*l*l)/random;
548     if(l<0) l = l * -1;
549     String returnString = ""+l;
550     return returnString.substring(5);
551   }
552
553 }
554
555