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