Scarab commit: svn commit: r10748 - trunk/src: java/org/tigris/scarab/notification java/org/tigris/scarab/tools java/org/tigris/scarab/tools/localization webapp/WEB-INF/templates/email/notification

Hussayn Dabbous <[email protected]>
Newsgroups gmane.comp.java.scarab.cvs
Message-ID <[email protected]>
Author: dabbous
Date: 2009-06-03 16:13:23-0700
New Revision: 10748

Modified:
   trunk/src/java/org/tigris/scarab/notification/ActivityType.java
   trunk/src/java/org/tigris/scarab/notification/ScarabNewNotificationManager.java
   trunk/src/java/org/tigris/scarab/tools/ScarabLocalizationTool.java
   trunk/src/java/org/tigris/scarab/tools/localization/L10NKeySet.java
   trunk/src/webapp/WEB-INF/templates/email/notification/IssueActivitySubject.vm

Log:
SCB2893 started refactoring. Fixed a bug where sometimes the most significant notification was wrongly calulated. Added L10NKeys for the email subject. Significantly cleaned up code in NotificationManager. Still work in progress)

Modified: trunk/src/java/org/tigris/scarab/notification/ActivityType.java
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/java/org/tigris/scarab/notification/ActivityType.java?view=diff&pathrev=10748&r1=10747&r2=10748
==============================================================================
--- trunk/src/java/org/tigris/scarab/notification/ActivityType.java	(original)
+++ trunk/src/java/org/tigris/scarab/notification/ActivityType.java	2009-06-03 16:13:23-0700
@@ -4,31 +4,34 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.tigris.scarab.tools.localization.L10NKeySet;
+import org.tigris.scarab.tools.localization.LocalizationKey;
+
 public class ActivityType
 {
-    String code           = null;
-    String resourceId     = null;
-    String notificationId = null;
-    Integer notificationPriority      = null;
-    
-    public static final ActivityType ISSUE_CREATED = new ActivityType("issue_created","ActivityTypeIssueCreated", "NotificationIssueCreated", 17);
-    public static final ActivityType ISSUE_MOVED = new ActivityType("issue_moved","ActivityTypeIssueMoved", "NotificationIssueMoved", 16);
-    public static final ActivityType ISSUE_COPIED = new ActivityType("issue_copied","ActivityTypeIssueCopied", "NotificationIssueCopied", 15);
-    public static final ActivityType ISSUE_DELETED = new ActivityType("issue_deleted","ActivityTypeIssueDeleted", "NotificationIssueDeleted", 14);
-    public static final ActivityType COMMENT_ADDED = new ActivityType("comment_added","ActivityTypeCommentAdded", "NotificationCommentAdded", 13);
-    public static final ActivityType COMMENT_CHANGED = new ActivityType("comment_changed","ActivityTypeCommentChanged", "NotificationCommentChanged", 12);
-    public static final ActivityType ATTRIBUTE_CHANGED = new ActivityType("attribute_changed","ActivityTypeAttributeChanged", "NotificationAttributeChanged", 11);
-    public static final ActivityType USER_ATTRIBUTE_CHANGED = new ActivityType("user_attribute_changed","ActivityTypeUserAttributeChanged", "NotificationUserAttributeChanged", 10);
-    public static final ActivityType URL_ADDED = new ActivityType("url_added","ActivityTypeURLAdded", "NotificationURLAdded", 9);
-    public static final ActivityType URL_CHANGED = new ActivityType("url_changed","ActivityTypeURLChanged", "NotificationURLCHanged", 8);
-    public static final ActivityType URL_DESC_CHANGED = new ActivityType("url_desc_changed","ActivityTypeURLDescChanged", "NotificationURLDESCCHanged", 7);
-    public static final ActivityType URL_DELETED = new ActivityType("url_deleted","ActivityTypeURLDeleted", "NotificationURLDeleted", 6);
-    public static final ActivityType ATTACHMENT_CREATED = new ActivityType("attachment_created","ActivityTypeAttachmentCreated", "NotificationAttachmentCreated", 5);
-    public static final ActivityType ATTACHMENT_REMOVED = new ActivityType("attachment_removed","ActivityTypeAttachmentRemoved", "NotificationAttachmentRemoved", 4);
-    public static final ActivityType DEPENDENCY_CREATED = new ActivityType("dependency_created","ActivityTypeDependencyCreated", "NotificationDependencyCreated", 3);
-    public static final ActivityType DEPENDENCY_CHANGED = new ActivityType("dependency_changed","ActivityTypeDependencyChanged", "NotificationDependencyChanged", 2);
-    public static final ActivityType DEPENDENCY_DELETED = new ActivityType("dependency_deleted","ActivityTypeDependencyDeleted", "NotificationDependencyDeleted", 1);
-    public static final ActivityType OTHER = new ActivityType("other","ActivityTypeOther", "NotificationIssueOther", 0);
+    String code                     = null;
+    String resourceId               = null;
+    LocalizationKey notificationKey = null;
+    Integer notificationPriority    = null;
+    
+    public static final ActivityType ISSUE_CREATED      = new ActivityType("issue_created","ActivityTypeIssueCreated",           L10NKeySet.NotificationIssueCreated, 17);
+    public static final ActivityType ISSUE_MOVED        = new ActivityType("issue_moved","ActivityTypeIssueMoved",               L10NKeySet.NotificationIssueMoved, 16);
+    public static final ActivityType ISSUE_COPIED       = new ActivityType("issue_copied","ActivityTypeIssueCopied",             L10NKeySet.NotificationIssueCopied, 15);
+    public static final ActivityType ISSUE_DELETED      = new ActivityType("issue_deleted","ActivityTypeIssueDeleted",           L10NKeySet.NotificationIssueDeleted, 14);
+    public static final ActivityType ATTRIBUTE_CHANGED  = new ActivityType("attribute_changed","ActivityTypeAttributeChanged",   L10NKeySet.NotificationAttributeChanged, 13);
+    public static final ActivityType USER_ATTRIBUTE_CHANGED = new ActivityType("user_attribute_changed","ActivityTypeUserAttributeChanged", L10NKeySet.NotificationUserAttributeChanged, 12);
+    public static final ActivityType URL_ADDED          = new ActivityType("url_added","ActivityTypeURLAdded",                   L10NKeySet.NotificationURLAdded, 11);
+    public static final ActivityType URL_CHANGED        = new ActivityType("url_changed","ActivityTypeURLChanged",               L10NKeySet.NotificationURLCHanged, 10);
+    public static final ActivityType URL_DESC_CHANGED   = new ActivityType("url_desc_changed","ActivityTypeURLDescChanged",      L10NKeySet.NotificationURLDESCCHanged, 9);
+    public static final ActivityType URL_DELETED        = new ActivityType("url_deleted","ActivityTypeURLDeleted",               L10NKeySet.NotificationURLDeleted, 8);
+    public static final ActivityType ATTACHMENT_CREATED = new ActivityType("attachment_created","ActivityTypeAttachmentCreated", L10NKeySet.NotificationAttachmentCreated, 7);
+    public static final ActivityType ATTACHMENT_REMOVED = new ActivityType("attachment_removed","ActivityTypeAttachmentRemoved", L10NKeySet.NotificationAttachmentRemoved, 6);
+    public static final ActivityType DEPENDENCY_CREATED = new ActivityType("dependency_created","ActivityTypeDependencyCreated", L10NKeySet.NotificationDependencyCreated, 5);
+    public static final ActivityType DEPENDENCY_CHANGED = new ActivityType("dependency_changed","ActivityTypeDependencyChanged", L10NKeySet.NotificationDependencyChanged, 4);
+    public static final ActivityType DEPENDENCY_DELETED = new ActivityType("dependency_deleted","ActivityTypeDependencyDeleted", L10NKeySet.NotificationDependencyDeleted, 3);
+    public static final ActivityType COMMENT_ADDED      = new ActivityType("comment_added","ActivityTypeCommentAdded",           L10NKeySet.NotificationCommentAdded, 2);
+    public static final ActivityType COMMENT_CHANGED    = new ActivityType("comment_changed","ActivityTypeCommentChanged",       L10NKeySet.NotificationCommentChanged, 1);
+    public static final ActivityType OTHER              = new ActivityType("other","ActivityTypeOther",                          L10NKeySet.NotificationIssueOther, 0);
     
     private static Map types       = new HashMap();
     private static HashMap activityPriority;
@@ -59,8 +62,8 @@
      * Return the L10N Id for the Notification hint
      * @return
      */
-    public String getHint() {
-        return notificationId;
+    public LocalizationKey getNotificationKey() {
+        return notificationKey;
     }
     
     /**
@@ -100,11 +103,11 @@
         return this.code;
     }
    
-    private ActivityType(String desc, String resourceId, String notificationId, Integer notificationPriority)
+    private ActivityType(String desc, String resourceId, LocalizationKey notificationKey, Integer notificationPriority)
     {
         this.code = desc;
         this.resourceId = resourceId;
-        this.notificationId = notificationId;
+        this.notificationKey = notificationKey;
         this.notificationPriority = notificationPriority;
     }
     

Modified: trunk/src/java/org/tigris/scarab/notification/ScarabNewNotificationManager.java
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/java/org/tigris/scarab/notification/ScarabNewNotificationManager.java?view=diff&pathrev=10748&r1=10747&r2=10748
==============================================================================
--- trunk/src/java/org/tigris/scarab/notification/ScarabNewNotificationManager.java	(original)
+++ trunk/src/java/org/tigris/scarab/notification/ScarabNewNotificationManager.java	2009-06-03 16:13:23-0700
@@ -202,6 +202,7 @@
     {
         ScarabCache.clear();
         log.debug("sendPendingNotifications(): Collect pending notifications ...");
+        // It is now guaranteed, that the notifications arrive in order of CreationDate!
         List pending = NotificationStatusPeer.getPendingNotifications();
 
         if(pending == null)
@@ -215,22 +216,35 @@
         Map issueActivities                  = new HashMap(); 
         Map archiverActivities               = new HashMap();
         Set creators                         = new HashSet();
-        NotificationStatus firstNotification;
-        NotificationStatus lastNotification;
 
         //Process each Issue ...
         Iterator pendingIssuesIterator = pendingIssueMap.keySet().iterator();
+        int pendingIssueCount = pendingIssueMap.size();
+        int processedIssueCount = 0;
         while( pendingIssuesIterator.hasNext())
         {
             Issue issue = (Issue)pendingIssuesIterator.next();
-            String issueId = "???";
+            
+            String issueId;
+            try
+            {
+                issueId = issue.getUniqueId();
+            }
+            catch (TorqueException te)
+            {
+                log.error("sendPendingNotifications(): No access to Issue [" + te + "]");
+                // Can not proceed with this issue !
+                continue;
+            }
+                
+
             // clear volatile data structures ...
             issueActivities.clear();
             archiverActivities.clear();
             creators.clear();
-            firstNotification                     = null;
-            lastNotification                      = null;
-            Long issueTime                        = null;
+            
+            NotificationStatus firstNotification        = null;
+            NotificationStatus lastNotification         = null;
             NotificationStatus mostRelevantNotification = null;
             
             List notificationList = (List)pendingIssueMap.get(issue);
@@ -243,13 +257,14 @@
                 {
                     firstNotification = currentNotification;
                 }
-                lastNotification = currentNotification;
+                if(!it.hasNext())
+                {
+                    lastNotification = currentNotification;
+                }
 
                 mostRelevantNotification = getMostRelevantNotification(currentNotification, mostRelevantNotification, issue);
-                                
                 try
                 {
-                    issueId = issue.getUniqueId();
                     Integer receiverId = currentNotification.getReceiverId();
                     ScarabUser receiver = null;
                     if(receiverId.equals(Email.getArchiveUser().getUserId()))
@@ -265,11 +280,12 @@
                     Map userActivities = getActivitiesForUser(issueActivities, receiver);
                     addActivity(currentNotification, userActivities);
                     addActivity(currentNotification, archiverActivities);
-                    issueTime = adjustTimeToNewer(issueTime, currentNotification);
                 }
                 catch (TorqueException te)
                 {
-                    log.error("sendPendingNotifications(): " + te);
+                    log.error("sendPendingNotifications(): No access to current Scarab User" + te);
+                    // We can continue processing here. We just don't know how to process Emails
+                    // for the current user.
                 }
             }
             
@@ -279,8 +295,27 @@
              * issueActivities and send one E-Mail per receiver for this issue: 
              */
             
+            Long issueTime = lastNotification.getCreationDate().getTime();
             if (isOldEnough(issueTime))
             {
+                processedIssueCount += 1;
+                
+                // ===========================================================
+                // Determine the changeKey (l10n) for the most relevant notification 
+                // The resolved l10n key will appear in the subject line of the email!
+                // Note: If the key can not be resolved, the key itself will be 
+                // used as replacement without further notification! (to be changed in the future)
+                // ===========================================================
+                LocalizationKey changeKey;
+                if (isStatusNotification(mostRelevantNotification, issue))
+                {
+                    changeKey = getStatusKey(mostRelevantNotification, issue);
+                }
+                else
+                {
+                    changeKey = getNotificationKey(mostRelevantNotification, issue);
+                }
+                
                 log.debug("processing notifications for issue : ["+issueId+"]");
                 Iterator userIterator = getUsersToNotifyIterator(issueActivities);
                 while( userIterator.hasNext())
@@ -292,8 +327,9 @@
                     ectx.setLinkTool(new ScarabLink());
                     ectx.put("creators", creators);
                     ectx.put("firstNotification", firstNotification);
-                    ectx.put("lastNotification", lastNotification);
-                    ectx.put("changeHint",getChangeHint(mostRelevantNotification, issue));
+                    ectx.put("lastNotification", lastNotification);                    
+                    ectx.put("changeKey",changeKey);
+
                     ectx.put("cr", "\n"); // for email template to get a reliable Carriage return
 
                     Map groupedActivities = (Map) issueActivities.get(user);
@@ -322,45 +358,81 @@
             {
                 log.debug("Issue " + issueId + ": Is not old enough.");
             }
-        }    
-        log.debug("sendPendingNotifications(): ...finished!");
+        }
+        if(pendingIssueCount > 0)
+        {
+            log.info("sendPendingNotifications(): processed " + processedIssueCount + " of " + pendingIssueCount + " pending issues.");
+        }
+        else
+        {
+            log.debug("sendPendingNotifications(): nothing todo.");
+        }
     }
 
     
-    private Object getChangeHint(NotificationStatus notification, Issue issue) 
+    /**
+     * Return the L10NKey associated to the Attribute change.
+     * @param notification
+     * @param issue
+     * @return
+     */
+    private LocalizationKey getNotificationKey(NotificationStatus notification, Issue issue) 
     {
-        String result = null;
+        LocalizationKey result = null;
         ActivityType activityType = notification.getActivityType();
-        if(activityType.equals(ActivityType.ATTRIBUTE_CHANGED))
+        result = activityType.getNotificationKey();
+        return result;
+    }
+    
+    /**
+     * Return the L10NKey representation of the status value.
+     * Note: This method strongly assumes, that the given notification
+     * contains an Activity of type ATTRIBUTE_CHANGED and the contained
+     * attribute is expected to be a status-attribute. This method throws
+     * an exception, if these constraints are not fulfilled!
+     * In case of success, the method returns an L10N key. This key is currently
+     * not expected to be backed by an l10n resource. Please consider this
+     * as a preparation for a future enhancement, where it will become possible
+     * to define localized attribute values. For now the key is a verbatim copy of the
+     * attribute value.
+     * @param notification
+     * @param issue
+     * @return
+     */
+    private LocalizationKey getStatusKey(NotificationStatus notification, Issue issue) 
+    {
+        LocalizationKey result = null;
+        try
         {
-            try
+            Attribute attribute = notification.getActivity().getAttribute();
+            if (attribute == null || !getIsStatusAttribute(attribute, issue))
             {
-                Attribute attribute = notification.getActivity().getAttribute();
-                if (getIsStatusAttribute(attribute, issue))
-                {
-                    String name = attribute.getName();
-                    AttributeValue av = issue.getAttributeValue(name);
-                    if(av != null)
-                    {
-                        result = av.getValue();
-                    }
-                }
+                throw new IllegalArgumentException("Expected a notification containing a status attribute.");
             }
-            catch (TorqueException e)
+
+            String name = attribute.getName();
+            AttributeValue av = issue.getAttributeValue(name);
+            if(av != null)
             {
-                Log.get().warn("Database acess error while retrieving status attribute value.(ignored)");
-                Log.get().warn("db layer reported: ["+e.getMessage()+"]");
+                result = new L10NKey(av.getValue()); // interpret the value as a L10NKey (for future use!)
+            }
+            else
+            {
+                throw new IllegalArgumentException("Received a notification containing a status attribute without a given value.");
             }
         }
-        
-        if(result == null)
+        catch (TorqueException e)
         {
-            result = activityType.getHint();
+            Log.get().warn("Database acess error while retrieving status attribute value.(ignored)");
+            Log.get().warn("db layer reported: ["+e.getMessage()+"]");
         }
         
         return result;
     }
+    
+    
 
+     
 
     private NotificationStatus getMostRelevantNotification(
             NotificationStatus currentNotification,
@@ -400,15 +472,55 @@
         }
         else
         {
-            ActivityType mostRelevantActivityType = mostRelevantNotification.getActivityType();
-            if  (  currentActivityType.getPriority() > mostRelevantActivityType.getPriority() )
+            if( !isStatusNotification(mostRelevantNotification, issue))
             {
-                mostRelevantNotification = currentNotification;
+                ActivityType mostRelevantActivityType = mostRelevantNotification.getActivityType();
+                if  (  currentActivityType.getPriority() >= mostRelevantActivityType.getPriority() )
+                {
+                    mostRelevantNotification = currentNotification;
+                }
             }
         }
         return mostRelevantNotification;
     }
         
+    /**
+     * Tell if the notification contains a status-attribute.
+     * @param notification
+     * @param issue
+     * @return
+     */
+    private boolean isStatusNotification(NotificationStatus notification, Issue issue) 
+    {
+        boolean result = false;
+        {
+            ActivityType activityType = notification.getActivityType();
+            if(activityType.equals(ActivityType.ATTRIBUTE_CHANGED))
+            {
+                try
+                {
+                    Attribute attribute = notification.getActivity().getAttribute();
+                    if (getIsStatusAttribute(attribute, issue))
+                    {
+                        String name = attribute.getName();
+                        AttributeValue av = issue.getAttributeValue(name);
+                        if(av != null)
+                        {
+                            result = true;
+                        }
+                    }
+                }
+                catch (TorqueException e)
+                {
+                    Log.get().warn("Database acess error while retrieving status attribute value.(ignored)");
+                    Log.get().warn("db layer reported: ["+e.getMessage()+"]");
+                }
+            }
+        }
+        return result;
+    }
+
+
 
 
     /**
@@ -566,35 +678,6 @@
 
 
     /**
-     * @param notificationTime
-     * @param notification
-     */
-    private Long adjustTimeToNewer(Long notificationTime, NotificationStatus notification)
-    {
-        /**
-         * Keep the time of the younger notification for every issue
-         */
-        long newTime = notification.getCreationDate().getTime();
-        if (notificationTime == null)
-        {
-            notificationTime = new Long(newTime);
-        }
-        else
-        {
-            if (notificationTime.longValue() < newTime)
-            {
-                notificationTime = new Long(newTime);
-            }
-            else
-            {
-                // keep current notificationTime;
-            }
-        }
-        return notificationTime;
-    }
-
-
-    /**
      * @param issueActivities
      * @param user
      * @return

Modified: trunk/src/java/org/tigris/scarab/tools/ScarabLocalizationTool.java
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/java/org/tigris/scarab/tools/ScarabLocalizationTool.java?view=diff&pathrev=10748&r1=10747&r2=10748
==============================================================================
--- trunk/src/java/org/tigris/scarab/tools/ScarabLocalizationTool.java	(original)
+++ trunk/src/java/org/tigris/scarab/tools/ScarabLocalizationTool.java	2009-06-03 16:13:23-0700
@@ -143,8 +143,31 @@
      */
     public String get(Localizable key)
     {
+        return this.get(key, false);
+    }
+
+    
+    /**
+     * Return the localized property value.
+     * Take into account the Browser settings (in order of preference), 
+     * the Turbine default settings and the System Locale, 
+     * if the Turbine Default Locale is not defined.
+     * If ignoreMissingResource is set to true, return the resource key
+     * instead of throwing an exception. (Typically usefull from velocity)
+     */
+    public String get(Localizable key, boolean ignoreMissingResource)
+    {
         String theKey = key.toString();
-        return this.get(theKey);
+        String result;
+        if ( ignoreMissingResource )
+        {
+            result = this.getIgnoreMissingResource(theKey);
+        }
+        else
+        {
+            result = this.get(theKey);
+        }
+        return result;
     }
 
 
@@ -209,6 +232,9 @@
      */
     public String getIgnoreMissingResource(String key)
     {
+        // [HD]: I plan to make this method private.
+        // Currently it is only used from the OldNotificationManager,
+        // which IMHO can be silently removed from the project.
         String value;
         try
         {

Modified: trunk/src/java/org/tigris/scarab/tools/localization/L10NKeySet.java
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/java/org/tigris/scarab/tools/localization/L10NKeySet.java?view=diff&pathrev=10748&r1=10747&r2=10748
==============================================================================
--- trunk/src/java/org/tigris/scarab/tools/localization/L10NKeySet.java	(original)
+++ trunk/src/java/org/tigris/scarab/tools/localization/L10NKeySet.java	2009-06-03 16:13:23-0700
@@ -1,5 +1,7 @@
 package org.tigris.scarab.tools.localization;
 
+import org.tigris.scarab.notification.ActivityType;
+
 /* ================================================================
  * Copyright (c) 2000 CollabNet.  All rights reserved.
  * 
@@ -465,6 +467,26 @@
     public static final LocalizationKey ActivityComments = new L10NKey("ActivityComments");
     public static final LocalizationKey ActivityAssociatedInfo = new L10NKey("ActivityAssociatedInfo");
     public static final LocalizationKey ActivityDependencies = new L10NKey("ActivityDependencies");
+
+    public static final LocalizationKey NotificationIssueCreated          = new L10NKey("NotificationIssueCreated");
+    public static final LocalizationKey NotificationIssueMoved            = new L10NKey("NotificationIssueMoved");
+    public static final LocalizationKey NotificationIssueCopied           = new L10NKey("NotificationIssueCopied");
+    public static final LocalizationKey NotificationIssueDeleted          = new L10NKey("NotificationIssueDeleted");
+    public static final LocalizationKey NotificationAttributeChanged      = new L10NKey("NotificationAttributeChanged");
+    public static final LocalizationKey NotificationUserAttributeChanged  = new L10NKey("NotificationUserAttributeChanged");
+    public static final LocalizationKey NotificationURLAdded              = new L10NKey("NotificationURLAdded");
+    public static final LocalizationKey NotificationURLCHanged            = new L10NKey("NotificationURLCHanged");
+    public static final LocalizationKey NotificationURLDESCCHanged        = new L10NKey("NotificationURLDESCCHanged");
+    public static final LocalizationKey NotificationURLDeleted            = new L10NKey("NotificationURLDeleted");
+    public static final LocalizationKey NotificationAttachmentCreated     = new L10NKey("NotificationAttachmentCreated");
+    public static final LocalizationKey NotificationAttachmentRemoved     = new L10NKey("NotificationAttachmentRemoved");
+    public static final LocalizationKey NotificationDependencyCreated     = new L10NKey("NotificationDependencyCreated");
+    public static final LocalizationKey NotificationDependencyChanged     = new L10NKey("NotificationDependencyChanged");
+    public static final LocalizationKey NotificationDependencyDeleted     = new L10NKey("NotificationDependencyDeleted");
+    public static final LocalizationKey NotificationCommentAdded          = new L10NKey("NotificationCommentAdded");
+    public static final LocalizationKey NotificationCommentChanged        = new L10NKey("NotificationCommentChanged");
+    public static final LocalizationKey NotificationIssueOther            = new L10NKey("NotificationIssueOther");
+    
     public static final LocalizationKey IssueIsNowLocatedIn = new L10NKey("IssueIsNowLocatedIn");
     public static final LocalizationKey IssueIdNotValid = new L10NKey("IssueIdNotValid");
     public static final LocalizationKey NoPermissionToViewIssue = new L10NKey("NoPermissionToViewIssue");

Modified: trunk/src/webapp/WEB-INF/templates/email/notification/IssueActivitySubject.vm
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/webapp/WEB-INF/templates/email/notification/IssueActivitySubject.vm?view=diff&pathrev=10748&r1=10747&r2=10748
==============================================================================
--- trunk/src/webapp/WEB-INF/templates/email/notification/IssueActivitySubject.vm	(original)
+++ trunk/src/webapp/WEB-INF/templates/email/notification/IssueActivitySubject.vm	2009-06-03 16:13:23-0700
@@ -1 +1 @@
-#set ($args = [$issue.Module.RealName.toUpperCase(), $issue.UniqueId, $l10n.getIgnoreMissingResource($changeHint), $issue.defaultText]) $l10n.format("DefaultModifyIssueEmailSubject", $args)
\ No newline at end of file
+#set ($args = [$issue.Module.RealName.toUpperCase(), $issue.UniqueId, $l10n.get($changeKey, true), $issue.defaultText]) $l10n.format("DefaultModifyIssueEmailSubject", $args)

------------------------------------------------------
http://scarab.tigris.org/ds/viewMessage.do?dsForumId=3577&dsMessageId=2359255
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.