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