1 package mircoders.servlet;
8 import java.lang.reflect.*;
9 import javax.servlet.*;
10 import javax.servlet.http.*;
12 import freemarker.template.*;
13 import com.oreilly.servlet.multipart.*;
14 import com.oreilly.servlet.*;
23 import mircoders.entity.*;
24 import mircoders.storage.*;
25 import mircoders.module.*;
26 import mircoders.producer.*;
29 * ServletModuleOpenIndy -
30 * is the open-access-servlet, which is responsible for
31 * adding comments to articles &
32 * open-postings to the newswire
37 public class ServletModuleOpenIndy extends ServletModule
40 private String commentFormTemplate, commentFormDoneTemplate,
41 commentFormDupeTemplate;
42 private String postingFormTemplate, postingFormDoneTemplate,
43 postingFormDupeTemplate;
44 private ModuleContent contentModule;
45 private ModuleImages imageModule;
46 private ModuleTopics themenModule;
47 private String directOp ="yes";
48 private String passwdProtection ="yes";
49 // Singelton / Kontruktor
50 private static ServletModuleOpenIndy instance = new ServletModuleOpenIndy();
51 public static ServletModule getInstance() { return instance; }
53 private ServletModuleOpenIndy() {
55 theLog = Logfile.getInstance(MirConfig.getProp("Home") + MirConfig.getProp("ServletModule.OpenIndy.Logfile"));
56 commentFormTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentTemplate");
57 commentFormDoneTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentDoneTemplate");
58 commentFormDupeTemplate = MirConfig.getProp("ServletModule.OpenIndy.CommentDupeTemplate");
59 postingFormTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingTemplate");
60 postingFormDoneTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingDoneTemplate");
61 postingFormDupeTemplate = MirConfig.getProp("ServletModule.OpenIndy.PostingDupeTemplate");
62 directOp = MirConfig.getProp("DirectOpenposting").toLowerCase();
63 passwdProtection = MirConfig.getProp("PasswdProtection").toLowerCase();
64 mainModule = new ModuleComment(DatabaseComment.getInstance());
65 contentModule = new ModuleContent(DatabaseContent.getInstance());
66 themenModule = new ModuleTopics(DatabaseTopics.getInstance());
67 imageModule = new ModuleImages(DatabaseImages.getInstance());
68 defaultAction="addposting";
71 catch (StorageObjectException e) {
72 theLog.printError("servletmoduleopenindy could not be initialized");
78 * Method for making a comment
81 public void addcomment(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException
83 String aid = req.getParameter("aid"); // the article id the comment will belong to
84 if (aid!=null && !aid.equals(""))
86 SimpleHash mergeData = new SimpleHash();
89 if(passwdProtection.equals("yes")){
90 String passwd = this.createOneTimePasswd();
91 System.out.println(passwd);
92 HttpSession session = req.getSession(false);
93 session.setAttribute("passwd",passwd);
94 mergeData.put("passwd", passwd);
97 mergeData.put("aid", aid);
98 deliver(req, res, mergeData, commentFormTemplate);
100 else throw new ServletModuleException("aid not set!");
104 * Method for inserting a comment into the Database and delivering
105 * the commentDone Page
108 public void inscomment(HttpServletRequest req, HttpServletResponse res)
109 throws ServletModuleException,ServletModuleUserException
111 String aid = req.getParameter("to_media"); // the article id the comment will belong to
112 if (aid!=null && !aid.equals(""))
114 // ok, collecting data from form
116 HashMap withValues = getIntersectingValues(req, DatabaseComment.getInstance());
118 //no html in comments(for now)
119 for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
120 String k=(String)i.next();
121 String v=(String)withValues.get(k);
123 withValues.put(k,StringUtil.removeHTMLTags(v));
125 withValues.put("is_published","1");
127 //checking the onetimepasswd
128 if(passwdProtection.equals("yes")){
129 HttpSession session = req.getSession(false);
130 String sessionPasswd = (String)session.getAttribute("passwd");
131 if ( sessionPasswd == null){
132 throw new ServletModuleUserException("Lost password");
134 String passwd = req.getParameter("passwd");
135 if ( passwd == null || (!sessionPasswd.equals(passwd))) {
136 throw new ServletModuleUserException("Missing password");
138 session.invalidate();
141 // inserting into database
142 String id = mainModule.add(withValues);
143 theLog.printDebugInfo("id: "+id);
144 //insert was not successfull
146 deliver(req, res, new SimpleHash(), commentFormDupeTemplate);
149 // producing new page
150 new ProducerContent().handle(null, null, true, false, aid);
153 int exitValue = Helper.rsync();
154 theLog.printDebugInfo("rsync:"+exitValue);
156 // redirecting to url
157 // should implement back to article
158 SimpleHash mergeData = new SimpleHash();
159 deliver(req, res, mergeData, commentFormDoneTemplate);
161 catch (StorageObjectException e) { throw new ServletModuleException(e.toString());}
162 catch (ModuleException e) { throw new ServletModuleException(e.toString());}
165 else throw new ServletModuleException("aid not set!");
170 * Method for delivering the form-Page for open posting
173 public void addposting(HttpServletRequest req, HttpServletResponse res)
174 throws ServletModuleException {
175 SimpleHash mergeData = new SimpleHash();
178 if(passwdProtection.equals("yes")){
179 String passwd = this.createOneTimePasswd();
180 System.out.println(passwd);
181 HttpSession session = req.getSession(false);
182 session.setAttribute("passwd",passwd);
183 mergeData.put("passwd", passwd);
186 String maxMedia = MirConfig.getProp("ServletModule.OpenIndy.MaxMediaUploadItems");
187 String numOfMedia = req.getParameter("medianum");
188 if(numOfMedia==null||numOfMedia.equals("")){
190 } else if(Integer.parseInt(numOfMedia) > Integer.parseInt(maxMedia)) {
191 numOfMedia = maxMedia;
194 int mediaNum = Integer.parseInt(numOfMedia);
195 SimpleList mediaFields = new SimpleList();
196 for(int i =0; i<mediaNum;i++){
197 Integer mNum = new Integer(i+1);
198 mediaFields.add(mNum.toString());
200 mergeData.put("medianum",numOfMedia);
201 mergeData.put("mediafields",mediaFields);
204 SimpleHash extraInfo = new SimpleHash();
206 SimpleList popUpData = DatabaseLanguage.getInstance().getPopupData();
207 extraInfo.put("languagePopUpData", popUpData );
208 extraInfo.put("themenPopupData", themenModule.getTopicsAsSimpleList());
209 } catch (Exception e) {
210 theLog.printError("languagePopUpData or getTopicslist failed "
212 throw new ServletModuleException("OpenIndy -- failed getting language or topics: "+e.toString());
215 deliver(req, res, mergeData, extraInfo, postingFormTemplate);
219 * Method for inserting an open posting into the Database and delivering
220 * the postingDone Page
223 public void insposting(HttpServletRequest req, HttpServletResponse res)
224 throws ServletModuleException, ServletModuleUserException
226 SimpleHash mergeData = new SimpleHash();
227 boolean setMedia=false;
228 boolean setTopic = false;
231 WebdbMultipartRequest mp = new WebdbMultipartRequest(req);
233 HashMap withValues = mp.getParameters();
235 //checking the onetimepasswd
236 if(passwdProtection.equals("yes")){
237 HttpSession session = req.getSession(false);
238 String sessionPasswd = (String)session.getAttribute("passwd");
239 if ( sessionPasswd == null){
240 throw new ServletModuleUserException("Lost password");
242 String passwd = (String)withValues.get("passwd");
243 if ( passwd == null || (!sessionPasswd.equals(passwd))) {
244 throw new ServletModuleUserException("Missing password");
246 session.invalidate();
249 if ((((String)withValues.get("title")).length() == 0) ||
250 (((String)withValues.get("description")).length() == 0) ||
251 (((String)withValues.get("content_data")).length() == 0))
252 throw new ServletModuleUserException("Missing field");
254 // call the routines that escape html
256 for (Iterator i=withValues.keySet().iterator(); i.hasNext(); ){
257 String k=(String)i.next();
258 String v=(String)withValues.get(k);
260 if (k.equals("content_data")){
261 //this doesn't quite work yet, so for now, all html goes
262 //withValues.put(k,StringUtil.approveHTMLTags(v));
263 //withValues.put(k,StringUtil.removeHTMLTags(v));
265 withValues.put(k,StringUtil.removeHTMLTags(v));
270 withValues.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
271 withValues.put("publish_path", StringUtil.webdbDate2path((String)withValues.get("date")));
272 withValues.put("is_produced", "0");
273 // op-articles are not immediatly published
274 // we don't know that all is good yet (media, title is present, etc..)
275 withValues.put("is_published","0");
276 // if op direct article-type == newswire
277 if (directOp.equals("yes")) withValues.put("to_article_type","1");
279 // owner is openposting user
280 withValues.put("to_publisher","1");
281 if (withValues.get("creator").toString().equals(""))
282 withValues.put("creator","Anonym");
284 // inserting content into database
285 String cid = contentModule.add(withValues);
286 theLog.printDebugInfo("id: "+cid);
287 //insert was not successfull
289 //How do we know that it was not succesful cause of a
290 //dupe, what if it failed cause of "No space left on device"?
291 //Or is there something I am missing? Wouldn't it be better
292 //to have an explicit dupe check and then insert? I have no
293 //idea what I am talking about. this comment is in case
294 //I forget to explicitely ask. -mh
295 deliver(req, res, mergeData, postingFormDupeTemplate);
298 String[] to_topicsArr = mp.getParameterValues("to_topic");
300 if (to_topicsArr != null && to_topicsArr.length > 0) {
302 DatabaseContentToTopics.getInstance().setTopics(cid,to_topicsArr);
304 } catch (Exception e) {
305 theLog.printError("setting content_x_topic failed");
306 contentModule.deleteById(cid);
307 throw new ServletModuleException("smod - openindy :: insposting: setting content_x_topic failed: "+e.toString());
311 // if op contains uploaddata
314 for(Iterator it = mp.requestList.iterator(); it.hasNext();){
315 MpRequest mpReq = (MpRequest)it.next();
316 String fileName = mpReq.getFilename();
318 //get the content-type from what the client browser
319 //sends us. (the "Oreilly method")
320 String contentType = mpReq.getContentType();
322 theLog.printInfo("FROM BROWSER: "+contentType);
324 //if the client browser sent us unknown (text/plain is default)
325 //or if we got application/octet-stream, it's possible that
326 //the browser is in error, better check against the file extension
327 if (contentType.equals("text/plain") ||
328 contentType.equals("application/octet-stream")) {
330 * Fallback to finding the mime-type through the standard ServletApi
331 * ServletContext getMimeType() method.
333 * This is a way to get the content-type via the .extension,
334 * we could maybe use a magic method as an additional method of
335 * figuring out the content-type, by looking at the header (first
336 * few bytes) of the file. (like the file(1) command). We could
337 * also call the "file" command through Runtime. This is an
338 * option that I almost prefer as it is already implemented and
339 * exists with an up-to-date map on most modern Unix like systems.
340 * I haven't found a really nice implementation of the magic method
343 * The first method we try thought is the "Oreilly method". It
344 * relies on the content-type that the client browser sends and
345 * that sometimes is application-octet stream with
346 * broken/mis-configured browsers.
348 * The map file we use for the extensions is the standard web-app
349 * deployment descriptor file (web.xml). See Mir's web.xml or see
350 * your Servlet containers (most likely Tomcat) documentation.
351 * So if you support a new media type you have to make sure that
352 * it is in this file -mh
355 (ServletContext)MirConfig.getPropAsObject("ServletContext");
356 contentType = ctx.getMimeType(fileName);
357 if (contentType==null)
358 contentType = "text/plain"; // rfc1867 says this is the default
360 HashMap mediaValues = new HashMap();
362 theLog.printInfo("CONTENT TYPE IS: "+contentType);
364 if (contentType.equals("text/plain") ||
365 contentType.equals("application/octet-stream")) {
366 contentModule.deleteById(cid);
367 _throwBadContentType(fileName, contentType);
370 String mediaTitle=(String)withValues.get("media_title"+i);
373 if (mediaTitle==null)
374 mediaTitle = (String)withValues.get("title");
376 mediaValues.put("title", mediaTitle);
377 mediaValues.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
378 mediaValues.put("to_publisher", "1"); // op user
379 mediaValues.put("to_media_folder", "7"); // op media_folder
380 mediaValues.put("is_produced", "0");
381 mediaValues.put("is_published","0");
383 // @todo this should probably be moved to DatabaseMediaType -mh
384 String[] cTypeSplit = StringUtil.split(contentType, "/");
385 String wc = " mime_type LIKE '"+cTypeSplit[0]+"%'";
387 DatabaseMediaType mediaTypeStor = DatabaseMediaType.getInstance();
388 EntityList mediaTypesList = mediaTypeStor.selectByWhereClause(wc);
390 String mediaTypeId = null;
391 MirMedia mediaHandler;
392 Database mediaStorage;
393 ProducerMedia mediaProducer;
395 //if we didn't find an entry matching the
396 //content-type int the table.
397 if (mediaTypesList.size() == 0) {
398 contentModule.deleteById(cid);
399 _throwBadContentType(fileName, contentType);
402 Entity mediaType = null;
403 Entity mediaType2 = null;
405 // find out if we an exact content-type match if so take it.
406 // otherwise try to match majortype/*
407 // @todo this should probably be moved to DatabaseMediaType -mh
408 for(int j=0;j<mediaTypesList.size();j++) {
409 if(contentType.equals(
410 mediaTypesList.elementAt(j).getValue("mime_type")))
411 mediaType = mediaTypesList.elementAt(j);
412 else if ((mediaTypesList.elementAt(j).getValue("mime_type")).equals(
413 cTypeSplit[0]+"/*") )
414 mediaType2= mediaTypesList.elementAt(j);
417 if ( (mediaType == null) && (mediaType2 == null) ) {
418 contentModule.deleteById(cid);
419 _throwBadContentType(fileName, contentType);
421 else if( (mediaType == null) && (mediaType2 != null) )
422 mediaType = mediaType2;
424 //get the class names from the media_type table.
425 mediaTypeId = mediaType.getId();
427 // ############### @todo: merge these and the getURL call into one
428 // getURL helper call that just takes the Entity as a parameter
429 // along with media_type
430 mediaHandler = MediaHelper.getHandler(mediaType);
431 mediaStorage = MediaHelper.getStorage(mediaType,
432 "mircoders.storage.Database");
433 Class prodCls = Class.forName("mircoders.producer.Producer"
434 +mediaType.getValue("tablename"));
435 mediaProducer = (ProducerMedia)prodCls.newInstance();
436 } catch (Exception e) {
437 theLog.printError("getting media handler failed: "+e.toString());
438 contentModule.deleteById(cid);
439 throw new ServletModuleException("getting media handler failed: "
443 mediaValues.put("to_media_type",mediaTypeId);
445 //load the classes via reflection
447 Entity mediaEnt = null;
449 mediaEnt = (Entity)mediaStorage.getEntityClass().newInstance();
450 mediaEnt.setStorage(mediaStorage);
451 mediaEnt.setValues(mediaValues);
452 mediaId = mediaEnt.insert();
454 //save and store the media data/metadata
455 mediaHandler.set(mpReq.getMedia(), mediaEnt,
458 //were done with mpReq at this point, dereference it.
459 //as it contains mucho mem. -mh 01.10.2001
462 //we got this far, associate the media to the article
463 mediaEnt.setValueForProperty("is_published","1");
466 mediaProducer.handle(null, null, false, false, mediaId);
467 DatabaseContentToMedia.getInstance().addMedia(cid,mediaId);
468 } catch (Exception e) {
469 theLog.printError("setting media failed: "+e.toString());
470 contentModule.deleteById(cid);
471 throw new ServletModuleException("setting media failed: "
475 } //end for Iterator...
477 //if we're here all is ok...
478 EntityContent contentEnt = (EntityContent)contentModule.getById(cid);
479 contentEnt.setValueForProperty("is_published","1");
483 //dereference mp. -mh
486 // producing openpostinglist
487 new ProducerOpenPosting().handle(null,null,false,false);
488 // producing new page
489 new ProducerContent().handle(null, null, false, false,cid);
490 //if direct op producing startpage
491 if (directOp.equals("yes")) new ProducerStartPage().handle(null,null);
493 //produce the topicPages if set
494 //should be more intelligent
495 //if(setTopic==true) new ProducerTopics().handle(null,null);
498 //should be configureable
499 int exitValue = Helper.rsync();
500 theLog.printDebugInfo("rsync: "+exitValue);
503 catch (IOException e) { throw new ServletModuleException("IOException: "+ e.toString());}
504 catch (StorageObjectException e) { throw new ServletModuleException("StorageObjectException" + e.toString());}
505 catch (ModuleException e) { throw new ServletModuleException("ModuleException"+e.toString());}
507 deliver(req, res, mergeData, postingFormDoneTemplate);
510 private void _throwBadContentType (String fileName, String contentType)
511 throws ServletModuleUserException {
513 theLog.printDebugInfo("Wrong file type uploaded!: " + fileName+" "
515 throw new ServletModuleUserException("The file you uploaded is of the "
516 +"following mime-type: "+contentType
517 +", we do not support this mime-type. "
518 +"Error One or more files of unrecognized type. Sorry");
521 protected String createOneTimePasswd(){
522 Random r = new Random();
523 int random = r.nextInt();
524 long l = System.currentTimeMillis();
525 l = (l*l*l*l)/random;
527 String returnString = ""+l;
528 return returnString.substring(5);