support for CAPTCHAs
[mir.git] / source / mircoders / localizer / basic / MirBasicAdminInterfaceLocalizer.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.localizer.basic;
32
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.GregorianCalendar;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43
44 import mir.bundle.Bundle;
45 import mir.config.MirPropertiesConfiguration;
46 import mir.entity.Entity;
47 import mir.entity.adapter.EntityAdapter;
48 import mir.entity.adapter.EntityAdapterFailure;
49 import mir.generator.Generator;
50 import mir.generator.GeneratorExc;
51 import mir.log.LoggerWrapper;
52 import mir.misc.StringUtil;
53 import mir.module.ModuleExc;
54 import mir.storage.DatabaseFailure;
55 import mir.util.DateTimeRoutines;
56 import mir.util.EntityUtility;
57 import mir.util.StringRoutines;
58 import mir.util.generator.BundleGeneratorFunction;
59 import mircoders.entity.EntityComment;
60 import mircoders.entity.EntityContent;
61 import mircoders.global.MirGlobal;
62 import mircoders.localizer.MirAdminInterfaceLocalizer;
63 import mircoders.localizer.MirLocalizerExc;
64 import mircoders.localizer.MirLocalizerFailure;
65 import mircoders.module.ModuleLanguage;
66 import mircoders.module.ModuleContent;
67 import mircoders.module.ModuleComment;
68 import mircoders.storage.DatabaseContent;
69
70
71 public class MirBasicAdminInterfaceLocalizer implements MirAdminInterfaceLocalizer {
72   /** preview page name (String) -> generator name (String) */
73   private Map previewPages;
74   private List previewPageNames;
75
76   private List simpleCommentOperations;
77   private List simpleArticleOperations;
78   private Map simpleCommentOperationsMap;
79   private Map simpleArticleOperationsMap;
80
81   protected static LoggerWrapper logger = new LoggerWrapper("Localizer.AdminInterface");
82   protected MirPropertiesConfiguration configuration = MirPropertiesConfiguration.instance();
83
84   public MirBasicAdminInterfaceLocalizer() throws MirLocalizerFailure {
85     simpleCommentOperations = new ArrayList();
86     simpleArticleOperations = new ArrayList();
87     simpleCommentOperationsMap = new HashMap();
88     simpleArticleOperationsMap = new HashMap();
89
90     previewPages = new HashMap();
91     previewPageNames = new ArrayList();
92
93     String[] previewConfiguration = configuration.getStringArray("Mir.Localizer.Admin.ArticlePreview");
94
95     for (int i = 0; i<previewConfiguration.length; i++) {
96       try {
97         List parts = StringRoutines.separateString(previewConfiguration[i], "=");
98         if (parts.size() == 2) {
99           String key = ((String) parts.get(0)).trim();
100           previewPages.put(key,((String) parts.get(1)).trim());
101           previewPageNames.add(key);
102         }
103         else {
104           throw new Exception("'=' expected");
105         }
106       }
107       catch (Exception e) {
108         logger.error("Error while processing preview configuration '" + previewConfiguration[i] + "': " + e.toString());
109       }
110     }
111
112     addSimpleArticleOperation(new ChangeArticleFieldOperation("newswire", "to_article_type", "0", "1", false));
113     addSimpleArticleOperation(new ModifyArticleFieldOperation("unhide", "is_published", "1", false));
114     addSimpleArticleOperation(new ModifyArticleFieldOperation("hide", "is_published", "0", false));
115     addSimpleArticleOperation(new DeleteEntityOperation("delete"));
116
117     addSimpleCommentOperation(new ModifyCommentFieldOperation("unhide", "is_published", "1"));
118     addSimpleCommentOperation(new ModifyCommentFieldOperation("hide", "is_published", "0"));
119     addSimpleCommentOperation(new DeleteEntityOperation("delete"));
120   }
121
122   /** {@inheritDoc} */
123   public String getAdminPageGenerator(String aPage, Map aTemplateData, EntityAdapter aUser,
124                                       String aDefault) throws MirLocalizerExc {
125     return aDefault;
126   }
127
128   /** {@inheritDoc} */
129   public Generator prepareArticlePreview(String aPreviewPage, EntityAdapter anArticle,
130                                          Map aContext) throws MirLocalizerExc {
131     MirGlobal.localizer().producerAssistant().initializeGenerationValueSet(aContext);
132     aContext.put("article", anArticle);
133
134     try {
135       aContext.put(
136           "language",
137           MirGlobal.localizer().dataModel().adapterModel().makeEntityAdapter("language",
138               new ModuleLanguage().languageForCode(configuration.getString("Mir.Localizer.Admin.ArticlePreviewLanguage"))));
139     }
140     catch (EntityAdapterFailure e) {
141       throw new MirLocalizerFailure("Can't create entity adapter", e);
142     }
143     catch (ModuleExc e) {
144       throw new MirLocalizerFailure("Can't find language", e);
145     }
146     aContext.put("pathprefix", configuration.getString("Mir.Localizer.Admin.ArticlePreviewLanguage")); 
147
148     aContext.put("lang",
149         new BundleGeneratorFunction(
150             new Bundle[] {
151               MirGlobal.getBundleFactory().getBundle(
152                   "etc/bundles/producer",
153                   new String[] {
154                     configuration.getString("Mir.Localizer.Admin.ArticlePreviewLanguage") }) }));
155
156
157     if (previewPages.containsKey(aPreviewPage)) {
158       try {
159         return MirGlobal.localizer().generators().makeAdminGeneratorLibrary().
160             makeGenerator((String) previewPages.get(aPreviewPage), null);
161       }
162       catch (GeneratorExc e) {
163         throw new MirLocalizerFailure(e);
164       }
165     }
166                 throw new MirLocalizerExc("Unknown preview: " + aPreviewPage);
167   }
168
169   /** {@inheritDoc} */
170   public List getPreviewPages(EntityAdapter anArticle) throws MirLocalizerExc{
171     return Collections.unmodifiableList(previewPageNames);
172   }
173
174   /** {@inheritDoc} */
175   public String makePasswordDigest(String aPassword) {
176     
177
178     return aPassword;
179   }
180
181   /** {@inheritDoc} */
182   public void initializeArticle(Map anArticle) {
183     anArticle.put("is_published", "0");
184     anArticle.put("date", StringUtil.date2webdbDate(new GregorianCalendar()));
185   }
186
187   public List simpleCommentOperations() {
188     return Collections.unmodifiableList(simpleCommentOperations);
189   }
190
191   public List simpleArticleOperations() {
192     return Collections.unmodifiableList(simpleArticleOperations);
193   }
194
195   public EntityOperation simpleArticleOperationForName(String aName) {
196     return (EntityOperation) simpleArticleOperationsMap.get(aName);
197   }
198
199   public EntityOperation simpleCommentOperationForName(String aName) {
200     return (EntityOperation) simpleCommentOperationsMap.get(aName);
201   }
202
203   public void removeSimpleArticleOperation(String aName) {
204     simpleArticleOperations.remove(simpleArticleOperationsMap.get(aName));
205     simpleArticleOperationsMap.remove(aName);
206   }
207
208   public void addSimpleArticleOperation(EntityOperation anOperation) {
209     removeSimpleArticleOperation(anOperation.getName());
210     simpleArticleOperationsMap.put(anOperation.getName(), anOperation);
211     simpleArticleOperations.add(anOperation);
212   }
213
214   public void removeSimpleCommentOperation(String aName) {
215     simpleCommentOperations.remove(simpleCommentOperationsMap.get(aName));
216     simpleCommentOperationsMap.remove(aName);
217   }
218
219   public void addSimpleCommentOperation(EntityOperation anOperation) {
220     removeSimpleCommentOperation(anOperation.getName());
221     simpleCommentOperationsMap.put(anOperation.getName(), anOperation);
222     simpleCommentOperations.add(anOperation);
223   }
224
225   protected abstract static class EntityModifyingOperation implements EntityOperation {
226     private String name;
227     private boolean logOperation;
228
229     protected EntityModifyingOperation(String aName, boolean aLogOperation) {
230       name = aName;
231       logOperation = aLogOperation;
232     }
233
234     public String getName() {
235       return name;
236     }
237
238     public boolean isAvailable(EntityAdapter anEntity) {
239       try {
240         Entity entity = anEntity.getEntity();
241         return isAvailable(entity);
242       }
243       catch (Throwable t) {
244         return false;
245       }
246     }
247
248     public void perform(EntityAdapter aUser, EntityAdapter anEntity) throws MirLocalizerExc, MirLocalizerFailure {
249       Entity entity = anEntity.getEntity();
250       try {
251         performModification(aUser, entity);
252
253         if (logOperation) {
254           try {
255             StringBuffer line = new StringBuffer();
256
257             line.append(DateTimeRoutines.advancedDateFormat(
258                 MirGlobal.config().getString("Mir.DefaultDateTimeFormat"),
259                 (new GregorianCalendar()).getTime(),
260                 MirGlobal.config().getString("Mir.DefaultTimezone")));
261             line.append(" ");
262             if (aUser != null) {
263               line.append(aUser.get("login"));
264             }
265             else {
266               line.append("system");
267             }
268
269             line.append(" ");
270             line.append(getName());
271             EntityUtility.appendLineToField(entity, "comment", line.toString());
272           }
273           catch (Throwable t) {
274             logger.error("Error while trying to log an article operation: " + t.toString());
275           }
276         }
277
278         entity.update();
279       }
280       catch (Throwable t) {
281         throw new MirLocalizerFailure(t);
282       }
283     }
284
285     protected abstract boolean isAvailable(Entity anEntity) throws DatabaseFailure ;
286     protected abstract void performModification(EntityAdapter aUser, Entity anEntity)  throws MirLocalizerExc, MirLocalizerFailure ;
287   }
288
289   public static abstract class CommentModifyingOperation extends EntityModifyingOperation {
290     public CommentModifyingOperation(String aName, boolean aLogOperation) {
291       super(aName, aLogOperation);
292     }
293
294     public CommentModifyingOperation(String aName) {
295       this(aName, true);
296     }
297
298     protected boolean isAvailable(Entity anEntity) throws DatabaseFailure {
299       return anEntity instanceof EntityComment && isAvailable((EntityComment) anEntity);
300     }
301
302     protected void performModification(EntityAdapter aUser, Entity anEntity) throws DatabaseFailure {
303       performModification(aUser, (EntityComment) anEntity);
304       DatabaseContent.getInstance().setUnproduced("id="+anEntity.getFieldValue("to_media"));
305     }
306
307     protected abstract boolean isAvailable(EntityComment aComment) throws DatabaseFailure ;
308     protected abstract void performModification(EntityAdapter aUser, EntityComment aComment) throws DatabaseFailure ;
309   }
310
311   public static abstract class ArticleModifyingOperation extends EntityModifyingOperation {
312     public ArticleModifyingOperation(String aName, boolean aLogOperation) {
313       super(aName, aLogOperation);
314     }
315
316     protected boolean isAvailable(Entity anEntity) throws DatabaseFailure {
317       return anEntity instanceof EntityContent && isAvailable((EntityContent) anEntity);
318     }
319
320     protected void performModification(EntityAdapter aUser, Entity anEntity) throws DatabaseFailure {
321       performModification(aUser, (EntityContent) anEntity);
322       anEntity.setFieldValue("is_produced", "0");
323     }
324
325     protected abstract boolean isAvailable(EntityContent anArticle) throws DatabaseFailure ;
326     protected abstract void performModification(EntityAdapter aUser, EntityContent anArticle) throws DatabaseFailure ;
327   }
328
329   protected static class SetCommentFieldOperation extends CommentModifyingOperation {
330     private String field;
331     private String value;
332
333     public SetCommentFieldOperation(String aName, String aField, String aValue) {
334       super(aName);
335
336       field = aField;
337       value = aValue;
338     }
339
340     protected boolean isAvailable(EntityComment aComment) {
341       return true;
342     }
343
344     protected void performModification(EntityAdapter aUser, EntityComment aComment) throws DatabaseFailure {
345       aComment.setFieldValue(field, value);
346     }
347   }
348
349   protected static class SetCommentFieldsOperation extends CommentModifyingOperation {
350     private Map values;
351
352     public SetCommentFieldsOperation(String aName, String aFields[], String aValues[]) {
353       super(aName);
354
355       values = new HashMap();
356
357       for (int i=0; i<aFields.length; i++)
358         values.put(aFields[i], aValues[i]);
359     }
360
361     protected boolean isAvailable(EntityComment aComment) {
362       return true;
363     }
364
365     protected void performModification(EntityAdapter aUser, EntityComment aComment) throws DatabaseFailure {
366       Iterator i = values.entrySet().iterator();
367
368       while (i.hasNext()) {
369         Map.Entry entry = (Map.Entry) i.next();
370         aComment.setFieldValue((String) entry.getKey(), (String) entry.getValue());
371       }
372     }
373   }
374
375
376   protected static class ModifyCommentFieldOperation extends CommentModifyingOperation {
377     private String field;
378     private String value;
379
380     public ModifyCommentFieldOperation(String aName, String aField, String aValue) {
381       super(aName);
382
383       field = aField;
384       value = aValue;
385     }
386
387     protected boolean isAvailable(EntityComment aComment) {
388       return aComment.getFieldValue(field) == null || !aComment.getFieldValue(field).equals(value);
389     }
390
391     protected void performModification(EntityAdapter aUser, EntityComment aComment) throws DatabaseFailure {
392       aComment.setFieldValue(field, value);
393     }
394   }
395
396   protected static class SetArticleFieldOperation extends ArticleModifyingOperation {
397     private String field;
398     private String value;
399
400     public SetArticleFieldOperation(String aName, String aField, String aValue, boolean aLogOperation) {
401       super(aName, aLogOperation);
402
403       field = aField;
404       value = aValue;
405     }
406
407     protected boolean isAvailable(EntityContent anArticle) {
408       return true;
409     }
410
411     protected void performModification(EntityAdapter aUser, EntityContent anArticle) throws DatabaseFailure {
412       anArticle.setFieldValue(field, value);
413     }
414   }
415
416   protected static class ModifyArticleFieldOperation extends ArticleModifyingOperation {
417     private String field;
418     private String value;
419
420     public ModifyArticleFieldOperation(String aName, String aField, String aValue, boolean aLogOperation) {
421       super(aName, aLogOperation);
422
423       field = aField;
424       value = aValue;
425     }
426
427     protected boolean isAvailable(EntityContent anArticle) {
428       return anArticle.getFieldValue(field) == null || !anArticle.getFieldValue(field).equals(value);
429     }
430
431     protected void performModification(EntityAdapter aUser, EntityContent anArticle) throws DatabaseFailure {
432       anArticle.setFieldValue(field, value);
433     }
434   }
435
436   protected static class ChangeArticleFieldOperation extends ArticleModifyingOperation {
437     private String field;
438     private Set oldValues;
439     private String newValue;
440
441     public ChangeArticleFieldOperation(String aName, String aField, String anOldValues[], String aNewValue, boolean aLogOperation) {
442       super(aName, aLogOperation);
443
444       field = aField;
445       newValue = aNewValue;
446       oldValues = new HashSet(Arrays.asList(anOldValues));
447     }
448     public ChangeArticleFieldOperation(String aName, String aField, String anOldValue, String aNewValue, boolean aLogOperation) {
449       this(aName, aField, new String[] {anOldValue}, aNewValue, aLogOperation);
450     }
451
452     protected boolean isAvailable(EntityContent anArticle) {
453       return anArticle.getFieldValue(field) != null && oldValues.contains(anArticle.getFieldValue(field));
454     }
455
456     protected void performModification(EntityAdapter aUser, EntityContent anArticle) throws DatabaseFailure {
457       anArticle.setFieldValue(field, newValue);
458     }
459   }
460
461   public static class DeleteEntityOperation implements EntityOperation {
462     private String name;
463     private ModuleContent content;
464     private ModuleComment comment;
465
466     public DeleteEntityOperation(String aName) {
467       name = aName;
468       comment = new ModuleComment();
469       content = new ModuleContent();
470     }
471
472     public String getName() {
473       return "delete";
474     }
475
476     public boolean isAvailable(EntityAdapter anEntity) throws MirLocalizerExc, MirLocalizerFailure {
477       return false;
478     }
479
480     public void perform(EntityAdapter aUser, EntityAdapter anEntity) throws MirLocalizerExc, MirLocalizerFailure {
481       Entity entity = anEntity.getEntity();
482       try {
483         if (entity instanceof EntityContent) {
484           content.deleteById(entity.getId());
485         }
486         else if (entity instanceof EntityComment) {
487           comment.deleteById(entity.getId());
488         }
489       }
490       catch (ModuleExc e) {
491         throw new MirLocalizerFailure(e);
492       }
493     }
494   }
495 }