########## admin ##########
# language: english
-# $Id: admin_en.properties,v 1.48.2.28 2006/03/19 20:53:11 zapata Exp $
+# $Id: admin_en.properties,v 1.48.2.29 2006/12/25 20:10:22 zapata Exp $
languagename=English
comment.operation.hide=hide
comment.operation.unhide=unhide
+comment.operation.delete=delete
#commentlist
content.operation.hide=hide
content.operation.unhide=unhide
content.operation.newswire=newswire
+content.operation.delete=delete
+
content.preview.default = Preview
filtertype.throttle = Throttle
filtertype.hostname = Host name
filtertype.size= Posting size
+filtertype.urlblacklist = URL Blacklist query
filtererror.title = Error:
filtererror.invalidtype = Invalid filter type
</verbs>
<body>
+ <ReportChanges format="${config.now.formatted['HH:mm:ss']} ${change.type} ${config['Producer.ProductionHost']}${change.path}"
+ file="${config['Producer.StorageRoot']}/changes/changes${config.now.formatted['yyyyMMdd']}.txt"
+ basepath="${config['Producer.StorageRoot']}" />
+
+
+
+
<If condition="config['Rsync'] in ('1', 'y', 'yes', 'Y')">
<then>
<Execute command="${config['Rsync.Script.Path']}"/>
import mir.entity.Entity;
import mir.entity.EntityList;
import mir.storage.Database;
+import mir.storage.DatabaseExc;
import java.util.Map;
return database;
}
- public Entity getById (String id) throws ModuleExc, ModuleFailure {
- try {
- if (database == null)
- throw new ModuleExc("AbstractModule.getById: No Database set!");
- Entity entity = database.selectById(id);
+ public Entity getById (String anId) throws ModuleFailure, EntityNotFoundExc {
+ if (database == null) {
+ throw new ModuleFailure("AbstractModule.getById: No Database set!");
+ }
- if (entity == null)
- throw new ModuleExc("AbstractModule.getById: No object for id = " + id);
- return entity;
- }
- catch (Throwable e) {
- throw new ModuleFailure(e);
- }
+ try {
+ Entity result = database.selectById(anId);
+
+ if (result == null) {
+ throw new EntityNotFoundExc("AbstractModule.getById: No object for id = " + anId);
+ }
+
+ return result;
+ }
+ catch (DatabaseExc e) {
+ throw new ModuleFailure("Database exception while retrieving entity with id " + anId);
+ }
}
public EntityList getByWhereClause (String whereClause, int offset) throws ModuleExc, ModuleFailure {
import multex.Failure;
public class ModuleFailure extends Failure {
+ public ModuleFailure(String aMessage) {
+ super(aMessage, null);
+ }
- public ModuleFailure(String msg,Throwable cause) {
- super(msg,cause);
+ public ModuleFailure(String aMessage,Throwable aCause) {
+ super(aMessage,aCause);
}
public ModuleFailure(Throwable aCause) {
/**
* Implements database access.
*
- * @version $Id: Database.java,v 1.44.2.36 2006/08/10 19:29:36 zapata Exp $
+ * @version $Id: Database.java,v 1.44.2.37 2006/12/25 20:10:22 zapata Exp $
* @author rk
* @author Zapata
*
}
/**
- * Return an entity specified by id
+ * Return an entity specified by id, or <code>null</code> if no such
+ * entity exists.
*/
public Entity selectById(String anId) throws DatabaseExc {
if ((anId == null) || anId.equals("")) {
package mir.util;
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.List;
public class InternetRoutines {
return (1L<<32)-1;
}
-
}
\ No newline at end of file
}
}
- public static String performCaseInsensitiveRegularExpressionReplacement(String aSource, String aSearchExpression, String aReplacement) {
- try {
- RE regularExpression;
-
- regularExpression = new RE(aSearchExpression, RE.REG_ICASE);
-
- return regularExpression.substituteAll(aSource, aReplacement);
- }
- catch (Throwable t) {
- throw new UtilFailure("StringRoutines.performRegularExpressionReplacement: " + t.toString(), t);
- }
- }
-
- public static boolean performRegularExpressionSearch(String aSource, String aSearchExpression) {
- try {
- RE regularExpression;
-
- regularExpression = new RE(aSearchExpression);
-
- return regularExpression.isMatch(aSource);
- }
- catch (Throwable t) {
- throw new UtilFailure("StringRoutines.performRegularExpressionSearch: " + t.toString(), t);
- }
- }
-
/**
* Separates a string based on a separator:
* <code>seperateString("a:b:c", ":");</code> will lead to
caseSensitive = aCaseSensitive;
exactMatch = anExactMatch;
- if (aSelectedFields==null)
+ if (aSelectedFields==null) {
selectedFields = null;
- else
+ }
+ else {
selectedFields = Arrays.asList(aSelectedFields);
+ }
}
}
break;
case ENTITY_FIELDS:
- if (selectedFields != null)
+ if (selectedFields != null) {
j = selectedFields.iterator();
- else
+ }
+ else {
j = anEntity.getFieldNames().iterator();
+ }
while (j.hasNext()) {
String field = anEntity.getFieldValue( (String) j.next());
import mir.entity.Entity;
import mir.entity.adapter.EntityAdapterModel;
import mir.log.LoggerWrapper;
+import mir.module.EntityNotFoundExc;
import mir.session.Request;
import mir.util.DateTimeRoutines;
import mir.util.EntityUtility;
import mir.util.GeneratorFormatAdapters;
-import mir.util.StringRoutines;
import mircoders.abuse.FilterEngine;
import mircoders.entity.EntityComment;
import mircoders.entity.EntityContent;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Date;
private boolean cookieOnBlock;
private String articleBlockAction;
private String commentBlockAction;
- private List log;
+ private final List log = new ArrayList();
private File configFile = MirGlobal.config().getFile("Abuse.Config");
private FilterEngine filterEngine;
filterEngine = new FilterEngine(aModel);
model = aModel;
- log = new ArrayList();
-
try {
configuration = MirPropertiesConfiguration.instance();
}
ModuleComment commentModule = new ModuleComment();
synchronized (log) {
- try {
- List result = new ArrayList();
+ List result = new ArrayList();
- Iterator i = log.iterator();
- while (i.hasNext()) {
- LogEntry logEntry = (LogEntry) i.next();
- Map entry = new HashMap();
+ Iterator i = log.iterator();
+ while (i.hasNext()) {
+ LogEntry logEntry = (LogEntry) i.next();
+ Map entry = new HashMap();
- entry.put("ip", logEntry.getIpNumber());
- entry.put("id", logEntry.getId());
- entry.put("timestamp", new GeneratorFormatAdapters.DateFormatAdapter(logEntry.getTimeStamp(), MirPropertiesConfiguration.instance().getString("Mir.DefaultTimezone")));
+ entry.put("ip", logEntry.getIpNumber());
+ entry.put("id", logEntry.getId());
+ entry.put("timestamp", new GeneratorFormatAdapters.DateFormatAdapter(logEntry.getTimeStamp(), MirPropertiesConfiguration.instance().getString("Mir.DefaultTimezone")));
- if (logEntry.getIsArticle()) {
- entry.put("type", "content");
+ if (logEntry.getIsArticle()) {
+ entry.put("type", "content");
+ try {
entry.put("object",
model.makeEntityAdapter("content", contentModule.getById(logEntry.getId())));
}
- else {
- entry.put("type", "comment");
+ catch (EntityNotFoundExc e) {
+ entry.put("object", null);
+ }
+ }
+ else {
+ entry.put("type", "comment");
+ try {
entry.put("object",
model.makeEntityAdapter("comment", commentModule.getById(logEntry.getId())));
}
-
- entry.put("browser", logEntry.getBrowserString());
- entry.put("filtertag", logEntry.getMatchingFilterTag());
-
- result.add(entry);
+ catch (EntityNotFoundExc e) {
+ entry.put("object", null);
+ }
}
- return result;
- }
- catch (Throwable t) {
- throw new RuntimeException(t.toString());
+ entry.put("browser", logEntry.getBrowserString());
+ entry.put("filtertag", logEntry.getMatchingFilterTag());
+
+ result.add(entry);
}
+
+ return result;
}
}
public synchronized void load() {
try {
- ExtendedProperties configuration = new ExtendedProperties();
-
- try {
- configuration = new ExtendedProperties(configFile.getAbsolutePath());
- }
- catch (FileNotFoundException e) {
- }
+ ExtendedProperties configuration = new ExtendedProperties(configFile.getAbsolutePath());
setOpenPostingDisabled(configuration.getString("abuse.openPostingDisabled", "0").equals("1"));
setOpenPostingPassword(configuration.getString("abuse.openPostingPassword", "0").equals("1"));
Iterator i = MirGlobal.localizer().adminInterface().simpleArticleOperations().iterator();
while (i.hasNext()) {
- MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =
- (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) i.next();
+ MirAdminInterfaceLocalizer.EntityOperation operation =
+ (MirAdminInterfaceLocalizer.EntityOperation) i.next();
Map action = new HashMap();
action.put("resource", operation.getName());
Iterator i = MirGlobal.localizer().adminInterface().simpleCommentOperations().iterator();
while (i.hasNext()) {
- MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =
- (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) i.next();
+ MirAdminInterfaceLocalizer.EntityOperation operation =
+ (MirAdminInterfaceLocalizer.EntityOperation) i.next();
Map action = new HashMap();
action.put("resource", operation.getName());
}
}
- private String escapeConfigListEntry(String aFilterPart) {
- return StringRoutines.replaceStringCharacters(aFilterPart,
- new char[] {'\\', ':'},
- new String[] {"\\\\", "\\:"});
- }
-
- private String escapeFilterPart(String aFilterPart) {
- return StringRoutines.replaceStringCharacters(aFilterPart,
- new char[] {'\\', '\n', '\r', '\t', ' '},
- new String[] {"\\\\", "\\n", "\\r", "\\t", "\\ "});
- }
-
- private String deescapeFilterPart(String aFilterPart) {
- return StringRoutines.replaceEscapedStringCharacters(aFilterPart,
- '\\',
- new char[] {'\\', ':', 'n', 'r', 't', ' '},
- new String[] {"\\", ":", "\n", "\r", "\t", " "});
- }
-
private static class LogEntry {
private String ipNumber;
private String browserString;
}
public static void performArticleOperation(EntityUsers aUser, EntityContent anArticle, String anOperation) {
- MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation = getArticleOperationForName(anOperation);
+ MirAdminInterfaceLocalizer.EntityOperation operation = getArticleOperationForName(anOperation);
try {
EntityAdapter user = null;
}
public static void performCommentOperation(EntityUsers aUser, EntityComment aComment, String anOperation) {
- MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation = getCommentOperationForName(anOperation);
+ MirAdminInterfaceLocalizer.EntityOperation operation = getCommentOperationForName(anOperation);
try {
EntityAdapter user = null;
}
}
- private synchronized static MirAdminInterfaceLocalizer.MirSimpleEntityOperation
+ private synchronized static MirAdminInterfaceLocalizer.EntityOperation
getArticleOperationForName(String aName) {
try {
if (articleOperations == null) {
articleOperations = new HashMap();
Iterator i = localizer().adminInterface().simpleArticleOperations().iterator();
while (i.hasNext()) {
- MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =
- (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) i.next();
+ MirAdminInterfaceLocalizer.EntityOperation operation =
+ (MirAdminInterfaceLocalizer.EntityOperation) i.next();
articleOperations.put(operation.getName(), operation);
}
}
- return (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) articleOperations.get(aName);
+ return (MirAdminInterfaceLocalizer.EntityOperation) articleOperations.get(aName);
}
catch (Throwable t) {
throw new MirGlobalFailure(t.getMessage(), t);
}
}
- private synchronized static MirAdminInterfaceLocalizer.MirSimpleEntityOperation
+ private synchronized static MirAdminInterfaceLocalizer.EntityOperation
getCommentOperationForName(String aName) {
try {
if (commentOperations == null) {
commentOperations = new HashMap();
Iterator i = localizer().adminInterface().simpleCommentOperations().iterator();
while (i.hasNext()) {
- MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =
- (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) i.next();
+ MirAdminInterfaceLocalizer.EntityOperation operation =
+ (MirAdminInterfaceLocalizer.EntityOperation) i.next();
commentOperations.put(operation.getName(), operation);
}
}
- return (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) commentOperations.get(aName);
+ return (MirAdminInterfaceLocalizer.EntityOperation) commentOperations.get(aName);
}
catch (Throwable t) {
throw new MirGlobalFailure(t.getMessage(), t);
public List getPreviewPages(EntityAdapter anArticle) throws MirLocalizerExc, MirLocalizerFailure;
/**
- * Get the {@link List} of {@link MirSimpleEntityOperation}s available for comments
+ * Get the {@link List} of {@link EntityOperation}s available for comments
*/
public List simpleCommentOperations();
/**
- * Get the {@link List} of {@link MirSimpleEntityOperation}s available for articles
+ * Get the {@link List} of {@link EntityOperation}s available for articles
*/
public List simpleArticleOperations();
- public interface MirSimpleEntityOperation {
+ public interface EntityOperation {
/**
* Returns the name of the operation. Must be unique and immutable.
*/
import mircoders.localizer.MirLocalizerExc;
import mircoders.localizer.MirLocalizerFailure;
import mircoders.module.ModuleLanguage;
+import mircoders.module.ModuleContent;
+import mircoders.module.ModuleComment;
import mircoders.storage.DatabaseContent;
addSimpleArticleOperation(new ChangeArticleFieldOperation("newswire", "to_article_type", "0", "1", false));
addSimpleArticleOperation(new ModifyArticleFieldOperation("unhide", "is_published", "1", false));
addSimpleArticleOperation(new ModifyArticleFieldOperation("hide", "is_published", "0", false));
+ addSimpleArticleOperation(new DeleteEntityOperation("delete"));
addSimpleCommentOperation(new ModifyCommentFieldOperation("unhide", "is_published", "1"));
addSimpleCommentOperation(new ModifyCommentFieldOperation("hide", "is_published", "0"));
+ addSimpleCommentOperation(new DeleteEntityOperation("delete"));
}
/** {@inheritDoc} */
- public String getAdminPageGenerator(String aPage, Map aTemplateData, EntityAdapter aUser, String aDefault) throws MirLocalizerExc {
+ public String getAdminPageGenerator(String aPage, Map aTemplateData, EntityAdapter aUser,
+ String aDefault) throws MirLocalizerExc {
return aDefault;
}
/** {@inheritDoc} */
- public Generator prepareArticlePreview(String aPreviewPage, EntityAdapter anArticle, Map aContext) throws MirLocalizerExc {
+ public Generator prepareArticlePreview(String aPreviewPage, EntityAdapter anArticle,
+ Map aContext) throws MirLocalizerExc {
MirGlobal.localizer().producerAssistant().initializeGenerationValueSet(aContext);
aContext.put("article", anArticle);
return Collections.unmodifiableList(simpleArticleOperations);
}
- public MirSimpleEntityOperation simpleArticleOperationForName(String aName) {
- return (MirSimpleEntityOperation) simpleArticleOperationsMap.get(aName);
+ public EntityOperation simpleArticleOperationForName(String aName) {
+ return (EntityOperation) simpleArticleOperationsMap.get(aName);
}
- public MirSimpleEntityOperation simpleCommentOperationForName(String aName) {
- return (MirSimpleEntityOperation) simpleCommentOperationsMap.get(aName);
+ public EntityOperation simpleCommentOperationForName(String aName) {
+ return (EntityOperation) simpleCommentOperationsMap.get(aName);
}
public void removeSimpleArticleOperation(String aName) {
simpleArticleOperationsMap.remove(aName);
}
- public void addSimpleArticleOperation(MirSimpleEntityOperation anOperation) {
+ public void addSimpleArticleOperation(EntityOperation anOperation) {
removeSimpleArticleOperation(anOperation.getName());
simpleArticleOperationsMap.put(anOperation.getName(), anOperation);
simpleArticleOperations.add(anOperation);
simpleCommentOperationsMap.remove(aName);
}
- public void addSimpleCommentOperation(MirSimpleEntityOperation anOperation) {
+ public void addSimpleCommentOperation(EntityOperation anOperation) {
removeSimpleCommentOperation(anOperation.getName());
simpleCommentOperationsMap.put(anOperation.getName(), anOperation);
simpleCommentOperations.add(anOperation);
}
- protected abstract static class EntityModifyingOperation implements MirSimpleEntityOperation {
+ protected abstract static class EntityModifyingOperation implements EntityOperation {
private String name;
private boolean logOperation;
anArticle.setFieldValue(field, newValue);
}
}
+
+ public static class DeleteEntityOperation implements EntityOperation {
+ private String name;
+ private ModuleContent content;
+ private ModuleComment comment;
+
+ public DeleteEntityOperation(String aName) {
+ name = aName;
+ comment = new ModuleComment();
+ content = new ModuleContent();
+ }
+
+ public String getName() {
+ return "delete";
+ }
+
+ public boolean isAvailable(EntityAdapter anEntity) throws MirLocalizerExc, MirLocalizerFailure {
+ return false;
+ }
+
+ public void perform(EntityAdapter aUser, EntityAdapter anEntity) throws MirLocalizerExc, MirLocalizerFailure {
+ Entity entity = anEntity.getEntity();
+ try {
+ if (entity instanceof EntityContent) {
+ content.deleteById(entity.getId());
+ }
+ else if (entity instanceof EntityComment) {
+ comment.deleteById(entity.getId());
+ }
+ }
+ catch (ModuleExc e) {
+ throw new MirLocalizerFailure(e);
+ }
+ }
+ }
}
List availableOperations = new ArrayList();
while (i.hasNext()) {
- MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =
- (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) i.next();
+ MirAdminInterfaceLocalizer.EntityOperation operation =
+ (MirAdminInterfaceLocalizer.EntityOperation) i.next();
if (operation.isAvailable(anEntityAdapter)) {
availableOperations.add(operation.getName());
import mircoders.abuse.RegularExpressionFilterType;
import mircoders.abuse.ThrottleFilter;
import mircoders.abuse.PostingSizeFilterType;
+import mircoders.abuse.URLBlacklistFilterType;
import mircoders.entity.EntityComment;
import mircoders.entity.EntityContent;
import mircoders.global.MirGlobal;
import java.util.List;
import java.util.Map;
import java.util.Random;
+import java.util.Arrays;
public class MirBasicOpenPostingLocalizer implements MirOpenPostingLocalizer {
private List afterContentProducerTasks;
RegularExpressionFilterType.REQUEST_HEADERS, new String[] {"hostname"}));
addSimpleAntiAbuseFilterType(new ThrottleFilter("throttle"));
addSimpleAntiAbuseFilterType(new PostingSizeFilterType("size"));
+ addSimpleAntiAbuseFilterType(new URLBlacklistFilterType("urlblacklist",
+ Arrays.asList(MirGlobal.config().getStringArray("Mir.URLBlacklistFilter.WhiteList"))));
}
public SessionHandler getOpenSessionHandler(String aSessionType) throws MirLocalizerExc, MirLocalizerFailure {
return StringRoutines.performRegularExpressionReplacement(aString, anExpression, aReplacement);
}
- public boolean regexpmatch(String aString, String anExpression) {
- return StringRoutines.performRegularExpressionSearch(aString, anExpression);
- }
}
import mircoders.localizer.basic.MirBasicAdminInterfaceLocalizer;
import mircoders.storage.DatabaseContentToTopics;
-public class ArticleTopicAction implements MirBasicAdminInterfaceLocalizer.MirSimpleEntityOperation{
+public class ArticleTopicAction implements MirBasicAdminInterfaceLocalizer.EntityOperation {
private String name;
private List deleteTopics;
private List addTopics;
* in the config file.
*
* @author $Author: zapata $
- * @version $Revision: 1.13.2.13 $ $Date: 2006/11/11 15:48:50 $
+ * @version $Revision: 1.13.2.14 $ $Date: 2006/12/25 20:10:23 $
*
*/
return result;
}
- public void list(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
- {
+ public void list(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
listSubDirectory(getDirectory(aRequest), "/", aRequest, aResponse);
}
- public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
- {
+ public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
try {
HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
/**
* Called when an edited file is saved by the user
*/
- public void update(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
- {
+ public void update(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc {
HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
String filename = requestParser.getParameter("filename");
String subDirectory = requestParser.getParameter("subdirectory");
<td>${l.ip}</td>
<td>
<if l.type=="content">
- <a href="${config.actionRoot}?module=Content&do=edit&id=${l.id}&returnurl=${utility.encodeURI(thisurl)}">Article</a>
+ <if l.object>
+ <a href="${config.actionRoot}?module=Content&do=edit&id=${l.id}&returnurl=${utility.encodeURI(thisurl)}">Article</a>
+ <else>
+ Article ${l.id} (no longer available)
+ </if>
<else>
- <a href="${config.actionRoot}?module=Comment&do=edit&id=${l.id}&returnurl=${utility.encodeURI(thisurl)}">Comment</a>
+ <if l.object>
+ <a href="${config.actionRoot}?module=Comment&do=edit&id=${l.id}&returnurl=${utility.encodeURI(thisurl)}">Comment</a>
+ <else>
+ Comment ${l.id} (no longer available)
+ </if>
</if>
</td>
<td>
- <if config["Mir.Localizer.Admin.ListOperationsFlavor"]=="0">
- <list l.object.operations as op>
- [ <a href="${config.actionRoot}?module=Localizer&do=operation&objectype=${l.type}&operation=${op}&id=${l.object.id}&returnurl=${utility.encodeURI(thisurl + "#" + l.object.id)}">${lang(l.type+".operation."+op)}</a> ]
- </list>
- </if>
- <if config["Mir.Localizer.Admin.ListOperationsFlavor"]=="1">
- <list l.object.operations as op>
- <input type="checkbox" name="operation" value="${l.type};${l.object.id};${op}">${lang(l.type+".operation."+op)}
- </list>
- </if>
- <if config["Mir.Localizer.Admin.ListOperationsFlavor"]=="2">
- <select name="operation">
- <option value="" selected> </option>
+ <if l.object>
+ <if config["Mir.Localizer.Admin.ListOperationsFlavor"]=="0">
+ <list l.object.operations as op>
+ [ <a href="${config.actionRoot}?module=Localizer&do=operation&objectype=${l.type}&operation=${op}&id=${l.object.id}&returnurl=${utility.encodeURI(thisurl + "#" + l.object.id)}">${lang(l.type+".operation."+op)}</a> ]
+ </list>
+ </if>
+ <if config["Mir.Localizer.Admin.ListOperationsFlavor"]=="1">
<list l.object.operations as op>
- <option value="${l.type};${l.object.id};${op}">${lang(l.type+".operation."+op)}</option>
+ <input type="checkbox" name="operation" value="${l.type};${l.object.id};${op}">${lang(l.type+".operation."+op)}
</list>
- </select>
+ </if>
+ <if config["Mir.Localizer.Admin.ListOperationsFlavor"]=="2">
+ <select name="operation">
+ <option value="" selected> </option>
+ <list l.object.operations as op>
+ <option value="${l.type};${l.object.id};${op}">${lang(l.type+".operation."+op)}</option>
+ </list>
+ </select>
+ </if>
</if>
</td>
<td>${utility.encodeHTML(l.browser)}</td>